Merge pull request #4327 from vkargov/vk-abcremedy
[mono.git] / mono / metadata / handle.c
1 /**
2  * \file
3  * Handle to object in native code
4  *
5  * Authors:
6  *  - Ludovic Henry <ludovic@xamarin.com>
7  *  - Aleksey Klieger <aleksey.klieger@xamarin.com>
8  *  - Rodrigo Kumpera <kumpera@xamarin.com>
9  *
10  * Copyright 2016 Dot net foundation.
11  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
12  */
13
14 #include <config.h>
15 #include <glib.h>
16
17 #include <mono/metadata/handle.h>
18 #include <mono/metadata/object-internals.h>
19 #include <mono/metadata/gc-internals.h>
20 #include <mono/utils/atomic.h>
21 #include <mono/utils/mono-lazy-init.h>
22 #include <mono/utils/mono-threads.h>
23 /* TODO (missing pieces)
24
25 Add counters for:
26         number of stack marks
27         stack marks per icall
28         mix/max/avg size of stack marks
29         handle stack wastage
30
31 Actually do something in mono_handle_verify
32
33 Shrink the handles stack in mono_handle_stack_scan
34 Properly report it to the profiler.
35 Add a boehm implementation
36
37 TODO (things to explore):
38
39 There's no convenient way to wrap the object allocation function.
40 Right now we do this:
41         MonoCultureInfoHandle culture = MONO_HANDLE_NEW (MonoCultureInfo, mono_object_new_checked (domain, klass, &error));
42
43 Maybe what we need is a round of cleanup around all exposed types in the runtime to unify all helpers under the same hoof.
44 Combine: MonoDefaults, GENERATE_GET_CLASS_WITH_CACHE, TYPED_HANDLE_DECL and friends.
45         This would solve the age old issue of making it clear which types are optional and tell that to the linker.
46         We could then generate neat type safe wrappers.
47 */
48
49 /*
50  * NOTE: Async suspend
51  * 
52  * If we are running with cooperative GC, all the handle stack
53  * manipulation will complete before a GC thread scans the handle
54  * stack. If we are using async suspend, however, a thread may be
55  * trying to allocate a new handle, or unwind the handle stack when
56  * the GC stops the world.
57  *
58  * In particular, we need to ensure that if the mutator thread is
59  * suspended while manipulating the handle stack, the stack is in a
60  * good enough state to be scanned.  In particular, the size of each
61  * chunk should be updated before an object is written into the
62  * handle, and chunks to be scanned (between bottom and top) should
63  * always be valid.
64  *
65  * Note that the handle stack is scanned PRECISELY (see
66  * sgen_client_scan_thread_data ()).  That means there should not be
67  * stale objects scanned.  So when we manipulate the size of a chunk,
68  * wemust ensure that the newly scannable slot is either null or
69  * points to a valid value.
70  */
71
72 const MonoObjectHandle mono_null_value_handle = NULL;
73
74 #define THIS_IS_AN_OK_NUMBER_OF_HANDLES 100
75
76 enum {
77         HANDLE_CHUNK_PTR_OBJ = 0x0, /* chunk element points to beginning of a managed object */
78         HANDLE_CHUNK_PTR_INTERIOR = 0x1, /* chunk element points into the middle of a managed object */
79         HANDLE_CHUNK_PTR_MASK = 0x1
80 };
81
82 /* number of bits in each word of the interior pointer bitmap */
83 #define INTERIOR_HANDLE_BITMAP_BITS_PER_WORD (sizeof(guint32) << 3)
84
85 static gboolean
86 bitset_bits_test (guint32 *bitmaps, int idx)
87 {
88         int w = idx / INTERIOR_HANDLE_BITMAP_BITS_PER_WORD;
89         int b = idx % INTERIOR_HANDLE_BITMAP_BITS_PER_WORD;
90         guint32 bitmap = bitmaps [w];
91         guint32 mask = 1u << b;
92         return ((bitmap & mask) != 0);
93 }
94
95 static void
96 bitset_bits_set (guint32 *bitmaps, int idx)
97 {
98         int w = idx / INTERIOR_HANDLE_BITMAP_BITS_PER_WORD;
99         int b = idx % INTERIOR_HANDLE_BITMAP_BITS_PER_WORD;
100         guint32 *bitmap = &bitmaps [w];
101         guint32 mask = 1u << b;
102         *bitmap |= mask;
103 }
104 static void
105 bitset_bits_clear (guint32 *bitmaps, int idx)
106 {
107         int w = idx / INTERIOR_HANDLE_BITMAP_BITS_PER_WORD;
108         int b = idx % INTERIOR_HANDLE_BITMAP_BITS_PER_WORD;
109         guint32 *bitmap = &bitmaps [w];
110         guint32 mask = ~(1u << b);
111         *bitmap &= mask;
112 }
113
114 static gpointer*
115 chunk_element_objslot_init (HandleChunk *chunk, int idx, gboolean interior)
116 {
117         if (interior)
118                 bitset_bits_set (chunk->interior_bitmap, idx);
119         else
120                 bitset_bits_clear (chunk->interior_bitmap, idx);
121         return &chunk->elems [idx].o;
122 }
123
124 static HandleChunkElem*
125 chunk_element (HandleChunk *chunk, int idx)
126 {
127         return &chunk->elems[idx];
128 }
129
130 static guint
131 chunk_element_kind (HandleChunk *chunk, int idx)
132 {
133         return bitset_bits_test (chunk->interior_bitmap, idx) ? HANDLE_CHUNK_PTR_INTERIOR : HANDLE_CHUNK_PTR_OBJ;
134 }
135
136 static HandleChunkElem*
137 handle_to_chunk_element (MonoObjectHandle o)
138 {
139         return (HandleChunkElem*)o;
140 }
141
142 /* Given a HandleChunkElem* search through the current handle stack to find its chunk and offset. */
143 static HandleChunk*
144 chunk_element_to_chunk_idx (HandleStack *stack, HandleChunkElem *elem, int *out_idx)
145 {
146         HandleChunk *top = stack->top;
147         HandleChunk *cur = stack->bottom;
148
149         *out_idx = 0;
150
151         while (cur != NULL) {
152                 HandleChunkElem *front = &cur->elems [0];
153                 HandleChunkElem *back = &cur->elems [cur->size];
154
155                 if (front <= elem && elem < back) {
156                         *out_idx = (int)(elem - front);
157                         return cur;
158                 }
159
160                 if (cur == top)
161                         break; /* didn't find it. */
162                 cur = cur->next;
163         }
164         return NULL;
165 }
166
167 #ifdef MONO_HANDLE_TRACK_OWNER
168 #define SET_OWNER(chunk,idx) do { (chunk)->elems[(idx)].owner = owner; } while (0)
169 #else
170 #define SET_OWNER(chunk,idx) do { } while (0)
171 #endif
172
173 MonoRawHandle
174 #ifndef MONO_HANDLE_TRACK_OWNER
175 mono_handle_new (MonoObject *object)
176 #else
177 mono_handle_new (MonoObject *object const char *owner)
178 #endif
179 {
180 #ifndef MONO_HANDLE_TRACK_OWNER
181         return mono_handle_new_full (object, FALSE);
182 #else
183         return mono_handle_new_full (object, FALSE, owner);
184 #endif
185 }
186 /* Actual handles implementation */
187 MonoRawHandle
188 #ifndef MONO_HANDLE_TRACK_OWNER
189 mono_handle_new_full (gpointer rawptr, gboolean interior)
190 #else
191 mono_handle_new_full (gpointer rawptr, gboolean interior, const char *owner)
192 #endif
193 {
194         MonoThreadInfo *info = mono_thread_info_current ();
195         HandleStack *handles = (HandleStack *)info->handle_stack;
196         HandleChunk *top = handles->top;
197
198 retry:
199         if (G_LIKELY (top->size < OBJECTS_PER_HANDLES_CHUNK)) {
200                 int idx = top->size;
201                 gpointer* objslot = chunk_element_objslot_init (top, idx, interior);
202                 /* can be interrupted anywhere here, so:
203                  * 1. make sure the new slot is null
204                  * 2. make the new slot scannable (increment size)
205                  * 3. put a valid object in there
206                  *
207                  * (have to do 1 then 3 so that if we're interrupted
208                  * between 1 and 2, the object is still live)
209                  */
210                 *objslot = NULL;
211                 mono_memory_write_barrier ();
212                 top->size++;
213                 mono_memory_write_barrier ();
214                 *objslot = rawptr;
215                 SET_OWNER (top,idx);
216                 return objslot;
217         }
218         if (G_LIKELY (top->next)) {
219                 top->next->size = 0;
220                 /* make sure size == 0 is visible to a GC thread before it sees the new top */
221                 mono_memory_write_barrier ();
222                 top = top->next;
223                 handles->top = top;
224                 goto retry;
225         }
226         HandleChunk *new_chunk = g_new (HandleChunk, 1);
227         new_chunk->size = 0;
228         memset (new_chunk->interior_bitmap, 0, INTERIOR_HANDLE_BITMAP_WORDS);
229         new_chunk->prev = top;
230         new_chunk->next = NULL;
231         /* make sure size == 0 before new chunk is visible */
232         mono_memory_write_barrier ();
233         top->next = new_chunk;
234         handles->top = new_chunk;
235         goto retry;
236 }
237
238
239
240 HandleStack*
241 mono_handle_stack_alloc (void)
242 {
243         HandleStack *stack = g_new (HandleStack, 1);
244         HandleChunk *chunk = g_new (HandleChunk, 1);
245
246         chunk->size = 0;
247         memset (chunk->interior_bitmap, 0, INTERIOR_HANDLE_BITMAP_WORDS);
248         chunk->prev = chunk->next = NULL;
249         mono_memory_write_barrier ();
250         stack->top = stack->bottom = chunk;
251         return stack;
252 }
253
254 void
255 mono_handle_stack_free (HandleStack *stack)
256 {
257         if (!stack)
258                 return;
259         HandleChunk *c = stack->bottom;
260         stack->top = stack->bottom = NULL;
261         mono_memory_write_barrier ();
262         while (c) {
263                 HandleChunk *next = c->next;
264                 g_free (c);
265                 c = next;
266         }
267         g_free (c);
268         g_free (stack);
269 }
270
271 void
272 mono_handle_stack_scan (HandleStack *stack, GcScanFunc func, gpointer gc_data, gboolean precise)
273 {
274         /*
275           We're called twice - on the imprecise pass we call func to pin the
276           objects where the handle points to its interior.  On the precise
277           pass, we scan all the objects where the handles point to the start of
278           the object.
279
280           Note that if we're running, we know the world is stopped.
281         */
282         HandleChunk *cur = stack->bottom;
283         HandleChunk *last = stack->top;
284
285         if (!cur)
286                 return;
287
288         while (cur) {
289                 /* assume that object pointers will be much more common than interior pointers.
290                  * scan the object pointers by iterating over the chunk elements.
291                  * scan the interior pointers by iterating over the bitmap bits.
292                  */
293                 if (precise) {
294                         for (int i = 0; i < cur->size; ++i) {
295                                 HandleChunkElem* elem = chunk_element (cur, i);
296                                 int kind = chunk_element_kind (cur, i);
297                                 gpointer* obj_slot = &elem->o;
298                                 if (kind == HANDLE_CHUNK_PTR_OBJ && *obj_slot != NULL)
299                                         func (obj_slot, gc_data);
300                         }
301                 } else {
302                         int elem_idx = 0;
303                         for (int i = 0; i < INTERIOR_HANDLE_BITMAP_WORDS; ++i) {
304                                 elem_idx = i * INTERIOR_HANDLE_BITMAP_BITS_PER_WORD;
305                                 if (elem_idx >= cur->size)
306                                         break;
307                                 /* no interior pointers in the range */ 
308                                 if (cur->interior_bitmap [i] == 0)
309                                         continue;
310                                 for (int j = 0; j < INTERIOR_HANDLE_BITMAP_BITS_PER_WORD && elem_idx < cur->size; ++j,++elem_idx) {
311                                         HandleChunkElem *elem = chunk_element (cur, elem_idx);
312                                         int kind = chunk_element_kind (cur, elem_idx);
313                                         gpointer *ptr_slot = &elem->o;
314                                         if (kind == HANDLE_CHUNK_PTR_INTERIOR && *ptr_slot != NULL)
315                                                 func (ptr_slot, gc_data);
316                                 }
317                         }            
318                 }
319                 if (cur == last)
320                         break;
321                 cur = cur->next;
322         }
323 }
324
325 void
326 mono_stack_mark_record_size (MonoThreadInfo *info, HandleStackMark *stackmark, const char *func_name)
327 {
328         HandleStack *handles = (HandleStack *)info->handle_stack;
329         HandleChunk *cur = stackmark->chunk;
330         int size = -stackmark->size; //discard the starting point of the stack
331         while (cur) {
332                 size += cur->size;
333                 if (cur == handles->top)
334                         break;
335                 cur = cur->next;
336         }
337
338         if (size > THIS_IS_AN_OK_NUMBER_OF_HANDLES)
339                 g_warning ("%s USED %d handles\n", func_name, size);
340 }
341
342 /*
343  * Pop the stack until @stackmark and make @value the top value.
344  *
345  * @return the new handle for what @value points to 
346  */
347 MonoRawHandle
348 mono_stack_mark_pop_value (MonoThreadInfo *info, HandleStackMark *stackmark, MonoRawHandle value)
349 {
350         MonoObject *obj = value ? *((MonoObject**)value) : NULL;
351         mono_stack_mark_pop (info, stackmark);
352 #ifndef MONO_HANDLE_TRACK_OWNER
353         return mono_handle_new (obj);
354 #else
355         return mono_handle_new (obj, "<mono_stack_mark_pop_value>");
356 #endif
357 }
358
359 /* Temporary place for some of the handle enabled wrapper functions*/
360
361 MonoStringHandle
362 mono_string_new_handle (MonoDomain *domain, const char *data, MonoError *error)
363 {
364         return MONO_HANDLE_NEW (MonoString, mono_string_new_checked (domain, data, error));
365 }
366
367 MonoArrayHandle
368 mono_array_new_handle (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
369 {
370         return MONO_HANDLE_NEW (MonoArray, mono_array_new_checked (domain, eclass, n, error));
371 }
372
373 MonoArrayHandle
374 mono_array_new_full_handle (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
375 {
376         return MONO_HANDLE_NEW (MonoArray, mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, error));
377 }
378
379 #ifdef ENABLE_CHECKED_BUILD
380 /* Checked build helpers */
381 void
382 mono_handle_verify (MonoRawHandle raw_handle)
383 {
384         
385 }
386 #endif
387
388 uintptr_t
389 mono_array_handle_length (MonoArrayHandle arr)
390 {
391         MONO_REQ_GC_UNSAFE_MODE;
392
393         return MONO_HANDLE_RAW (arr)->max_length;
394 }
395
396 uint32_t
397 mono_gchandle_from_handle (MonoObjectHandle handle, mono_bool pinned)
398 {
399         /* FIXME: chunk_element_to_chunk_idx does a linear search through the
400          * chunks and we only need it for the assert */
401         MonoThreadInfo *info = mono_thread_info_current ();
402         HandleStack *stack = (HandleStack*) info->handle_stack;
403         HandleChunkElem* elem = handle_to_chunk_element (handle);
404         int elem_idx = 0;
405         HandleChunk *chunk = chunk_element_to_chunk_idx (stack, elem, &elem_idx);
406         /* gchandles cannot deal with interior pointers */
407         g_assert (chunk != NULL);
408         g_assert (chunk_element_kind (chunk, elem_idx) != HANDLE_CHUNK_PTR_INTERIOR);
409         return mono_gchandle_new (MONO_HANDLE_RAW (handle), pinned);
410 }
411
412 MonoObjectHandle
413 mono_gchandle_get_target_handle (uint32_t gchandle)
414 {
415         return MONO_HANDLE_NEW (MonoObject, mono_gchandle_get_target (gchandle));
416 }
417
418 gpointer
419 mono_array_handle_pin_with_size (MonoArrayHandle handle, int size, uintptr_t idx, uint32_t *gchandle)
420 {
421         g_assert (gchandle != NULL);
422         *gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST(MonoObject,handle), TRUE);
423         MonoArray *raw = MONO_HANDLE_RAW (handle);
424         return mono_array_addr_with_size (raw, size, idx);
425 }
426
427 void
428 mono_array_handle_memcpy_refs (MonoArrayHandle dest, uintptr_t dest_idx, MonoArrayHandle src, uintptr_t src_idx, uintptr_t len)
429 {
430         mono_array_memcpy_refs (MONO_HANDLE_RAW (dest), dest_idx, MONO_HANDLE_RAW (src), src_idx, len);
431 }
432
433 gboolean
434 mono_handle_stack_is_empty (HandleStack *stack)
435 {
436         return (stack->top == stack->bottom && stack->top->size == 0);
437 }