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