Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mono / metadata / handle.h
index 102f9f4da7244fbb8aac1b0909d239bd1a49b190..40784ea78f17d41d7c1f49a4a168e83fdfd7be92 100644 (file)
@@ -1,5 +1,6 @@
-/*
- * handle.h: Handle to object in native code
+/**
+ * \file
+ * Handle to object in native code
  *
  * Authors:
  *  - Ludovic Henry <ludovic@xamarin.com>
@@ -24,7 +25,6 @@
 
 G_BEGIN_DECLS
 
-
 /*
 Handle stack.
 
@@ -50,20 +50,52 @@ Whether this config needs stack watermark recording to know where to start scann
 
 typedef struct _HandleChunk HandleChunk;
 
+/* define MONO_HANDLE_TRACK_OWNER to store the file and line number of each call to MONO_HANDLE_NEW
+ * in the handle stack.  (This doubles the amount of memory used for handles, so it's only useful for debugging).
+ */
+/*#define MONO_HANDLE_TRACK_OWNER*/
+
+/* define MONO_HANDLE_TRACK_SP to record the C stack pointer at the time of each HANDLE_FUNCTION_ENTER and
+ * to ensure that when a new handle is allocated the previous newest handle is not lower in the stack.
+ * This is useful to catch missing HANDLE_FUNCTION_ENTER / HANDLE_FUNCTION_RETURN pairs which could cause
+ * handle leaks.
+ */
+/*#define MONO_HANDLE_TRACK_SP*/
+
+typedef struct {
+       gpointer o; /* MonoObject ptr or interior ptr */
+#ifdef MONO_HANDLE_TRACK_OWNER
+       const char *owner;
+       gpointer backtrace_ips[7]; /* result of backtrace () at time of allocation */
+#endif
+#ifdef MONO_HANDLE_TRACK_SP
+       gpointer alloc_sp; /* sp from HandleStack:stackmark_sp at time of allocation */
+#endif
+} HandleChunkElem;
+
 struct _HandleChunk {
-       int size; //number of bytes
+       int size; //number of handles
        HandleChunk *prev, *next;
-       MonoObject *objects [OBJECTS_PER_HANDLES_CHUNK];
+       HandleChunkElem elems [OBJECTS_PER_HANDLES_CHUNK];
 };
 
 typedef struct {
        HandleChunk *top; //alloc from here
        HandleChunk *bottom; //scan from here
+#ifdef MONO_HANDLE_TRACK_SP
+       gpointer stackmark_sp; // C stack pointer top when from most recent mono_stack_mark_init
+#endif
+       /* Chunk for storing interior pointers. Not extended right now */
+       HandleChunk *interior;
 } HandleStack;
 
+// Keep this in sync with RuntimeStructs.cs
 typedef struct {
-       int size;
+       int size, interior_size;
        HandleChunk *chunk;
+#ifdef MONO_HANDLE_TRACK_SP
+       gpointer prev_sp; // C stack pointer from prior mono_stack_mark_init
+#endif
 } HandleStackMark;
 
 typedef void *MonoRawHandle;
@@ -71,28 +103,57 @@ typedef void *MonoRawHandle;
 typedef void (*GcScanFunc) (gpointer*, gpointer);
 
 
+#ifndef MONO_HANDLE_TRACK_OWNER
 MonoRawHandle mono_handle_new (MonoObject *object);
+MonoRawHandle mono_handle_new_full (gpointer rawptr, gboolean interior);
+MonoRawHandle mono_handle_new_interior (gpointer rawptr);
+#else
+MonoRawHandle mono_handle_new (MonoObject *object, const char* owner);
+MonoRawHandle mono_handle_new_full (gpointer rawptr, gboolean interior, const char *owner);
+MonoRawHandle mono_handle_new_interior (gpointer rawptr, const char *owner);
+#endif
 
-void mono_handle_stack_scan (HandleStack *stack, GcScanFunc func, gpointer gc_data);
+void mono_handle_stack_scan (HandleStack *stack, GcScanFunc func, gpointer gc_data, gboolean precise);
+gboolean mono_handle_stack_is_empty (HandleStack *stack);
 HandleStack* mono_handle_stack_alloc (void);
 void mono_handle_stack_free (HandleStack *handlestack);
 MonoRawHandle mono_stack_mark_pop_value (MonoThreadInfo *info, HandleStackMark *stackmark, MonoRawHandle value);
 void mono_stack_mark_record_size (MonoThreadInfo *info, HandleStackMark *stackmark, const char *func_name);
+void mono_handle_stack_free_domain (HandleStack *stack, MonoDomain *domain);
+
+#ifdef MONO_HANDLE_TRACK_SP
+void mono_handle_chunk_leak_check (HandleStack *handles);
+#endif
 
 static inline void
 mono_stack_mark_init (MonoThreadInfo *info, HandleStackMark *stackmark)
 {
+#ifdef MONO_HANDLE_TRACK_SP
+       gpointer sptop = (gpointer)(intptr_t)&stackmark;
+#endif
        HandleStack *handles = (HandleStack *)info->handle_stack;
        stackmark->size = handles->top->size;
        stackmark->chunk = handles->top;
+       stackmark->interior_size = handles->interior->size;
+#ifdef MONO_HANDLE_TRACK_SP
+       stackmark->prev_sp = handles->stackmark_sp;
+       handles->stackmark_sp = sptop;
+#endif
 }
 
 static inline void
 mono_stack_mark_pop (MonoThreadInfo *info, HandleStackMark *stackmark)
 {
        HandleStack *handles = (HandleStack *)info->handle_stack;
-       handles->top = stackmark->chunk;
-       handles->top->size = stackmark->size;
+       HandleChunk *old_top = stackmark->chunk;
+       old_top->size = stackmark->size;
+       mono_memory_write_barrier ();
+       handles->top = old_top;
+       handles->interior->size = stackmark->interior_size;
+#ifdef MONO_HANDLE_TRACK_SP
+       mono_memory_write_barrier (); /* write to top before prev_sp */
+       handles->stackmark_sp = stackmark->prev_sp;
+#endif
 }
 
 /*
@@ -115,6 +176,38 @@ Icall macros
        mono_stack_mark_record_size (__info, &__mark, __FUNCTION__);    \
        mono_stack_mark_pop (__info, &__mark);
 
+#define CLEAR_ICALL_FRAME_VALUE(RESULT, HANDLE)                                \
+       mono_stack_mark_record_size (__info, &__mark, __FUNCTION__);    \
+       (RESULT) = mono_stack_mark_pop_value (__info, &__mark, (HANDLE));
+
+
+#define HANDLE_FUNCTION_ENTER() do {                           \
+       MonoThreadInfo *__info = mono_thread_info_current ();   \
+       SETUP_ICALL_FRAME                                       \
+
+#define HANDLE_FUNCTION_RETURN()               \
+       CLEAR_ICALL_FRAME;                      \
+       } while (0)
+
+#define HANDLE_FUNCTION_RETURN_VAL(VAL)                \
+       CLEAR_ICALL_FRAME;                      \
+       return (VAL);                           \
+       } while (0)
+
+#define HANDLE_FUNCTION_RETURN_OBJ(HANDLE)                     \
+       do {                                                    \
+               void* __result = (MONO_HANDLE_RAW (HANDLE));    \
+               CLEAR_ICALL_FRAME;                              \
+               return __result;                                \
+       } while (0); } while (0);
+
+#define HANDLE_FUNCTION_RETURN_REF(TYPE, HANDLE)                       \
+       do {                                                            \
+               MonoRawHandle __result;                                 \
+               CLEAR_ICALL_FRAME_VALUE (__result, ((MonoRawHandle) (HANDLE))); \
+               return MONO_HANDLE_CAST (TYPE, __result);               \
+       } while (0); } while (0);
+
 #ifdef MONO_NEEDS_STACK_WATERMARK
 
 static void
@@ -187,6 +280,14 @@ void mono_handle_verify (MonoRawHandle handle);
 
 #define TYPED_HANDLE_PAYLOAD_NAME(TYPE) TYPE ## HandlePayload
 #define TYPED_HANDLE_NAME(TYPE) TYPE ## Handle
+#define TYPED_OUT_HANDLE_NAME(TYPE) TYPE ## HandleOut
+
+#ifdef MONO_HANDLE_TRACK_OWNER
+#define STRINGIFY_(x) #x
+#define STRINGIFY(x) STRINGIFY_(x)
+#define HANDLE_OWNER_STRINGIFY(file,lineno) (const char*) (file ":" STRINGIFY(lineno))
+#endif
+
 
 /*
  * TYPED_HANDLE_DECL(SomeType):
@@ -195,25 +296,50 @@ void mono_handle_verify (MonoRawHandle handle);
  * For example, TYPED_HANDLE_DECL(MonoObject) (see below) expands to:
  *
  * typedef struct {
- *   MonoObject *__obj;
+ *   MonoObject *__raw;
  * } MonoObjectHandlePayload;
  *
  * typedef MonoObjectHandlePayload* MonoObjectHandle;
+ * typedef MonoObjectHandlePayload* MonoObjectHandleOut;
+ */
+#define TYPED_HANDLE_DECL(TYPE)                                                \
+       typedef struct { TYPE *__raw; } TYPED_HANDLE_PAYLOAD_NAME (TYPE) ; \
+       typedef TYPED_HANDLE_PAYLOAD_NAME (TYPE) * TYPED_HANDLE_NAME (TYPE); \
+       typedef TYPED_HANDLE_PAYLOAD_NAME (TYPE) * TYPED_OUT_HANDLE_NAME (TYPE)
+/*
+ * TYPED_VALUE_HANDLE_DECL(SomeType):
+ *   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.
+ * For example TYPED_HANDLE_DECL(MonoMethodInfo) expands to:
+ *
+ * typedef struct {
+ *   MonoMethodInfo *__raw;
+ * } MonoMethodInfoHandlePayload;
+ * typedef MonoMethodInfoHandlePayload* MonoMethodInfoHandle;
  */
-#define TYPED_HANDLE_DECL(TYPE) typedef struct { TYPE *__obj; } TYPED_HANDLE_PAYLOAD_NAME (TYPE) ; typedef TYPED_HANDLE_PAYLOAD_NAME (TYPE) * TYPED_HANDLE_NAME (TYPE)
+#define TYPED_VALUE_HANDLE_DECL(TYPE) TYPED_HANDLE_DECL(TYPE)
+
 /* Have to double expand because MONO_STRUCT_OFFSET is doing token pasting on cross-compilers. */
-#define MONO_HANDLE_PAYLOAD_OFFSET_(PayloadType) MONO_STRUCT_OFFSET(PayloadType, __obj)
+#define MONO_HANDLE_PAYLOAD_OFFSET_(PayloadType) MONO_STRUCT_OFFSET(PayloadType, __raw)
 #define MONO_HANDLE_PAYLOAD_OFFSET(TYPE) MONO_HANDLE_PAYLOAD_OFFSET_(TYPED_HANDLE_PAYLOAD_NAME (TYPE))
 
 #define MONO_HANDLE_INIT ((void*) mono_null_value_handle)
 #define NULL_HANDLE mono_null_value_handle
 
 //XXX add functions to get/set raw, set field, set field to null, set array, set array to null
-#define MONO_HANDLE_RAW(HANDLE) (HANDLE_INVARIANTS (HANDLE), ((HANDLE)->__obj))
-#define MONO_HANDLE_DCL(TYPE, NAME) TYPED_HANDLE_NAME(TYPE) NAME = (TYPED_HANDLE_NAME(TYPE))(mono_handle_new ((MonoObject*)(NAME ## _raw)))
+#define MONO_HANDLE_RAW(HANDLE) (HANDLE_INVARIANTS (HANDLE), ((HANDLE)->__raw))
+#define MONO_HANDLE_DCL(TYPE, NAME) TYPED_HANDLE_NAME(TYPE) NAME = MONO_HANDLE_NEW (TYPE, (NAME ## _raw))
+
+#ifndef MONO_HANDLE_TRACK_OWNER
 #define MONO_HANDLE_NEW(TYPE, VALUE) (TYPED_HANDLE_NAME(TYPE))( mono_handle_new ((MonoObject*)(VALUE)) )
+#else
+#define MONO_HANDLE_NEW(TYPE, VALUE) (TYPED_HANDLE_NAME(TYPE))( mono_handle_new ((MonoObject*)(VALUE), HANDLE_OWNER_STRINGIFY(__FILE__, __LINE__)))
+#endif
+
 #define MONO_HANDLE_CAST(TYPE, VALUE) (TYPED_HANDLE_NAME(TYPE))( VALUE )
 
+#define MONO_HANDLE_IS_NULL(HANDLE) (MONO_HANDLE_RAW(HANDLE) == NULL)
+
+
 /*
 WARNING WARNING WARNING
 
@@ -226,12 +352,22 @@ This is why we evaluate index and value before any call to MONO_HANDLE_RAW or ot
 #define MONO_HANDLE_SETRAW(HANDLE, FIELD, VALUE) do {  \
                MonoObject *__val = (MonoObject*)(VALUE);       \
                MONO_OBJECT_SETREF (MONO_HANDLE_RAW (HANDLE), FIELD, __val);    \
-       } while (0);
+       } while (0)
 
 #define MONO_HANDLE_SET(HANDLE, FIELD, VALUE) do {     \
                MonoObjectHandle __val = MONO_HANDLE_CAST (MonoObject, VALUE);  \
                MONO_OBJECT_SETREF (MONO_HANDLE_RAW (HANDLE), FIELD, MONO_HANDLE_RAW (__val));  \
-       } while (0);
+       } while (0)
+
+/* N.B. RESULT is evaluated before HANDLE */
+#define MONO_HANDLE_GET(RESULT, HANDLE, FIELD) do {                    \
+               MonoObjectHandle __dest = MONO_HANDLE_CAST(MonoObject, RESULT); \
+               mono_gc_wbarrier_generic_store (&__dest->__raw,  (MonoObject*)(MONO_HANDLE_RAW(HANDLE)->FIELD)); \
+       } while (0)
+
+#define MONO_HANDLE_NEW_GET(TYPE,HANDLE,FIELD) (MONO_HANDLE_NEW(TYPE,MONO_HANDLE_RAW(HANDLE)->FIELD))
+
+#define MONO_HANDLE_GETVAL(HANDLE, FIELD) (MONO_HANDLE_RAW(HANDLE)->FIELD)
 
 /* VS doesn't support typeof :( :( :( */
 #define MONO_HANDLE_SETVAL(HANDLE, FIELD, TYPE, VALUE) do {    \
@@ -245,19 +381,68 @@ This is why we evaluate index and value before any call to MONO_HANDLE_RAW or ot
                mono_array_setref_fast (MONO_HANDLE_RAW (HANDLE), __idx, MONO_HANDLE_RAW (__val));      \
        } while (0)
 
+#define MONO_HANDLE_ARRAY_SETVAL(HANDLE, TYPE, IDX, VALUE) do {                \
+               int __idx = (IDX);                                      \
+               TYPE __val = (VALUE);                   \
+               mono_array_set (MONO_HANDLE_RAW (HANDLE), TYPE, __idx, __val); \
+       } while (0)
+
 #define MONO_HANDLE_ARRAY_SETRAW(HANDLE, IDX, VALUE) do {      \
                int __idx = (IDX);      \
                MonoObject *__val = (MonoObject*)(VALUE);       \
-               mono_array_setref_fast (MONO_HANDLE_RAW (HANDLE), __idx, __val);        \
+               mono_array_setref_fast (MONO_HANDLE_RAW (HANDLE), __idx, __val); \
+       } while (0)
+
+/* N.B. DEST is evaluated AFTER all the other arguments */
+#define MONO_HANDLE_ARRAY_GETVAL(DEST, HANDLE, TYPE, IDX) do {         \
+               MonoArrayHandle __arr = (HANDLE);                       \
+               int __idx = (IDX);                                      \
+               TYPE __result = mono_array_get (MONO_HANDLE_RAW(__arr), TYPE, __idx); \
+               (DEST) =  __result;                                     \
+       } while (0)
+
+#define MONO_HANDLE_ARRAY_GETREF(DEST, HANDLE, IDX) do {               \
+               mono_handle_array_getref (MONO_HANDLE_CAST(MonoObject, (DEST)), (HANDLE), (IDX)); \
        } while (0)
 
+#define MONO_HANDLE_ASSIGN(DESTH, SRCH)                                \
+       mono_handle_assign (MONO_HANDLE_CAST (MonoObject, (DESTH)), MONO_HANDLE_CAST(MonoObject, (SRCH)))
 
 #define MONO_HANDLE_DOMAIN(HANDLE) (mono_object_domain (MONO_HANDLE_RAW (MONO_HANDLE_CAST (MonoObject, HANDLE))))
 
+/* Given an object and a MonoClassField, return the value (must be non-object)
+ * of the field.  It's the caller's responsibility to check that the object is
+ * of the correct class. */
+#define MONO_HANDLE_GET_FIELD_VAL(HANDLE,TYPE,FIELD) *(TYPE *)(mono_handle_unsafe_field_addr (MONO_HANDLE_CAST (MonoObject, (HANDLE)), (FIELD)))
+
+#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))))
+
+#define MONO_HANDLE_SET_FIELD_VAL(HANDLE,TYPE,FIELD,VAL) do {          \
+               MonoObjectHandle __obj = (HANDLE);                      \
+               MonoClassField *__field = (FIELD);                      \
+               TYPE __value = (VAL);                                   \
+               *(TYPE*)(mono_handle_unsafe_field_addr (__obj, __field)) = __value; \
+       } while (0)
+
+#define MONO_HANDLE_SET_FIELD_REF(HANDLE,FIELD,VALH) do {              \
+               MonoObjectHandle __obj = MONO_HANDLE_CAST (MonoObject, (HANDLE)); \
+               MonoClassField *__field = (FIELD);                      \
+               MonoObjectHandle __value = MONO_HANDLE_CAST (MonoObject, (VALH)); \
+               mono_gc_wbarrier_generic_store (mono_handle_unsafe_field_addr (__obj, __field), MONO_HANDLE_RAW (__value)); \
+       } while (0)
+
 /* Baked typed handles we all want */
 TYPED_HANDLE_DECL (MonoString);
 TYPED_HANDLE_DECL (MonoArray);
 TYPED_HANDLE_DECL (MonoObject);
+TYPED_HANDLE_DECL (MonoException);
+TYPED_HANDLE_DECL (MonoAppContext);
+
+/* Unfortunately MonoThreadHandle is already a typedef used for something unrelated.  So
+ * the coop handle for MonoThread* is MonoThreadObjectHandle.
+ */
+typedef MonoThread MonoThreadObject;
+TYPED_HANDLE_DECL (MonoThreadObject);
 
 #define NULL_HANDLE_STRING MONO_HANDLE_CAST(MonoString, NULL_HANDLE)
 
@@ -267,10 +452,70 @@ Init values to it.
 */
 extern const MonoObjectHandle mono_null_value_handle;
 
+static inline void
+mono_handle_assign (MonoObjectHandleOut dest, MonoObjectHandle src)
+{
+       mono_gc_wbarrier_generic_store (&dest->__raw, src ? MONO_HANDLE_RAW(src) : NULL);
+}
+
+/* It is unsafe to call this function directly - it does not pin the handle!  Use MONO_HANDLE_GET_FIELD_VAL(). */
+static inline gchar*
+mono_handle_unsafe_field_addr (MonoObjectHandle h, MonoClassField *field)
+{
+       return ((gchar *)MONO_HANDLE_RAW (h)) + field->offset;
+}
 
 //FIXME this should go somewhere else
 MonoStringHandle mono_string_new_handle (MonoDomain *domain, const char *data, MonoError *error);
 MonoArrayHandle mono_array_new_handle (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error);
+MonoArrayHandle
+mono_array_new_full_handle (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error);
+
+
+uintptr_t mono_array_handle_length (MonoArrayHandle arr);
+
+static inline void
+mono_handle_array_getref (MonoObjectHandleOut dest, MonoArrayHandle array, uintptr_t index)
+{
+       mono_gc_wbarrier_generic_store (&dest->__raw, mono_array_get (MONO_HANDLE_RAW (array),gpointer, index));
+}
+
+#define mono_handle_class(o) mono_object_class (MONO_HANDLE_RAW (o))
+
+/* Local handles to global GC handles and back */
+
+uint32_t
+mono_gchandle_from_handle (MonoObjectHandle handle, mono_bool pinned);
+
+MonoObjectHandle
+mono_gchandle_get_target_handle (uint32_t gchandle);
+
+void
+mono_array_handle_memcpy_refs (MonoArrayHandle dest, uintptr_t dest_idx, MonoArrayHandle src, uintptr_t src_idx, uintptr_t len);
+
+/* Pins the MonoArray using a gchandle and returns a pointer to the
+ * element with the given index (where each element is of the given
+ * size.  Call mono_gchandle_free to unpin.
+ */
+gpointer
+mono_array_handle_pin_with_size (MonoArrayHandle handle, int size, uintptr_t index, uint32_t *gchandle);
+
+#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))
+
+gunichar2 *
+mono_string_handle_pin_chars (MonoStringHandle s, uint32_t *gchandle_out);
+
+gpointer
+mono_object_handle_pin_unbox (MonoObjectHandle boxed_valuetype_obj, uint32_t *gchandle_out);
+
+void
+mono_error_set_exception_handle (MonoError *error, MonoExceptionHandle exc);
+
+MonoAppContextHandle
+mono_context_get_handle (void);
+
+void
+mono_context_set_handle (MonoAppContextHandle new_context);
 
 G_END_DECLS