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