[Mono.Runtime.Tests] Exclude simd tests
[mono-project.git] / mono / metadata / handle.c
blobbce1308ad9e95eb2d9657f0247be6cd2abff05a5
1 /**
2 * \file
3 * Handle to object in native code
5 * Authors:
6 * - Ludovic Henry <ludovic@xamarin.com>
7 * - Aleksey Klieger <aleksey.klieger@xamarin.com>
8 * - Rodrigo Kumpera <kumpera@xamarin.com>
10 * Copyright 2016 Dot net foundation.
11 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
14 #include <config.h>
15 #include <glib.h>
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
27 /* TODO (missing pieces)
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
35 Shrink the handles stack in mono_handle_stack_scan
36 Add a boehm implementation
38 TODO (things to explore):
40 There's no convenient way to wrap the object allocation function.
41 Right now we do this:
42 MonoCultureInfoHandle culture = MONO_HANDLE_NEW (MonoCultureInfo, mono_object_new_checked (domain, klass, error));
44 Maybe what we need is a round of cleanup around all exposed types in the runtime to unify all helpers under the same hoof.
45 Combine: MonoDefaults, GENERATE_GET_CLASS_WITH_CACHE, TYPED_HANDLE_DECL and friends.
46 This would solve the age old issue of making it clear which types are optional and tell that to the linker.
47 We could then generate neat type safe wrappers.
51 * NOTE: Async suspend
53 * If we are running with cooperative GC, all the handle stack
54 * manipulation will complete before a GC thread scans the handle
55 * stack. If we are using async suspend, however, a thread may be
56 * trying to allocate a new handle, or unwind the handle stack when
57 * the GC stops the world.
59 * In particular, we need to ensure that if the mutator thread is
60 * suspended while manipulating the handle stack, the stack is in a
61 * good enough state to be scanned. In particular, the size of each
62 * chunk should be updated before an object is written into the
63 * handle, and chunks to be scanned (between bottom and top) should
64 * always be valid.
66 * Note that the handle stack is scanned PRECISELY (see
67 * sgen_client_scan_thread_data ()). That means there should not be
68 * stale objects scanned. So when we manipulate the size of a chunk,
69 * we must ensure that the newly scannable slot is either null or
70 * points to a valid value.
73 static HandleStack*
74 new_handle_stack (void)
76 return g_new (HandleStack, 1);
79 static void
80 free_handle_stack (HandleStack *stack)
82 g_free (stack);
85 static HandleChunk*
86 new_handle_chunk (void)
88 return g_new (HandleChunk, 1);
91 static void
92 free_handle_chunk (HandleChunk *chunk)
94 g_free (chunk);
97 const MonoObjectHandle mono_null_value_handle = { 0 };
99 #define THIS_IS_AN_OK_NUMBER_OF_HANDLES 100
101 static HandleChunkElem*
102 chunk_element (HandleChunk *chunk, int idx)
104 return &chunk->elems[idx];
108 #ifdef MONO_HANDLE_TRACK_OWNER
109 #ifdef HAVE_BACKTRACE_SYMBOLS
110 #define SET_BACKTRACE(btaddrs) do { \
111 backtrace(btaddrs, 7); \
112 } while (0)
113 #else
114 #define SET_BACKTRACE(btaddrs) 0
115 #endif
116 #define SET_OWNER(chunk,idx) do { (chunk)->elems[(idx)].owner = owner; SET_BACKTRACE (&((chunk)->elems[(idx)].backtrace_ips[0])); } while (0)
117 #else
118 #define SET_OWNER(chunk,idx) do { } while (0)
119 #endif
121 #ifdef MONO_HANDLE_TRACK_SP
122 #define SET_SP(handles,chunk,idx) do { (chunk)->elems[(idx)].alloc_sp = handles->stackmark_sp; } while (0)
123 #else
124 #define SET_SP(handles,chunk,idx) do { } while (0)
125 #endif
127 #ifdef MONO_HANDLE_TRACK_SP
128 void
129 mono_handle_chunk_leak_check (HandleStack *handles) {
130 if (handles->stackmark_sp) {
131 /* walk back from the top to the topmost non-empty chunk */
132 HandleChunk *c = handles->top;
133 while (c && c->size <= 0 && c != handles->bottom) {
134 c = c->prev;
136 if (c == NULL || c->size == 0)
137 return;
138 g_assert (c && c->size > 0);
139 HandleChunkElem *e = chunk_element (c, c->size - 1);
140 if (e->alloc_sp < handles->stackmark_sp) {
141 /* If we get here, the topmost object on the handle stack was
142 * allocated from a function that is deeper in the call stack than
143 * the most recent HANDLE_FUNCTION_ENTER. That means it was
144 * probably not wrapped in a HANDLE_FUNCTION_ENTER/_RETURN pair
145 * and will never be reclaimed. */
146 g_warning ("Handle %p (object = %p) (allocated from \"%s\") is leaking.\n", e, e->o,
147 #ifdef MONO_HANDLE_TRACK_OWNER
148 e->owner
149 #else
150 "<unknown owner>"
151 #endif
156 #endif
158 // There are deliberately locals and a constant NULL global with this same name.
159 #ifdef __cplusplus
160 extern MonoThreadInfo * const mono_thread_info_current_var = NULL;
161 #else
162 MonoThreadInfo * const mono_thread_info_current_var = NULL;
163 #endif
165 /* Actual handles implementation */
166 MonoRawHandle
167 #ifndef MONO_HANDLE_TRACK_OWNER
168 mono_handle_new (MonoObject *obj, MonoThreadInfo *info)
169 #else
170 mono_handle_new (MonoObject *obj, MonoThreadInfo *info, const char *owner)
171 #endif
173 info = info ? info : mono_thread_info_current ();
174 HandleStack *handles = info->handle_stack;
175 HandleChunk *top = handles->top;
176 #ifdef MONO_HANDLE_TRACK_SP
177 mono_handle_chunk_leak_check (handles);
178 #endif
180 retry:
181 if (G_LIKELY (top->size < OBJECTS_PER_HANDLES_CHUNK)) {
182 int idx = top->size;
183 gpointer* objslot = &top->elems [idx].o;
184 /* can be interrupted anywhere here, so:
185 * 1. make sure the new slot is null
186 * 2. make the new slot scannable (increment size)
187 * 3. put a valid object in there
189 * (have to do 1 then 3 so that if we're interrupted
190 * between 1 and 2, the object is still live)
192 *objslot = NULL;
193 SET_OWNER (top,idx);
194 SET_SP (handles, top, idx);
195 mono_memory_write_barrier ();
196 top->size++;
197 mono_memory_write_barrier ();
198 *objslot = obj;
199 return objslot;
201 if (G_LIKELY (top->next)) {
202 top->next->size = 0;
203 /* make sure size == 0 is visible to a GC thread before it sees the new top */
204 mono_memory_write_barrier ();
205 top = top->next;
206 handles->top = top;
207 goto retry;
209 HandleChunk *new_chunk = new_handle_chunk ();
210 new_chunk->size = 0;
211 new_chunk->prev = top;
212 new_chunk->next = NULL;
213 /* make sure size == 0 before new chunk is visible */
214 mono_memory_write_barrier ();
215 top->next = new_chunk;
216 handles->top = new_chunk;
217 goto retry;
220 HandleStack*
221 mono_handle_stack_alloc (void)
223 HandleStack *stack = new_handle_stack ();
224 HandleChunk *chunk = new_handle_chunk ();
226 chunk->prev = chunk->next = NULL;
227 chunk->size = 0;
228 mono_memory_write_barrier ();
229 stack->top = stack->bottom = chunk;
230 #ifdef MONO_HANDLE_TRACK_SP
231 stack->stackmark_sp = NULL;
232 #endif
233 return stack;
236 void
237 mono_handle_stack_free (HandleStack *stack)
239 if (!stack)
240 return;
241 HandleChunk *c = stack->bottom;
242 stack->top = stack->bottom = NULL;
243 mono_memory_write_barrier ();
244 while (c) {
245 HandleChunk *next = c->next;
246 free_handle_chunk (c);
247 c = next;
249 free_handle_chunk (c);
250 free_handle_stack (stack);
253 void
254 mono_handle_stack_free_domain (HandleStack *stack, MonoDomain *domain)
256 /* Called by the GC while clearing out objects of the given domain from the heap. */
257 /* If there are no handles-related bugs, there is nothing to do: if a
258 * thread accessed objects from the domain it was aborted, so any
259 * threads left alive cannot have any handles that point into the
260 * unloading domain. However if there is a handle leak, the handle stack is not */
261 if (!stack)
262 return;
263 /* Root domain only unloaded when mono is shutting down, don't need to check anything */
264 if (domain == mono_get_root_domain () || mono_runtime_is_shutting_down ())
265 return;
266 HandleChunk *cur = stack->bottom;
267 HandleChunk *last = stack->top;
268 if (!cur)
269 return;
270 while (cur) {
271 for (int idx = 0; idx < cur->size; ++idx) {
272 HandleChunkElem *elem = &cur->elems[idx];
273 if (!elem->o)
274 continue;
275 g_assert (mono_object_domain (elem->o) != domain);
277 if (cur == last)
278 break;
279 cur = cur->next;
283 static void
284 check_handle_stack_monotonic (HandleStack *stack)
286 /* check that every allocated handle in the current handle stack is at no higher in the native stack than its predecessors */
287 #ifdef MONO_HANDLE_TRACK_SP
288 HandleChunk *cur = stack->bottom;
289 HandleChunk *last = stack->top;
290 if (!cur)
291 return;
292 HandleChunkElem *prev = NULL;
293 gboolean monotonic = TRUE;
294 while (cur) {
295 for (int i = 0;i < cur->size; ++i) {
296 HandleChunkElem *elem = chunk_element (cur, i);
297 if (prev && elem->alloc_sp > prev->alloc_sp) {
298 monotonic = FALSE;
299 #ifdef MONO_HANDLE_TRACK_OWNER
300 g_warning ("Handle %p (object %p) (allocated from \"%s\") was allocated deeper in the call stack than its successor Handle %p (object %p) (allocated from \"%s\").", prev, prev->o, prev->owner, elem, elem->o, elem->owner);
301 #else
302 g_warning ("Handle %p (object %p) was allocated deeper in the call stack than its successor Handle %p (object %p).", prev, prev->o, elem, elem->o);
303 #endif
305 prev = elem;
307 if (cur == last)
308 break;
309 cur = cur->next;
311 g_assert (monotonic);
312 #endif
315 void
316 mono_handle_stack_scan (HandleStack *stack, GcScanFunc func, gpointer gc_data, gboolean precise, gboolean check)
318 if (check) /* run just once (per handle stack) per GC */
319 check_handle_stack_monotonic (stack);
322 We're called twice - on the imprecise pass we do nothing.
323 Interior pointers are retained in managed frames.
324 On the precise pass, we scan all the objects where the handles point to the start of
325 the object.
327 Note that if we're running, we know the world is stopped.
329 if (!precise)
330 return;
332 HandleChunk *cur = stack->bottom;
333 HandleChunk *last = stack->top;
335 while (cur) {
336 for (int i = 0; i < cur->size; ++i) {
337 HandleChunkElem* elem = chunk_element (cur, i);
338 gpointer* obj_slot = &elem->o;
339 if (*obj_slot != NULL)
340 func (obj_slot, gc_data);
342 if (cur == last)
343 break;
344 cur = cur->next;
348 void
349 mono_stack_mark_record_size (MonoThreadInfo *info, HandleStackMark *stackmark, const char *func_name)
351 HandleStack *handles = info->handle_stack;
352 HandleChunk *cur = stackmark->chunk;
353 int size = -stackmark->size; //discard the starting point of the stack
354 while (cur) {
355 size += cur->size;
356 if (cur == handles->top)
357 break;
358 cur = cur->next;
361 if (size > THIS_IS_AN_OK_NUMBER_OF_HANDLES)
362 g_warning ("%s USED %d handles\n", func_name, size);
366 * Pop the stack until @stackmark and make @value the top value.
368 * @return the new handle for what @value points to
370 MonoRawHandle
371 mono_stack_mark_pop_value (MonoThreadInfo *info, HandleStackMark *stackmark, MonoRawHandle value)
373 MonoObject *obj = value ? *((MonoObject**)value) : NULL;
374 mono_stack_mark_pop (info, stackmark);
375 #ifndef MONO_HANDLE_TRACK_OWNER
376 return mono_handle_new (obj, info);
377 #else
378 return mono_handle_new (obj, info, "<mono_stack_mark_pop_value>");
379 #endif
382 /* Temporary place for some of the handle enabled wrapper functions*/
384 MonoStringHandle
385 mono_string_new_handle (MonoDomain *domain, const char *data, MonoError *error)
387 return MONO_HANDLE_NEW (MonoString, mono_string_new_checked (domain, data, error));
390 MonoArrayHandle
391 mono_array_new_handle (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
393 return MONO_HANDLE_NEW (MonoArray, mono_array_new_checked (domain, eclass, n, error));
396 MonoArrayHandle
397 mono_array_new_full_handle (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
399 return MONO_HANDLE_NEW (MonoArray, mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, error));
402 uintptr_t
403 mono_array_handle_length (MonoArrayHandle arr)
405 MONO_REQ_GC_UNSAFE_MODE;
407 return MONO_HANDLE_RAW (arr)->max_length;
410 uint32_t
411 mono_gchandle_from_handle (MonoObjectHandle handle, mono_bool pinned)
413 // FIXME This used to check for out of scope handles.
414 // Stack-based handles coming from icall wrappers do not
415 // work with that. This functionality can be largely restored
416 // by introducing a tag bit in handles -- 0 for managed stack-based,
417 // 1 for native TLS-based, having MONO_HANDLE_RAW clear it, and only
418 // doing the former checking for native TLS-based handles.
419 return mono_gchandle_new_internal (MONO_HANDLE_RAW (handle), pinned);
422 MonoObjectHandle
423 mono_gchandle_get_target_handle (uint32_t gchandle)
425 return MONO_HANDLE_NEW (MonoObject, mono_gchandle_get_target_internal (gchandle));
428 gpointer
429 mono_array_handle_pin_with_size (MonoArrayHandle handle, int size, uintptr_t idx, uint32_t *gchandle)
431 g_assert (gchandle != NULL);
432 *gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST(MonoObject,handle), TRUE);
433 MonoArray *raw = MONO_HANDLE_RAW (handle);
434 return mono_array_addr_with_size_internal (raw, size, idx);
437 gunichar2*
438 mono_string_handle_pin_chars (MonoStringHandle handle, uint32_t *gchandle)
440 g_assert (gchandle != NULL);
441 *gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, handle), TRUE);
442 MonoString *raw = MONO_HANDLE_RAW (handle);
443 return mono_string_chars_internal (raw);
446 gpointer
447 mono_object_handle_pin_unbox (MonoObjectHandle obj, uint32_t *gchandle)
449 g_assert (!MONO_HANDLE_IS_NULL (obj));
450 MonoClass *klass = mono_handle_class (obj);
451 g_assert (m_class_is_valuetype (klass));
452 *gchandle = mono_gchandle_from_handle (obj, TRUE);
453 return mono_object_unbox_internal (MONO_HANDLE_RAW (obj));
456 //FIXME inline
457 void
458 mono_array_handle_memcpy_refs (MonoArrayHandle dest, uintptr_t dest_idx, MonoArrayHandle src, uintptr_t src_idx, uintptr_t len)
460 mono_array_memcpy_refs_internal (MONO_HANDLE_RAW (dest), dest_idx, MONO_HANDLE_RAW (src), src_idx, len);
463 gboolean
464 mono_handle_stack_is_empty (HandleStack *stack)
466 return stack->top == stack->bottom && stack->top->size == 0;
469 //FIXME inline
470 gboolean
471 mono_gchandle_target_equal (uint32_t gchandle, MonoObjectHandle equal)
473 // This function serves to reduce coop handle creation.
474 MONO_HANDLE_SUPPRESS_SCOPE (1);
475 return mono_gchandle_get_target_internal (gchandle) == MONO_HANDLE_RAW (equal);
478 //FIXME inline
479 void
480 mono_gchandle_target_is_null_or_equal (uint32_t gchandle, MonoObjectHandle equal, gboolean *is_null,
481 gboolean *is_equal)
483 // This function serves to reduce coop handle creation.
484 MONO_HANDLE_SUPPRESS_SCOPE (1);
485 MonoObject *target = mono_gchandle_get_target_internal (gchandle);
486 *is_null = target == NULL;
487 *is_equal = target == MONO_HANDLE_RAW (equal);
490 //FIXME inline
491 void
492 mono_gchandle_set_target_handle (guint32 gchandle, MonoObjectHandle obj)
494 mono_gchandle_set_target (gchandle, MONO_HANDLE_RAW (obj));
497 //FIXME inline
498 guint32
499 mono_gchandle_new_weakref_from_handle (MonoObjectHandle handle)
501 return mono_gchandle_new_weakref_internal (MONO_HANDLE_SUPPRESS (MONO_HANDLE_RAW (handle)), FALSE);
504 //FIXME inline
506 mono_handle_hash (MonoObjectHandle object)
508 return mono_object_hash_internal (MONO_HANDLE_SUPPRESS (MONO_HANDLE_RAW (object)));
511 //FIXME inline
512 guint32
513 mono_gchandle_new_weakref_from_handle_track_resurrection (MonoObjectHandle handle)
515 return mono_gchandle_new_weakref_internal (MONO_HANDLE_SUPPRESS (MONO_HANDLE_RAW (handle)), TRUE);
518 //FIXME inline
519 void
520 mono_handle_array_getref (MonoObjectHandleOut dest, MonoArrayHandle array, uintptr_t index)
522 MONO_HANDLE_SUPPRESS (g_assert (dest.__raw));
523 MONO_HANDLE_SUPPRESS (*dest.__raw = (MonoObject*)mono_array_get_internal (MONO_HANDLE_RAW (array), gpointer, index));