2 * Copyright 2001-2003 Ximian, Inc
3 * Copyright 2003-2010 Novell, Inc.
4 * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 #ifdef HAVE_SEMAPHORE_H
35 #include <semaphore.h>
49 #include "metadata/sgen-gc.h"
51 #define MAX_USER_DESCRIPTORS 16
53 #define MAKE_ROOT_DESC(type,val) ((type) | ((val) << ROOT_DESC_TYPE_SHIFT))
54 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
57 static gsize
* complex_descriptors
= NULL
;
58 static int complex_descriptors_size
= 0;
59 static int complex_descriptors_next
= 0;
60 static MonoGCRootMarkFunc user_descriptors
[MAX_USER_DESCRIPTORS
];
61 static int user_descriptors_next
= 0;
62 static void *all_ref_root_descrs
[32];
66 alloc_complex_descriptor (gsize
*bitmap
, int numbits
)
70 numbits
= ALIGN_TO (numbits
, GC_BITS_PER_WORD
);
71 nwords
= numbits
/ GC_BITS_PER_WORD
+ 1;
74 res
= complex_descriptors_next
;
75 /* linear search, so we don't have duplicates with domain load/unload
76 * this should not be performance critical or we'd have bigger issues
77 * (the number and size of complex descriptors should be small).
79 for (i
= 0; i
< complex_descriptors_next
; ) {
80 if (complex_descriptors
[i
] == nwords
) {
82 for (j
= 0; j
< nwords
- 1; ++j
) {
83 if (complex_descriptors
[i
+ 1 + j
] != bitmap
[j
]) {
89 mono_sgen_gc_unlock ();
93 i
+= complex_descriptors
[i
];
95 if (complex_descriptors_next
+ nwords
> complex_descriptors_size
) {
96 int new_size
= complex_descriptors_size
* 2 + nwords
;
97 complex_descriptors
= g_realloc (complex_descriptors
, new_size
* sizeof (gsize
));
98 complex_descriptors_size
= new_size
;
100 DEBUG (6, fprintf (gc_debug_file
, "Complex descriptor %d, size: %d (total desc memory: %d)\n", res
, nwords
, complex_descriptors_size
));
101 complex_descriptors_next
+= nwords
;
102 complex_descriptors
[res
] = nwords
;
103 for (i
= 0; i
< nwords
- 1; ++i
) {
104 complex_descriptors
[res
+ 1 + i
] = bitmap
[i
];
105 DEBUG (6, fprintf (gc_debug_file
, "\tvalue: %p\n", (void*)complex_descriptors
[res
+ 1 + i
]));
107 mono_sgen_gc_unlock ();
112 mono_sgen_get_complex_descriptor (mword desc
)
114 return complex_descriptors
+ (desc
>> LOW_TYPE_BITS
);
118 * Descriptor builders.
121 mono_gc_make_descr_for_string (gsize
*bitmap
, int numbits
)
123 return (void*) DESC_TYPE_RUN_LENGTH
;
127 mono_gc_make_descr_for_object (gsize
*bitmap
, int numbits
, size_t obj_size
)
129 int first_set
= -1, num_set
= 0, last_set
= -1, i
;
131 size_t stored_size
= obj_size
;
133 stored_size
+= SGEN_ALLOC_ALIGN
- 1;
134 stored_size
&= ~(SGEN_ALLOC_ALIGN
- 1);
136 for (i
= 0; i
< numbits
; ++i
) {
137 if (bitmap
[i
/ GC_BITS_PER_WORD
] & ((gsize
)1 << (i
% GC_BITS_PER_WORD
))) {
146 DEBUG (6, fprintf (gc_debug_file
, "Ptrfree descriptor %p, size: %zd\n", (void*)desc
, stored_size
));
147 if (stored_size
<= MAX_RUNLEN_OBJECT_SIZE
)
148 return (void*)(DESC_TYPE_RUN_LENGTH
| stored_size
);
149 return (void*)DESC_TYPE_COMPLEX_PTRFREE
;
152 g_assert (!(stored_size
& 0x7));
154 if (stored_size
<= MAX_RUNLEN_OBJECT_SIZE
) {
155 /* check run-length encoding first: one byte offset, one byte number of pointers
156 * on 64 bit archs, we can have 3 runs, just one on 32.
157 * It may be better to use nibbles.
159 if (first_set
< 256 && num_set
< 256 && (first_set
+ num_set
== last_set
+ 1)) {
160 desc
= DESC_TYPE_RUN_LENGTH
| stored_size
| (first_set
<< 16) | (num_set
<< 24);
161 DEBUG (6, fprintf (gc_debug_file
, "Runlen descriptor %p, size: %zd, first set: %d, num set: %d\n", (void*)desc
, stored_size
, first_set
, num_set
));
166 /* we know the 2-word header is ptr-free */
167 if (last_set
< SMALL_BITMAP_SIZE
+ OBJECT_HEADER_WORDS
) {
168 desc
= DESC_TYPE_SMALL_BITMAP
| stored_size
| ((*bitmap
>> OBJECT_HEADER_WORDS
) << SMALL_BITMAP_SHIFT
);
169 DEBUG (6, fprintf (gc_debug_file
, "Smallbitmap descriptor %p, size: %zd, last set: %d\n", (void*)desc
, stored_size
, last_set
));
173 /* we know the 2-word header is ptr-free */
174 if (last_set
< LARGE_BITMAP_SIZE
+ OBJECT_HEADER_WORDS
) {
175 desc
= DESC_TYPE_LARGE_BITMAP
| ((*bitmap
>> OBJECT_HEADER_WORDS
) << LOW_TYPE_BITS
);
176 DEBUG (6, fprintf (gc_debug_file
, "Largebitmap descriptor %p, size: %zd, last set: %d\n", (void*)desc
, stored_size
, last_set
));
179 /* it's a complex object ... */
180 desc
= DESC_TYPE_COMPLEX
| (alloc_complex_descriptor (bitmap
, last_set
+ 1) << LOW_TYPE_BITS
);
184 /* If the array holds references, numbits == 1 and the first bit is set in elem_bitmap */
186 mono_gc_make_descr_for_array (int vector
, gsize
*elem_bitmap
, int numbits
, size_t elem_size
)
188 int first_set
= -1, num_set
= 0, last_set
= -1, i
;
189 mword desc
= DESC_TYPE_VECTOR
| (vector
? VECTOR_KIND_SZARRAY
: VECTOR_KIND_ARRAY
);
190 for (i
= 0; i
< numbits
; ++i
) {
191 if (elem_bitmap
[i
/ GC_BITS_PER_WORD
] & ((gsize
)1 << (i
% GC_BITS_PER_WORD
))) {
200 if (elem_size
<= MAX_ELEMENT_SIZE
)
201 return (void*)(desc
| VECTOR_SUBTYPE_PTRFREE
| (elem_size
<< VECTOR_ELSIZE_SHIFT
));
202 return (void*)DESC_TYPE_COMPLEX_PTRFREE
;
205 if (elem_size
<= MAX_ELEMENT_SIZE
) {
206 desc
|= elem_size
<< VECTOR_ELSIZE_SHIFT
;
208 return (void*)(desc
| VECTOR_SUBTYPE_PTRFREE
);
210 /* Note: we also handle structs with just ref fields */
211 if (num_set
* sizeof (gpointer
) == elem_size
) {
212 return (void*)(desc
| VECTOR_SUBTYPE_REFS
| ((gssize
)(-1) << 16));
214 /* FIXME: try run-len first */
215 /* Note: we can't skip the object header here, because it's not present */
216 if (last_set
<= SMALL_BITMAP_SIZE
) {
217 return (void*)(desc
| VECTOR_SUBTYPE_BITMAP
| (*elem_bitmap
<< 16));
220 /* it's am array of complex structs ... */
221 desc
= DESC_TYPE_COMPLEX_ARR
;
222 desc
|= alloc_complex_descriptor (elem_bitmap
, last_set
+ 1) << LOW_TYPE_BITS
;
226 /* Return the bitmap encoded by a descriptor */
228 mono_gc_get_bitmap_for_descr (void *descr
, int *numbits
)
230 mword d
= (mword
)descr
;
234 case DESC_TYPE_RUN_LENGTH
: {
235 int first_set
= (d
>> 16) & 0xff;
236 int num_set
= (d
>> 24) & 0xff;
239 bitmap
= g_new0 (gsize
, (first_set
+ num_set
+ 7) / 8);
241 for (i
= first_set
; i
< first_set
+ num_set
; ++i
)
242 bitmap
[i
/ GC_BITS_PER_WORD
] |= ((gsize
)1 << (i
% GC_BITS_PER_WORD
));
244 *numbits
= first_set
+ num_set
;
249 case DESC_TYPE_SMALL_BITMAP
:
250 bitmap
= g_new0 (gsize
, 1);
252 bitmap
[0] = (d
>> SMALL_BITMAP_SHIFT
) << OBJECT_HEADER_WORDS
;
254 *numbits
= GC_BITS_PER_WORD
;
257 case DESC_TYPE_LARGE_BITMAP
: {
258 gsize bmap
= (d
>> LOW_TYPE_BITS
) << OBJECT_HEADER_WORDS
;
260 bitmap
= g_new0 (gsize
, 1);
270 g_assert_not_reached ();
275 mono_gc_make_descr_from_bitmap (gsize
*bitmap
, int numbits
)
278 return (void*)MAKE_ROOT_DESC (ROOT_DESC_BITMAP
, 0);
279 } else if (numbits
< ((sizeof (*bitmap
) * 8) - ROOT_DESC_TYPE_SHIFT
)) {
280 return (void*)MAKE_ROOT_DESC (ROOT_DESC_BITMAP
, bitmap
[0]);
282 mword
complex = alloc_complex_descriptor (bitmap
, numbits
);
283 return (void*)MAKE_ROOT_DESC (ROOT_DESC_COMPLEX
, complex);
288 mono_gc_make_root_descr_all_refs (int numbits
)
292 int num_bytes
= numbits
/ 8;
294 if (numbits
< 32 && all_ref_root_descrs
[numbits
])
295 return all_ref_root_descrs
[numbits
];
297 gc_bitmap
= g_malloc0 (ALIGN_TO (ALIGN_TO (numbits
, 8) + 1, sizeof (gsize
)));
298 memset (gc_bitmap
, 0xff, num_bytes
);
299 if (numbits
< ((sizeof (*gc_bitmap
) * 8) - ROOT_DESC_TYPE_SHIFT
))
300 gc_bitmap
[0] = GUINT64_TO_LE(gc_bitmap
[0]);
301 else if (numbits
&& num_bytes
% (sizeof (*gc_bitmap
)))
302 gc_bitmap
[num_bytes
/ 8] = GUINT64_TO_LE(gc_bitmap
[num_bytes
/ 8]);
304 gc_bitmap
[numbits
/ 8] = (1 << (numbits
% 8)) - 1;
305 descr
= mono_gc_make_descr_from_bitmap (gc_bitmap
, numbits
);
309 all_ref_root_descrs
[numbits
] = descr
;
315 mono_gc_make_root_descr_user (MonoGCRootMarkFunc marker
)
319 g_assert (user_descriptors_next
< MAX_USER_DESCRIPTORS
);
320 descr
= (void*)MAKE_ROOT_DESC (ROOT_DESC_USER
, (mword
)user_descriptors_next
);
321 user_descriptors
[user_descriptors_next
++] = marker
;
327 mono_sgen_get_complex_descriptor_bitmap (mword desc
)
329 return complex_descriptors
+ (desc
>> ROOT_DESC_TYPE_SHIFT
);
333 mono_sgen_get_user_descriptor_func (mword desc
)
335 return user_descriptors
[desc
>> ROOT_DESC_TYPE_SHIFT
];