2 * sgen-descriptor.c: GC descriptors describe object layout.
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
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;
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.
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.
31 #ifdef HAVE_SEMAPHORE_H
32 #include <semaphore.h>
45 #include "mono/sgen/sgen-gc.h"
46 #include "mono/sgen/gc-internal-agnostic.h"
48 #define MAX_USER_DESCRIPTORS 16
50 #define MAKE_ROOT_DESC(type,val) ((type) | ((val) << ROOT_DESC_TYPE_SHIFT))
51 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
54 static gsize* complex_descriptors = NULL;
55 static int complex_descriptors_size = 0;
56 static int complex_descriptors_next = 0;
57 static SgenUserRootMarkFunc user_descriptors [MAX_USER_DESCRIPTORS];
58 static int user_descriptors_next = 0;
59 static SgenDescriptor all_ref_root_descrs [32];
61 #ifdef HEAVY_STATISTICS
62 static guint64 stat_scanned_count_per_descriptor [DESC_TYPE_MAX];
63 static guint64 stat_copied_count_per_descriptor [DESC_TYPE_MAX];
67 alloc_complex_descriptor (gsize *bitmap, int numbits)
71 numbits = ALIGN_TO (numbits, GC_BITS_PER_WORD);
72 nwords = numbits / GC_BITS_PER_WORD + 1;
75 res = complex_descriptors_next;
76 /* linear search, so we don't have duplicates with domain load/unload
77 * this should not be performance critical or we'd have bigger issues
78 * (the number and size of complex descriptors should be small).
80 for (i = 0; i < complex_descriptors_next; ) {
81 if (complex_descriptors [i] == nwords) {
83 for (j = 0; j < nwords - 1; ++j) {
84 if (complex_descriptors [i + 1 + j] != bitmap [j]) {
94 i += (int)complex_descriptors [i];
96 if (complex_descriptors_next + nwords > complex_descriptors_size) {
97 int new_size = complex_descriptors_size * 2 + nwords;
98 complex_descriptors = (gsize *)g_realloc (complex_descriptors, new_size * sizeof (gsize));
99 complex_descriptors_size = new_size;
101 SGEN_LOG (6, "Complex descriptor %d, size: %d (total desc memory: %d)", res, nwords, complex_descriptors_size);
102 complex_descriptors_next += nwords;
103 complex_descriptors [res] = nwords;
104 for (i = 0; i < nwords - 1; ++i) {
105 complex_descriptors [res + 1 + i] = bitmap [i];
106 SGEN_LOG (6, "\tvalue: %p", (void*)complex_descriptors [res + 1 + i]);
113 sgen_get_complex_descriptor (SgenDescriptor desc)
115 return complex_descriptors + (desc >> LOW_TYPE_BITS);
119 * Descriptor builders.
122 mono_gc_make_descr_for_object (gsize *bitmap, int numbits, size_t obj_size)
124 int first_set = -1, num_set = 0, last_set = -1, i;
125 SgenDescriptor desc = 0;
126 size_t stored_size = SGEN_ALIGN_UP (obj_size);
128 for (i = 0; i < numbits; ++i) {
129 if (bitmap [i / GC_BITS_PER_WORD] & ((gsize)1 << (i % GC_BITS_PER_WORD))) {
138 SGEN_LOG (6, "Ptrfree descriptor %p, size: %zd", (void*)desc, stored_size);
139 if (stored_size <= MAX_RUNLEN_OBJECT_SIZE && stored_size <= SGEN_MAX_SMALL_OBJ_SIZE)
140 return DESC_TYPE_SMALL_PTRFREE | stored_size;
141 return DESC_TYPE_COMPLEX_PTRFREE;
144 g_assert (!(stored_size & 0x7));
146 SGEN_ASSERT (5, stored_size == SGEN_ALIGN_UP (stored_size), "Size is not aligned");
148 /* we know the 2-word header is ptr-free */
149 if (last_set < BITMAP_NUM_BITS + OBJECT_HEADER_WORDS && stored_size <= SGEN_MAX_SMALL_OBJ_SIZE) {
150 desc = DESC_TYPE_BITMAP | ((*bitmap >> OBJECT_HEADER_WORDS) << LOW_TYPE_BITS);
151 SGEN_LOG (6, "Largebitmap descriptor %p, size: %zd, last set: %d", (void*)desc, stored_size, last_set);
155 if (stored_size <= MAX_RUNLEN_OBJECT_SIZE && stored_size <= SGEN_MAX_SMALL_OBJ_SIZE) {
156 /* check run-length encoding first: one byte offset, one byte number of pointers
157 * on 64 bit archs, we can have 3 runs, just one on 32.
158 * It may be better to use nibbles.
160 if (first_set < 256 && num_set < 256 && (first_set + num_set == last_set + 1)) {
161 desc = DESC_TYPE_RUN_LENGTH | stored_size | (first_set << 16) | (num_set << 24);
162 SGEN_LOG (6, "Runlen descriptor %p, size: %zd, first set: %d, num set: %d", (void*)desc, stored_size, first_set, num_set);
167 /* it's a complex object ... */
168 desc = DESC_TYPE_COMPLEX | (alloc_complex_descriptor (bitmap, last_set + 1) << LOW_TYPE_BITS);
172 /* If the array holds references, numbits == 1 and the first bit is set in elem_bitmap */
174 mono_gc_make_descr_for_array (int vector, gsize *elem_bitmap, int numbits, size_t elem_size)
176 int first_set = -1, num_set = 0, last_set = -1, i;
177 SgenDescriptor desc = DESC_TYPE_VECTOR | (vector ? VECTOR_KIND_SZARRAY : VECTOR_KIND_ARRAY);
178 for (i = 0; i < numbits; ++i) {
179 if (elem_bitmap [i / GC_BITS_PER_WORD] & ((gsize)1 << (i % GC_BITS_PER_WORD))) {
188 if (elem_size <= MAX_ELEMENT_SIZE)
189 return desc | VECTOR_SUBTYPE_PTRFREE | (elem_size << VECTOR_ELSIZE_SHIFT);
190 return DESC_TYPE_COMPLEX_PTRFREE;
193 if (elem_size <= MAX_ELEMENT_SIZE) {
194 desc |= elem_size << VECTOR_ELSIZE_SHIFT;
196 return desc | VECTOR_SUBTYPE_PTRFREE;
198 /* Note: we also handle structs with just ref fields */
199 if (num_set * sizeof (gpointer) == elem_size) {
200 return desc | VECTOR_SUBTYPE_REFS | ((gssize)(-1) << 16);
202 /* FIXME: try run-len first */
203 /* Note: we can't skip the object header here, because it's not present */
204 if (last_set < VECTOR_BITMAP_SIZE) {
205 return desc | VECTOR_SUBTYPE_BITMAP | (*elem_bitmap << 16);
208 /* it's am array of complex structs ... */
209 desc = DESC_TYPE_COMPLEX_ARR;
210 desc |= alloc_complex_descriptor (elem_bitmap, last_set + 1) << LOW_TYPE_BITS;
214 /* Return the bitmap encoded by a descriptor */
216 mono_gc_get_bitmap_for_descr (SgenDescriptor descr, int *numbits)
218 SgenDescriptor d = (SgenDescriptor)descr;
221 switch (d & DESC_TYPE_MASK) {
222 case DESC_TYPE_RUN_LENGTH: {
223 int first_set = (d >> 16) & 0xff;
224 int num_set = (d >> 24) & 0xff;
227 bitmap = g_new0 (gsize, (first_set + num_set + 7) / 8);
229 for (i = first_set; i < first_set + num_set; ++i)
230 bitmap [i / GC_BITS_PER_WORD] |= ((gsize)1 << (i % GC_BITS_PER_WORD));
232 *numbits = first_set + num_set;
237 case DESC_TYPE_BITMAP: {
238 gsize bmap = (d >> LOW_TYPE_BITS) << OBJECT_HEADER_WORDS;
240 bitmap = g_new0 (gsize, 1);
250 case DESC_TYPE_COMPLEX: {
251 gsize *bitmap_data = sgen_get_complex_descriptor (d);
252 int bwords = (int)(*bitmap_data) - 1;//Max scalar object size is 1Mb, which means up to 32k descriptor words
255 bitmap = g_new0 (gsize, bwords);
256 *numbits = bwords * GC_BITS_PER_WORD;
258 for (i = 0; i < bwords; ++i) {
259 bitmap [i] = bitmap_data [i + 1];
266 g_assert_not_reached ();
271 mono_gc_make_descr_from_bitmap (gsize *bitmap, int numbits)
274 return MAKE_ROOT_DESC (ROOT_DESC_BITMAP, 0);
275 } else if (numbits < ((sizeof (*bitmap) * 8) - ROOT_DESC_TYPE_SHIFT)) {
276 return MAKE_ROOT_DESC (ROOT_DESC_BITMAP, bitmap [0]);
278 SgenDescriptor complex = alloc_complex_descriptor (bitmap, numbits);
279 return MAKE_ROOT_DESC (ROOT_DESC_COMPLEX, complex);
284 mono_gc_make_root_descr_all_refs (int numbits)
287 SgenDescriptor descr;
288 int num_bytes = numbits / 8;
290 if (numbits < 32 && all_ref_root_descrs [numbits])
291 return all_ref_root_descrs [numbits];
293 gc_bitmap = (gsize *)g_malloc0 (ALIGN_TO (ALIGN_TO (numbits, 8) + 1, sizeof (gsize)));
294 memset (gc_bitmap, 0xff, num_bytes);
295 if (numbits < ((sizeof (*gc_bitmap) * 8) - ROOT_DESC_TYPE_SHIFT))
296 gc_bitmap[0] = GUINT64_TO_LE(gc_bitmap[0]);
297 else if (numbits && num_bytes % (sizeof (*gc_bitmap)))
298 gc_bitmap[num_bytes / 8] = GUINT64_TO_LE(gc_bitmap [num_bytes / 8]);
300 gc_bitmap [numbits / 8] = (1 << (numbits % 8)) - 1;
301 descr = mono_gc_make_descr_from_bitmap (gc_bitmap, numbits);
305 all_ref_root_descrs [numbits] = descr;
311 sgen_make_user_root_descriptor (SgenUserRootMarkFunc marker)
313 SgenDescriptor descr;
315 g_assert (user_descriptors_next < MAX_USER_DESCRIPTORS);
316 descr = MAKE_ROOT_DESC (ROOT_DESC_USER, (SgenDescriptor)user_descriptors_next);
317 user_descriptors [user_descriptors_next ++] = marker;
323 sgen_get_complex_descriptor_bitmap (SgenDescriptor desc)
325 return complex_descriptors + (desc >> ROOT_DESC_TYPE_SHIFT);
329 sgen_get_user_descriptor_func (SgenDescriptor desc)
331 return user_descriptors [desc >> ROOT_DESC_TYPE_SHIFT];
334 #ifdef HEAVY_STATISTICS
336 sgen_descriptor_count_scanned_object (SgenDescriptor desc)
338 int type = desc & DESC_TYPE_MASK;
339 SGEN_ASSERT (0, type, "Descriptor type can't be zero");
340 ++stat_scanned_count_per_descriptor [type - 1];
344 sgen_descriptor_count_copied_object (SgenDescriptor desc)
346 int type = desc & DESC_TYPE_MASK;
347 SGEN_ASSERT (0, type, "Descriptor type can't be zero");
348 ++stat_copied_count_per_descriptor [type - 1];
353 sgen_init_descriptors (void)
355 #ifdef HEAVY_STATISTICS
356 mono_counters_register ("# scanned RUN_LENGTH", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_scanned_count_per_descriptor [DESC_TYPE_RUN_LENGTH - 1]);
357 mono_counters_register ("# scanned SMALL_PTRFREE", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_scanned_count_per_descriptor [DESC_TYPE_SMALL_PTRFREE - 1]);
358 mono_counters_register ("# scanned COMPLEX", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_scanned_count_per_descriptor [DESC_TYPE_COMPLEX - 1]);
359 mono_counters_register ("# scanned VECTOR", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_scanned_count_per_descriptor [DESC_TYPE_VECTOR - 1]);
360 mono_counters_register ("# scanned BITMAP", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_scanned_count_per_descriptor [DESC_TYPE_BITMAP - 1]);
361 mono_counters_register ("# scanned COMPLEX_ARR", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_scanned_count_per_descriptor [DESC_TYPE_COMPLEX_ARR - 1]);
362 mono_counters_register ("# scanned COMPLEX_PTRFREE", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_scanned_count_per_descriptor [DESC_TYPE_COMPLEX_PTRFREE - 1]);
364 mono_counters_register ("# copied RUN_LENGTH", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_copied_count_per_descriptor [DESC_TYPE_RUN_LENGTH - 1]);
365 mono_counters_register ("# copied SMALL_PTRFREE", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_copied_count_per_descriptor [DESC_TYPE_SMALL_PTRFREE - 1]);
366 mono_counters_register ("# copied COMPLEX", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_copied_count_per_descriptor [DESC_TYPE_COMPLEX - 1]);
367 mono_counters_register ("# copied VECTOR", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_copied_count_per_descriptor [DESC_TYPE_VECTOR - 1]);
368 mono_counters_register ("# copied BITMAP", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_copied_count_per_descriptor [DESC_TYPE_BITMAP - 1]);
369 mono_counters_register ("# copied COMPLEX_ARR", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_copied_count_per_descriptor [DESC_TYPE_COMPLEX_ARR - 1]);
370 mono_counters_register ("# copied COMPLEX_PTRFREE", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_copied_count_per_descriptor [DESC_TYPE_COMPLEX_PTRFREE - 1]);