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