Enable incompatible-pointer warnings on Windows/gcc like Unix/gcc. (#9221)
[mono-project.git] / mono / metadata / handle.h
blob1138c0ed6b9de1bb89dc273141039c86d6d929d0
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 #ifndef __MONO_HANDLE_H__
15 #define __MONO_HANDLE_H__
17 #include <config.h>
18 #include <glib.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>
25 #include <mono/metadata/class-internals.h>
27 // Type-safe handles are a struct with a pointer to pointer.
28 // The only operations allowed on them are the functions/macros in this file, and assignment
29 // from same handle type to same handle type.
31 // Type-unsafe handles are a pointer to a struct with a pointer.
32 // Besides the type-safe operations, these can also be:
33 // 1. compared to NULL, instead of only MONO_HANDLE_IS_NULL
34 // 2. assigned from NULL, instead of only a handle
35 // 3. MONO_HANDLE_NEW (T) from anything, instead of only a T*
36 // 4. MONO_HANDLE_CAST from anything, instead of only another handle type
37 // 5. assigned from any void*, at least in C
38 // 6. Cast from any handle type to any handle type, without using MONO_HANDLE_CAST.
39 // 7. Cast from any handle type to any pointer type and vice versa, such as incorrect unboxing.
40 // 8. mono_object_class (handle), instead of mono_handle_class
42 // None of those operations were likely intended.
44 // FIXME Do this only on checked builds? Or certain architectures?
45 // There is not runtime cost.
46 // NOTE: Running this code depends on the ABI to pass a struct
47 // with a pointer the same as a pointer. This is tied in with
48 // marshaling. If this is not the case, turn off type-safety, perhaps per-OS per-CPU.
49 #if defined (HOST_DARWIN) || defined (HOST_WIN32) || defined (HOST_ARM64) || defined (HOST_ARM) || defined (HOST_AMD64)
50 #define MONO_TYPE_SAFE_HANDLES 1
51 #else
52 #define MONO_TYPE_SAFE_HANDLES 0 // PowerPC, S390X, SPARC, MIPS, Linux/x86, BSD/x86, etc.
53 #endif
55 G_BEGIN_DECLS
58 Handle stack.
60 The handle stack is designed so it's efficient to pop a large amount of entries at once.
61 The stack is made out of a series of fixed size segments.
63 To do bulk operations you use a stack mark.
68 3 is the number of fields besides the data in the struct;
69 128 words makes each chunk 512 or 1024 bytes each
71 #define OBJECTS_PER_HANDLES_CHUNK (128 - 3)
74 Whether this config needs stack watermark recording to know where to start scanning from.
76 #ifdef HOST_WATCHOS
77 #define MONO_NEEDS_STACK_WATERMARK 1
78 #endif
80 typedef struct _HandleChunk HandleChunk;
83 * Define MONO_HANDLE_TRACK_OWNER to store the file and line number of each call to MONO_HANDLE_NEW
84 * in the handle stack. (This doubles the amount of memory used for handles, so it's only useful for debugging).
86 /*#define MONO_HANDLE_TRACK_OWNER*/
89 * Define MONO_HANDLE_TRACK_SP to record the C stack pointer at the time of each HANDLE_FUNCTION_ENTER and
90 * to ensure that when a new handle is allocated the previous newest handle is not lower in the stack.
91 * This is useful to catch missing HANDLE_FUNCTION_ENTER / HANDLE_FUNCTION_RETURN pairs which could cause
92 * handle leaks.
94 * If defined, keep HandleStackMark in sync in RuntimeStructs.cs
96 /*#define MONO_HANDLE_TRACK_SP*/
98 typedef struct {
99 gpointer o; /* MonoObject ptr or interior ptr */
100 #ifdef MONO_HANDLE_TRACK_OWNER
101 const char *owner;
102 gpointer backtrace_ips[7]; /* result of backtrace () at time of allocation */
103 #endif
104 #ifdef MONO_HANDLE_TRACK_SP
105 gpointer alloc_sp; /* sp from HandleStack:stackmark_sp at time of allocation */
106 #endif
107 } HandleChunkElem;
109 struct _HandleChunk {
110 int size; //number of handles
111 HandleChunk *prev, *next;
112 HandleChunkElem elems [OBJECTS_PER_HANDLES_CHUNK];
115 typedef struct {
116 HandleChunk *top; //alloc from here
117 HandleChunk *bottom; //scan from here
118 #ifdef MONO_HANDLE_TRACK_SP
119 gpointer stackmark_sp; // C stack pointer top when from most recent mono_stack_mark_init
120 #endif
121 /* Chunk for storing interior pointers. Not extended right now */
122 HandleChunk *interior;
123 } HandleStack;
125 // Keep this in sync with RuntimeStructs.cs
126 typedef struct {
127 int size, interior_size;
128 HandleChunk *chunk;
129 #ifdef MONO_HANDLE_TRACK_SP
130 gpointer prev_sp; // C stack pointer from prior mono_stack_mark_init
131 #endif
132 } HandleStackMark;
134 typedef void *MonoRawHandle;
136 typedef void (*GcScanFunc) (gpointer*, gpointer);
139 /* If Centrinel is analyzing Mono, use the SUPPRESS macros to mark the bodies
140 * of the handle macros as allowed to perform operations on raw pointers to
141 * managed objects. Take care to UNSUPPRESS the _arguments_ to the macros - we
142 * want warnings if the argument uses pointers unsafely.
144 #ifdef __CENTRINEL__
145 #define MONO_HANDLE_SUPPRESS_SCOPE(b) __CENTRINEL_SUPPRESS_SCOPE(b)
146 #define MONO_HANDLE_SUPPRESS(expr) __CENTRINEL_SUPPRESS(expr)
147 #define MONO_HANDLE_UNSUPPRESS(expr) __CENTRINEL_UNSUPPRESS(expr)
148 #else
149 #define MONO_HANDLE_SUPPRESS_SCOPE(b) ;
150 #define MONO_HANDLE_SUPPRESS(expr) (expr)
151 #define MONO_HANDLE_UNSUPPRESS(expr) (expr)
152 #endif
154 #ifndef MONO_HANDLE_TRACK_OWNER
155 MonoRawHandle mono_handle_new (MonoObject *object);
156 gpointer mono_handle_new_interior (gpointer rawptr);
157 #else
158 MonoRawHandle mono_handle_new (MonoObject *object, const char* owner);
159 gpointer mono_handle_new_interior (gpointer rawptr, const char *owner);
160 #endif
162 void mono_handle_stack_scan (HandleStack *stack, GcScanFunc func, gpointer gc_data, gboolean precise, gboolean check);
163 gboolean mono_handle_stack_is_empty (HandleStack *stack);
164 HandleStack* mono_handle_stack_alloc (void);
165 void mono_handle_stack_free (HandleStack *handlestack);
166 MonoRawHandle mono_stack_mark_pop_value (MonoThreadInfo *info, HandleStackMark *stackmark, MonoRawHandle value);
167 void mono_stack_mark_record_size (MonoThreadInfo *info, HandleStackMark *stackmark, const char *func_name);
168 void mono_handle_stack_free_domain (HandleStack *stack, MonoDomain *domain);
170 #ifdef MONO_HANDLE_TRACK_SP
171 void mono_handle_chunk_leak_check (HandleStack *handles);
172 #endif
174 static inline void
175 mono_stack_mark_init (MonoThreadInfo *info, HandleStackMark *stackmark)
177 #ifdef MONO_HANDLE_TRACK_SP
178 gpointer sptop = &stackmark;
179 #endif
180 HandleStack *handles = (HandleStack *)info->handle_stack;
181 stackmark->size = handles->top->size;
182 stackmark->chunk = handles->top;
183 stackmark->interior_size = handles->interior->size;
184 #ifdef MONO_HANDLE_TRACK_SP
185 stackmark->prev_sp = handles->stackmark_sp;
186 handles->stackmark_sp = sptop;
187 #endif
190 static inline void
191 mono_stack_mark_pop (MonoThreadInfo *info, HandleStackMark *stackmark)
193 HandleStack *handles = (HandleStack *)info->handle_stack;
194 HandleChunk *old_top = stackmark->chunk;
195 old_top->size = stackmark->size;
196 mono_memory_write_barrier ();
197 handles->top = old_top;
198 handles->interior->size = stackmark->interior_size;
199 #ifdef MONO_HANDLE_TRACK_SP
200 mono_memory_write_barrier (); /* write to top before prev_sp */
201 handles->stackmark_sp = stackmark->prev_sp;
202 #endif
206 Icall macros
208 #define SETUP_ICALL_COMMON \
209 do { \
210 ERROR_DECL (error); \
211 MonoThreadInfo *__info = mono_thread_info_current (); \
212 error_init (error); \
214 #define CLEAR_ICALL_COMMON \
215 mono_error_set_pending_exception (error);
217 #define SETUP_ICALL_FRAME \
218 HandleStackMark __mark; \
219 mono_stack_mark_init (__info, &__mark);
221 #define CLEAR_ICALL_FRAME \
222 mono_stack_mark_record_size (__info, &__mark, __FUNCTION__); \
223 mono_stack_mark_pop (__info, &__mark);
225 #define CLEAR_ICALL_FRAME_VALUE(RESULT, HANDLE) \
226 mono_stack_mark_record_size (__info, &__mark, __FUNCTION__); \
227 (RESULT) = mono_stack_mark_pop_value (__info, &__mark, (HANDLE));
229 #define HANDLE_FUNCTION_ENTER() do { \
230 MonoThreadInfo *__info = mono_thread_info_current (); \
231 SETUP_ICALL_FRAME \
233 #define HANDLE_FUNCTION_RETURN() \
234 CLEAR_ICALL_FRAME; \
235 } while (0)
237 // Return a non-pointer or non-managed pointer, e.g. gboolean.
238 #define HANDLE_FUNCTION_RETURN_VAL(VAL) \
239 CLEAR_ICALL_FRAME; \
240 return (VAL); \
241 } while (0)
243 // Return a raw pointer from coop handle.
244 #define HANDLE_FUNCTION_RETURN_OBJ(HANDLE) \
245 do { \
246 void* __result = MONO_HANDLE_RAW (HANDLE); \
247 CLEAR_ICALL_FRAME; \
248 return __result; \
249 } while (0); } while (0);
251 #if MONO_TYPE_SAFE_HANDLES
253 // Return a coop handle from coop handle.
254 #define HANDLE_FUNCTION_RETURN_REF(TYPE, HANDLE) \
255 do { \
256 MonoObjectHandle __result; \
257 CLEAR_ICALL_FRAME_VALUE (__result.__raw, (HANDLE).__raw); \
258 return MONO_HANDLE_CAST (TYPE, __result); \
259 } while (0); } while (0);
261 #else
263 // Return a coop handle from coop handle.
264 #define HANDLE_FUNCTION_RETURN_REF(TYPE, HANDLE) \
265 do { \
266 MonoRawHandle __result; \
267 CLEAR_ICALL_FRAME_VALUE (__result, ((MonoRawHandle) (HANDLE))); \
268 return MONO_HANDLE_CAST (TYPE, __result); \
269 } while (0); } while (0);
271 #endif
273 #ifdef MONO_NEEDS_STACK_WATERMARK
275 static void
276 mono_thread_info_pop_stack_mark (MonoThreadInfo *info, void *old_mark)
278 info->stack_mark = old_mark;
281 static void*
282 mono_thread_info_push_stack_mark (MonoThreadInfo *info, void *mark)
284 void *old = info->stack_mark;
285 info->stack_mark = mark;
286 return old;
289 #define SETUP_STACK_WATERMARK \
290 int __dummy; \
291 __builtin_unwind_init (); \
292 void *__old_stack_mark = mono_thread_info_push_stack_mark (__info, &__dummy);
294 #define CLEAR_STACK_WATERMARK \
295 mono_thread_info_pop_stack_mark (__info, __old_stack_mark);
297 #else
298 #define SETUP_STACK_WATERMARK
299 #define CLEAR_STACK_WATERMARK
300 #endif
302 #define ICALL_ENTRY() \
303 SETUP_ICALL_COMMON \
304 SETUP_ICALL_FRAME \
305 SETUP_STACK_WATERMARK
307 #define ICALL_RETURN() \
308 do { \
309 CLEAR_STACK_WATERMARK \
310 CLEAR_ICALL_COMMON \
311 CLEAR_ICALL_FRAME \
312 return; \
313 } while (0); } while (0)
315 #define ICALL_RETURN_VAL(VAL) \
316 do { \
317 CLEAR_STACK_WATERMARK \
318 CLEAR_ICALL_COMMON \
319 CLEAR_ICALL_FRAME \
320 return VAL; \
321 } while (0); } while (0)
323 #define ICALL_RETURN_OBJ(HANDLE) \
324 do { \
325 CLEAR_STACK_WATERMARK \
326 CLEAR_ICALL_COMMON \
327 void* __ret = MONO_HANDLE_RAW (HANDLE); \
328 CLEAR_ICALL_FRAME \
329 return __ret; \
330 } while (0); } while (0)
333 Handle macros/functions
336 #define TYPED_HANDLE_PAYLOAD_NAME(TYPE) TYPE ## HandlePayload
337 #define TYPED_HANDLE_NAME(TYPE) TYPE ## Handle
338 #define TYPED_OUT_HANDLE_NAME(TYPE) TYPE ## HandleOut
340 // internal helpers:
341 #define MONO_HANDLE_CAST_FOR(type) mono_handle_cast_##type
342 #define MONO_HANDLE_TYPECHECK_FOR(type) mono_handle_typecheck_##type
344 #ifdef MONO_HANDLE_TRACK_OWNER
345 #define STRINGIFY_(x) #x
346 #define STRINGIFY(x) STRINGIFY_(x)
347 #define HANDLE_OWNER (__FILE__ ":" STRINGIFY (__LINE__))
348 #endif
352 * TYPED_HANDLE_DECL(SomeType):
353 * Expands to a decl for handles to SomeType and to an internal payload struct.
355 * For example, TYPED_HANDLE_DECL(MonoObject) (see below) expands to:
357 * #if MONO_TYPE_SAFE_HANDLES
359 * typedef struct {
360 * MonoObject **__raw;
361 * } MonoObjectHandlePayload,
362 * MonoObjectHandle,
363 * MonoObjectHandleOut;
365 * Internal helper functions are also generated.
367 * #else
369 * typedef struct {
370 * MonoObject *__raw;
371 * } MonoObjectHandlePayload;
373 * typedef MonoObjectHandlePayload* MonoObjectHandle;
374 * typedef MonoObjectHandlePayload* MonoObjectHandleOut;
376 * #endif
379 #if MONO_TYPE_SAFE_HANDLES
380 #define TYPED_HANDLE_DECL(TYPE) \
381 typedef struct { TYPE **__raw; } TYPED_HANDLE_PAYLOAD_NAME (TYPE), \
382 TYPED_HANDLE_NAME (TYPE), \
383 TYPED_OUT_HANDLE_NAME (TYPE); \
384 /* Do not call these functions directly. Use MONO_HANDLE_NEW and MONO_HANDLE_CAST. */ \
385 /* Another way to do this involved casting mono_handle_new function to a different type. */ \
386 static inline MONO_ALWAYS_INLINE TYPED_HANDLE_NAME (TYPE) \
387 MONO_HANDLE_CAST_FOR (TYPE) (gpointer a) \
389 TYPED_HANDLE_NAME (TYPE) b = { (TYPE**)a }; \
390 return b; \
392 static inline MONO_ALWAYS_INLINE gpointer \
393 MONO_HANDLE_TYPECHECK_FOR (TYPE) (TYPE *a) \
395 return a; \
398 #else
399 #define TYPED_HANDLE_DECL(TYPE) \
400 typedef struct { TYPE *__raw; } TYPED_HANDLE_PAYLOAD_NAME (TYPE) ; \
401 typedef TYPED_HANDLE_PAYLOAD_NAME (TYPE) * TYPED_HANDLE_NAME (TYPE); \
402 typedef TYPED_HANDLE_PAYLOAD_NAME (TYPE) * TYPED_OUT_HANDLE_NAME (TYPE)
403 #endif
406 * TYPED_VALUE_HANDLE_DECL(SomeType):
407 * 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.
408 * It is currently identical to TYPED_HANDLE_DECL (valuetypes vs. referencetypes).
410 #define TYPED_VALUE_HANDLE_DECL(TYPE) TYPED_HANDLE_DECL(TYPE)
412 /* Have to double expand because MONO_STRUCT_OFFSET is doing token pasting on cross-compilers. */
413 #define MONO_HANDLE_PAYLOAD_OFFSET_(PayloadType) MONO_STRUCT_OFFSET(PayloadType, __raw)
414 #define MONO_HANDLE_PAYLOAD_OFFSET(TYPE) MONO_HANDLE_PAYLOAD_OFFSET_(TYPED_HANDLE_PAYLOAD_NAME (TYPE))
416 //XXX add functions to get/set raw, set field, set field to null, set array, set array to null
417 #define MONO_HANDLE_DCL(TYPE, NAME) TYPED_HANDLE_NAME(TYPE) NAME = MONO_HANDLE_NEW (TYPE, (NAME ## _raw))
419 // With Visual C++ compiling as C, the type of a ternary expression
420 // yielding two unrelated non-void pointers is the type of the first, plus a warning.
421 // This can be used to simulate gcc typeof extension.
422 // Otherwise we are forced to evaluate twice, or use C++.
423 #ifdef _MSC_VER
424 typedef struct _MonoTypeofCastHelper *MonoTypeofCastHelper; // a pointer type unrelated to anything else
425 #define MONO_TYPEOF_CAST(typeexpr, expr) __pragma(warning(suppress:4133))(0 ? (typeexpr) : (MonoTypeofCastHelper)(expr))
426 #else
427 #define MONO_TYPEOF_CAST(typeexpr, expr) ((typeof (typeexpr))(expr))
428 #endif
430 #if MONO_TYPE_SAFE_HANDLES
432 #ifndef MONO_HANDLE_TRACK_OWNER
434 #define MONO_HANDLE_NEW(type, object) \
435 (MONO_HANDLE_CAST_FOR (type) (mono_handle_new (MONO_HANDLE_TYPECHECK_FOR (type) (object))))
437 #else
439 #define MONO_HANDLE_NEW(type, object) \
440 (MONO_HANDLE_CAST_FOR (type) (mono_handle_new (MONO_HANDLE_TYPECHECK_FOR (type) (object, HANDLE_OWNER))))
442 #endif
444 #define MONO_HANDLE_CAST(type, value) (MONO_HANDLE_CAST_FOR (type) ((value).__raw))
445 #define MONO_HANDLE_RAW(handle) (MONO_TYPEOF_CAST (*(handle).__raw, mono_handle_raw ((handle).__raw)))
446 #define MONO_HANDLE_IS_NULL(handle) (mono_handle_is_null ((handle).__raw))
448 #else // MONO_TYPE_SAFE_HANDLES
450 #ifndef MONO_HANDLE_TRACK_OWNER
451 #define MONO_HANDLE_NEW(TYPE, VALUE) (TYPED_HANDLE_NAME(TYPE))( mono_handle_new ((MonoObject*)(VALUE)) )
452 #else
453 #define MONO_HANDLE_NEW(TYPE, VALUE) (TYPED_HANDLE_NAME(TYPE))( mono_handle_new ((MonoObject*)(VALUE), HANDLE_OWNER))
454 #endif
455 #define MONO_HANDLE_CAST(TYPE, VALUE) (TYPED_HANDLE_NAME(TYPE))( VALUE )
457 #define MONO_HANDLE_RAW(handle) (MONO_TYPEOF_CAST ((handle)->__raw, mono_handle_raw (handle)))
458 #define MONO_HANDLE_IS_NULL(handle) (mono_handle_is_null (handle))
460 #endif // MONO_TYPE_SAFE_HANDLES
463 WARNING WARNING WARNING
465 The following functions require a particular evaluation ordering to ensure correctness.
466 We must not have exposed handles while any sort of evaluation is happening as that very evaluation might trigger
467 a safepoint and break us.
469 This is why we evaluate index and value before any call to MONO_HANDLE_RAW or other functions that deal with naked objects.
471 #define MONO_HANDLE_SETRAW(HANDLE, FIELD, VALUE) do { \
472 MONO_HANDLE_SUPPRESS_SCOPE(1); \
473 MonoObject *__val = MONO_HANDLE_SUPPRESS ((MonoObject*)(MONO_HANDLE_UNSUPPRESS (VALUE))); \
474 MONO_OBJECT_SETREF (MONO_HANDLE_RAW (MONO_HANDLE_UNSUPPRESS (HANDLE)), FIELD, __val); \
475 } while (0)
477 #define MONO_HANDLE_SET(HANDLE, FIELD, VALUE) do { \
478 MonoObjectHandle __val = MONO_HANDLE_CAST (MonoObject, VALUE); \
479 do { \
480 MONO_HANDLE_SUPPRESS_SCOPE(1); \
481 MONO_OBJECT_SETREF (MONO_HANDLE_RAW (MONO_HANDLE_UNSUPPRESS (HANDLE)), FIELD, MONO_HANDLE_RAW (__val)); \
482 } while (0); \
483 } while (0)
485 #if MONO_TYPE_SAFE_HANDLES
487 /* N.B. RESULT is evaluated before HANDLE */
488 #define MONO_HANDLE_GET(RESULT, HANDLE, FIELD) do { \
489 MonoObjectHandle __dest = MONO_HANDLE_CAST (MonoObject, RESULT); \
490 MONO_HANDLE_SUPPRESS (*(gpointer*)__dest.__raw = (gpointer)MONO_HANDLE_RAW (MONO_HANDLE_UNSUPPRESS (HANDLE))->FIELD); \
491 } while (0)
493 #else
495 /* N.B. RESULT is evaluated before HANDLE */
496 #define MONO_HANDLE_GET(RESULT, HANDLE, FIELD) do { \
497 MonoObjectHandle __dest = MONO_HANDLE_CAST(MonoObject, RESULT); \
498 MONO_HANDLE_SUPPRESS (*(gpointer*)&__dest->__raw = (gpointer)MONO_HANDLE_RAW (MONO_HANDLE_UNSUPPRESS (HANDLE))->FIELD); \
499 } while (0)
501 #endif
503 // Get ((type)handle)->field as a handle.
504 #define MONO_HANDLE_NEW_GET(TYPE,HANDLE,FIELD) (MONO_HANDLE_NEW(TYPE,MONO_HANDLE_SUPPRESS (MONO_HANDLE_RAW (MONO_HANDLE_UNSUPPRESS (HANDLE))->FIELD)))
506 // Get handle->field, where field is not a pointer (an integer or non-managed pointer).
507 #define MONO_HANDLE_GETVAL(HANDLE, FIELD) MONO_HANDLE_SUPPRESS (MONO_HANDLE_RAW (MONO_HANDLE_UNSUPPRESS (HANDLE))->FIELD)
509 // This would be easier to write with the gcc extension typeof,
510 // but it is not widely enough implemented (i.e. Microsoft C).
511 #define MONO_HANDLE_SETVAL(HANDLE, FIELD, TYPE, VALUE) do { \
512 TYPE __val = (VALUE); \
513 MONO_HANDLE_SUPPRESS (MONO_HANDLE_RAW (MONO_HANDLE_UNSUPPRESS (HANDLE))->FIELD = __val); \
514 } while (0)
516 #define MONO_HANDLE_ARRAY_SETREF(HANDLE, IDX, VALUE) do { \
517 uintptr_t __idx = (IDX); \
518 MonoObjectHandle __val = MONO_HANDLE_CAST (MonoObject, VALUE); \
519 { /* FIXME scope needed by Centrinel */ \
520 /* FIXME mono_array_setref_fast is not an expression. */ \
521 MONO_HANDLE_SUPPRESS_SCOPE(1); \
522 mono_array_setref_fast (MONO_HANDLE_RAW (MONO_HANDLE_UNSUPPRESS (HANDLE)), __idx, MONO_HANDLE_RAW (__val)); \
524 } while (0)
526 #define MONO_HANDLE_ARRAY_SETVAL(HANDLE, TYPE, IDX, VALUE) do { \
527 uintptr_t __idx = (IDX); \
528 TYPE __val = (VALUE); \
529 { /* FIXME scope needed by Centrinel */ \
530 /* FIXME mono_array_set is not an expression. */ \
531 MONO_HANDLE_SUPPRESS_SCOPE(1); \
532 mono_array_set (MONO_HANDLE_RAW (MONO_HANDLE_UNSUPPRESS (HANDLE)), TYPE, __idx, __val); \
534 } while (0)
536 #define MONO_HANDLE_ARRAY_SETRAW(HANDLE, IDX, VALUE) do { \
537 MONO_HANDLE_SUPPRESS_SCOPE(1); \
538 uintptr_t __idx = MONO_HANDLE_UNSUPPRESS(IDX); \
539 MonoObject *__val = (MonoObject*)(VALUE); \
540 mono_array_setref_fast (MONO_HANDLE_RAW (MONO_HANDLE_UNSUPPRESS (HANDLE)), __idx, __val); \
541 } while (0)
543 /* N.B. DEST is evaluated AFTER all the other arguments */
544 #define MONO_HANDLE_ARRAY_GETVAL(DEST, HANDLE, TYPE, IDX) do { \
545 MonoArrayHandle __arr = (HANDLE); \
546 uintptr_t __idx = (IDX); \
547 TYPE __result = MONO_HANDLE_SUPPRESS (mono_array_get (MONO_HANDLE_RAW(__arr), TYPE, __idx)); \
548 (DEST) = __result; \
549 } while (0)
551 #define MONO_HANDLE_ARRAY_GETREF(DEST, HANDLE, IDX) do { \
552 mono_handle_array_getref (MONO_HANDLE_CAST(MonoObject, (DEST)), (HANDLE), (IDX)); \
553 } while (0)
555 #define MONO_HANDLE_ASSIGN(DESTH, SRCH) \
556 mono_handle_assign (MONO_HANDLE_CAST (MonoObject, (DESTH)), MONO_HANDLE_CAST(MonoObject, (SRCH)))
558 #define MONO_HANDLE_DOMAIN(HANDLE) MONO_HANDLE_SUPPRESS (mono_object_domain (MONO_HANDLE_RAW (MONO_HANDLE_CAST (MonoObject, MONO_HANDLE_UNSUPPRESS (HANDLE)))))
560 /* Given an object and a MonoClassField, return the value (must be non-object)
561 * of the field. It's the caller's responsibility to check that the object is
562 * of the correct class. */
563 #define MONO_HANDLE_GET_FIELD_VAL(HANDLE,TYPE,FIELD) (*(TYPE *)(mono_handle_unsafe_field_addr (MONO_HANDLE_CAST (MonoObject, (HANDLE)), (FIELD))))
565 #define MONO_HANDLE_NEW_GET_FIELD(HANDLE,TYPE,FIELD) MONO_HANDLE_NEW (TYPE, MONO_HANDLE_SUPPRESS (*(TYPE**)(mono_handle_unsafe_field_addr (MONO_HANDLE_CAST (MonoObject, MONO_HANDLE_UNSUPPRESS (HANDLE)), (FIELD)))))
567 #define MONO_HANDLE_SET_FIELD_VAL(HANDLE,TYPE,FIELD,VAL) do { \
568 MonoObjectHandle __obj = (HANDLE); \
569 MonoClassField *__field = (FIELD); \
570 TYPE __value = (VAL); \
571 *(TYPE*)(mono_handle_unsafe_field_addr (__obj, __field)) = __value; \
572 } while (0)
574 #define MONO_HANDLE_SET_FIELD_REF(HANDLE,FIELD,VALH) do { \
575 MonoObjectHandle __obj = MONO_HANDLE_CAST (MonoObject, (HANDLE)); \
576 MonoClassField *__field = (FIELD); \
577 MonoObjectHandle __value = MONO_HANDLE_CAST (MonoObject, (VALH)); \
578 MONO_HANDLE_SUPPRESS (mono_gc_wbarrier_generic_store (mono_handle_unsafe_field_addr (__obj, __field), MONO_HANDLE_RAW (__value))); \
579 } while (0)
581 /* Baked typed handles we all want */
582 TYPED_HANDLE_DECL (MonoString);
583 TYPED_HANDLE_DECL (MonoArray);
584 TYPED_HANDLE_DECL (MonoObject);
585 TYPED_HANDLE_DECL (MonoException);
586 TYPED_HANDLE_DECL (MonoAppContext);
588 #if MONO_TYPE_SAFE_HANDLES
590 // Structs cannot be cast to structs.
591 // Therefore, cast the function pointer to change its return type.
592 // As well, a function is needed because an anonymous struct cannot be initialized in C.
593 static inline MonoObjectHandle
594 mono_handle_cast (gpointer a)
596 return *(MonoObjectHandle*)&a;
599 #endif
601 static inline MONO_ALWAYS_INLINE gboolean
602 mono_handle_is_null (MonoRawHandle raw_handle)
604 MONO_HANDLE_SUPPRESS_SCOPE (1);
605 #if MONO_TYPE_SAFE_HANDLES
606 MonoObjectHandle *handle = (MonoObjectHandle*)&raw_handle;
607 return !handle->__raw || !*handle->__raw;
608 #else
609 MonoObjectHandle handle = (MonoObjectHandle)raw_handle;
610 return !handle || !handle->__raw;
611 #endif
614 static inline MONO_ALWAYS_INLINE gpointer
615 mono_handle_raw (MonoRawHandle raw_handle)
617 MONO_HANDLE_SUPPRESS_SCOPE (1);
618 #if MONO_TYPE_SAFE_HANDLES
619 MonoObjectHandle *handle = (MonoObjectHandle*)&raw_handle;
620 return handle->__raw ? *handle->__raw : NULL;
621 #else
622 MonoObjectHandle handle = (MonoObjectHandle)raw_handle;
623 return handle ? handle->__raw : NULL;
624 #endif
627 /* Unfortunately MonoThreadHandle is already a typedef used for something unrelated. So
628 * the coop handle for MonoThread* is MonoThreadObjectHandle.
630 typedef MonoThread MonoThreadObject;
631 TYPED_HANDLE_DECL (MonoThreadObject);
634 This is the constant for a handle that points nowhere.
635 Constant handles may be initialized to it, but non-constant
636 handles must be NEW'ed. Uses of these are suspicious and should
637 be reviewed and probably changed FIXME.
639 extern const MonoObjectHandle mono_null_value_handle;
640 #define NULL_HANDLE mono_null_value_handle
641 #define NULL_HANDLE_STRING MONO_HANDLE_CAST(MonoString, NULL_HANDLE)
642 #define NULL_HANDLE_ARRAY (MONO_HANDLE_CAST (MonoArray, NULL_HANDLE))
644 #if MONO_TYPE_SAFE_HANDLES
646 static inline void
647 mono_handle_assign (MonoObjectHandleOut dest, MonoObjectHandle src)
649 g_assert (dest.__raw);
650 MONO_HANDLE_SUPPRESS (*dest.__raw = src.__raw ? *src.__raw : NULL);
653 #else
655 static inline void
656 mono_handle_assign (MonoObjectHandleOut dest, MonoObjectHandle src)
658 g_assert (dest);
659 MONO_HANDLE_SUPPRESS (dest->__raw = (MonoObject *)(src ? MONO_HANDLE_RAW (src) : NULL));
662 #endif
664 /* It is unsafe to call this function directly - it does not pin the handle! Use MONO_HANDLE_GET_FIELD_VAL(). */
665 static inline gpointer
666 mono_handle_unsafe_field_addr (MonoObjectHandle h, MonoClassField *field)
668 return MONO_HANDLE_SUPPRESS (((gchar *)MONO_HANDLE_RAW (h)) + field->offset);
671 //FIXME this should go somewhere else
672 MonoStringHandle mono_string_new_handle (MonoDomain *domain, const char *data, MonoError *error);
673 MonoArrayHandle mono_array_new_handle (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error);
674 MonoArrayHandle
675 mono_array_new_full_handle (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error);
678 uintptr_t mono_array_handle_length (MonoArrayHandle arr);
680 static inline void
681 mono_handle_array_getref (MonoObjectHandleOut dest, MonoArrayHandle array, uintptr_t index)
683 #if MONO_TYPE_SAFE_HANDLES
684 MONO_HANDLE_SUPPRESS (g_assert (dest.__raw));
685 MONO_HANDLE_SUPPRESS (*dest.__raw = (MonoObject*)mono_array_get(MONO_HANDLE_RAW (array), gpointer, index));
686 #else
687 MONO_HANDLE_SUPPRESS (dest->__raw = (MonoObject *)mono_array_get(MONO_HANDLE_RAW (array), gpointer, index));
688 #endif
691 #define mono_handle_class(o) MONO_HANDLE_SUPPRESS (mono_object_class (MONO_HANDLE_RAW (MONO_HANDLE_UNSUPPRESS (o))))
693 /* Local handles to global GC handles and back */
695 uint32_t
696 mono_gchandle_from_handle (MonoObjectHandle handle, mono_bool pinned);
698 MonoObjectHandle
699 mono_gchandle_get_target_handle (uint32_t gchandle);
701 void
702 mono_array_handle_memcpy_refs (MonoArrayHandle dest, uintptr_t dest_idx, MonoArrayHandle src, uintptr_t src_idx, uintptr_t len);
704 /* Pins the MonoArray using a gchandle and returns a pointer to the
705 * element with the given index (where each element is of the given
706 * size. Call mono_gchandle_free to unpin.
708 gpointer
709 mono_array_handle_pin_with_size (MonoArrayHandle handle, int size, uintptr_t index, uint32_t *gchandle);
711 #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))
713 gunichar2 *
714 mono_string_handle_pin_chars (MonoStringHandle s, uint32_t *gchandle_out);
716 gpointer
717 mono_object_handle_pin_unbox (MonoObjectHandle boxed_valuetype_obj, uint32_t *gchandle_out);
719 static inline gpointer
720 mono_handle_unbox_unsafe (MonoObjectHandle handle)
722 g_assert (m_class_is_valuetype (MONO_HANDLE_GETVAL (handle, vtable)->klass));
723 return MONO_HANDLE_SUPPRESS (MONO_HANDLE_RAW (handle) + 1);
726 void
727 mono_error_set_exception_handle (MonoError *error, MonoExceptionHandle exc);
729 MonoAppContextHandle
730 mono_context_get_handle (void);
732 void
733 mono_context_set_handle (MonoAppContextHandle new_context);
735 static inline guint32
736 mono_gchandle_new_weakref_from_handle (MonoObjectHandle handle)
738 return mono_gchandle_new_weakref (MONO_HANDLE_SUPPRESS (MONO_HANDLE_RAW (handle)), FALSE);
741 G_END_DECLS
743 #endif /* __MONO_HANDLE_H__ */