[runtime] Implement interior handles as a special case to simplify and speed up the...
authorZoltan Varga <vargaz@gmail.com>
Wed, 24 May 2017 17:58:18 +0000 (13:58 -0400)
committerGitHub <noreply@github.com>
Wed, 24 May 2017 17:58:18 +0000 (13:58 -0400)
configure.ac
mcs/class/corlib/Mono/RuntimeStructs.cs
mono/metadata/handle.c
mono/metadata/handle.h
mono/metadata/marshal.c

index 86a2354b389338d03914c8895349d15b7ba3c0db..c5c7ba58b9e3cfbd99ec0da64a13c1f3872cee0f 100644 (file)
@@ -40,7 +40,7 @@ MONO_VERSION_BUILD=`echo $VERSION | cut -d . -f 3`
 # This can be reset to 0 when Mono's version number is bumped
 # since it's part of the corlib version (the prefix '1' in the full
 # version number is to ensure the number isn't treated as octal in C)
-MONO_CORLIB_COUNTER=1
+MONO_CORLIB_COUNTER=2
 MONO_CORLIB_VERSION=`printf "1%02d%02d%02d%03d" $MONO_VERSION_MAJOR $MONO_VERSION_MINOR $MONO_VERSION_BUILD $MONO_CORLIB_COUNTER`
 
 AC_DEFINE_UNQUOTED(MONO_CORLIB_VERSION,$MONO_CORLIB_VERSION,[Version of the corlib-runtime interface])
index f70ee556ac6adb177de9fa5cc15cc469928fefca..92884a2591d87096214b2498460e1c9499351f3a 100644 (file)
@@ -51,7 +51,7 @@ namespace Mono {
 
                // handle.h HandleStackMark
                struct HandleStackMark {
-                       int size;
+                       int size, interior_size;
                        IntPtr chunk;
                }
 
index 00a11e67319e375ff9004906341b53320767fbcb..a0f5c4459f1a90c215ace491307b2ede24d7fb80 100644 (file)
@@ -73,66 +73,12 @@ const MonoObjectHandle mono_null_value_handle = NULL;
 
 #define THIS_IS_AN_OK_NUMBER_OF_HANDLES 100
 
-enum {
-       HANDLE_CHUNK_PTR_OBJ = 0x0, /* chunk element points to beginning of a managed object */
-       HANDLE_CHUNK_PTR_INTERIOR = 0x1, /* chunk element points into the middle of a managed object */
-       HANDLE_CHUNK_PTR_MASK = 0x1
-};
-
-/* number of bits in each word of the interior pointer bitmap */
-#define INTERIOR_HANDLE_BITMAP_BITS_PER_WORD (sizeof(guint32) << 3)
-
-static gboolean
-bitset_bits_test (guint32 *bitmaps, int idx)
-{
-       int w = idx / INTERIOR_HANDLE_BITMAP_BITS_PER_WORD;
-       int b = idx % INTERIOR_HANDLE_BITMAP_BITS_PER_WORD;
-       guint32 bitmap = bitmaps [w];
-       guint32 mask = 1u << b;
-       return ((bitmap & mask) != 0);
-}
-
-static void
-bitset_bits_set (guint32 *bitmaps, int idx)
-{
-       int w = idx / INTERIOR_HANDLE_BITMAP_BITS_PER_WORD;
-       int b = idx % INTERIOR_HANDLE_BITMAP_BITS_PER_WORD;
-       guint32 *bitmap = &bitmaps [w];
-       guint32 mask = 1u << b;
-       *bitmap |= mask;
-}
-static void
-bitset_bits_clear (guint32 *bitmaps, int idx)
-{
-       int w = idx / INTERIOR_HANDLE_BITMAP_BITS_PER_WORD;
-       int b = idx % INTERIOR_HANDLE_BITMAP_BITS_PER_WORD;
-       guint32 *bitmap = &bitmaps [w];
-       guint32 mask = ~(1u << b);
-       *bitmap &= mask;
-}
-
-static gpointer*
-chunk_element_objslot_init (HandleChunk *chunk, int idx, gboolean interior)
-{
-       if (interior)
-               bitset_bits_set (chunk->interior_bitmap, idx);
-       else
-               bitset_bits_clear (chunk->interior_bitmap, idx);
-       return &chunk->elems [idx].o;
-}
-
 static HandleChunkElem*
 chunk_element (HandleChunk *chunk, int idx)
 {
        return &chunk->elems[idx];
 }
 
-static guint
-chunk_element_kind (HandleChunk *chunk, int idx)
-{
-       return bitset_bits_test (chunk->interior_bitmap, idx) ? HANDLE_CHUNK_PTR_INTERIOR : HANDLE_CHUNK_PTR_OBJ;
-}
-
 static HandleChunkElem*
 handle_to_chunk_element (MonoObjectHandle o)
 {
@@ -207,25 +153,12 @@ mono_handle_chunk_leak_check (HandleStack *handles) {
 }
 #endif
 
-MonoRawHandle
-#ifndef MONO_HANDLE_TRACK_OWNER
-mono_handle_new (MonoObject *object)
-#else
-mono_handle_new (MonoObject *object, const char *owner)
-#endif
-{
-#ifndef MONO_HANDLE_TRACK_OWNER
-       return mono_handle_new_full (object, FALSE);
-#else
-       return mono_handle_new_full (object, FALSE, owner);
-#endif
-}
 /* Actual handles implementation */
 MonoRawHandle
 #ifndef MONO_HANDLE_TRACK_OWNER
-mono_handle_new_full (gpointer rawptr, gboolean interior)
+mono_handle_new (MonoObject *obj)
 #else
-mono_handle_new_full (gpointer rawptr, gboolean interior, const char *owner)
+mono_handle_new (MonoObject *obj, const char *owner)
 #endif
 {
        MonoThreadInfo *info = mono_thread_info_current ();
@@ -238,7 +171,7 @@ mono_handle_new_full (gpointer rawptr, gboolean interior, const char *owner)
 retry:
        if (G_LIKELY (top->size < OBJECTS_PER_HANDLES_CHUNK)) {
                int idx = top->size;
-               gpointer* objslot = chunk_element_objslot_init (top, idx, interior);
+               gpointer* objslot = &top->elems [idx].o;
                /* can be interrupted anywhere here, so:
                 * 1. make sure the new slot is null
                 * 2. make the new slot scannable (increment size)
@@ -251,7 +184,7 @@ retry:
                mono_memory_write_barrier ();
                top->size++;
                mono_memory_write_barrier ();
-               *objslot = rawptr;
+               *objslot = obj;
                SET_OWNER (top,idx);
                SET_SP (handles, top, idx);
                return objslot;
@@ -266,7 +199,6 @@ retry:
        }
        HandleChunk *new_chunk = g_new (HandleChunk, 1);
        new_chunk->size = 0;
-       memset (new_chunk->interior_bitmap, 0, INTERIOR_HANDLE_BITMAP_WORDS);
        new_chunk->prev = top;
        new_chunk->next = NULL;
        /* make sure size == 0 before new chunk is visible */
@@ -276,19 +208,50 @@ retry:
        goto retry;
 }
 
+MonoRawHandle
+#ifndef MONO_HANDLE_TRACK_OWNER
+mono_handle_new_interior (gpointer rawptr)
+#else
+mono_handle_new_interior (gpointer rawptr, const char *owner)
+#endif
+{
+       MonoThreadInfo *info = mono_thread_info_current ();
+       HandleStack *handles = (HandleStack *)info->handle_stack;
+       HandleChunk *top = handles->interior;
+#ifdef MONO_HANDLE_TRACK_SP
+       mono_handle_chunk_leak_check (handles);
+#endif
 
+       g_assert (top);
+
+       /*
+        * Don't extend the chunk now, interior handles are
+        * only used for icall arguments, they shouldn't
+        * overflow.
+        */
+       g_assert (top->size < OBJECTS_PER_HANDLES_CHUNK);
+       int idx = top->size;
+       gpointer *objslot = &top->elems [idx].o;
+       *objslot = NULL;
+       mono_memory_write_barrier ();
+       top->size++;
+       mono_memory_write_barrier ();
+       *objslot = rawptr;
+       SET_OWNER (top,idx);
+       SET_SP (handles, top, idx);
+       return objslot;
+}
 
 HandleStack*
 mono_handle_stack_alloc (void)
 {
-       HandleStack *stack = g_new (HandleStack, 1);
-       HandleChunk *chunk = g_new (HandleChunk, 1);
+       HandleStack *stack = g_new0 (HandleStack, 1);
+       HandleChunk *chunk = g_new0 (HandleChunk, 1);
+       HandleChunk *interior = g_new0 (HandleChunk, 1);
 
-       chunk->size = 0;
-       memset (chunk->interior_bitmap, 0, INTERIOR_HANDLE_BITMAP_WORDS);
-       chunk->prev = chunk->next = NULL;
        mono_memory_write_barrier ();
        stack->top = stack->bottom = chunk;
+       stack->interior = interior;
 #ifdef MONO_HANDLE_TRACK_OWNER
        stack->stackmark_sp = NULL;
 #endif
@@ -309,6 +272,7 @@ mono_handle_stack_free (HandleStack *stack)
                c = next;
        }
        g_free (c);
+       g_free (stack->interior);
        g_free (stack);
 }
 
@@ -362,46 +326,32 @@ mono_handle_stack_scan (HandleStack *stack, GcScanFunc func, gpointer gc_data, g
 
          Note that if we're running, we know the world is stopped.
        */
-       HandleChunk *cur = stack->bottom;
-       HandleChunk *last = stack->top;
+       if (precise) {
+               HandleChunk *cur = stack->bottom;
+               HandleChunk *last = stack->top;
 
-       if (!cur)
-               return;
-
-       while (cur) {
-               /* assume that object pointers will be much more common than interior pointers.
-                * scan the object pointers by iterating over the chunk elements.
-                * scan the interior pointers by iterating over the bitmap bits.
-                */
-               if (precise) {
+               while (cur) {
                        for (int i = 0; i < cur->size; ++i) {
                                HandleChunkElem* elem = chunk_element (cur, i);
-                               int kind = chunk_element_kind (cur, i);
                                gpointer* obj_slot = &elem->o;
-                               if (kind == HANDLE_CHUNK_PTR_OBJ && *obj_slot != NULL)
+                               if (*obj_slot != NULL)
                                        func (obj_slot, gc_data);
                        }
-               } else {
-                       int elem_idx = 0;
-                       for (int i = 0; i < INTERIOR_HANDLE_BITMAP_WORDS; ++i) {
-                               elem_idx = i * INTERIOR_HANDLE_BITMAP_BITS_PER_WORD;
-                               if (elem_idx >= cur->size)
-                                       break;
-                               /* no interior pointers in the range */ 
-                               if (cur->interior_bitmap [i] == 0)
-                                       continue;
-                               for (int j = 0; j < INTERIOR_HANDLE_BITMAP_BITS_PER_WORD && elem_idx < cur->size; ++j,++elem_idx) {
-                                       HandleChunkElem *elem = chunk_element (cur, elem_idx);
-                                       int kind = chunk_element_kind (cur, elem_idx);
-                                       gpointer *ptr_slot = &elem->o;
-                                       if (kind == HANDLE_CHUNK_PTR_INTERIOR && *ptr_slot != NULL)
-                                               func (ptr_slot, gc_data);
-                               }
-                       }            
+                       if (cur == last)
+                               break;
+                       cur = cur->next;
+               }
+       } else {
+               HandleChunk *cur = stack->interior;
+
+               if (!cur)
+                       return;
+               for (int i = 0; i < cur->size; ++i) {
+                       HandleChunkElem* elem = chunk_element (cur, i);
+                       gpointer* ptr_slot = &elem->o;
+                       if (*ptr_slot != NULL)
+                               func (ptr_slot, gc_data);
                }
-               if (cur == last)
-                       break;
-               cur = cur->next;
        }
 }
 
@@ -488,7 +438,6 @@ mono_gchandle_from_handle (MonoObjectHandle handle, mono_bool pinned)
        HandleChunk *chunk = chunk_element_to_chunk_idx (stack, elem, &elem_idx);
        /* gchandles cannot deal with interior pointers */
        g_assert (chunk != NULL);
-       g_assert (chunk_element_kind (chunk, elem_idx) != HANDLE_CHUNK_PTR_INTERIOR);
        return mono_gchandle_new (MONO_HANDLE_RAW (handle), pinned);
 }
 
index fd6d0cfffee7cbd002523a8a2b2ee1bc06604140..dba7c26c90bafeafd4871281307ce910249718a3 100644 (file)
@@ -25,7 +25,6 @@
 
 G_BEGIN_DECLS
 
-
 /*
 Handle stack.
 
@@ -73,13 +72,8 @@ typedef struct {
 #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];
 };
@@ -90,10 +84,13 @@ typedef struct {
 #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
@@ -108,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);
@@ -134,6 +132,7 @@ mono_stack_mark_init (MonoThreadInfo *info, HandleStackMark *stackmark)
        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;
@@ -148,6 +147,7 @@ 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;
@@ -403,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)))
 
index b82e49d8ea51e9ae7701734751d53e6d7fe92e06..cabce432d44f6eda5d7b6c668cbe7d745feefa70 100644 (file)
@@ -12337,9 +12337,9 @@ static MonoObjectHandle
 mono_icall_handle_new (gpointer rawobj)
 {
 #ifdef MONO_HANDLE_TRACK_OWNER
-       return mono_handle_new_full (rawobj, FALSE, "<marshal args>");
+       return mono_handle_new (rawobj, "<marshal args>");
 #else
-       return mono_handle_new_full (rawobj, FALSE);
+       return mono_handle_new (rawobj);
 #endif
 }
 
@@ -12347,8 +12347,8 @@ static MonoObjectHandle
 mono_icall_handle_new_interior (gpointer rawobj)
 {
 #ifdef MONO_HANDLE_TRACK_OWNER
-       return mono_handle_new_full (rawobj, TRUE, "<marshal args>");
+       return mono_handle_new_interior (rawobj, "<marshal args>");
 #else
-       return mono_handle_new_full (rawobj, TRUE);
+       return mono_handle_new_interior (rawobj);
 #endif
 }