2 * handle.h: Handle to object in native code
5 * - Ludovic Henry <ludovic@xamarin.com>
6 * - Aleksey Klieger <aleksey.klieger@xamarin.com>
7 * - Rodrigo Kumpera <kumpera@xamarin.com>
9 * Copyright 2016 Dot net foundation.
10 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
13 #ifndef __MONO_HANDLE_H__
14 #define __MONO_HANDLE_H__
19 #include <mono/metadata/object.h>
20 #include <mono/metadata/class.h>
21 #include <mono/utils/mono-error-internals.h>
22 #include <mono/utils/mono-threads.h>
23 #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 */
60 #ifdef MONO_HANDLE_TRACK_OWNER
66 int size
; //number of bytes
67 HandleChunk
*prev
, *next
;
68 HandleChunkElem objects
[OBJECTS_PER_HANDLES_CHUNK
];
72 HandleChunk
*top
; //alloc from here
73 HandleChunk
*bottom
; //scan from here
81 typedef void *MonoRawHandle
;
83 typedef void (*GcScanFunc
) (gpointer
*, gpointer
);
86 #ifndef MONO_HANDLE_TRACK_OWNER
87 MonoRawHandle
mono_handle_new (MonoObject
*object
);
89 MonoRawHandle
mono_handle_new (MonoObject
*object
, const char* owner
);
92 void mono_handle_stack_scan (HandleStack
*stack
, GcScanFunc func
, gpointer gc_data
);
93 gboolean
mono_handle_stack_is_empty (HandleStack
*stack
);
94 HandleStack
* mono_handle_stack_alloc (void);
95 void mono_handle_stack_free (HandleStack
*handlestack
);
96 MonoRawHandle
mono_stack_mark_pop_value (MonoThreadInfo
*info
, HandleStackMark
*stackmark
, MonoRawHandle value
);
97 void mono_stack_mark_record_size (MonoThreadInfo
*info
, HandleStackMark
*stackmark
, const char *func_name
);
100 mono_stack_mark_init (MonoThreadInfo
*info
, HandleStackMark
*stackmark
)
102 HandleStack
*handles
= (HandleStack
*)info
->handle_stack
;
103 stackmark
->size
= handles
->top
->size
;
104 stackmark
->chunk
= handles
->top
;
108 mono_stack_mark_pop (MonoThreadInfo
*info
, HandleStackMark
*stackmark
)
110 HandleStack
*handles
= (HandleStack
*)info
->handle_stack
;
111 HandleChunk
*old_top
= stackmark
->chunk
;
112 old_top
->size
= stackmark
->size
;
113 mono_memory_write_barrier ();
114 handles
->top
= old_top
;
120 #define SETUP_ICALL_COMMON \
123 MonoThreadInfo *__info = mono_thread_info_current (); \
124 error_init (&error); \
126 #define CLEAR_ICALL_COMMON \
127 mono_error_set_pending_exception (&error);
129 #define SETUP_ICALL_FRAME \
130 HandleStackMark __mark; \
131 mono_stack_mark_init (__info, &__mark);
133 #define CLEAR_ICALL_FRAME \
134 mono_stack_mark_record_size (__info, &__mark, __FUNCTION__); \
135 mono_stack_mark_pop (__info, &__mark);
137 #define CLEAR_ICALL_FRAME_VALUE(RESULT, HANDLE) \
138 mono_stack_mark_record_size (__info, &__mark, __FUNCTION__); \
139 (RESULT) = mono_stack_mark_pop_value (__info, &__mark, (HANDLE));
142 #define HANDLE_FUNCTION_ENTER() do { \
143 MonoThreadInfo *__info = mono_thread_info_current (); \
146 #define HANDLE_FUNCTION_RETURN() \
150 #define HANDLE_FUNCTION_RETURN_VAL(VAL) \
155 #define HANDLE_FUNCTION_RETURN_OBJ(HANDLE) \
157 void* __result = (MONO_HANDLE_RAW (HANDLE)); \
160 } while (0); } while (0);
162 #define HANDLE_FUNCTION_RETURN_REF(TYPE, HANDLE) \
164 MonoRawHandle __result; \
165 CLEAR_ICALL_FRAME_VALUE (__result, ((MonoRawHandle) (HANDLE))); \
166 return MONO_HANDLE_CAST (TYPE, __result); \
167 } while (0); } while (0);
169 #ifdef MONO_NEEDS_STACK_WATERMARK
172 mono_thread_info_pop_stack_mark (MonoThreadInfo
*info
, void *old_mark
)
174 info
->stack_mark
= old_mark
;
178 mono_thread_info_push_stack_mark (MonoThreadInfo
*info
, void *mark
)
180 void *old
= info
->stack_mark
;
181 info
->stack_mark
= mark
;
185 #define SETUP_STACK_WATERMARK \
187 __builtin_unwind_init (); \
188 void *__old_stack_mark = mono_thread_info_push_stack_mark (__info, &__dummy);
190 #define CLEAR_STACK_WATERMARK \
191 mono_thread_info_pop_stack_mark (__info, __old_stack_mark);
194 #define SETUP_STACK_WATERMARK
195 #define CLEAR_STACK_WATERMARK
198 #define ICALL_ENTRY() \
201 SETUP_STACK_WATERMARK
203 #define ICALL_RETURN() \
205 CLEAR_STACK_WATERMARK \
209 } while (0); } while (0)
211 #define ICALL_RETURN_VAL(VAL) \
213 CLEAR_STACK_WATERMARK \
217 } while (0); } while (0)
219 #define ICALL_RETURN_OBJ(HANDLE) \
221 CLEAR_STACK_WATERMARK \
223 void* __ret = MONO_HANDLE_RAW (HANDLE); \
226 } while (0); } while (0)
229 Handle macros/functions
232 #ifdef ENABLE_CHECKED_BUILD
233 void mono_handle_verify (MonoRawHandle handle
);
234 #define HANDLE_INVARIANTS(H) mono_handle_verify((void*)(H))
236 #define HANDLE_INVARIANTS(H) (0)
239 #define TYPED_HANDLE_PAYLOAD_NAME(TYPE) TYPE ## HandlePayload
240 #define TYPED_HANDLE_NAME(TYPE) TYPE ## Handle
241 #define TYPED_OUT_HANDLE_NAME(TYPE) TYPE ## HandleOut
243 #ifdef MONO_HANDLE_TRACK_OWNER
244 #define STRINGIFY_(x) #x
245 #define STRINGIFY(x) STRINGIFY_(x)
246 #define HANDLE_OWNER_STRINGIFY(file,lineno) (const char*) (file ":" STRINGIFY(lineno))
251 * TYPED_HANDLE_DECL(SomeType):
252 * Expands to a decl for handles to SomeType and to an internal payload struct.
254 * For example, TYPED_HANDLE_DECL(MonoObject) (see below) expands to:
258 * } MonoObjectHandlePayload;
260 * typedef MonoObjectHandlePayload* MonoObjectHandle;
261 * typedef MonoObjectHandlePayload* MonoObjectHandleOut;
263 #define TYPED_HANDLE_DECL(TYPE) \
264 typedef struct { TYPE *__obj; } TYPED_HANDLE_PAYLOAD_NAME (TYPE) ; \
265 typedef TYPED_HANDLE_PAYLOAD_NAME (TYPE) * TYPED_HANDLE_NAME (TYPE); \
266 typedef TYPED_HANDLE_PAYLOAD_NAME (TYPE) * TYPED_OUT_HANDLE_NAME (TYPE)
267 /* Have to double expand because MONO_STRUCT_OFFSET is doing token pasting on cross-compilers. */
268 #define MONO_HANDLE_PAYLOAD_OFFSET_(PayloadType) MONO_STRUCT_OFFSET(PayloadType, __obj)
269 #define MONO_HANDLE_PAYLOAD_OFFSET(TYPE) MONO_HANDLE_PAYLOAD_OFFSET_(TYPED_HANDLE_PAYLOAD_NAME (TYPE))
271 #define MONO_HANDLE_INIT ((void*) mono_null_value_handle)
272 #define NULL_HANDLE mono_null_value_handle
274 //XXX add functions to get/set raw, set field, set field to null, set array, set array to null
275 #define MONO_HANDLE_RAW(HANDLE) (HANDLE_INVARIANTS (HANDLE), ((HANDLE)->__obj))
276 #define MONO_HANDLE_DCL(TYPE, NAME) TYPED_HANDLE_NAME(TYPE) NAME = MONO_HANDLE_NEW (TYPE, (NAME ## _raw))
278 #ifndef MONO_HANDLE_TRACK_OWNER
279 #define MONO_HANDLE_NEW(TYPE, VALUE) (TYPED_HANDLE_NAME(TYPE))( mono_handle_new ((MonoObject*)(VALUE)) )
281 #define MONO_HANDLE_NEW(TYPE, VALUE) (TYPED_HANDLE_NAME(TYPE))( mono_handle_new ((MonoObject*)(VALUE), HANDLE_OWNER_STRINGIFY(__FILE__, __LINE__)))
284 #define MONO_HANDLE_CAST(TYPE, VALUE) (TYPED_HANDLE_NAME(TYPE))( VALUE )
286 #define MONO_HANDLE_IS_NULL(HANDLE) (MONO_HANDLE_RAW(HANDLE) == NULL)
290 WARNING WARNING WARNING
292 The following functions require a particular evaluation ordering to ensure correctness.
293 We must not have exposed handles while any sort of evaluation is happening as that very evaluation might trigger
294 a safepoint and break us.
296 This is why we evaluate index and value before any call to MONO_HANDLE_RAW or other functions that deal with naked objects.
298 #define MONO_HANDLE_SETRAW(HANDLE, FIELD, VALUE) do { \
299 MonoObject *__val = (MonoObject*)(VALUE); \
300 MONO_OBJECT_SETREF (MONO_HANDLE_RAW (HANDLE), FIELD, __val); \
303 #define MONO_HANDLE_SET(HANDLE, FIELD, VALUE) do { \
304 MonoObjectHandle __val = MONO_HANDLE_CAST (MonoObject, VALUE); \
305 MONO_OBJECT_SETREF (MONO_HANDLE_RAW (HANDLE), FIELD, MONO_HANDLE_RAW (__val)); \
308 /* N.B. RESULT is evaluated before HANDLE */
309 #define MONO_HANDLE_GET(RESULT, HANDLE, FIELD) do { \
310 MonoObjectHandle __dest = MONO_HANDLE_CAST(MonoObject, RESULT); \
311 mono_gc_wbarrier_generic_store (&__dest->__obj, (MonoObject*)(MONO_HANDLE_RAW(HANDLE)->FIELD)); \
314 #define MONO_HANDLE_GETVAL(HANDLE, FIELD) (MONO_HANDLE_RAW(HANDLE)->FIELD)
316 /* VS doesn't support typeof :( :( :( */
317 #define MONO_HANDLE_SETVAL(HANDLE, FIELD, TYPE, VALUE) do { \
318 TYPE __val = (VALUE); \
319 MONO_HANDLE_RAW (HANDLE)->FIELD = __val; \
322 #define MONO_HANDLE_ARRAY_SETREF(HANDLE, IDX, VALUE) do { \
324 MonoObjectHandle __val = MONO_HANDLE_CAST (MonoObject, VALUE); \
325 mono_array_setref_fast (MONO_HANDLE_RAW (HANDLE), __idx, MONO_HANDLE_RAW (__val)); \
328 #define MONO_HANDLE_ARRAY_SETVAL(HANDLE, TYPE, IDX, VALUE) do { \
330 TYPE __val = (VALUE); \
331 mono_array_set (MONO_HANDLE_RAW (HANDLE), TYPE, __idx, __val); \
334 #define MONO_HANDLE_ARRAY_SETRAW(HANDLE, IDX, VALUE) do { \
336 MonoObject *__val = (MonoObject*)(VALUE); \
337 mono_array_setref_fast (MONO_HANDLE_RAW (HANDLE), __idx, __val); \
340 /* N.B. DEST is evaluated AFTER all the other arguments */
341 #define MONO_HANDLE_ARRAY_GETVAL(DEST, HANDLE, TYPE, IDX) do { \
342 MonoArrayHandle __arr = (HANDLE); \
344 TYPE __result = mono_array_get (MONO_HANDLE_RAW(__arr), TYPE, __idx); \
348 #define MONO_HANDLE_ARRAY_GETREF(DEST, HANDLE, IDX) do { \
349 mono_handle_array_getref (MONO_HANDLE_CAST(MonoObject, (DEST)), (HANDLE), (IDX)); \
352 #define MONO_HANDLE_ASSIGN(DESTH, SRCH) \
353 mono_handle_assign (MONO_HANDLE_CAST (MonoObject, (DESTH)), MONO_HANDLE_CAST(MonoObject, (SRCH)))
355 #define MONO_HANDLE_DOMAIN(HANDLE) (mono_object_domain (MONO_HANDLE_RAW (MONO_HANDLE_CAST (MonoObject, HANDLE))))
357 /* Baked typed handles we all want */
358 TYPED_HANDLE_DECL (MonoString
);
359 TYPED_HANDLE_DECL (MonoArray
);
360 TYPED_HANDLE_DECL (MonoObject
);
361 TYPED_HANDLE_DECL (MonoException
);
363 #define NULL_HANDLE_STRING MONO_HANDLE_CAST(MonoString, NULL_HANDLE)
366 This is the constant for a handle that points nowhere.
369 extern const MonoObjectHandle mono_null_value_handle
;
372 mono_handle_assign (MonoObjectHandleOut dest
, MonoObjectHandle src
)
374 mono_gc_wbarrier_generic_store (&dest
->__obj
, src
? MONO_HANDLE_RAW(src
) : NULL
);
377 //FIXME this should go somewhere else
378 MonoStringHandle
mono_string_new_handle (MonoDomain
*domain
, const char *data
, MonoError
*error
);
379 MonoArrayHandle
mono_array_new_handle (MonoDomain
*domain
, MonoClass
*eclass
, uintptr_t n
, MonoError
*error
);
381 uintptr_t mono_array_handle_length (MonoArrayHandle arr
);
384 mono_handle_array_getref (MonoObjectHandleOut dest
, MonoArrayHandle array
, uintptr_t index
)
386 mono_gc_wbarrier_generic_store (&dest
->__obj
, mono_array_get (MONO_HANDLE_RAW (array
),gpointer
, index
));
389 #define mono_handle_class(o) mono_object_class (MONO_HANDLE_RAW (o))
391 /* Local handles to global GC handles and back */
394 mono_gchandle_from_handle (MonoObjectHandle handle
, mono_bool pinned
);
397 mono_gchandle_get_target_handle (uint32_t gchandle
);
400 mono_array_handle_memcpy_refs (MonoArrayHandle dest
, uintptr_t dest_idx
, MonoArrayHandle src
, uintptr_t src_idx
, uintptr_t len
);
402 /* Pins the MonoArray using a gchandle and returns a pointer to the
403 * element with the given index (where each element is of the given
404 * size. Call mono_gchandle_free to unpin.
407 mono_array_handle_pin_with_size (MonoArrayHandle handle
, int size
, uintptr_t index
, uint32_t *gchandle
);
409 #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))
412 mono_error_set_exception_handle (MonoError
*error
, MonoExceptionHandle exc
);
416 #endif /* __MONO_HANDLE_H__ */