Mon Mar 22 18:06:38 CET 2010 Paolo Molaro <lupus@ximian.com>
authorPaolo Molaro <lupus@oddwiz.org>
Mon, 22 Mar 2010 17:10:20 +0000 (17:10 -0000)
committerPaolo Molaro <lupus@oddwiz.org>
Mon, 22 Mar 2010 17:10:20 +0000 (17:10 -0000)
* class-internals.h, class.c, object.c: introduce compressed
interface bitmaps (for now only under small config): this saves
about 600 KB of runtime memory on gmcs bootstraps or monodevelop
startups.

svn path=/trunk/mono/; revision=154002

mono/metadata/ChangeLog
mono/metadata/class-internals.h
mono/metadata/class.c
mono/metadata/object.c

index eed4add5503c050584f1924a79a8f132ee18eab9..27b53af4f2ab3c93673a9f7184f013c48a0eae16 100644 (file)
@@ -1,4 +1,11 @@
 
+Mon Mar 22 18:06:38 CET 2010 Paolo Molaro <lupus@ximian.com>
+
+       * class-internals.h, class.c, object.c: introduce compressed
+       interface bitmaps (for now only under small config): this saves
+       about 600 KB of runtime memory on gmcs bootstraps or monodevelop
+       startups.
+
 Mon Mar 22 16:03:34 CET 2010 Paolo Molaro <lupus@ximian.com>
 
        * mono-debug.c: don't try to get the method header, it causes a
index 3cc138a74604802d29c936972e3e99e5615728d8..f6a0cc425831a28436d441989f82b9e27ec0ade6 100644 (file)
@@ -366,8 +366,12 @@ struct _MonoClass {
        guint16     interface_offsets_count;
        MonoClass **interfaces_packed;
        guint16    *interface_offsets_packed;
+/* enabled only with small config for now: we might want to do it unconditionally */
+#ifdef MONO_SMALL_CONFIG
+#define COMPRESSED_INTERFACE_BITMAP 1
+#endif
        guint8     *interface_bitmap;
-       
+
        MonoClass **interfaces;
 
        union {
@@ -422,7 +426,16 @@ struct _MonoClass {
        MonoClassExt *ext;
 };
 
-#define MONO_CLASS_IMPLEMENTS_INTERFACE(k,uiid) (((uiid) <= (k)->max_interface_id) && ((k)->interface_bitmap [(uiid) >> 3] & (1 << ((uiid)&7))))
+#ifdef COMPRESSED_INTERFACE_BITMAP
+int mono_compress_bitmap (uint8_t *dest, const uint8_t *bitmap, int size) MONO_INTERNAL;
+int mono_class_interface_match (const uint8_t *bitmap, int id) MONO_INTERNAL;
+#else
+#define mono_class_interface_match(bmap,uiid) ((bmap) [(uiid) >> 3] & (1 << ((uiid)&7)))
+#endif
+
+#define MONO_CLASS_IMPLEMENTS_INTERFACE(k,uiid) (((uiid) <= (k)->max_interface_id) && mono_class_interface_match ((k)->interface_bitmap, (uiid)))
+
+
 int mono_class_interface_offset (MonoClass *klass, MonoClass *itf);
 int mono_class_interface_offset_with_variance (MonoClass *klass, MonoClass *itf, gboolean *non_exact_match) MONO_INTERNAL;
 
@@ -453,7 +466,7 @@ struct MonoVTable {
 
 #define MONO_SIZEOF_VTABLE (sizeof (MonoVTable) - MONO_ZERO_LEN_ARRAY * SIZEOF_VOID_P)
 
-#define MONO_VTABLE_IMPLEMENTS_INTERFACE(vt,uiid) (((uiid) <= (vt)->max_interface_id) && ((vt)->interface_bitmap [(uiid) >> 3] & (1 << ((uiid)&7))))
+#define MONO_VTABLE_IMPLEMENTS_INTERFACE(vt,uiid) (((uiid) <= (vt)->max_interface_id) && mono_class_interface_match ((vt)->interface_bitmap, (uiid)))
 
 /*
  * Generic instantiation data type encoding.
index ae24f3b763e3b6ccb078705c73eaabb771025e95..cf74f3a278ac1f94e163a84ceda796e3070f93da 100644 (file)
@@ -2468,8 +2468,20 @@ print_implemented_interfaces (MonoClass *klass) {
                        printf ("(%d,F)", i);
        printf ("\n");
        printf ("Dump interface flags:");
+#ifdef COMPRESSED_INTERFACE_BITMAP
+       {
+               const uint8_t* p = klass->interface_bitmap;
+               i = klass->max_interface_id;
+               while (i > 0) {
+                       printf (" %d x 00 %02X", p [0], p [1]);
+                       i -= p [0] * 8;
+                       i -= 8;
+               }
+       }
+#else
        for (i = 0; i < ((((klass->max_interface_id + 1) >> 3)) + (((klass->max_interface_id + 1) & 7)? 1 :0)); i++)
                printf (" %02X", klass->interface_bitmap [i]);
+#endif
        printf ("\n");
        while (klass != NULL) {
                printf ("[LEVEL %d] Implemented interfaces by class %s:\n", ancestor_level, klass->name);
@@ -2840,6 +2852,112 @@ set_interface_and_offset (int num_ifaces, MonoClass **interfaces_full, int *inte
        return FALSE;
 }
 
+#ifdef COMPRESSED_INTERFACE_BITMAP
+
+/*
+ * Compressed interface bitmap design.
+ *
+ * Interface bitmaps take a large amount of memory, because their size is
+ * linear with the maximum interface id assigned in the process (each interface
+ * is assigned a unique id as it is loaded). The number of interface classes
+ * is high because of the many implicit interfaces implemented by arrays (we'll
+ * need to lazy-load them in the future).
+ * Most classes implement a very small number of interfaces, so the bitmap is
+ * sparse. This bitmap needs to be checked by interface casts, so access to the
+ * needed bit must be fast and doable with few jit instructions.
+ *
+ * The current compression format is as follows:
+ * *) it is a sequence of one or more two-byte elements
+ * *) the first byte in the element is the count of empty bitmap bytes
+ * at the current bitmap position
+ * *) the second byte in the element is an actual bitmap byte at the current
+ * bitmap position
+ *
+ * As an example, the following compressed bitmap bytes:
+ *     0x07 0x01 0x00 0x7
+ * correspond to the following bitmap:
+ *     0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x07
+ *
+ * Each two-byte element can represent up to 2048 bitmap bits, but as few as a single
+ * bitmap byte for non-sparse sequences. In practice the interface bitmaps created
+ * during a gmcs bootstrap are reduced to less tha 5% of the original size.
+ */
+
+/**
+ * mono_compress_bitmap:
+ * @dest: destination buffer
+ * @bitmap: bitmap buffer
+ * @size: size of @bitmap in bytes
+ *
+ * This is a mono internal function.
+ * The @bitmap data is compressed into a format that is small but
+ * still searchable in few instructions by the JIT and runtime.
+ * The compressed data is stored in the buffer pointed to by the
+ * @dest array. Passing a #NULL value for @dest allows to just compute
+ * the size of the buffer.
+ * This compression algorithm assumes the bits set in the bitmap are
+ * few and far between, like in interface bitmaps.
+ * Returns: the size of the compressed bitmap in bytes.
+ */
+int
+mono_compress_bitmap (uint8_t *dest, const uint8_t *bitmap, int size)
+{
+       int numz = 0;
+       int res = 0;
+       const uint8_t *end = bitmap + size;
+       while (bitmap < end) {
+               if (*bitmap || numz == 255) {
+                       if (dest) {
+                               *dest++ = numz;
+                               *dest++ = *bitmap;
+                       }
+                       res += 2;
+                       numz = 0;
+                       bitmap++;
+                       continue;
+               }
+               bitmap++;
+               numz++;
+       }
+       if (numz) {
+               res += 2;
+               if (dest) {
+                       *dest++ = numz;
+                       *dest++ = 0;
+               }
+       }
+       return res;
+}
+
+/**
+ * mono_class_interface_match:
+ * @bitmap: a compressed bitmap buffer
+ * @id: the index to check in the bitmap
+ *
+ * This is a mono internal function.
+ * Checks if a bit is set in a compressed interface bitmap. @id must
+ * be already checked for being smaller than the maximum id encoded in the
+ * bitmap.
+ *
+ * Returns: a non-zero value if bit @id is set in the bitmap @bitmap,
+ * #FALSE otherwise.
+ */
+int
+mono_class_interface_match (const uint8_t *bitmap, int id)
+{
+       while (TRUE) {
+               id -= bitmap [0] * 8;
+               if (id < 8) {
+                       if (id < 0)
+                               return 0;
+                       return bitmap [1] & (1 << id);
+               }
+               bitmap += 2;
+               id -= 8;
+       }
+}
+#endif
+
 /*
  * LOCKING: this is supposed to be called with the loader lock held.
  * Return -1 on failure and set exception_type
@@ -3018,18 +3136,33 @@ setup_interface_offsets (MonoClass *class, int cur_slot)
        if (class->interfaces_packed) {
                g_assert (class->interface_offsets_count == interface_offsets_count);
        } else {
+               uint8_t *bitmap;
+               int bsize;
                class->interface_offsets_count = interface_offsets_count;
                class->interfaces_packed = mono_image_alloc (class->image, sizeof (MonoClass*) * interface_offsets_count);
                class->interface_offsets_packed = mono_image_alloc (class->image, sizeof (guint16) * interface_offsets_count);
-               class->interface_bitmap = mono_image_alloc0 (class->image, (sizeof (guint8) * ((max_iid + 1) >> 3)) + (((max_iid + 1) & 7)? 1 :0));
+               bsize = (sizeof (guint8) * ((max_iid + 1) >> 3)) + (((max_iid + 1) & 7)? 1 :0);
+#ifdef COMPRESSED_INTERFACE_BITMAP
+               bitmap = g_malloc0 (bsize);
+#else
+               bitmap = mono_image_alloc0 (class->image, bsize);
+#endif
                for (i = 0; i < interface_offsets_count; i++) {
                        int id = interfaces_full [i]->interface_id;
-                       class->interface_bitmap [id >> 3] |= (1 << (id & 7));
+                       bitmap [id >> 3] |= (1 << (id & 7));
                        class->interfaces_packed [i] = interfaces_full [i];
                        class->interface_offsets_packed [i] = interface_offsets_full [i];
                        /*if (num_array_interfaces)
                          g_print ("type %s has %s offset at %d\n", mono_type_get_name_full (&class->byval_arg, 0), mono_type_get_name_full (&interfaces_full [i]->byval_arg, 0), interface_offsets_full [i]);*/
                }
+#ifdef COMPRESSED_INTERFACE_BITMAP
+               i = mono_compress_bitmap (NULL, bitmap, bsize);
+               class->interface_bitmap = mono_image_alloc0 (class->image, i);
+               mono_compress_bitmap (class->interface_bitmap, bitmap, bsize);
+               g_free (bitmap);
+#else
+               class->interface_bitmap = bitmap;
+#endif
        }
 
 end:
index c35b54f2bd17ba090e0a5d91318927dddafe7cb1..bd079f61d4f31b60b3bdfe112d1e06ea89c7ce9d 100644 (file)
@@ -2080,6 +2080,8 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
        GSList *extra_interfaces = NULL;
        MonoClass *class = remote_class->proxy_class;
        gpointer *interface_offsets;
+       uint8_t *bitmap;
+       int bsize, bcsize;
 
        vt = mono_class_vtable (domain, class);
        g_assert (vt); /*FIXME property handle failure*/
@@ -2167,7 +2169,12 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
        }
 
        pvt->max_interface_id = max_interface_id;
-       pvt->interface_bitmap = mono_domain_alloc0 (domain, sizeof (guint8) * (max_interface_id/8 + 1 ));
+       bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
+#ifdef COMPRESSED_INTERFACE_BITMAP
+       bitmap = g_malloc0 (bsize);
+#else
+       bitmap = mono_domain_alloc0 (domain, bsize);
+#endif
 
        if (! ARCH_USE_IMT) {
                /* initialize interface offsets */
@@ -2179,7 +2186,7 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
        }
        for (i = 0; i < class->interface_offsets_count; ++i) {
                int interface_id = class->interfaces_packed [i]->interface_id;
-               pvt->interface_bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
+               bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
        }
 
        if (extra_interfaces) {
@@ -2196,7 +2203,7 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
                        if (! ARCH_USE_IMT) {
                                interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
                        }
-                       pvt->interface_bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
+                       bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
 
                        iter = NULL;
                        j = 0;
@@ -2218,6 +2225,14 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
                }
        }
 
+#ifdef COMPRESSED_INTERFACE_BITMAP
+       bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
+       pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
+       mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
+       g_free (bitmap);
+#else
+       pvt->interface_bitmap = bitmap;
+#endif
        return pvt;
 }