Rework gc descriptor to include size information in more cases.
authorRodrigo Kumpera <kumpera@gmail.com>
Wed, 28 Dec 2011 00:24:43 +0000 (22:24 -0200)
committerRodrigo Kumpera <kumpera@gmail.com>
Wed, 28 Dec 2011 00:54:21 +0000 (22:54 -0200)
* sgen-descriptor.h
* sgen-descriptor.c: Move the vector/array distrinction to
be a bit inside the descriptor.

Align the object size and store it without any shifts. This
causes no issues with remsets since the relevant code has been
reworked.

Try harder to encode the object size for ptrfree objects. When
not possible use a new kind of descriptor, DESC_TYPE_COMPLEX_PTRFREE.

mono/metadata/sgen-descriptor.c
mono/metadata/sgen-descriptor.h
mono/metadata/sgen-gc.c
mono/metadata/sgen-scan-object.h

index 15a06269c56bdac7c76d2ff039293a8a5e9003a6..7bb072975f00e3db689b6888eb01ec798189f471 100644 (file)
@@ -129,6 +129,10 @@ mono_gc_make_descr_for_object (gsize *bitmap, int numbits, size_t obj_size)
        int first_set = -1, num_set = 0, last_set = -1, i;
        mword desc = 0;
        size_t stored_size = obj_size;
+
+       stored_size += SGEN_ALLOC_ALIGN - 1;
+       stored_size &= ~(SGEN_ALLOC_ALIGN - 1);
+
        for (i = 0; i < numbits; ++i) {
                if (bitmap [i / GC_BITS_PER_WORD] & ((gsize)1 << (i % GC_BITS_PER_WORD))) {
                        if (first_set < 0)
@@ -137,28 +141,22 @@ mono_gc_make_descr_for_object (gsize *bitmap, int numbits, size_t obj_size)
                        num_set++;
                }
        }
-       /*
-        * We don't encode the size of types that don't contain
-        * references because they might not be aligned, i.e. the
-        * bottom two bits might be set, which would clash with the
-        * bits we need to encode the descriptor type.  Since we don't
-        * use the encoded size to skip objects, other than for
-        * processing remsets, in which case only the positions of
-        * references are relevant, this is not a problem.
-        */
-       if (first_set < 0)
-               return (void*)DESC_TYPE_RUN_LENGTH;
-       g_assert (!(stored_size & 0x3));
-       if (stored_size <= SGEN_MAX_SMALL_OBJ_SIZE) {
+
+       if (first_set < 0) {
+               DEBUG (6, fprintf (gc_debug_file, "Ptrfree descriptor %p, size: %zd\n", (void*)desc, stored_size));
+               if (stored_size <= MAX_RUNLEN_OBJECT_SIZE)
+                       return (void*)(DESC_TYPE_RUN_LENGTH | stored_size);
+               return (void*)DESC_TYPE_COMPLEX_PTRFREE;
+       }
+
+       g_assert (!(stored_size & 0x7));
+
+       if (stored_size <= MAX_RUNLEN_OBJECT_SIZE) {
                /* check run-length encoding first: one byte offset, one byte number of pointers
                 * on 64 bit archs, we can have 3 runs, just one on 32.
                 * It may be better to use nibbles.
                 */
-               if (first_set < 0) {
-                       desc = DESC_TYPE_RUN_LENGTH | (stored_size << 1);
-                       DEBUG (6, fprintf (gc_debug_file, "Ptrfree descriptor %p, size: %zd\n", (void*)desc, stored_size));
-                       return (void*) desc;
-               } else if (first_set < 256 && num_set < 256 && (first_set + num_set == last_set + 1)) {
+               if (first_set < 256 && num_set < 256 && (first_set + num_set == last_set + 1)) {
                        desc = DESC_TYPE_RUN_LENGTH | (stored_size << 1) | (first_set << 16) | (num_set << 24);
                        DEBUG (6, fprintf (gc_debug_file, "Runlen descriptor %p, size: %zd, first set: %d, num set: %d\n", (void*)desc, stored_size, first_set, num_set));
                        return (void*) desc;
@@ -188,7 +186,7 @@ void*
 mono_gc_make_descr_for_array (int vector, gsize *elem_bitmap, int numbits, size_t elem_size)
 {
        int first_set = -1, num_set = 0, last_set = -1, i;
-       mword desc = vector? DESC_TYPE_VECTOR: DESC_TYPE_ARRAY;
+       mword desc = DESC_TYPE_VECTOR | (vector ? VECTOR_KIND_SZARRAY : VECTOR_KIND_ARRAY);
        for (i = 0; i < numbits; ++i) {
                if (elem_bitmap [i / GC_BITS_PER_WORD] & ((gsize)1 << (i % GC_BITS_PER_WORD))) {
                        if (first_set < 0)
@@ -197,9 +195,13 @@ mono_gc_make_descr_for_array (int vector, gsize *elem_bitmap, int numbits, size_
                        num_set++;
                }
        }
-       /* See comment at the definition of DESC_TYPE_RUN_LENGTH. */
-       if (first_set < 0)
-               return (void*)DESC_TYPE_RUN_LENGTH;
+
+       if (first_set < 0) {
+               if (elem_size <= MAX_ELEMENT_SIZE)
+                       return (void*)(desc | VECTOR_SUBTYPE_PTRFREE | (elem_size << VECTOR_ELSIZE_SHIFT));
+               return (void*)DESC_TYPE_COMPLEX_PTRFREE;
+       }
+
        if (elem_size <= MAX_ELEMENT_SIZE) {
                desc |= elem_size << VECTOR_ELSIZE_SHIFT;
                if (!num_set) {
index 71ad9389cac1e8e69259344f0730e075fe9b25cc..a9d654de29776b99aaca9c07f073b10f717dcecf 100644 (file)
  */
 #define OBJECT_HEADER_WORDS (sizeof(MonoObject)/sizeof(gpointer))
 #define LOW_TYPE_BITS 3
+#define MAX_RUNLEN_OBJECT_SIZE 0xFFFF
 #define SMALL_BITMAP_SHIFT 16
 #define SMALL_BITMAP_SIZE (GC_BITS_PER_WORD - SMALL_BITMAP_SHIFT)
 #define VECTOR_INFO_SHIFT 14
+#define VECTOR_KIND_SHIFT 13
 #define VECTOR_ELSIZE_SHIFT 3
 #define LARGE_BITMAP_SIZE (GC_BITS_PER_WORD - LOW_TYPE_BITS)
 #define MAX_ELEMENT_SIZE 0x3ff
@@ -49,6 +51,9 @@
 #define VECTOR_SUBTYPE_RUN_LEN (DESC_TYPE_V_RUN_LEN << VECTOR_INFO_SHIFT)
 #define VECTOR_SUBTYPE_BITMAP  (DESC_TYPE_V_BITMAP << VECTOR_INFO_SHIFT)
 
+#define VECTOR_KIND_SZARRAY  (DESC_TYPE_V_SZARRAY << VECTOR_KIND_SHIFT)
+#define VECTOR_KIND_ARRAY  (DESC_TYPE_V_ARRAY << VECTOR_KIND_SHIFT)
+
 /* objects are aligned to 8 bytes boundaries
  * A descriptor is a pointer in MonoVTable, so 32 or 64 bits of size.
  * The low 3 bits define the type of the descriptor. The other bits
@@ -79,13 +84,16 @@ enum {
         * copy_object_no_checks(), without having to fetch the
         * object's class.
         */
-       DESC_TYPE_RUN_LENGTH = 1, /* 15 bits aligned byte size | 1-3 (offset, numptr) bytes tuples */
-       DESC_TYPE_SMALL_BITMAP,   /* 15 bits aligned byte size | 16-48 bit bitmap */
+       DESC_TYPE_RUN_LENGTH = 1, /* 16 bits aligned byte size | 1-3 (offset, numptr) bytes tuples */
+       DESC_TYPE_SMALL_BITMAP,   /* 16 bits aligned byte size | 16-48 bit bitmap */
        DESC_TYPE_COMPLEX,      /* index for bitmap into complex_descriptors */
-       DESC_TYPE_VECTOR,       /* 10 bits element size | 1 bit array | 2 bits desc | element desc */
-       DESC_TYPE_ARRAY,        /* 10 bits element size | 1 bit array | 2 bits desc | element desc */
+       DESC_TYPE_VECTOR,       /* 10 bits element size | 1 bit kind | 2 bits desc | element desc */
        DESC_TYPE_LARGE_BITMAP, /* | 29-61 bitmap bits */
        DESC_TYPE_COMPLEX_ARR,  /* index for bitmap into complex_descriptors */
+       DESC_TYPE_COMPLEX_PTRFREE, /*Nothing, used to encode large ptr objects. */
+       /* values for array kind */
+       DESC_TYPE_V_SZARRAY = 0, /*vector with no bounds data */
+       DESC_TYPE_V_ARRAY = 1, /* array with bounds data */
        /* subtypes for arrays and vectors */
        DESC_TYPE_V_PTRFREE = 0,/* there are no refs: keep first so it has a zero value  */
        DESC_TYPE_V_REFS,       /* all the array elements are refs */
@@ -120,16 +128,33 @@ void* mono_sgen_get_complex_descriptor_bitmap (mword desc) MONO_INTERNAL;
 MonoGCRootMarkFunc mono_sgen_get_user_descriptor_func (mword desc) MONO_INTERNAL;
 
 
-#define SGEN_VTABLE_HAS_REFERENCES(vt) (((MonoVTable*)(vt))->gc_descr != (void*)DESC_TYPE_RUN_LENGTH)
-#define SGEN_CLASS_HAS_REFERENCES(c)   ((c)->gc_descr != (void*)DESC_TYPE_RUN_LENGTH)
+static inline gboolean
+mono_sgen_gc_descr_has_references (mword desc)
+{
+       /*Both string and fixed size objects are encoded using a zero run RUN_LEN*/
+       if ((desc & 0xffff0007) == DESC_TYPE_RUN_LENGTH)
+               return FALSE;
+
+       /*The array is ptr-free*/
+       if ((desc & 0xC007) == (DESC_TYPE_VECTOR | VECTOR_SUBTYPE_PTRFREE))
+               return FALSE;
+
+       if ((desc & 0x7) == DESC_TYPE_COMPLEX_PTRFREE)
+               return FALSE;
+
+       return TRUE;
+}
+
+#define SGEN_VTABLE_HAS_REFERENCES(vt) (mono_sgen_gc_descr_has_references ((mword)((MonoVTable*)(vt))->gc_descr))
+#define SGEN_CLASS_HAS_REFERENCES(c)   (mono_sgen_gc_descr_has_references ((mword)(c)->gc_descr))
 
 /* helper macros to scan and traverse objects, macros because we resue them in many functions */
 #define OBJ_RUN_LEN_SIZE(size,desc,obj) do { \
-               (size) = ((desc) & 0xfff8) >> 1;        \
+               (size) = ((desc) & 0xfff8);     \
     } while (0)
 
 #define OBJ_BITMAP_SIZE(size,desc,obj) do { \
-               (size) = ((desc) & 0xfff8 >> 1);        \
+               (size) = ((desc) & 0xfff8);     \
     } while (0)
 
 #ifdef __GNUC__
index a23183fba4453cbb8656aa71dbfd6d1094394ee6..32df70176b66578dab60900c261b9f05dc290e76 100644 (file)
@@ -7493,6 +7493,7 @@ mono_sgen_get_array_fill_vtable (void)
        if (!array_fill_vtable) {
                static MonoClass klass;
                static MonoVTable vtable;
+               gsize bmap;
 
                MonoDomain *domain = mono_get_root_domain ();
                g_assert (domain);
@@ -7504,7 +7505,8 @@ mono_sgen_get_array_fill_vtable (void)
                klass.name = "array_filler_type";
 
                vtable.klass = &klass;
-               vtable.gc_descr = NULL;
+               bmap = 0;
+               vtable.gc_descr = mono_gc_make_descr_for_array (TRUE, &bmap, 0, 1);
                vtable.size_descr = mono_gc_compute_size_descr (&klass);
                vtable.rank = 1;
 
index 50f688158cd4c675d6c37e5f499638c0e50ec135..48490d781e227d7f58179e5b49e8521ad27923ce 100644 (file)
@@ -75,7 +75,6 @@
                SCAN_OBJECT_ACTION;
 #undef SCAN
                break;
-       case DESC_TYPE_ARRAY:
        case DESC_TYPE_VECTOR:
 #define SCAN OBJ_VECTOR_FOREACH_PTR (desc, start)
 #ifndef SCAN_OBJECT_NOSCAN
 #undef SCAN
                break;
 #endif
+       case DESC_TYPE_COMPLEX_PTRFREE:
+               /*Nothing to do*/
+               SCAN_OBJECT_ACTION;
+               break;
        default:
                g_assert_not_reached ();
        }