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