Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mono / sgen / sgen-descriptor.h
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  *
9  * Copyright (C) 2012 Xamarin Inc
10  *
11  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
12  */
13 #ifndef __MONO_SGEN_DESCRIPTOR_H__
14 #define __MONO_SGEN_DESCRIPTOR_H__
15
16 #include <mono/sgen/sgen-conf.h>
17
18 /*
19  * ######################################################################
20  * ########  GC descriptors
21  * ######################################################################
22  * Used to quickly get the info the GC needs about an object: size and
23  * where the references are held.
24  */
25 #define OBJECT_HEADER_WORDS (SGEN_CLIENT_OBJECT_HEADER_SIZE / sizeof(gpointer))
26 #define LOW_TYPE_BITS 3
27 #define DESC_TYPE_MASK  ((1 << LOW_TYPE_BITS) - 1)
28 #define MAX_RUNLEN_OBJECT_SIZE 0xFFFF
29 #define VECTOR_INFO_SHIFT 14
30 #define VECTOR_KIND_SHIFT 13
31 #define VECTOR_ELSIZE_SHIFT 3
32 #define VECTOR_BITMAP_SHIFT 16
33 #define VECTOR_BITMAP_SIZE (GC_BITS_PER_WORD - VECTOR_BITMAP_SHIFT)
34 #define BITMAP_NUM_BITS (GC_BITS_PER_WORD - LOW_TYPE_BITS)
35 #define MAX_ELEMENT_SIZE 0x3ff
36 #define VECTOR_SUBTYPE_PTRFREE (DESC_TYPE_V_PTRFREE << VECTOR_INFO_SHIFT)
37 #define VECTOR_SUBTYPE_REFS    (DESC_TYPE_V_REFS << VECTOR_INFO_SHIFT)
38 #define VECTOR_SUBTYPE_BITMAP  (DESC_TYPE_V_BITMAP << VECTOR_INFO_SHIFT)
39
40 #define VECTOR_KIND_SZARRAY  (DESC_TYPE_V_SZARRAY << VECTOR_KIND_SHIFT)
41 #define VECTOR_KIND_ARRAY  (DESC_TYPE_V_ARRAY << VECTOR_KIND_SHIFT)
42
43 /*
44  * Objects are aligned to 8 bytes boundaries.
45  *
46  * A descriptor is a pointer in GCVTable, so 32 or 64 bits of size.
47  * The low 3 bits define the type of the descriptor. The other bits
48  * depend on the type.
49  *
50  * It's important to be able to quickly identify two properties of classes from their
51  * descriptors: whether they are small enough to live in the regular major heap (size <=
52  * SGEN_MAX_SMALL_OBJ_SIZE), and whether they contain references.
53  *
54  * To that end we have three descriptor types that only apply to small classes: RUN_LENGTH,
55  * BITMAP, and SMALL_PTRFREE.  We also have the type COMPLEX_PTRFREE, which applies to
56  * classes that are either not small or of unknown size (those being strings and arrays).
57  * The lowest two bits of the SMALL_PTRFREE and COMPLEX_PTRFREE tags are the same, so we can
58  * quickly check for references.
59  *
60  * As a general rule the 13 remaining low bits define the size, either
61  * of the whole object or of the elements in the arrays. While for objects
62  * the size is already in bytes, for arrays we need to shift, because
63  * array elements might be smaller than 8 bytes. In case of arrays, we
64  * use two bits to describe what the additional high bits represents,
65  * so the default behaviour can handle element sizes less than 2048 bytes.
66  * The high 16 bits, if 0 it means the object is pointer-free.
67  * This design should make it easy and fast to skip over ptr-free data.
68  * The first 4 types should cover >95% of the objects.
69  * Note that since the size of objects is limited to 64K, larger objects
70  * will be allocated in the large object heap.
71  * If we want 4-bytes alignment, we need to put vector and small bitmap
72  * inside complex.
73  *
74  * We don't use 0 so that 0 isn't a valid GC descriptor.  No deep reason for this other than
75  * to be able to identify a non-inited descriptor for debugging.
76  */
77 enum {
78         /* Keep in sync with `descriptor_types` in sgen-debug.c! */
79         DESC_TYPE_RUN_LENGTH = 1,   /* 16 bits aligned byte size | 1-3 (offset, numptr) bytes tuples */
80         DESC_TYPE_BITMAP = 2,       /* | 29-61 bitmap bits */
81         DESC_TYPE_SMALL_PTRFREE = 3,
82         DESC_TYPE_MAX_SMALL_OBJ = 3,
83         DESC_TYPE_COMPLEX = 4,      /* index for bitmap into complex_descriptors */
84         DESC_TYPE_VECTOR = 5,       /* 10 bits element size | 1 bit kind | 2 bits desc | element desc */
85         DESC_TYPE_COMPLEX_ARR = 6,  /* index for bitmap into complex_descriptors */
86         DESC_TYPE_COMPLEX_PTRFREE = 7, /* Nothing, used to encode large ptr objects and strings. */
87         DESC_TYPE_MAX = 7,
88
89         DESC_TYPE_PTRFREE_MASK = 3,
90         DESC_TYPE_PTRFREE_BITS = 3
91 };
92
93 /* values for array kind */
94 enum {
95         DESC_TYPE_V_SZARRAY = 0, /*vector with no bounds data */
96         DESC_TYPE_V_ARRAY = 1, /* array with bounds data */
97 };
98
99 /* subtypes for arrays and vectors */
100 enum {
101         DESC_TYPE_V_PTRFREE = 0,/* there are no refs: keep first so it has a zero value  */
102         DESC_TYPE_V_REFS,       /* all the array elements are refs */
103         DESC_TYPE_V_RUN_LEN,    /* elements are run-length encoded as DESC_TYPE_RUN_LENGTH */
104         DESC_TYPE_V_BITMAP      /* elements are as the bitmap in DESC_TYPE_SMALL_BITMAP */
105 };
106
107 #define SGEN_DESC_STRING        (DESC_TYPE_COMPLEX_PTRFREE | (1 << LOW_TYPE_BITS))
108
109 /* Root bitmap descriptors are simpler: the lower three bits describe the type
110  * and we either have 30/62 bitmap bits or nibble-based run-length,
111  * or a complex descriptor, or a user defined marker function.
112  */
113 enum {
114         ROOT_DESC_CONSERVATIVE, /* 0, so matches NULL value */
115         ROOT_DESC_BITMAP,
116         ROOT_DESC_RUN_LEN, 
117         ROOT_DESC_COMPLEX,
118         ROOT_DESC_VECTOR,
119         ROOT_DESC_USER,
120         ROOT_DESC_TYPE_MASK = 0x7,
121         ROOT_DESC_TYPE_SHIFT = 3,
122 };
123
124 typedef void (*SgenUserMarkFunc)     (GCObject **addr, void *gc_data);
125 typedef void (*SgenUserRootMarkFunc) (void *addr, SgenUserMarkFunc mark_func, void *gc_data);
126
127 SgenDescriptor sgen_make_user_root_descriptor (SgenUserRootMarkFunc marker);
128
129 gsize* sgen_get_complex_descriptor (SgenDescriptor desc);
130 void* sgen_get_complex_descriptor_bitmap (SgenDescriptor desc);
131 SgenUserRootMarkFunc sgen_get_user_descriptor_func (SgenDescriptor desc);
132
133 void sgen_init_descriptors (void);
134
135 #ifdef HEAVY_STATISTICS
136 void sgen_descriptor_count_scanned_object (SgenDescriptor desc);
137 void sgen_descriptor_count_copied_object (SgenDescriptor desc);
138 #endif
139
140 static inline gboolean
141 sgen_gc_descr_has_references (SgenDescriptor desc)
142 {
143         /* This covers SMALL_PTRFREE and COMPLEX_PTRFREE */
144         if ((desc & DESC_TYPE_PTRFREE_MASK) == DESC_TYPE_PTRFREE_BITS)
145                 return FALSE;
146
147         /*The array is ptr-free*/
148         if ((desc & 0xC007) == (DESC_TYPE_VECTOR | VECTOR_SUBTYPE_PTRFREE))
149                 return FALSE;
150
151         return TRUE;
152 }
153
154 #define SGEN_VTABLE_HAS_REFERENCES(vt)  (sgen_gc_descr_has_references (sgen_vtable_get_descriptor ((vt))))
155 #define SGEN_OBJECT_HAS_REFERENCES(o)   (SGEN_VTABLE_HAS_REFERENCES (SGEN_LOAD_VTABLE ((o))))
156
157 /* helper macros to scan and traverse objects, macros because we resue them in many functions */
158 #ifdef __GNUC__
159 #define PREFETCH_READ(addr)     __builtin_prefetch ((addr), 0, 1)
160 #define PREFETCH_WRITE(addr)    __builtin_prefetch ((addr), 1, 1)
161 #else
162 #define PREFETCH_READ(addr)
163 #define PREFETCH_WRITE(addr)
164 #endif
165
166 #if defined(__GNUC__) && SIZEOF_VOID_P==4
167 #define GNUC_BUILTIN_CTZ(bmap)  __builtin_ctz(bmap)
168 #elif defined(__GNUC__) && SIZEOF_VOID_P==8
169 #define GNUC_BUILTIN_CTZ(bmap)  __builtin_ctzl(bmap)
170 #endif
171
172 /* code using these macros must define a HANDLE_PTR(ptr) macro that does the work */
173 #define OBJ_RUN_LEN_FOREACH_PTR(desc,obj)       do {    \
174                 if ((desc) & 0xffff0000) {      \
175                         /* there are pointers */        \
176                         void **_objptr_end;     \
177                         void **_objptr = (void**)(obj); \
178                         _objptr += ((desc) >> 16) & 0xff;       \
179                         _objptr_end = _objptr + (((desc) >> 24) & 0xff);        \
180                         while (_objptr < _objptr_end) { \
181                                 HANDLE_PTR ((GCObject**)_objptr, (obj)); \
182                                 _objptr++;      \
183                         };      \
184                 }       \
185         } while (0)
186
187 /* a bitmap desc means that there are pointer references or we'd have
188  * choosen run-length, instead: add an assert to check.
189  */
190 #ifdef __GNUC__
191 #define OBJ_BITMAP_FOREACH_PTR(desc,obj)        do {            \
192                 /* there are pointers */                        \
193                 void **_objptr = (void**)(obj);                 \
194                 gsize _bmap = (desc) >> LOW_TYPE_BITS;          \
195                 _objptr += OBJECT_HEADER_WORDS;                 \
196                 do {                                            \
197                         int _index = GNUC_BUILTIN_CTZ (_bmap);  \
198                         _objptr += _index;                      \
199                         _bmap >>= (_index + 1);                 \
200                         HANDLE_PTR ((GCObject**)_objptr, (obj));        \
201                         ++_objptr;                              \
202                 } while (_bmap);                                \
203         } while (0)
204 #else
205 #define OBJ_BITMAP_FOREACH_PTR(desc,obj)        do {    \
206                 /* there are pointers */        \
207                 void **_objptr = (void**)(obj); \
208                 gsize _bmap = (desc) >> LOW_TYPE_BITS;  \
209                 _objptr += OBJECT_HEADER_WORDS; \
210                 do {    \
211                         if ((_bmap & 1)) {      \
212                                 HANDLE_PTR ((GCObject**)_objptr, (obj));        \
213                         }       \
214                         _bmap >>= 1;    \
215                         ++_objptr;      \
216                 } while (_bmap);        \
217         } while (0)
218 #endif
219
220 #define OBJ_COMPLEX_FOREACH_PTR(desc,obj)       do {    \
221                 /* there are pointers */        \
222                 void **_objptr = (void**)(obj); \
223                 gsize *bitmap_data = sgen_get_complex_descriptor ((desc)); \
224                 gsize bwords = (*bitmap_data) - 1;      \
225                 void **start_run = _objptr;     \
226                 bitmap_data++;  \
227                 while (bwords-- > 0) {  \
228                         gsize _bmap = *bitmap_data++;   \
229                         _objptr = start_run;    \
230                         /*g_print ("bitmap: 0x%x/%d at %p\n", _bmap, bwords, _objptr);*/        \
231                         while (_bmap) { \
232                                 if ((_bmap & 1)) {      \
233                                         HANDLE_PTR ((GCObject**)_objptr, (obj));        \
234                                 }       \
235                                 _bmap >>= 1;    \
236                                 ++_objptr;      \
237                         }       \
238                         start_run += GC_BITS_PER_WORD;  \
239                 }       \
240         } while (0)
241
242 /* this one is untested */
243 #define OBJ_COMPLEX_ARR_FOREACH_PTR(desc,obj)   do {    \
244                 /* there are pointers */        \
245                 GCVTable vt = SGEN_LOAD_VTABLE (obj); \
246                 gsize *mbitmap_data = sgen_get_complex_descriptor ((desc)); \
247                 gsize mbwords = (*mbitmap_data++) - 1;  \
248                 gsize el_size = sgen_client_array_element_size (vt);    \
249                 char *e_start = sgen_client_array_data_start ((GCObject*)(obj));        \
250                 char *e_end = e_start + el_size * sgen_client_array_length ((GCObject*)(obj));  \
251                 while (e_start < e_end) {       \
252                         void **_objptr = (void**)e_start;       \
253                         gsize *bitmap_data = mbitmap_data;      \
254                         gsize bwords = mbwords; \
255                         while (bwords-- > 0) {  \
256                                 gsize _bmap = *bitmap_data++;   \
257                                 void **start_run = _objptr;     \
258                                 /*g_print ("bitmap: 0x%x\n", _bmap);*/  \
259                                 while (_bmap) { \
260                                         if ((_bmap & 1)) {      \
261                                                 HANDLE_PTR ((GCObject**)_objptr, (obj));        \
262                                         }       \
263                                         _bmap >>= 1;    \
264                                         ++_objptr;      \
265                                 }       \
266                                 _objptr = start_run + GC_BITS_PER_WORD; \
267                         }       \
268                         e_start += el_size;     \
269                 }       \
270         } while (0)
271
272 #define OBJ_VECTOR_FOREACH_PTR(desc,obj)        do {    \
273                 /* note: 0xffffc000 excludes DESC_TYPE_V_PTRFREE */     \
274                 if ((desc) & 0xffffc000) {                              \
275                         int el_size = ((desc) >> 3) & MAX_ELEMENT_SIZE; \
276                         /* there are pointers */        \
277                         int etype = (desc) & 0xc000;                    \
278                         if (etype == (DESC_TYPE_V_REFS << 14)) {        \
279                                 void **p = (void**)sgen_client_array_data_start ((GCObject*)(obj));     \
280                                 void **end_refs = (void**)((char*)p + el_size * sgen_client_array_length ((GCObject*)(obj)));   \
281                                 /* Note: this code can handle also arrays of struct with only references in them */     \
282                                 while (p < end_refs) {  \
283                                         HANDLE_PTR ((GCObject**)p, (obj));      \
284                                         ++p;    \
285                                 }       \
286                         } else if (etype == DESC_TYPE_V_RUN_LEN << 14) {        \
287                                 int offset = ((desc) >> 16) & 0xff;     \
288                                 int num_refs = ((desc) >> 24) & 0xff;   \
289                                 char *e_start = sgen_client_array_data_start ((GCObject*)(obj));        \
290                                 char *e_end = e_start + el_size * sgen_client_array_length ((GCObject*)(obj));  \
291                                 while (e_start < e_end) {       \
292                                         void **p = (void**)e_start;     \
293                                         int i;  \
294                                         p += offset;    \
295                                         for (i = 0; i < num_refs; ++i) {        \
296                                                 HANDLE_PTR ((GCObject**)p + i, (obj));  \
297                                         }       \
298                                         e_start += el_size;     \
299                                 }       \
300                         } else if (etype == DESC_TYPE_V_BITMAP << 14) { \
301                                 char *e_start = sgen_client_array_data_start ((GCObject*)(obj));        \
302                                 char *e_end = e_start + el_size * sgen_client_array_length ((GCObject*)(obj));  \
303                                 while (e_start < e_end) {       \
304                                         void **p = (void**)e_start;     \
305                                         gsize _bmap = (desc) >> 16;     \
306                                         /* Note: there is no object header here to skip */      \
307                                         while (_bmap) { \
308                                                 if ((_bmap & 1)) {      \
309                                                         HANDLE_PTR ((GCObject**)p, (obj));      \
310                                                 }       \
311                                                 _bmap >>= 1;    \
312                                                 ++p;    \
313                                         }       \
314                                         e_start += el_size;     \
315                                 }       \
316                         }       \
317                 }       \
318         } while (0)
319
320
321 #endif