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