Merge pull request #4967 from kumpera/profiler-arg-cleanup
[mono.git] / mono / metadata / handle.h
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 #ifndef __MONO_HANDLE_H__
15 #define __MONO_HANDLE_H__
16
17 #include <config.h>
18 #include <glib.h>
19
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
26 G_BEGIN_DECLS
27
28 /*
29 Handle stack.
30
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.
33
34 To do bulk operations you use a stack mark.
35         
36 */
37
38 /*
39 3 is the number of fields besides the data in the struct;
40 128 words makes each chunk 512 or 1024 bytes each
41 */
42 #define OBJECTS_PER_HANDLES_CHUNK (128 - 3)
43
44 /*
45 Whether this config needs stack watermark recording to know where to start scanning from.
46 */
47 #ifdef HOST_WATCHOS
48 #define MONO_NEEDS_STACK_WATERMARK 1
49 #endif
50
51 typedef struct _HandleChunk HandleChunk;
52
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).
55  */
56 /*#define MONO_HANDLE_TRACK_OWNER*/
57
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
61  * handle leaks.
62  */
63 /*#define MONO_HANDLE_TRACK_SP*/
64
65 typedef struct {
66         gpointer o; /* MonoObject ptr or interior ptr */
67 #ifdef MONO_HANDLE_TRACK_OWNER
68         const char *owner;
69 #endif
70 #ifdef MONO_HANDLE_TRACK_SP
71         gpointer alloc_sp; /* sp from HandleStack:stackmark_sp at time of allocation */
72 #endif
73 } HandleChunkElem;
74
75 struct _HandleChunk {
76         int size; //number of handles
77         HandleChunk *prev, *next;
78         HandleChunkElem elems [OBJECTS_PER_HANDLES_CHUNK];
79 };
80
81 typedef struct {
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
86 #endif
87         /* Chunk for storing interior pointers. Not extended right now */
88         HandleChunk *interior;
89 } HandleStack;
90
91 // Keep this in sync with RuntimeStructs.cs
92 typedef struct {
93         int size, interior_size;
94         HandleChunk *chunk;
95 #ifdef MONO_HANDLE_TRACK_SP
96         gpointer prev_sp; // C stack pointer from prior mono_stack_mark_init
97 #endif
98 } HandleStackMark;
99
100 typedef void *MonoRawHandle;
101
102 typedef void (*GcScanFunc) (gpointer*, gpointer);
103
104
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);
109 #else
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);
113 #endif
114
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);
121 void mono_handle_stack_free_domain (HandleStack *stack, MonoDomain *domain);
122
123 #ifdef MONO_HANDLE_TRACK_SP
124 void mono_handle_chunk_leak_check (HandleStack *handles);
125 #endif
126
127 static inline void
128 mono_stack_mark_init (MonoThreadInfo *info, HandleStackMark *stackmark)
129 {
130 #ifdef MONO_HANDLE_TRACK_SP
131         gpointer sptop = (gpointer)(intptr_t)&stackmark;
132 #endif
133         HandleStack *handles = (HandleStack *)info->handle_stack;
134         stackmark->size = handles->top->size;
135         stackmark->chunk = handles->top;
136         stackmark->interior_size = handles->interior->size;
137 #ifdef MONO_HANDLE_TRACK_SP
138         stackmark->prev_sp = handles->stackmark_sp;
139         handles->stackmark_sp = sptop;
140 #endif
141 }
142
143 static inline void
144 mono_stack_mark_pop (MonoThreadInfo *info, HandleStackMark *stackmark)
145 {
146         HandleStack *handles = (HandleStack *)info->handle_stack;
147         HandleChunk *old_top = stackmark->chunk;
148         old_top->size = stackmark->size;
149         mono_memory_write_barrier ();
150         handles->top = old_top;
151         handles->interior->size = stackmark->interior_size;
152 #ifdef MONO_HANDLE_TRACK_SP
153         mono_memory_write_barrier (); /* write to top before prev_sp */
154         handles->stackmark_sp = stackmark->prev_sp;
155 #endif
156 }
157
158 /*
159 Icall macros
160 */
161 #define SETUP_ICALL_COMMON      \
162         do { \
163                 MonoError error;        \
164                 MonoThreadInfo *__info = mono_thread_info_current ();   \
165                 error_init (&error);    \
166
167 #define CLEAR_ICALL_COMMON      \
168         mono_error_set_pending_exception (&error);
169
170 #define SETUP_ICALL_FRAME       \
171         HandleStackMark __mark; \
172         mono_stack_mark_init (__info, &__mark);
173
174 #define CLEAR_ICALL_FRAME       \
175         mono_stack_mark_record_size (__info, &__mark, __FUNCTION__);    \
176         mono_stack_mark_pop (__info, &__mark);
177
178 #define CLEAR_ICALL_FRAME_VALUE(RESULT, HANDLE)                         \
179         mono_stack_mark_record_size (__info, &__mark, __FUNCTION__);    \
180         (RESULT) = mono_stack_mark_pop_value (__info, &__mark, (HANDLE));
181
182
183 #define HANDLE_FUNCTION_ENTER() do {                            \
184         MonoThreadInfo *__info = mono_thread_info_current ();   \
185         SETUP_ICALL_FRAME                                       \
186
187 #define HANDLE_FUNCTION_RETURN()                \
188         CLEAR_ICALL_FRAME;                      \
189         } while (0)
190
191 #define HANDLE_FUNCTION_RETURN_VAL(VAL)         \
192         CLEAR_ICALL_FRAME;                      \
193         return (VAL);                           \
194         } while (0)
195
196 #define HANDLE_FUNCTION_RETURN_OBJ(HANDLE)                      \
197         do {                                                    \
198                 void* __result = (MONO_HANDLE_RAW (HANDLE));    \
199                 CLEAR_ICALL_FRAME;                              \
200                 return __result;                                \
201         } while (0); } while (0);
202
203 #define HANDLE_FUNCTION_RETURN_REF(TYPE, HANDLE)                        \
204         do {                                                            \
205                 MonoRawHandle __result;                                 \
206                 CLEAR_ICALL_FRAME_VALUE (__result, ((MonoRawHandle) (HANDLE))); \
207                 return MONO_HANDLE_CAST (TYPE, __result);               \
208         } while (0); } while (0);
209
210 #ifdef MONO_NEEDS_STACK_WATERMARK
211
212 static void
213 mono_thread_info_pop_stack_mark (MonoThreadInfo *info, void *old_mark)
214 {
215         info->stack_mark = old_mark;
216 }
217
218 static void*
219 mono_thread_info_push_stack_mark (MonoThreadInfo *info, void *mark)
220 {
221         void *old = info->stack_mark;
222         info->stack_mark = mark;
223         return old;
224 }
225
226 #define SETUP_STACK_WATERMARK   \
227         int __dummy;    \
228         __builtin_unwind_init ();       \
229         void *__old_stack_mark = mono_thread_info_push_stack_mark (__info, &__dummy);
230
231 #define CLEAR_STACK_WATERMARK   \
232         mono_thread_info_pop_stack_mark (__info, __old_stack_mark);
233
234 #else
235 #define SETUP_STACK_WATERMARK
236 #define CLEAR_STACK_WATERMARK
237 #endif
238
239 #define ICALL_ENTRY()   \
240         SETUP_ICALL_COMMON      \
241         SETUP_ICALL_FRAME       \
242         SETUP_STACK_WATERMARK
243
244 #define ICALL_RETURN()  \
245         do {    \
246                 CLEAR_STACK_WATERMARK   \
247                 CLEAR_ICALL_COMMON      \
248                 CLEAR_ICALL_FRAME       \
249                 return; \
250         } while (0); } while (0)
251
252 #define ICALL_RETURN_VAL(VAL)   \
253         do {    \
254                 CLEAR_STACK_WATERMARK   \
255                 CLEAR_ICALL_COMMON      \
256                 CLEAR_ICALL_FRAME       \
257                 return VAL;     \
258         } while (0); } while (0)
259
260 #define ICALL_RETURN_OBJ(HANDLE)        \
261         do {    \
262                 CLEAR_STACK_WATERMARK   \
263                 CLEAR_ICALL_COMMON      \
264                 void* __ret = MONO_HANDLE_RAW (HANDLE); \
265                 CLEAR_ICALL_FRAME       \
266                 return __ret;   \
267         } while (0); } while (0)
268
269 /*
270 Handle macros/functions
271 */
272
273 #ifdef ENABLE_CHECKED_BUILD
274 void mono_handle_verify (MonoRawHandle handle);
275 #define HANDLE_INVARIANTS(H) mono_handle_verify((void*)(H))
276 #else
277 #define HANDLE_INVARIANTS(H) (0)
278 #endif
279
280 #define TYPED_HANDLE_PAYLOAD_NAME(TYPE) TYPE ## HandlePayload
281 #define TYPED_HANDLE_NAME(TYPE) TYPE ## Handle
282 #define TYPED_OUT_HANDLE_NAME(TYPE) TYPE ## HandleOut
283
284 #ifdef MONO_HANDLE_TRACK_OWNER
285 #define STRINGIFY_(x) #x
286 #define STRINGIFY(x) STRINGIFY_(x)
287 #define HANDLE_OWNER_STRINGIFY(file,lineno) (const char*) (file ":" STRINGIFY(lineno))
288 #endif
289
290
291 /*
292  * TYPED_HANDLE_DECL(SomeType):
293  *   Expands to a decl for handles to SomeType and to an internal payload struct.
294  *
295  * For example, TYPED_HANDLE_DECL(MonoObject) (see below) expands to:
296  *
297  * typedef struct {
298  *   MonoObject *__raw;
299  * } MonoObjectHandlePayload;
300  *
301  * typedef MonoObjectHandlePayload* MonoObjectHandle;
302  * typedef MonoObjectHandlePayload* MonoObjectHandleOut;
303  */
304 #define TYPED_HANDLE_DECL(TYPE)                                         \
305         typedef struct { TYPE *__raw; } TYPED_HANDLE_PAYLOAD_NAME (TYPE) ; \
306         typedef TYPED_HANDLE_PAYLOAD_NAME (TYPE) * TYPED_HANDLE_NAME (TYPE); \
307         typedef TYPED_HANDLE_PAYLOAD_NAME (TYPE) * TYPED_OUT_HANDLE_NAME (TYPE)
308 /*
309  * TYPED_VALUE_HANDLE_DECL(SomeType):
310  *   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.
311  * For example TYPED_HANDLE_DECL(MonoMethodInfo) expands to:
312  *
313  * typedef struct {
314  *   MonoMethodInfo *__raw;
315  * } MonoMethodInfoHandlePayload;
316  * typedef MonoMethodInfoHandlePayload* MonoMethodInfoHandle;
317  */
318 #define TYPED_VALUE_HANDLE_DECL(TYPE) TYPED_HANDLE_DECL(TYPE)
319
320 /* Have to double expand because MONO_STRUCT_OFFSET is doing token pasting on cross-compilers. */
321 #define MONO_HANDLE_PAYLOAD_OFFSET_(PayloadType) MONO_STRUCT_OFFSET(PayloadType, __raw)
322 #define MONO_HANDLE_PAYLOAD_OFFSET(TYPE) MONO_HANDLE_PAYLOAD_OFFSET_(TYPED_HANDLE_PAYLOAD_NAME (TYPE))
323
324 #define MONO_HANDLE_INIT ((void*) mono_null_value_handle)
325 #define NULL_HANDLE mono_null_value_handle
326
327 //XXX add functions to get/set raw, set field, set field to null, set array, set array to null
328 #define MONO_HANDLE_RAW(HANDLE) (HANDLE_INVARIANTS (HANDLE), ((HANDLE)->__raw))
329 #define MONO_HANDLE_DCL(TYPE, NAME) TYPED_HANDLE_NAME(TYPE) NAME = MONO_HANDLE_NEW (TYPE, (NAME ## _raw))
330
331 #ifndef MONO_HANDLE_TRACK_OWNER
332 #define MONO_HANDLE_NEW(TYPE, VALUE) (TYPED_HANDLE_NAME(TYPE))( mono_handle_new ((MonoObject*)(VALUE)) )
333 #else
334 #define MONO_HANDLE_NEW(TYPE, VALUE) (TYPED_HANDLE_NAME(TYPE))( mono_handle_new ((MonoObject*)(VALUE), HANDLE_OWNER_STRINGIFY(__FILE__, __LINE__)))
335 #endif
336
337 #define MONO_HANDLE_CAST(TYPE, VALUE) (TYPED_HANDLE_NAME(TYPE))( VALUE )
338
339 #define MONO_HANDLE_IS_NULL(HANDLE) (MONO_HANDLE_RAW(HANDLE) == NULL)
340
341
342 /*
343 WARNING WARNING WARNING
344
345 The following functions require a particular evaluation ordering to ensure correctness.
346 We must not have exposed handles while any sort of evaluation is happening as that very evaluation might trigger
347 a safepoint and break us.
348
349 This is why we evaluate index and value before any call to MONO_HANDLE_RAW or other functions that deal with naked objects.
350 */
351 #define MONO_HANDLE_SETRAW(HANDLE, FIELD, VALUE) do {   \
352                 MonoObject *__val = (MonoObject*)(VALUE);       \
353                 MONO_OBJECT_SETREF (MONO_HANDLE_RAW (HANDLE), FIELD, __val);    \
354         } while (0)
355
356 #define MONO_HANDLE_SET(HANDLE, FIELD, VALUE) do {      \
357                 MonoObjectHandle __val = MONO_HANDLE_CAST (MonoObject, VALUE);  \
358                 MONO_OBJECT_SETREF (MONO_HANDLE_RAW (HANDLE), FIELD, MONO_HANDLE_RAW (__val));  \
359         } while (0)
360
361 /* N.B. RESULT is evaluated before HANDLE */
362 #define MONO_HANDLE_GET(RESULT, HANDLE, FIELD) do {                     \
363                 MonoObjectHandle __dest = MONO_HANDLE_CAST(MonoObject, RESULT); \
364                 mono_gc_wbarrier_generic_store (&__dest->__raw,  (MonoObject*)(MONO_HANDLE_RAW(HANDLE)->FIELD)); \
365         } while (0)
366
367 #define MONO_HANDLE_NEW_GET(TYPE,HANDLE,FIELD) (MONO_HANDLE_NEW(TYPE,MONO_HANDLE_RAW(HANDLE)->FIELD))
368
369 #define MONO_HANDLE_GETVAL(HANDLE, FIELD) (MONO_HANDLE_RAW(HANDLE)->FIELD)
370
371 /* VS doesn't support typeof :( :( :( */
372 #define MONO_HANDLE_SETVAL(HANDLE, FIELD, TYPE, VALUE) do {     \
373                 TYPE __val = (VALUE);   \
374                 MONO_HANDLE_RAW (HANDLE)->FIELD = __val;        \
375          } while (0)
376
377 #define MONO_HANDLE_ARRAY_SETREF(HANDLE, IDX, VALUE) do {       \
378                 int __idx = (IDX);      \
379                 MonoObjectHandle __val = MONO_HANDLE_CAST (MonoObject, VALUE);          \
380                 mono_array_setref_fast (MONO_HANDLE_RAW (HANDLE), __idx, MONO_HANDLE_RAW (__val));      \
381         } while (0)
382
383 #define MONO_HANDLE_ARRAY_SETVAL(HANDLE, TYPE, IDX, VALUE) do {         \
384                 int __idx = (IDX);                                      \
385                 TYPE __val = (VALUE);                   \
386                 mono_array_set (MONO_HANDLE_RAW (HANDLE), TYPE, __idx, __val); \
387         } while (0)
388
389 #define MONO_HANDLE_ARRAY_SETRAW(HANDLE, IDX, VALUE) do {       \
390                 int __idx = (IDX);      \
391                 MonoObject *__val = (MonoObject*)(VALUE);       \
392                 mono_array_setref_fast (MONO_HANDLE_RAW (HANDLE), __idx, __val); \
393         } while (0)
394
395 /* N.B. DEST is evaluated AFTER all the other arguments */
396 #define MONO_HANDLE_ARRAY_GETVAL(DEST, HANDLE, TYPE, IDX) do {          \
397                 MonoArrayHandle __arr = (HANDLE);                       \
398                 int __idx = (IDX);                                      \
399                 TYPE __result = mono_array_get (MONO_HANDLE_RAW(__arr), TYPE, __idx); \
400                 (DEST) =  __result;                                     \
401         } while (0)
402
403 #define MONO_HANDLE_ARRAY_GETREF(DEST, HANDLE, IDX) do {                \
404                 mono_handle_array_getref (MONO_HANDLE_CAST(MonoObject, (DEST)), (HANDLE), (IDX)); \
405         } while (0)
406
407 #define MONO_HANDLE_ASSIGN(DESTH, SRCH)                         \
408         mono_handle_assign (MONO_HANDLE_CAST (MonoObject, (DESTH)), MONO_HANDLE_CAST(MonoObject, (SRCH)))
409
410 #define MONO_HANDLE_DOMAIN(HANDLE) (mono_object_domain (MONO_HANDLE_RAW (MONO_HANDLE_CAST (MonoObject, HANDLE))))
411
412 /* Given an object and a MonoClassField, return the value (must be non-object)
413  * of the field.  It's the caller's responsibility to check that the object is
414  * of the correct class. */
415 #define MONO_HANDLE_GET_FIELD_VAL(HANDLE,TYPE,FIELD) *(TYPE *)(mono_handle_unsafe_field_addr (MONO_HANDLE_CAST (MonoObject, (HANDLE)), (FIELD)))
416
417 #define MONO_HANDLE_NEW_GET_FIELD(HANDLE,TYPE,FIELD) MONO_HANDLE_NEW (TYPE, *(TYPE**)(mono_handle_unsafe_field_addr (MONO_HANDLE_CAST (MonoObject, (HANDLE)), (FIELD))))
418
419 #define MONO_HANDLE_SET_FIELD_VAL(HANDLE,TYPE,FIELD,VAL) do {           \
420                 MonoObjectHandle __obj = (HANDLE);                      \
421                 MonoClassField *__field = (FIELD);                      \
422                 TYPE __value = (VAL);                                   \
423                 *(TYPE*)(mono_handle_unsafe_field_addr (__obj, __field)) = __value; \
424         } while (0)
425
426 /* Baked typed handles we all want */
427 TYPED_HANDLE_DECL (MonoString);
428 TYPED_HANDLE_DECL (MonoArray);
429 TYPED_HANDLE_DECL (MonoObject);
430 TYPED_HANDLE_DECL (MonoException);
431 TYPED_HANDLE_DECL (MonoAppContext);
432
433 /* Unfortunately MonoThreadHandle is already a typedef used for something unrelated.  So
434  * the coop handle for MonoThread* is MonoThreadObjectHandle.
435  */
436 typedef MonoThread MonoThreadObject;
437 TYPED_HANDLE_DECL (MonoThreadObject);
438
439 #define NULL_HANDLE_STRING MONO_HANDLE_CAST(MonoString, NULL_HANDLE)
440
441 /*
442 This is the constant for a handle that points nowhere.
443 Init values to it.
444 */
445 extern const MonoObjectHandle mono_null_value_handle;
446
447 static inline void
448 mono_handle_assign (MonoObjectHandleOut dest, MonoObjectHandle src)
449 {
450         mono_gc_wbarrier_generic_store (&dest->__raw, src ? MONO_HANDLE_RAW(src) : NULL);
451 }
452
453 /* It is unsafe to call this function directly - it does not pin the handle!  Use MONO_HANDLE_GET_FIELD_VAL(). */
454 static inline gchar*
455 mono_handle_unsafe_field_addr (MonoObjectHandle h, MonoClassField *field)
456 {
457         return ((gchar *)MONO_HANDLE_RAW (h)) + field->offset;
458 }
459
460 //FIXME this should go somewhere else
461 MonoStringHandle mono_string_new_handle (MonoDomain *domain, const char *data, MonoError *error);
462 MonoArrayHandle mono_array_new_handle (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error);
463 MonoArrayHandle
464 mono_array_new_full_handle (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error);
465
466
467 uintptr_t mono_array_handle_length (MonoArrayHandle arr);
468
469 static inline void
470 mono_handle_array_getref (MonoObjectHandleOut dest, MonoArrayHandle array, uintptr_t index)
471 {
472         mono_gc_wbarrier_generic_store (&dest->__raw, mono_array_get (MONO_HANDLE_RAW (array),gpointer, index));
473 }
474
475 #define mono_handle_class(o) mono_object_class (MONO_HANDLE_RAW (o))
476
477 /* Local handles to global GC handles and back */
478
479 uint32_t
480 mono_gchandle_from_handle (MonoObjectHandle handle, mono_bool pinned);
481
482 MonoObjectHandle
483 mono_gchandle_get_target_handle (uint32_t gchandle);
484
485 void
486 mono_array_handle_memcpy_refs (MonoArrayHandle dest, uintptr_t dest_idx, MonoArrayHandle src, uintptr_t src_idx, uintptr_t len);
487
488 /* Pins the MonoArray using a gchandle and returns a pointer to the
489  * element with the given index (where each element is of the given
490  * size.  Call mono_gchandle_free to unpin.
491  */
492 gpointer
493 mono_array_handle_pin_with_size (MonoArrayHandle handle, int size, uintptr_t index, uint32_t *gchandle);
494
495 #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))
496
497 gunichar2 *
498 mono_string_handle_pin_chars (MonoStringHandle s, uint32_t *gchandle_out);
499
500 void
501 mono_error_set_exception_handle (MonoError *error, MonoExceptionHandle exc);
502
503 MonoAppContextHandle
504 mono_context_get_handle (void);
505
506 void
507 mono_context_set_handle (MonoAppContextHandle new_context);
508
509 G_END_DECLS
510
511 #endif /* __MONO_HANDLE_H__ */