[sgen] Make sure we will scan the bits correctly for complex objects
[mono.git] / mono / sgen / sgen-descriptor.c
1 /*
2  * sgen-descriptor.c: GC descriptors describe object layout.
3  *
4  * Copyright 2001-2003 Ximian, Inc
5  * Copyright 2003-2010 Novell, Inc.
6  * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
7  * Copyright (C) 2012 Xamarin Inc
8  *
9  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
10  */
11 #include "config.h"
12 #ifdef HAVE_SGEN_GC
13
14 #ifdef HAVE_UNISTD_H
15 #include <unistd.h>
16 #endif
17 #ifdef HAVE_PTHREAD_H
18 #include <pthread.h>
19 #endif
20 #ifdef HAVE_SEMAPHORE_H
21 #include <semaphore.h>
22 #endif
23 #include <stdio.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <assert.h>
27 #ifdef __MACH__
28 #undef _XOPEN_SOURCE
29 #endif
30 #ifdef __MACH__
31 #define _XOPEN_SOURCE
32 #endif
33
34 #include "mono/sgen/sgen-gc.h"
35 #include "mono/sgen/gc-internal-agnostic.h"
36
37 #define MAX_USER_DESCRIPTORS 16
38
39 #define MAKE_ROOT_DESC(type,val) ((type) | ((val) << ROOT_DESC_TYPE_SHIFT))
40 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
41
42
43 static gsize* complex_descriptors = NULL;
44 static int complex_descriptors_size = 0;
45 static int complex_descriptors_next = 0;
46 static SgenUserRootMarkFunc user_descriptors [MAX_USER_DESCRIPTORS];
47 static int user_descriptors_next = 0;
48 static SgenDescriptor all_ref_root_descrs [32];
49
50 #ifdef HEAVY_STATISTICS
51 static guint64 stat_scanned_count_per_descriptor [DESC_TYPE_MAX];
52 static guint64 stat_copied_count_per_descriptor [DESC_TYPE_MAX];
53 #endif
54
55 static int
56 alloc_complex_descriptor (gsize *bitmap, int numbits)
57 {
58         int nwords, res, i;
59
60         SGEN_ASSERT (0, sizeof (gsize) == sizeof (mword), "We expect gsize and mword to have same size");
61
62         numbits = ALIGN_TO (numbits, GC_BITS_PER_WORD);
63         nwords = numbits / GC_BITS_PER_WORD + 1;
64
65         sgen_gc_lock ();
66         res = complex_descriptors_next;
67         /* linear search, so we don't have duplicates with domain load/unload
68          * this should not be performance critical or we'd have bigger issues
69          * (the number and size of complex descriptors should be small).
70          */
71         for (i = 0; i < complex_descriptors_next; ) {
72                 if (complex_descriptors [i] == nwords) {
73                         int j, found = TRUE;
74                         for (j = 0; j < nwords - 1; ++j) {
75                                 if (complex_descriptors [i + 1 + j] != bitmap [j]) {
76                                         found = FALSE;
77                                         break;
78                                 }
79                         }
80                         if (found) {
81                                 sgen_gc_unlock ();
82                                 return i;
83                         }
84                 }
85                 i += (int)complex_descriptors [i];
86         }
87         if (complex_descriptors_next + nwords > complex_descriptors_size) {
88                 int new_size = complex_descriptors_size * 2 + nwords;
89                 complex_descriptors = (gsize *)g_realloc (complex_descriptors, new_size * sizeof (gsize));
90                 complex_descriptors_size = new_size;
91         }
92         SGEN_LOG (6, "Complex descriptor %d, size: %d (total desc memory: %d)", res, nwords, complex_descriptors_size);
93         complex_descriptors_next += nwords;
94         complex_descriptors [res] = nwords;
95         for (i = 0; i < nwords - 1; ++i) {
96                 complex_descriptors [res + 1 + i] = bitmap [i];
97                 SGEN_LOG (6, "\tvalue: %p", (void*)complex_descriptors [res + 1 + i]);
98         }
99         sgen_gc_unlock ();
100         return res;
101 }
102
103 gsize*
104 sgen_get_complex_descriptor (SgenDescriptor desc)
105 {
106         return complex_descriptors + (desc >> LOW_TYPE_BITS);
107 }
108
109 /*
110  * Descriptor builders.
111  */
112 SgenDescriptor
113 mono_gc_make_descr_for_object (gsize *bitmap, int numbits, size_t obj_size)
114 {
115         int first_set = -1, num_set = 0, last_set = -1, i;
116         SgenDescriptor desc = 0;
117         size_t stored_size = SGEN_ALIGN_UP (obj_size);
118
119         for (i = 0; i < numbits; ++i) {
120                 if (bitmap [i / GC_BITS_PER_WORD] & ((gsize)1 << (i % GC_BITS_PER_WORD))) {
121                         if (first_set < 0)
122                                 first_set = i;
123                         last_set = i;
124                         num_set++;
125                 }
126         }
127
128         if (first_set < 0) {
129                 SGEN_LOG (6, "Ptrfree descriptor %p, size: %zd", (void*)desc, stored_size);
130                 if (stored_size <= MAX_RUNLEN_OBJECT_SIZE && stored_size <= SGEN_MAX_SMALL_OBJ_SIZE)
131                         return DESC_TYPE_SMALL_PTRFREE | stored_size;
132                 return DESC_TYPE_COMPLEX_PTRFREE;
133         }
134
135         g_assert (!(stored_size & 0x7));
136
137         SGEN_ASSERT (5, stored_size == SGEN_ALIGN_UP (stored_size), "Size is not aligned");
138
139         /* we know the 2-word header is ptr-free */
140         if (last_set < BITMAP_NUM_BITS + OBJECT_HEADER_WORDS && stored_size <= SGEN_MAX_SMALL_OBJ_SIZE) {
141                 desc = DESC_TYPE_BITMAP | ((*bitmap >> OBJECT_HEADER_WORDS) << LOW_TYPE_BITS);
142                 SGEN_LOG (6, "Largebitmap descriptor %p, size: %zd, last set: %d", (void*)desc, stored_size, last_set);
143                 return desc;
144         }
145
146         if (stored_size <= MAX_RUNLEN_OBJECT_SIZE && stored_size <= SGEN_MAX_SMALL_OBJ_SIZE) {
147                 /* check run-length encoding first: one byte offset, one byte number of pointers
148                  * on 64 bit archs, we can have 3 runs, just one on 32.
149                  * It may be better to use nibbles.
150                  */
151                 if (first_set < 256 && num_set < 256 && (first_set + num_set == last_set + 1)) {
152                         desc = DESC_TYPE_RUN_LENGTH | stored_size | (first_set << 16) | (num_set << 24);
153                         SGEN_LOG (6, "Runlen descriptor %p, size: %zd, first set: %d, num set: %d", (void*)desc, stored_size, first_set, num_set);
154                         return desc;
155                 }
156         }
157
158         /* it's a complex object ... */
159         desc = DESC_TYPE_COMPLEX | (alloc_complex_descriptor (bitmap, last_set + 1) << LOW_TYPE_BITS);
160         return desc;
161 }
162
163 /* If the array holds references, numbits == 1 and the first bit is set in elem_bitmap */
164 SgenDescriptor
165 mono_gc_make_descr_for_array (int vector, gsize *elem_bitmap, int numbits, size_t elem_size)
166 {
167         int first_set = -1, num_set = 0, last_set = -1, i;
168         SgenDescriptor desc = DESC_TYPE_VECTOR | (vector ? VECTOR_KIND_SZARRAY : VECTOR_KIND_ARRAY);
169         for (i = 0; i < numbits; ++i) {
170                 if (elem_bitmap [i / GC_BITS_PER_WORD] & ((gsize)1 << (i % GC_BITS_PER_WORD))) {
171                         if (first_set < 0)
172                                 first_set = i;
173                         last_set = i;
174                         num_set++;
175                 }
176         }
177
178         if (first_set < 0) {
179                 if (elem_size <= MAX_ELEMENT_SIZE)
180                         return desc | VECTOR_SUBTYPE_PTRFREE | (elem_size << VECTOR_ELSIZE_SHIFT);
181                 return DESC_TYPE_COMPLEX_PTRFREE;
182         }
183
184         if (elem_size <= MAX_ELEMENT_SIZE) {
185                 desc |= elem_size << VECTOR_ELSIZE_SHIFT;
186                 if (!num_set) {
187                         return desc | VECTOR_SUBTYPE_PTRFREE;
188                 }
189                 /* Note: we also handle structs with just ref fields */
190                 if (num_set * sizeof (gpointer) == elem_size) {
191                         return desc | VECTOR_SUBTYPE_REFS | ((gsize)(-1) << 16);
192                 }
193                 /* FIXME: try run-len first */
194                 /* Note: we can't skip the object header here, because it's not present */
195                 if (last_set < VECTOR_BITMAP_SIZE) {
196                         return desc | VECTOR_SUBTYPE_BITMAP | (*elem_bitmap << 16);
197                 }
198         }
199         /* it's am array of complex structs ... */
200         desc = DESC_TYPE_COMPLEX_ARR;
201         desc |= alloc_complex_descriptor (elem_bitmap, last_set + 1) << LOW_TYPE_BITS;
202         return desc;
203 }
204
205 /* Return the bitmap encoded by a descriptor */
206 gsize*
207 mono_gc_get_bitmap_for_descr (SgenDescriptor descr, int *numbits)
208 {
209         SgenDescriptor d = (SgenDescriptor)descr;
210         gsize *bitmap;
211
212         switch (d & DESC_TYPE_MASK) {
213         case DESC_TYPE_RUN_LENGTH: {            
214                 int first_set = (d >> 16) & 0xff;
215                 int num_set = (d >> 24) & 0xff;
216                 int i;
217
218                 bitmap = g_new0 (gsize, (first_set + num_set + 7) / 8);
219
220                 for (i = first_set; i < first_set + num_set; ++i)
221                         bitmap [i / GC_BITS_PER_WORD] |= ((gsize)1 << (i % GC_BITS_PER_WORD));
222
223                 *numbits = first_set + num_set;
224
225                 return bitmap;
226         }
227
228         case DESC_TYPE_BITMAP: {
229                 gsize bmap = (d >> LOW_TYPE_BITS) << OBJECT_HEADER_WORDS;
230
231                 bitmap = g_new0 (gsize, 1);
232                 bitmap [0] = bmap;
233                 *numbits = 0;
234                 while (bmap) {
235                         (*numbits) ++;
236                         bmap >>= 1;
237                 }
238                 return bitmap;
239         }
240
241         case DESC_TYPE_COMPLEX: {
242                 gsize *bitmap_data = sgen_get_complex_descriptor (d);
243                 int bwords = (int)(*bitmap_data) - 1;//Max scalar object size is 1Mb, which means up to 32k descriptor words
244                 int i;
245
246                 bitmap = g_new0 (gsize, bwords);
247                 *numbits = bwords * GC_BITS_PER_WORD;
248
249                 for (i = 0; i < bwords; ++i) {
250                         bitmap [i] = bitmap_data [i + 1];
251                 }
252
253                 return bitmap;
254         }
255
256         default:
257                 g_assert_not_reached ();
258         }
259 }
260
261 SgenDescriptor
262 mono_gc_make_descr_from_bitmap (gsize *bitmap, int numbits)
263 {
264         if (numbits == 0) {
265                 return MAKE_ROOT_DESC (ROOT_DESC_BITMAP, 0);
266         } else if (numbits < ((sizeof (*bitmap) * 8) - ROOT_DESC_TYPE_SHIFT)) {
267                 return MAKE_ROOT_DESC (ROOT_DESC_BITMAP, bitmap [0]);
268         } else {
269                 SgenDescriptor complex = alloc_complex_descriptor (bitmap, numbits);
270                 return MAKE_ROOT_DESC (ROOT_DESC_COMPLEX, complex);
271         }
272 }
273
274 SgenDescriptor
275 mono_gc_make_root_descr_all_refs (int numbits)
276 {
277         gsize *gc_bitmap;
278         SgenDescriptor descr;
279         int num_bytes = numbits / 8;
280
281         if (numbits < 32 && all_ref_root_descrs [numbits])
282                 return all_ref_root_descrs [numbits];
283
284         gc_bitmap = (gsize *)g_malloc0 (ALIGN_TO (ALIGN_TO (numbits, 8) + 1, sizeof (gsize)));
285         memset (gc_bitmap, 0xff, num_bytes);
286         if (numbits < ((sizeof (*gc_bitmap) * 8) - ROOT_DESC_TYPE_SHIFT)) 
287                 gc_bitmap[0] = GUINT64_TO_LE(gc_bitmap[0]);
288         else if (numbits && num_bytes % (sizeof (*gc_bitmap)))
289                 gc_bitmap[num_bytes / 8] = GUINT64_TO_LE(gc_bitmap [num_bytes / 8]);
290         if (numbits % 8)
291                 gc_bitmap [numbits / 8] = (1 << (numbits % 8)) - 1;
292         descr = mono_gc_make_descr_from_bitmap (gc_bitmap, numbits);
293         g_free (gc_bitmap);
294
295         if (numbits < 32)
296                 all_ref_root_descrs [numbits] = descr;
297
298         return descr;
299 }
300
301 SgenDescriptor
302 sgen_make_user_root_descriptor (SgenUserRootMarkFunc marker)
303 {
304         SgenDescriptor descr;
305
306         g_assert (user_descriptors_next < MAX_USER_DESCRIPTORS);
307         descr = MAKE_ROOT_DESC (ROOT_DESC_USER, (SgenDescriptor)user_descriptors_next);
308         user_descriptors [user_descriptors_next ++] = marker;
309
310         return descr;
311 }
312
313 void*
314 sgen_get_complex_descriptor_bitmap (SgenDescriptor desc)
315 {
316         return complex_descriptors + (desc >> ROOT_DESC_TYPE_SHIFT);
317 }
318
319 SgenUserRootMarkFunc
320 sgen_get_user_descriptor_func (SgenDescriptor desc)
321 {
322         return user_descriptors [desc >> ROOT_DESC_TYPE_SHIFT];
323 }
324
325 #ifdef HEAVY_STATISTICS
326 void
327 sgen_descriptor_count_scanned_object (SgenDescriptor desc)
328 {
329         int type = desc & DESC_TYPE_MASK;
330         SGEN_ASSERT (0, type, "Descriptor type can't be zero");
331         ++stat_scanned_count_per_descriptor [type - 1];
332 }
333
334 void
335 sgen_descriptor_count_copied_object (SgenDescriptor desc)
336 {
337         int type = desc & DESC_TYPE_MASK;
338         SGEN_ASSERT (0, type, "Descriptor type can't be zero");
339         ++stat_copied_count_per_descriptor [type - 1];
340 }
341 #endif
342
343 void
344 sgen_init_descriptors (void)
345 {
346 #ifdef HEAVY_STATISTICS
347         mono_counters_register ("# scanned RUN_LENGTH", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_scanned_count_per_descriptor [DESC_TYPE_RUN_LENGTH - 1]);
348         mono_counters_register ("# scanned SMALL_PTRFREE", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_scanned_count_per_descriptor [DESC_TYPE_SMALL_PTRFREE - 1]);
349         mono_counters_register ("# scanned COMPLEX", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_scanned_count_per_descriptor [DESC_TYPE_COMPLEX - 1]);
350         mono_counters_register ("# scanned VECTOR", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_scanned_count_per_descriptor [DESC_TYPE_VECTOR - 1]);
351         mono_counters_register ("# scanned BITMAP", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_scanned_count_per_descriptor [DESC_TYPE_BITMAP - 1]);
352         mono_counters_register ("# scanned COMPLEX_ARR", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_scanned_count_per_descriptor [DESC_TYPE_COMPLEX_ARR - 1]);
353         mono_counters_register ("# scanned COMPLEX_PTRFREE", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_scanned_count_per_descriptor [DESC_TYPE_COMPLEX_PTRFREE - 1]);
354
355         mono_counters_register ("# copied RUN_LENGTH", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_copied_count_per_descriptor [DESC_TYPE_RUN_LENGTH - 1]);
356         mono_counters_register ("# copied SMALL_PTRFREE", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_copied_count_per_descriptor [DESC_TYPE_SMALL_PTRFREE - 1]);
357         mono_counters_register ("# copied COMPLEX", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_copied_count_per_descriptor [DESC_TYPE_COMPLEX - 1]);
358         mono_counters_register ("# copied VECTOR", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_copied_count_per_descriptor [DESC_TYPE_VECTOR - 1]);
359         mono_counters_register ("# copied BITMAP", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_copied_count_per_descriptor [DESC_TYPE_BITMAP - 1]);
360         mono_counters_register ("# copied COMPLEX_ARR", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_copied_count_per_descriptor [DESC_TYPE_COMPLEX_ARR - 1]);
361         mono_counters_register ("# copied COMPLEX_PTRFREE", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_copied_count_per_descriptor [DESC_TYPE_COMPLEX_PTRFREE - 1]);
362 #endif
363 }
364
365 #endif