[runtime] Implement interior handles as a special case to simplify and speed up the...
[mono.git] / mono / metadata / handle.h
index 2b35c878e3680fb9a92d45f47f8ae216982e6bc2..dba7c26c90bafeafd4871281307ce910249718a3 100644 (file)
@@ -25,7 +25,6 @@
 
 G_BEGIN_DECLS
 
-
 /*
 Handle stack.
 
@@ -54,22 +53,27 @@ 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_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;
 #endif
+#ifdef MONO_HANDLE_TRACK_SP
+       gpointer alloc_sp; /* sp from HandleStack:stackmark_sp at time of allocation */
+#endif
 } HandleChunkElem;
 
-/* number of guint32's needed to store the interior pointers bitmap */
-#define INTERIOR_HANDLE_BITMAP_WORDS ((OBJECTS_PER_HANDLES_CHUNK + 31) / 32)
-
 struct _HandleChunk {
        int size; //number of handles
-       /* bits in the range 0..size-1 of interior_bitmap are valid; rest are ignored. */
-       guint32 interior_bitmap [INTERIOR_HANDLE_BITMAP_WORDS];
        HandleChunk *prev, *next;
        HandleChunkElem elems [OBJECTS_PER_HANDLES_CHUNK];
 };
@@ -77,11 +81,20 @@ struct _HandleChunk {
 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;
@@ -92,12 +105,13 @@ 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, gboolean precise);
 gboolean mono_handle_stack_is_empty (HandleStack *stack);
 HandleStack* mono_handle_stack_alloc (void);
@@ -105,12 +119,24 @@ 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);
 
+#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
@@ -121,6 +147,11 @@ mono_stack_mark_pop (MonoThreadInfo *info, HandleStackMark *stackmark)
        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
 }
 
 /*
@@ -372,20 +403,6 @@ This is why we evaluate index and value before any call to MONO_HANDLE_RAW or ot
                mono_handle_array_getref (MONO_HANDLE_CAST(MonoObject, (DEST)), (HANDLE), (IDX)); \
        } while (0)
 
-/* Handles into the interior of objects.
- *
- * Typically when working with value types, we pass them by reference.  In the case where the value type
- * is a field in a managed class, the reference will be a pointer into the middle of a managed object.
- * We need to identify such pointers in order for SGen to scan them correctly.
- */
-
-#ifndef MONO_HANDLE_TRACK_OWNER
-#define MONO_HANDLE_NEW_GET_VALPTR(HANDLE,TYPE,FIELD) (TYPE_VALUE_HANDLE_NAME(TYPE))(mono_handle_new_full (&(HANDLE)->__raw->FIELD), TRUE))
-#else
-#define MONO_HANDLE_NEW_GET_VALPTR(HANDLE,TYPE,FIELD) (TYPE_VALUE_HANDLE_NAME(TYPE))(mono_handle_new_full (&(HANDLE)->__raw->FIELD), TRUE, HANDLE_OWNER_STRINGIFY(__FILE__, __LINE__))
-#endif
-
-
 #define MONO_HANDLE_ASSIGN(DESTH, SRCH)                                \
        mono_handle_assign (MONO_HANDLE_CAST (MonoObject, (DESTH)), MONO_HANDLE_CAST(MonoObject, (SRCH)))
 
@@ -397,6 +414,7 @@ TYPED_HANDLE_DECL (MonoString);
 TYPED_HANDLE_DECL (MonoArray);
 TYPED_HANDLE_DECL (MonoObject);
 TYPED_HANDLE_DECL (MonoException);
+TYPED_HANDLE_DECL (MonoAppContext);
 
 #define NULL_HANDLE_STRING MONO_HANDLE_CAST(MonoString, NULL_HANDLE)
 
@@ -452,6 +470,13 @@ mono_array_handle_pin_with_size (MonoArrayHandle handle, int size, uintptr_t ind
 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
 
 #endif /* __MONO_HANDLE_H__ */