Merge pull request #5714 from alexischr/update_bockbuild
[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 #ifdef HAVE_BACKTRACE_SYMBOLS
24 #include <execinfo.h>
25 #endif
26
27 /* TODO (missing pieces)
28
29 Add counters for:
30         number of stack marks
31         stack marks per icall
32         mix/max/avg size of stack marks
33         handle stack wastage
34
35 Actually do something in mono_handle_verify
36
37 Shrink the handles stack in mono_handle_stack_scan
38 Properly report it to the profiler.
39 Add a boehm implementation
40
41 TODO (things to explore):
42
43 There's no convenient way to wrap the object allocation function.
44 Right now we do this:
45         MonoCultureInfoHandle culture = MONO_HANDLE_NEW (MonoCultureInfo, mono_object_new_checked (domain, klass, &error));
46
47 Maybe what we need is a round of cleanup around all exposed types in the runtime to unify all helpers under the same hoof.
48 Combine: MonoDefaults, GENERATE_GET_CLASS_WITH_CACHE, TYPED_HANDLE_DECL and friends.
49         This would solve the age old issue of making it clear which types are optional and tell that to the linker.
50         We could then generate neat type safe wrappers.
51 */
52
53 /*
54  * NOTE: Async suspend
55  * 
56  * If we are running with cooperative GC, all the handle stack
57  * manipulation will complete before a GC thread scans the handle
58  * stack. If we are using async suspend, however, a thread may be
59  * trying to allocate a new handle, or unwind the handle stack when
60  * the GC stops the world.
61  *
62  * In particular, we need to ensure that if the mutator thread is
63  * suspended while manipulating the handle stack, the stack is in a
64  * good enough state to be scanned.  In particular, the size of each
65  * chunk should be updated before an object is written into the
66  * handle, and chunks to be scanned (between bottom and top) should
67  * always be valid.
68  *
69  * Note that the handle stack is scanned PRECISELY (see
70  * sgen_client_scan_thread_data ()).  That means there should not be
71  * stale objects scanned.  So when we manipulate the size of a chunk,
72  * wemust ensure that the newly scannable slot is either null or
73  * points to a valid value.
74  */
75
76 #if defined(HAVE_BOEHM_GC) || defined(HAVE_NULL_GC)
77 static HandleStack*
78 new_handle_stack (void)
79 {
80         return (HandleStack *)mono_gc_alloc_fixed (sizeof (HandleStack), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_HANDLE, "Thread Handle Stack");
81 }
82
83 static void
84 free_handle_stack (HandleStack *stack)
85 {
86         mono_gc_free_fixed (stack);
87 }
88
89 static HandleChunk*
90 new_handle_chunk (void)
91 {
92 #if defined(HAVE_BOEHM_GC)
93         return (HandleChunk *)GC_MALLOC (sizeof (HandleChunk));
94 #elif defined(HAVE_NULL_GC)
95         return (HandleChunk *)g_malloc (sizeof (HandleChunk));
96 #endif
97 }
98
99 static void
100 free_handle_chunk (HandleChunk *chunk)
101 {
102 #if defined(HAVE_NULL_GC)
103         g_free (chunk);
104 #endif
105 }
106 #else
107 static HandleStack*
108 new_handle_stack (void)
109 {
110         return g_new (HandleStack, 1);
111 }
112
113 static void
114 free_handle_stack (HandleStack *stack)
115 {
116         g_free (stack);
117 }
118
119 static HandleChunk*
120 new_handle_chunk (void)
121 {
122         return g_new (HandleChunk, 1);
123 }
124
125 static void
126 free_handle_chunk (HandleChunk *chunk)
127 {
128         g_free (chunk);
129 }
130 #endif
131
132 const MonoObjectHandle mono_null_value_handle = NULL;
133
134 #define THIS_IS_AN_OK_NUMBER_OF_HANDLES 100
135
136 static HandleChunkElem*
137 chunk_element (HandleChunk *chunk, int idx)
138 {
139         return &chunk->elems[idx];
140 }
141
142 static HandleChunkElem*
143 handle_to_chunk_element (MonoObjectHandle o)
144 {
145         return (HandleChunkElem*)o;
146 }
147
148 /* Given a HandleChunkElem* search through the current handle stack to find its chunk and offset. */
149 static HandleChunk*
150 chunk_element_to_chunk_idx (HandleStack *stack, HandleChunkElem *elem, int *out_idx)
151 {
152         HandleChunk *top = stack->top;
153         HandleChunk *cur = stack->bottom;
154
155         *out_idx = 0;
156
157         while (cur != NULL) {
158                 HandleChunkElem *front = &cur->elems [0];
159                 HandleChunkElem *back = &cur->elems [cur->size];
160
161                 if (front <= elem && elem < back) {
162                         *out_idx = (int)(elem - front);
163                         return cur;
164                 }
165
166                 if (cur == top)
167                         break; /* didn't find it. */
168                 cur = cur->next;
169         }
170         return NULL;
171 }
172
173 #ifdef MONO_HANDLE_TRACK_OWNER
174 #ifdef HAVE_BACKTRACE_SYMBOLS
175 #define SET_BACKTRACE(btaddrs) do {                                     \
176         backtrace(btaddrs, 7);                                          \
177         } while (0)
178 #else
179 #define SET_BACKTRACE(btaddrs) 0
180 #endif
181 #define SET_OWNER(chunk,idx) do { (chunk)->elems[(idx)].owner = owner; SET_BACKTRACE (&((chunk)->elems[(idx)].backtrace_ips[0])); } while (0)
182 #else
183 #define SET_OWNER(chunk,idx) do { } while (0)
184 #endif
185
186 #ifdef MONO_HANDLE_TRACK_SP
187 #define SET_SP(handles,chunk,idx) do { (chunk)->elems[(idx)].alloc_sp = handles->stackmark_sp; } while (0)
188 #else
189 #define SET_SP(handles,chunk,idx) do { } while (0)
190 #endif
191
192 #ifdef MONO_HANDLE_TRACK_SP
193 void
194 mono_handle_chunk_leak_check (HandleStack *handles) {
195         if (handles->stackmark_sp) {
196                 /* walk back from the top to the topmost non-empty chunk */
197                 HandleChunk *c = handles->top;
198                 while (c && c->size <= 0 && c != handles->bottom) {
199                         c = c->prev;
200                 }
201                 if (c == NULL || c->size == 0)
202                         return;
203                 g_assert (c && c->size > 0);
204                 HandleChunkElem *e = chunk_element (c, c->size - 1);
205                 if (e->alloc_sp < handles->stackmark_sp) {
206                         /* If we get here, the topmost object on the handle stack was
207                          * allocated from a function that is deeper in the call stack than
208                          * the most recent HANDLE_FUNCTION_ENTER.  That means it was
209                          * probably not wrapped in a HANDLE_FUNCTION_ENTER/_RETURN pair
210                          * and will never be reclaimed. */
211                         g_warning ("Handle %p (object = %p) (allocated from \"%s\") is leaking.\n", e, e->o,
212 #ifdef MONO_HANDLE_TRACK_OWNER
213                                    e->owner
214 #else
215                                    "<unknown owner>"
216 #endif
217                                 );
218                 }
219         }
220 }
221 #endif
222
223 /* Actual handles implementation */
224 MonoRawHandle
225 #ifndef MONO_HANDLE_TRACK_OWNER
226 mono_handle_new (MonoObject *obj)
227 #else
228 mono_handle_new (MonoObject *obj, const char *owner)
229 #endif
230 {
231         MonoThreadInfo *info = mono_thread_info_current ();
232         HandleStack *handles = (HandleStack *)info->handle_stack;
233         HandleChunk *top = handles->top;
234 #ifdef MONO_HANDLE_TRACK_SP
235         mono_handle_chunk_leak_check (handles);
236 #endif
237
238 retry:
239         if (G_LIKELY (top->size < OBJECTS_PER_HANDLES_CHUNK)) {
240                 int idx = top->size;
241                 gpointer* objslot = &top->elems [idx].o;
242                 /* can be interrupted anywhere here, so:
243                  * 1. make sure the new slot is null
244                  * 2. make the new slot scannable (increment size)
245                  * 3. put a valid object in there
246                  *
247                  * (have to do 1 then 3 so that if we're interrupted
248                  * between 1 and 2, the object is still live)
249                  */
250                 *objslot = NULL;
251                 mono_memory_write_barrier ();
252                 top->size++;
253                 mono_memory_write_barrier ();
254                 *objslot = obj;
255                 SET_OWNER (top,idx);
256                 SET_SP (handles, top, idx);
257                 return objslot;
258         }
259         if (G_LIKELY (top->next)) {
260                 top->next->size = 0;
261                 /* make sure size == 0 is visible to a GC thread before it sees the new top */
262                 mono_memory_write_barrier ();
263                 top = top->next;
264                 handles->top = top;
265                 goto retry;
266         }
267         HandleChunk *new_chunk = new_handle_chunk ();
268         new_chunk->size = 0;
269         new_chunk->prev = top;
270         new_chunk->next = NULL;
271         /* make sure size == 0 before new chunk is visible */
272         mono_memory_write_barrier ();
273         top->next = new_chunk;
274         handles->top = new_chunk;
275         goto retry;
276 }
277
278 MonoRawHandle
279 #ifndef MONO_HANDLE_TRACK_OWNER
280 mono_handle_new_interior (gpointer rawptr)
281 #else
282 mono_handle_new_interior (gpointer rawptr, const char *owner)
283 #endif
284 {
285         MonoThreadInfo *info = mono_thread_info_current ();
286         HandleStack *handles = (HandleStack *)info->handle_stack;
287         HandleChunk *top = handles->interior;
288 #ifdef MONO_HANDLE_TRACK_SP
289         mono_handle_chunk_leak_check (handles);
290 #endif
291
292         g_assert (top);
293
294         /*
295          * Don't extend the chunk now, interior handles are
296          * only used for icall arguments, they shouldn't
297          * overflow.
298          */
299         g_assert (top->size < OBJECTS_PER_HANDLES_CHUNK);
300         int idx = top->size;
301         gpointer *objslot = &top->elems [idx].o;
302         *objslot = NULL;
303         mono_memory_write_barrier ();
304         top->size++;
305         mono_memory_write_barrier ();
306         *objslot = rawptr;
307         SET_OWNER (top,idx);
308         SET_SP (handles, top, idx);
309         return objslot;
310 }
311
312 HandleStack*
313 mono_handle_stack_alloc (void)
314 {
315         HandleStack *stack = new_handle_stack ();
316         HandleChunk *chunk = new_handle_chunk ();
317         HandleChunk *interior = new_handle_chunk ();
318
319         chunk->prev = chunk->next = NULL;
320         chunk->size = 0;
321         interior->prev = interior->next = NULL;
322         interior->size = 0;
323         mono_memory_write_barrier ();
324         stack->top = stack->bottom = chunk;
325         stack->interior = interior;
326 #ifdef MONO_HANDLE_TRACK_SP
327         stack->stackmark_sp = NULL;
328 #endif
329         return stack;
330 }
331
332 void
333 mono_handle_stack_free (HandleStack *stack)
334 {
335         if (!stack)
336                 return;
337         HandleChunk *c = stack->bottom;
338         stack->top = stack->bottom = NULL;
339         mono_memory_write_barrier ();
340         while (c) {
341                 HandleChunk *next = c->next;
342                 free_handle_chunk (c);
343                 c = next;
344         }
345         free_handle_chunk (c);
346         free_handle_chunk (stack->interior);
347         free_handle_stack (stack);
348 }
349
350 void
351 mono_handle_stack_free_domain (HandleStack *stack, MonoDomain *domain)
352 {
353         /* Called by the GC while clearing out objects of the given domain from the heap. */
354         /* If there are no handles-related bugs, there is nothing to do: if a
355          * thread accessed objects from the domain it was aborted, so any
356          * threads left alive cannot have any handles that point into the
357          * unloading domain.  However if there is a handle leak, the handle stack is not */
358         if (!stack)
359                 return;
360         /* Root domain only unloaded when mono is shutting down, don't need to check anything */
361         if (domain == mono_get_root_domain () || mono_runtime_is_shutting_down ())
362                 return;
363         HandleChunk *cur = stack->bottom;
364         HandleChunk *last = stack->top;
365         if (!cur)
366                 return;
367         while (cur) {
368                 for (int idx = 0; idx < cur->size; ++idx) {
369                         HandleChunkElem *elem = &cur->elems[idx];
370                         if (!elem->o)
371                                 continue;
372                         g_assert (mono_object_domain (elem->o) != domain);
373                 }
374                 if (cur == last)
375                         break;
376                 cur = cur->next;
377         }
378         /* We don't examine the interior pointers here because the GC treats
379          * them conservatively and anyway we don't have enough information here to
380          * find the object's vtable.
381          */
382 }
383
384 static void
385 check_handle_stack_monotonic (HandleStack *stack)
386 {
387         /* check that every allocated handle in the current handle stack is at no higher in the native stack than its predecessors */
388 #ifdef MONO_HANDLE_TRACK_SP
389         HandleChunk *cur = stack->bottom;
390         HandleChunk *last = stack->top;
391         if (!cur)
392                 return;
393         HandleChunkElem *prev = NULL;
394         gboolean monotonic = TRUE;
395         while (cur) {
396                 for (int i = 0;i < cur->size; ++i) {
397                         HandleChunkElem *elem = chunk_element (cur, i);
398                         if (prev && elem->alloc_sp < prev->alloc_sp) {
399                                 monotonic = FALSE;
400                                 g_warning ("Handle %p (object %p) (allocated from \"%s\") is was allocated deeper in the call stack than its successor (allocated from \"%s\").", prev, prev->o,
401 #ifdef MONO_HANDLE_TRACK_OWNER
402                                            prev->owner,
403                                            elem->owner
404 #else
405                                            "unknown owner",
406                                            "unknown owner"
407 #endif
408                                         );
409                                 
410                         }
411                         prev = elem;
412                 }
413                 if (cur == last)
414                         break;
415                 cur = cur->next;
416         }
417         g_assert (monotonic);
418 #endif
419 }
420
421 void
422 mono_handle_stack_scan (HandleStack *stack, GcScanFunc func, gpointer gc_data, gboolean precise)
423 {
424         if (precise) /* run just once (per handle stack) per GC */
425                 check_handle_stack_monotonic (stack);
426         /*
427           We're called twice - on the imprecise pass we call func to pin the
428           objects where the handle points to its interior.  On the precise
429           pass, we scan all the objects where the handles point to the start of
430           the object.
431
432           Note that if we're running, we know the world is stopped.
433         */
434         if (precise) {
435                 HandleChunk *cur = stack->bottom;
436                 HandleChunk *last = stack->top;
437
438                 while (cur) {
439                         for (int i = 0; i < cur->size; ++i) {
440                                 HandleChunkElem* elem = chunk_element (cur, i);
441                                 gpointer* obj_slot = &elem->o;
442                                 if (*obj_slot != NULL)
443                                         func (obj_slot, gc_data);
444                         }
445                         if (cur == last)
446                                 break;
447                         cur = cur->next;
448                 }
449         } else {
450                 HandleChunk *cur = stack->interior;
451
452                 if (!cur)
453                         return;
454                 for (int i = 0; i < cur->size; ++i) {
455                         HandleChunkElem* elem = chunk_element (cur, i);
456                         gpointer* ptr_slot = &elem->o;
457                         if (*ptr_slot != NULL)
458                                 func (ptr_slot, gc_data);
459                 }
460         }
461 }
462
463 void
464 mono_stack_mark_record_size (MonoThreadInfo *info, HandleStackMark *stackmark, const char *func_name)
465 {
466         HandleStack *handles = (HandleStack *)info->handle_stack;
467         HandleChunk *cur = stackmark->chunk;
468         int size = -stackmark->size; //discard the starting point of the stack
469         while (cur) {
470                 size += cur->size;
471                 if (cur == handles->top)
472                         break;
473                 cur = cur->next;
474         }
475
476         if (size > THIS_IS_AN_OK_NUMBER_OF_HANDLES)
477                 g_warning ("%s USED %d handles\n", func_name, size);
478 }
479
480 /*
481  * Pop the stack until @stackmark and make @value the top value.
482  *
483  * @return the new handle for what @value points to 
484  */
485 MonoRawHandle
486 mono_stack_mark_pop_value (MonoThreadInfo *info, HandleStackMark *stackmark, MonoRawHandle value)
487 {
488         MonoObject *obj = value ? *((MonoObject**)value) : NULL;
489         mono_stack_mark_pop (info, stackmark);
490 #ifndef MONO_HANDLE_TRACK_OWNER
491         return mono_handle_new (obj);
492 #else
493         return mono_handle_new (obj, "<mono_stack_mark_pop_value>");
494 #endif
495 }
496
497 /* Temporary place for some of the handle enabled wrapper functions*/
498
499 MonoStringHandle
500 mono_string_new_handle (MonoDomain *domain, const char *data, MonoError *error)
501 {
502         return MONO_HANDLE_NEW (MonoString, mono_string_new_checked (domain, data, error));
503 }
504
505 MonoArrayHandle
506 mono_array_new_handle (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
507 {
508         return MONO_HANDLE_NEW (MonoArray, mono_array_new_checked (domain, eclass, n, error));
509 }
510
511 MonoArrayHandle
512 mono_array_new_full_handle (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
513 {
514         return MONO_HANDLE_NEW (MonoArray, mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, error));
515 }
516
517 #ifdef ENABLE_CHECKED_BUILD
518 /* Checked build helpers */
519 void
520 mono_handle_verify (MonoRawHandle raw_handle)
521 {
522         
523 }
524 #endif
525
526 uintptr_t
527 mono_array_handle_length (MonoArrayHandle arr)
528 {
529         MONO_REQ_GC_UNSAFE_MODE;
530
531         return MONO_HANDLE_RAW (arr)->max_length;
532 }
533
534 uint32_t
535 mono_gchandle_from_handle (MonoObjectHandle handle, mono_bool pinned)
536 {
537         /* FIXME: chunk_element_to_chunk_idx does a linear search through the
538          * chunks and we only need it for the assert */
539         MonoThreadInfo *info = mono_thread_info_current ();
540         HandleStack *stack = (HandleStack*) info->handle_stack;
541         HandleChunkElem* elem = handle_to_chunk_element (handle);
542         int elem_idx = 0;
543         HandleChunk *chunk = chunk_element_to_chunk_idx (stack, elem, &elem_idx);
544         /* gchandles cannot deal with interior pointers */
545         g_assert (chunk != NULL);
546         return mono_gchandle_new (MONO_HANDLE_RAW (handle), pinned);
547 }
548
549 MonoObjectHandle
550 mono_gchandle_get_target_handle (uint32_t gchandle)
551 {
552         return MONO_HANDLE_NEW (MonoObject, mono_gchandle_get_target (gchandle));
553 }
554
555 gpointer
556 mono_array_handle_pin_with_size (MonoArrayHandle handle, int size, uintptr_t idx, uint32_t *gchandle)
557 {
558         g_assert (gchandle != NULL);
559         *gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST(MonoObject,handle), TRUE);
560         MonoArray *raw = MONO_HANDLE_RAW (handle);
561         return mono_array_addr_with_size (raw, size, idx);
562 }
563
564 gunichar2*
565 mono_string_handle_pin_chars (MonoStringHandle handle, uint32_t *gchandle)
566 {
567         g_assert (gchandle != NULL);
568         *gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, handle), TRUE);
569         MonoString *raw = MONO_HANDLE_RAW (handle);
570         return mono_string_chars (raw);
571 }
572
573 gpointer
574 mono_object_handle_pin_unbox (MonoObjectHandle obj, uint32_t *gchandle)
575 {
576         g_assert (!MONO_HANDLE_IS_NULL (obj));
577         MonoClass *klass = mono_handle_class (obj);
578         g_assert (klass->valuetype);
579         *gchandle = mono_gchandle_from_handle (obj, TRUE);
580         return mono_object_unbox (MONO_HANDLE_RAW (obj));
581 }
582
583 void
584 mono_array_handle_memcpy_refs (MonoArrayHandle dest, uintptr_t dest_idx, MonoArrayHandle src, uintptr_t src_idx, uintptr_t len)
585 {
586         mono_array_memcpy_refs (MONO_HANDLE_RAW (dest), dest_idx, MONO_HANDLE_RAW (src), src_idx, len);
587 }
588
589 gboolean
590 mono_handle_stack_is_empty (HandleStack *stack)
591 {
592         return (stack->top == stack->bottom && stack->top->size == 0);
593 }