do not check order sequence if option /order was not used
[mono.git] / mono / metadata / sgen-descriptor.c
1 /*
2  * Copyright 2001-2003 Ximian, Inc
3  * Copyright 2003-2010 Novell, Inc.
4  * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
5  * 
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:
13  * 
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  * 
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.
24  */
25 #include "config.h"
26 #ifdef HAVE_SGEN_GC
27
28 #ifdef HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif
31 #ifdef HAVE_PTHREAD_H
32 #include <pthread.h>
33 #endif
34 #ifdef HAVE_SEMAPHORE_H
35 #include <semaphore.h>
36 #endif
37 #include <stdio.h>
38 #include <string.h>
39 #include <signal.h>
40 #include <errno.h>
41 #include <assert.h>
42 #ifdef __MACH__
43 #undef _XOPEN_SOURCE
44 #endif
45 #ifdef __MACH__
46 #define _XOPEN_SOURCE
47 #endif
48
49 #include "metadata/sgen-gc.h"
50
51 #define MAX_USER_DESCRIPTORS 16
52
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))
55
56
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];
63
64
65 static int
66 alloc_complex_descriptor (gsize *bitmap, int numbits)
67 {
68         int nwords, res, i;
69
70         numbits = ALIGN_TO (numbits, GC_BITS_PER_WORD);
71         nwords = numbits / GC_BITS_PER_WORD + 1;
72
73         sgen_gc_lock ();
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).
78          */
79         for (i = 0; i < complex_descriptors_next; ) {
80                 if (complex_descriptors [i] == nwords) {
81                         int j, found = TRUE;
82                         for (j = 0; j < nwords - 1; ++j) {
83                                 if (complex_descriptors [i + 1 + j] != bitmap [j]) {
84                                         found = FALSE;
85                                         break;
86                                 }
87                         }
88                         if (found) {
89                                 sgen_gc_unlock ();
90                                 return i;
91                         }
92                 }
93                 i += complex_descriptors [i];
94         }
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;
99         }
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]));
106         }
107         sgen_gc_unlock ();
108         return res;
109 }
110
111 gsize*
112 sgen_get_complex_descriptor (mword desc)
113 {
114         return complex_descriptors + (desc >> LOW_TYPE_BITS);
115 }
116
117 /*
118  * Descriptor builders.
119  */
120 void*
121 mono_gc_make_descr_for_string (gsize *bitmap, int numbits)
122 {
123         return (void*) DESC_TYPE_RUN_LENGTH;
124 }
125
126 void*
127 mono_gc_make_descr_for_object (gsize *bitmap, int numbits, size_t obj_size)
128 {
129         int first_set = -1, num_set = 0, last_set = -1, i;
130         mword desc = 0;
131         size_t stored_size = obj_size;
132
133         stored_size += SGEN_ALLOC_ALIGN - 1;
134         stored_size &= ~(SGEN_ALLOC_ALIGN - 1);
135
136         for (i = 0; i < numbits; ++i) {
137                 if (bitmap [i / GC_BITS_PER_WORD] & ((gsize)1 << (i % GC_BITS_PER_WORD))) {
138                         if (first_set < 0)
139                                 first_set = i;
140                         last_set = i;
141                         num_set++;
142                 }
143         }
144
145         if (first_set < 0) {
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;
150         }
151
152         g_assert (!(stored_size & 0x7));
153
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.
158                  */
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));
162                         return (void*) desc;
163                 }
164         }
165
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));
170                 return (void*) desc;
171         }
172
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));
177                 return (void*) desc;
178         }
179         /* it's a complex object ... */
180         desc = DESC_TYPE_COMPLEX | (alloc_complex_descriptor (bitmap, last_set + 1) << LOW_TYPE_BITS);
181         return (void*) desc;
182 }
183
184 /* If the array holds references, numbits == 1 and the first bit is set in elem_bitmap */
185 void*
186 mono_gc_make_descr_for_array (int vector, gsize *elem_bitmap, int numbits, size_t elem_size)
187 {
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))) {
192                         if (first_set < 0)
193                                 first_set = i;
194                         last_set = i;
195                         num_set++;
196                 }
197         }
198
199         if (first_set < 0) {
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;
203         }
204
205         if (elem_size <= MAX_ELEMENT_SIZE) {
206                 desc |= elem_size << VECTOR_ELSIZE_SHIFT;
207                 if (!num_set) {
208                         return (void*)(desc | VECTOR_SUBTYPE_PTRFREE);
209                 }
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));
213                 }
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));
218                 }
219         }
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;
223         return (void*) desc;
224 }
225
226 /* Return the bitmap encoded by a descriptor */
227 gsize*
228 mono_gc_get_bitmap_for_descr (void *descr, int *numbits)
229 {
230         mword d = (mword)descr;
231         gsize *bitmap;
232
233         switch (d & 0x7) {
234         case DESC_TYPE_RUN_LENGTH: {            
235                 int first_set = (d >> 16) & 0xff;
236                 int num_set = (d >> 24) & 0xff;
237                 int i;
238
239                 bitmap = g_new0 (gsize, (first_set + num_set + 7) / 8);
240
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));
243
244                 *numbits = first_set + num_set;
245
246                 return bitmap;
247         }
248
249         case DESC_TYPE_SMALL_BITMAP:
250                 bitmap = g_new0 (gsize, 1);
251
252                 bitmap [0] = (d >> SMALL_BITMAP_SHIFT) << OBJECT_HEADER_WORDS;
253
254                 *numbits = GC_BITS_PER_WORD;
255                 return bitmap;
256
257         case DESC_TYPE_LARGE_BITMAP: {
258                 gsize bmap = (d >> LOW_TYPE_BITS) << OBJECT_HEADER_WORDS;
259
260                 bitmap = g_new0 (gsize, 1);
261                 bitmap [0] = bmap;
262                 *numbits = 0;
263                 while (bmap) {
264                         (*numbits) ++;
265                         bmap >>= 1;
266                 }
267                 return bitmap;
268         }
269
270         case DESC_TYPE_COMPLEX: {
271                 gsize *bitmap_data = sgen_get_complex_descriptor (d);
272                 int bwords = (*bitmap_data) - 1;
273                 int i;
274
275                 bitmap = g_new0 (gsize, bwords);
276                 *numbits = bwords * GC_BITS_PER_WORD;
277
278                 for (i = 0; i < bwords; ++i) {
279                         bitmap [i] = bitmap_data [i + 1];
280                 }
281
282                 return bitmap;
283         }
284
285         default:
286                 g_assert_not_reached ();
287         }
288 }
289
290 void*
291 mono_gc_make_descr_from_bitmap (gsize *bitmap, int numbits)
292 {
293         if (numbits == 0) {
294                 return (void*)MAKE_ROOT_DESC (ROOT_DESC_BITMAP, 0);
295         } else if (numbits < ((sizeof (*bitmap) * 8) - ROOT_DESC_TYPE_SHIFT)) {
296                 return (void*)MAKE_ROOT_DESC (ROOT_DESC_BITMAP, bitmap [0]);
297         } else {
298                 mword complex = alloc_complex_descriptor (bitmap, numbits);
299                 return (void*)MAKE_ROOT_DESC (ROOT_DESC_COMPLEX, complex);
300         }
301 }
302
303 void*
304 mono_gc_make_root_descr_all_refs (int numbits)
305 {
306         gsize *gc_bitmap;
307         void *descr;
308         int num_bytes = numbits / 8;
309
310         if (numbits < 32 && all_ref_root_descrs [numbits])
311                 return all_ref_root_descrs [numbits];
312
313         gc_bitmap = g_malloc0 (ALIGN_TO (ALIGN_TO (numbits, 8) + 1, sizeof (gsize)));
314         memset (gc_bitmap, 0xff, num_bytes);
315         if (numbits < ((sizeof (*gc_bitmap) * 8) - ROOT_DESC_TYPE_SHIFT)) 
316                 gc_bitmap[0] = GUINT64_TO_LE(gc_bitmap[0]);
317         else if (numbits && num_bytes % (sizeof (*gc_bitmap)))
318                 gc_bitmap[num_bytes / 8] = GUINT64_TO_LE(gc_bitmap [num_bytes / 8]);
319         if (numbits % 8)
320                 gc_bitmap [numbits / 8] = (1 << (numbits % 8)) - 1;
321         descr = mono_gc_make_descr_from_bitmap (gc_bitmap, numbits);
322         g_free (gc_bitmap);
323
324         if (numbits < 32)
325                 all_ref_root_descrs [numbits] = descr;
326
327         return descr;
328 }
329
330 void*
331 mono_gc_make_root_descr_user (MonoGCRootMarkFunc marker)
332 {
333         void *descr;
334
335         g_assert (user_descriptors_next < MAX_USER_DESCRIPTORS);
336         descr = (void*)MAKE_ROOT_DESC (ROOT_DESC_USER, (mword)user_descriptors_next);
337         user_descriptors [user_descriptors_next ++] = marker;
338
339         return descr;
340 }
341
342 void*
343 sgen_get_complex_descriptor_bitmap (mword desc)
344 {
345         return complex_descriptors + (desc >> ROOT_DESC_TYPE_SHIFT);
346 }
347
348 MonoGCRootMarkFunc
349 sgen_get_user_descriptor_func (mword desc)
350 {
351         return user_descriptors [desc >> ROOT_DESC_TYPE_SHIFT];
352 }
353
354 #endif