3 * Handle to object in native code
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 #ifndef __MONO_HANDLE_H__
15 #define __MONO_HANDLE_H__
20 #include <mono/metadata/object.h>
21 #include <mono/metadata/class.h>
22 #include <mono/utils/mono-error-internals.h>
23 #include <mono/utils/mono-threads.h>
24 #include <mono/utils/checked-build.h>
31 The handle stack is designed so it's efficient to pop a large amount of entries at once.
32 The stack is made out of a series of fixed size segments.
34 To do bulk operations you use a stack mark.
39 3 is the number of fields besides the data in the struct;
40 128 words makes each chunk 512 or 1024 bytes each
42 #define OBJECTS_PER_HANDLES_CHUNK (128 - 3)
45 Whether this config needs stack watermark recording to know where to start scanning from.
48 #define MONO_NEEDS_STACK_WATERMARK 1
51 typedef struct _HandleChunk HandleChunk;
53 /* define MONO_HANDLE_TRACK_OWNER to store the file and line number of each call to MONO_HANDLE_NEW
54 * in the handle stack. (This doubles the amount of memory used for handles, so it's only useful for debugging).
56 /*#define MONO_HANDLE_TRACK_OWNER*/
58 /* define MONO_HANDLE_TRACK_SP to record the C stack pointer at the time of each HANDLE_FUNCTION_ENTER and
59 * to ensure that when a new handle is allocated the previous newest handle is not lower in the stack.
60 * This is useful to catch missing HANDLE_FUNCTION_ENTER / HANDLE_FUNCTION_RETURN pairs which could cause
63 /*#define MONO_HANDLE_TRACK_SP*/
66 gpointer o; /* MonoObject ptr or interior ptr */
67 #ifdef MONO_HANDLE_TRACK_OWNER
70 #ifdef MONO_HANDLE_TRACK_SP
71 gpointer alloc_sp; /* sp from HandleStack:stackmark_sp at time of allocation */
76 int size; //number of handles
77 HandleChunk *prev, *next;
78 HandleChunkElem elems [OBJECTS_PER_HANDLES_CHUNK];
82 HandleChunk *top; //alloc from here
83 HandleChunk *bottom; //scan from here
84 #ifdef MONO_HANDLE_TRACK_SP
85 gpointer stackmark_sp; // C stack pointer top when from most recent mono_stack_mark_init
87 /* Chunk for storing interior pointers. Not extended right now */
88 HandleChunk *interior;
91 // Keep this in sync with RuntimeStructs.cs
93 int size, interior_size;
95 #ifdef MONO_HANDLE_TRACK_SP
96 gpointer prev_sp; // C stack pointer from prior mono_stack_mark_init
100 typedef void *MonoRawHandle;
102 typedef void (*GcScanFunc) (gpointer*, gpointer);
105 #ifndef MONO_HANDLE_TRACK_OWNER
106 MonoRawHandle mono_handle_new (MonoObject *object);
107 MonoRawHandle mono_handle_new_full (gpointer rawptr, gboolean interior);
108 MonoRawHandle mono_handle_new_interior (gpointer rawptr);
110 MonoRawHandle mono_handle_new (MonoObject *object, const char* owner);
111 MonoRawHandle mono_handle_new_full (gpointer rawptr, gboolean interior, const char *owner);
112 MonoRawHandle mono_handle_new_interior (gpointer rawptr, const char *owner);
115 void mono_handle_stack_scan (HandleStack *stack, GcScanFunc func, gpointer gc_data, gboolean precise);
116 gboolean mono_handle_stack_is_empty (HandleStack *stack);
117 HandleStack* mono_handle_stack_alloc (void);
118 void mono_handle_stack_free (HandleStack *handlestack);
119 MonoRawHandle mono_stack_mark_pop_value (MonoThreadInfo *info, HandleStackMark *stackmark, MonoRawHandle value);
120 void mono_stack_mark_record_size (MonoThreadInfo *info, HandleStackMark *stackmark, const char *func_name);
122 #ifdef MONO_HANDLE_TRACK_SP
123 void mono_handle_chunk_leak_check (HandleStack *handles);
127 mono_stack_mark_init (MonoThreadInfo *info, HandleStackMark *stackmark)
129 #ifdef MONO_HANDLE_TRACK_SP
130 gpointer sptop = (gpointer)(intptr_t)&stackmark;
132 HandleStack *handles = (HandleStack *)info->handle_stack;
133 stackmark->size = handles->top->size;
134 stackmark->chunk = handles->top;
135 stackmark->interior_size = handles->interior->size;
136 #ifdef MONO_HANDLE_TRACK_SP
137 stackmark->prev_sp = handles->stackmark_sp;
138 handles->stackmark_sp = sptop;
143 mono_stack_mark_pop (MonoThreadInfo *info, HandleStackMark *stackmark)
145 HandleStack *handles = (HandleStack *)info->handle_stack;
146 HandleChunk *old_top = stackmark->chunk;
147 old_top->size = stackmark->size;
148 mono_memory_write_barrier ();
149 handles->top = old_top;
150 handles->interior->size = stackmark->interior_size;
151 #ifdef MONO_HANDLE_TRACK_SP
152 mono_memory_write_barrier (); /* write to top before prev_sp */
153 handles->stackmark_sp = stackmark->prev_sp;
160 #define SETUP_ICALL_COMMON \
163 MonoThreadInfo *__info = mono_thread_info_current (); \
164 error_init (&error); \
166 #define CLEAR_ICALL_COMMON \
167 mono_error_set_pending_exception (&error);
169 #define SETUP_ICALL_FRAME \
170 HandleStackMark __mark; \
171 mono_stack_mark_init (__info, &__mark);
173 #define CLEAR_ICALL_FRAME \
174 mono_stack_mark_record_size (__info, &__mark, __FUNCTION__); \
175 mono_stack_mark_pop (__info, &__mark);
177 #define CLEAR_ICALL_FRAME_VALUE(RESULT, HANDLE) \
178 mono_stack_mark_record_size (__info, &__mark, __FUNCTION__); \
179 (RESULT) = mono_stack_mark_pop_value (__info, &__mark, (HANDLE));
182 #define HANDLE_FUNCTION_ENTER() do { \
183 MonoThreadInfo *__info = mono_thread_info_current (); \
186 #define HANDLE_FUNCTION_RETURN() \
190 #define HANDLE_FUNCTION_RETURN_VAL(VAL) \
195 #define HANDLE_FUNCTION_RETURN_OBJ(HANDLE) \
197 void* __result = (MONO_HANDLE_RAW (HANDLE)); \
200 } while (0); } while (0);
202 #define HANDLE_FUNCTION_RETURN_REF(TYPE, HANDLE) \
204 MonoRawHandle __result; \
205 CLEAR_ICALL_FRAME_VALUE (__result, ((MonoRawHandle) (HANDLE))); \
206 return MONO_HANDLE_CAST (TYPE, __result); \
207 } while (0); } while (0);
209 #ifdef MONO_NEEDS_STACK_WATERMARK
212 mono_thread_info_pop_stack_mark (MonoThreadInfo *info, void *old_mark)
214 info->stack_mark = old_mark;
218 mono_thread_info_push_stack_mark (MonoThreadInfo *info, void *mark)
220 void *old = info->stack_mark;
221 info->stack_mark = mark;
225 #define SETUP_STACK_WATERMARK \
227 __builtin_unwind_init (); \
228 void *__old_stack_mark = mono_thread_info_push_stack_mark (__info, &__dummy);
230 #define CLEAR_STACK_WATERMARK \
231 mono_thread_info_pop_stack_mark (__info, __old_stack_mark);
234 #define SETUP_STACK_WATERMARK
235 #define CLEAR_STACK_WATERMARK
238 #define ICALL_ENTRY() \
241 SETUP_STACK_WATERMARK
243 #define ICALL_RETURN() \
245 CLEAR_STACK_WATERMARK \
249 } while (0); } while (0)
251 #define ICALL_RETURN_VAL(VAL) \
253 CLEAR_STACK_WATERMARK \
257 } while (0); } while (0)
259 #define ICALL_RETURN_OBJ(HANDLE) \
261 CLEAR_STACK_WATERMARK \
263 void* __ret = MONO_HANDLE_RAW (HANDLE); \
266 } while (0); } while (0)
269 Handle macros/functions
272 #ifdef ENABLE_CHECKED_BUILD
273 void mono_handle_verify (MonoRawHandle handle);
274 #define HANDLE_INVARIANTS(H) mono_handle_verify((void*)(H))
276 #define HANDLE_INVARIANTS(H) (0)
279 #define TYPED_HANDLE_PAYLOAD_NAME(TYPE) TYPE ## HandlePayload
280 #define TYPED_HANDLE_NAME(TYPE) TYPE ## Handle
281 #define TYPED_OUT_HANDLE_NAME(TYPE) TYPE ## HandleOut
283 #ifdef MONO_HANDLE_TRACK_OWNER
284 #define STRINGIFY_(x) #x
285 #define STRINGIFY(x) STRINGIFY_(x)
286 #define HANDLE_OWNER_STRINGIFY(file,lineno) (const char*) (file ":" STRINGIFY(lineno))
291 * TYPED_HANDLE_DECL(SomeType):
292 * Expands to a decl for handles to SomeType and to an internal payload struct.
294 * For example, TYPED_HANDLE_DECL(MonoObject) (see below) expands to:
298 * } MonoObjectHandlePayload;
300 * typedef MonoObjectHandlePayload* MonoObjectHandle;
301 * typedef MonoObjectHandlePayload* MonoObjectHandleOut;
303 #define TYPED_HANDLE_DECL(TYPE) \
304 typedef struct { TYPE *__raw; } TYPED_HANDLE_PAYLOAD_NAME (TYPE) ; \
305 typedef TYPED_HANDLE_PAYLOAD_NAME (TYPE) * TYPED_HANDLE_NAME (TYPE); \
306 typedef TYPED_HANDLE_PAYLOAD_NAME (TYPE) * TYPED_OUT_HANDLE_NAME (TYPE)
308 * TYPED_VALUE_HANDLE_DECL(SomeType):
309 * Expands to a decl for handles to SomeType (which is a managed valuetype (likely a struct) of some sort) and to an internal payload struct.
310 * For example TYPED_HANDLE_DECL(MonoMethodInfo) expands to:
313 * MonoMethodInfo *__raw;
314 * } MonoMethodInfoHandlePayload;
315 * typedef MonoMethodInfoHandlePayload* MonoMethodInfoHandle;
317 #define TYPED_VALUE_HANDLE_DECL(TYPE) TYPED_HANDLE_DECL(TYPE)
319 /* Have to double expand because MONO_STRUCT_OFFSET is doing token pasting on cross-compilers. */
320 #define MONO_HANDLE_PAYLOAD_OFFSET_(PayloadType) MONO_STRUCT_OFFSET(PayloadType, __raw)
321 #define MONO_HANDLE_PAYLOAD_OFFSET(TYPE) MONO_HANDLE_PAYLOAD_OFFSET_(TYPED_HANDLE_PAYLOAD_NAME (TYPE))
323 #define MONO_HANDLE_INIT ((void*) mono_null_value_handle)
324 #define NULL_HANDLE mono_null_value_handle
326 //XXX add functions to get/set raw, set field, set field to null, set array, set array to null
327 #define MONO_HANDLE_RAW(HANDLE) (HANDLE_INVARIANTS (HANDLE), ((HANDLE)->__raw))
328 #define MONO_HANDLE_DCL(TYPE, NAME) TYPED_HANDLE_NAME(TYPE) NAME = MONO_HANDLE_NEW (TYPE, (NAME ## _raw))
330 #ifndef MONO_HANDLE_TRACK_OWNER
331 #define MONO_HANDLE_NEW(TYPE, VALUE) (TYPED_HANDLE_NAME(TYPE))( mono_handle_new ((MonoObject*)(VALUE)) )
333 #define MONO_HANDLE_NEW(TYPE, VALUE) (TYPED_HANDLE_NAME(TYPE))( mono_handle_new ((MonoObject*)(VALUE), HANDLE_OWNER_STRINGIFY(__FILE__, __LINE__)))
336 #define MONO_HANDLE_CAST(TYPE, VALUE) (TYPED_HANDLE_NAME(TYPE))( VALUE )
338 #define MONO_HANDLE_IS_NULL(HANDLE) (MONO_HANDLE_RAW(HANDLE) == NULL)
342 WARNING WARNING WARNING
344 The following functions require a particular evaluation ordering to ensure correctness.
345 We must not have exposed handles while any sort of evaluation is happening as that very evaluation might trigger
346 a safepoint and break us.
348 This is why we evaluate index and value before any call to MONO_HANDLE_RAW or other functions that deal with naked objects.
350 #define MONO_HANDLE_SETRAW(HANDLE, FIELD, VALUE) do { \
351 MonoObject *__val = (MonoObject*)(VALUE); \
352 MONO_OBJECT_SETREF (MONO_HANDLE_RAW (HANDLE), FIELD, __val); \
355 #define MONO_HANDLE_SET(HANDLE, FIELD, VALUE) do { \
356 MonoObjectHandle __val = MONO_HANDLE_CAST (MonoObject, VALUE); \
357 MONO_OBJECT_SETREF (MONO_HANDLE_RAW (HANDLE), FIELD, MONO_HANDLE_RAW (__val)); \
360 /* N.B. RESULT is evaluated before HANDLE */
361 #define MONO_HANDLE_GET(RESULT, HANDLE, FIELD) do { \
362 MonoObjectHandle __dest = MONO_HANDLE_CAST(MonoObject, RESULT); \
363 mono_gc_wbarrier_generic_store (&__dest->__raw, (MonoObject*)(MONO_HANDLE_RAW(HANDLE)->FIELD)); \
366 #define MONO_HANDLE_NEW_GET(TYPE,HANDLE,FIELD) (MONO_HANDLE_NEW(TYPE,MONO_HANDLE_RAW(HANDLE)->FIELD))
368 #define MONO_HANDLE_GETVAL(HANDLE, FIELD) (MONO_HANDLE_RAW(HANDLE)->FIELD)
370 /* VS doesn't support typeof :( :( :( */
371 #define MONO_HANDLE_SETVAL(HANDLE, FIELD, TYPE, VALUE) do { \
372 TYPE __val = (VALUE); \
373 MONO_HANDLE_RAW (HANDLE)->FIELD = __val; \
376 #define MONO_HANDLE_ARRAY_SETREF(HANDLE, IDX, VALUE) do { \
378 MonoObjectHandle __val = MONO_HANDLE_CAST (MonoObject, VALUE); \
379 mono_array_setref_fast (MONO_HANDLE_RAW (HANDLE), __idx, MONO_HANDLE_RAW (__val)); \
382 #define MONO_HANDLE_ARRAY_SETVAL(HANDLE, TYPE, IDX, VALUE) do { \
384 TYPE __val = (VALUE); \
385 mono_array_set (MONO_HANDLE_RAW (HANDLE), TYPE, __idx, __val); \
388 #define MONO_HANDLE_ARRAY_SETRAW(HANDLE, IDX, VALUE) do { \
390 MonoObject *__val = (MonoObject*)(VALUE); \
391 mono_array_setref_fast (MONO_HANDLE_RAW (HANDLE), __idx, __val); \
394 /* N.B. DEST is evaluated AFTER all the other arguments */
395 #define MONO_HANDLE_ARRAY_GETVAL(DEST, HANDLE, TYPE, IDX) do { \
396 MonoArrayHandle __arr = (HANDLE); \
398 TYPE __result = mono_array_get (MONO_HANDLE_RAW(__arr), TYPE, __idx); \
402 #define MONO_HANDLE_ARRAY_GETREF(DEST, HANDLE, IDX) do { \
403 mono_handle_array_getref (MONO_HANDLE_CAST(MonoObject, (DEST)), (HANDLE), (IDX)); \
406 #define MONO_HANDLE_ASSIGN(DESTH, SRCH) \
407 mono_handle_assign (MONO_HANDLE_CAST (MonoObject, (DESTH)), MONO_HANDLE_CAST(MonoObject, (SRCH)))
409 #define MONO_HANDLE_DOMAIN(HANDLE) (mono_object_domain (MONO_HANDLE_RAW (MONO_HANDLE_CAST (MonoObject, HANDLE))))
412 /* Baked typed handles we all want */
413 TYPED_HANDLE_DECL (MonoString);
414 TYPED_HANDLE_DECL (MonoArray);
415 TYPED_HANDLE_DECL (MonoObject);
416 TYPED_HANDLE_DECL (MonoException);
417 TYPED_HANDLE_DECL (MonoAppContext);
419 #define NULL_HANDLE_STRING MONO_HANDLE_CAST(MonoString, NULL_HANDLE)
422 This is the constant for a handle that points nowhere.
425 extern const MonoObjectHandle mono_null_value_handle;
428 mono_handle_assign (MonoObjectHandleOut dest, MonoObjectHandle src)
430 mono_gc_wbarrier_generic_store (&dest->__raw, src ? MONO_HANDLE_RAW(src) : NULL);
433 //FIXME this should go somewhere else
434 MonoStringHandle mono_string_new_handle (MonoDomain *domain, const char *data, MonoError *error);
435 MonoArrayHandle mono_array_new_handle (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error);
437 mono_array_new_full_handle (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error);
440 uintptr_t mono_array_handle_length (MonoArrayHandle arr);
443 mono_handle_array_getref (MonoObjectHandleOut dest, MonoArrayHandle array, uintptr_t index)
445 mono_gc_wbarrier_generic_store (&dest->__raw, mono_array_get (MONO_HANDLE_RAW (array),gpointer, index));
448 #define mono_handle_class(o) mono_object_class (MONO_HANDLE_RAW (o))
450 /* Local handles to global GC handles and back */
453 mono_gchandle_from_handle (MonoObjectHandle handle, mono_bool pinned);
456 mono_gchandle_get_target_handle (uint32_t gchandle);
459 mono_array_handle_memcpy_refs (MonoArrayHandle dest, uintptr_t dest_idx, MonoArrayHandle src, uintptr_t src_idx, uintptr_t len);
461 /* Pins the MonoArray using a gchandle and returns a pointer to the
462 * element with the given index (where each element is of the given
463 * size. Call mono_gchandle_free to unpin.
466 mono_array_handle_pin_with_size (MonoArrayHandle handle, int size, uintptr_t index, uint32_t *gchandle);
468 #define MONO_ARRAY_HANDLE_PIN(handle,type,index,gchandle_out) mono_array_handle_pin_with_size (MONO_HANDLE_CAST(MonoArray,(handle)), sizeof (type), (index), (gchandle_out))
471 mono_error_set_exception_handle (MonoError *error, MonoExceptionHandle exc);
474 mono_context_get_handle (void);
477 mono_context_set_handle (MonoAppContextHandle new_context);
482 #endif /* __MONO_HANDLE_H__ */