Merge pull request #4701 from kumpera/jit_improvements
authorRodrigo Kumpera <kumpera@users.noreply.github.com>
Fri, 21 Apr 2017 21:03:35 +0000 (17:03 -0400)
committerGitHub <noreply@github.com>
Fri, 21 Apr 2017 21:03:35 +0000 (17:03 -0400)
[JIT] Last two optimizations to Roslyn.

mono/metadata/boehm-gc.c
mono/metadata/gc-internals.h
mono/metadata/marshal.c
mono/metadata/null-gc.c
mono/metadata/sgen-mono.c
mono/mini/method-to-ir.c
mono/mini/mini-runtime.c
mono/sgen/sgen-cardtable.c
mono/sgen/sgen-gc.c
mono/sgen/sgen-gc.h

index 8adf077e6b1956fca0f4f3accd195b8b72394126..f9ea588a30e2b7636e6ce48cdb5355bf1a21e692 100644 (file)
@@ -1329,11 +1329,16 @@ mono_gc_is_disabled (void)
 }
 
 void
-mono_gc_wbarrier_value_copy_bitmap (gpointer _dest, gpointer _src, int size, unsigned bitmap)
+mono_gc_wbarrier_range_copy (gpointer _dest, gpointer _src, int size)
 {
        g_assert_not_reached ();
 }
 
+void*
+mono_gc_get_range_copy_func (void)
+{
+       return &mono_gc_wbarrier_range_copy;
+}
 
 guint8*
 mono_gc_get_card_table (int *shift_bits, gpointer *card_mask)
index 65488d77923aa78246fbd577e2a9019a4e70b06d..c6cffb2881b69d78cb4c806b361b1300af28bb94 100644 (file)
@@ -193,7 +193,10 @@ MonoMethod* mono_gc_get_specific_write_barrier (gboolean is_concurrent);
 MonoMethod* mono_gc_get_write_barrier (void);
 
 /* Fast valuetype copy */
-void mono_gc_wbarrier_value_copy_bitmap (gpointer dest, gpointer src, int size, unsigned bitmap);
+/* WARNING: [dest, dest + size] must be within the bounds of a single type, otherwise the GC will lose remset entries */
+void mono_gc_wbarrier_range_copy (gpointer dest, gpointer src, int size);
+void* mono_gc_get_range_copy_func (void);
+
 
 /* helper for the managed alloc support */
 MonoString *
index ad1db94d88ec3c2302512a529fce62e0d5a75f80..84737d60b202cf10313bdfa635a9a74de2e66123 100644 (file)
@@ -9660,13 +9660,14 @@ enum {
        STELEMREF_OBJECT, /*no check at all*/
        STELEMREF_SEALED_CLASS, /*check vtable->klass->element_type */
        STELEMREF_CLASS, /*only the klass->parents check*/
+       STELEMREF_CLASS_SMALL_IDEPTH, /* like STELEMREF_CLASS bit without the idepth check */
        STELEMREF_INTERFACE, /*interfaces without variant generic arguments. */
        STELEMREF_COMPLEX, /*arrays, MBR or types with variant generic args - go straight to icalls*/
        STELEMREF_KIND_COUNT
 };
 
 static const char *strelemref_wrapper_name[] = {
-       "object", "sealed_class", "class", "interface", "complex"
+       "object", "sealed_class", "class", "class_small_idepth", "interface", "complex"
 };
 
 static gboolean
@@ -9699,6 +9700,9 @@ get_virtual_stelemref_kind (MonoClass *element_class)
                return STELEMREF_COMPLEX;
        if (mono_class_is_sealed (element_class))
                return STELEMREF_SEALED_CLASS;
+       if (element_class->idepth <= MONO_DEFAULT_SUPERTABLE_SIZE)
+               return STELEMREF_CLASS_SMALL_IDEPTH;
+
        return STELEMREF_CLASS;
 }
 
@@ -10013,6 +10017,76 @@ get_virtual_stelemref_wrapper (int kind)
                mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL);
                break;
        }
+
+       case STELEMREF_CLASS_SMALL_IDEPTH:
+               /*
+               the method:
+               <ldelema (bound check)>
+               if (!value)
+                       goto do_store;
+
+               aklass = array->vtable->klass->element_class;
+               vklass = value->vtable->klass;
+
+               if (vklass->supertypes [aklass->idepth - 1] != aklass)
+                       goto do_exception;
+
+               do_store:
+                       *array_slot_addr = value;
+                       return;
+
+               long:
+                       throw new ArrayTypeMismatchException ();
+               */
+               aklass = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+               vklass = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+               array_slot_addr = mono_mb_add_local (mb, &mono_defaults.object_class->this_arg);
+
+               /* ldelema (implicit bound check) */
+               load_array_element_address (mb);
+               mono_mb_emit_stloc (mb, array_slot_addr);
+
+               /* if (!value) goto do_store */
+               mono_mb_emit_ldarg (mb, 2);
+               b1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
+
+               /* aklass = array->vtable->klass->element_class */
+               load_array_class (mb, aklass);
+
+               /* vklass = value->vtable->klass */
+               load_value_class (mb, vklass);
+
+               /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */
+               mono_mb_emit_ldloc (mb, vklass);
+               mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoClass, supertypes));
+               mono_mb_emit_byte (mb, CEE_LDIND_I);
+
+               mono_mb_emit_ldloc (mb, aklass);
+               mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoClass, idepth));
+               mono_mb_emit_byte (mb, CEE_LDIND_U2);
+               mono_mb_emit_icon (mb, 1);
+               mono_mb_emit_byte (mb, CEE_SUB);
+               mono_mb_emit_icon (mb, sizeof (void*));
+               mono_mb_emit_byte (mb, CEE_MUL);
+               mono_mb_emit_byte (mb, CEE_ADD);
+               mono_mb_emit_byte (mb, CEE_LDIND_I);
+
+               mono_mb_emit_ldloc (mb, aklass);
+               b4 = mono_mb_emit_branch (mb, CEE_BNE_UN);
+
+               /* do_store: */
+               mono_mb_patch_branch (mb, b1);
+               mono_mb_emit_ldloc (mb, array_slot_addr);
+               mono_mb_emit_ldarg (mb, 2);
+               mono_mb_emit_byte (mb, CEE_STIND_REF);
+               mono_mb_emit_byte (mb, CEE_RET);
+
+               /* do_exception: */
+               mono_mb_patch_branch (mb, b4);
+
+               mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL);
+               break;
+
        case STELEMREF_INTERFACE:
                /*Mono *klass;
                MonoVTable *vt;
index 5dff7bf1940f93d32d0950476a80e0a475460fa0..597224a7672a44a2674fab5369b412e75b5e8759 100644 (file)
@@ -426,11 +426,17 @@ mono_gc_is_disabled (void)
 }
 
 void
-mono_gc_wbarrier_value_copy_bitmap (gpointer _dest, gpointer _src, int size, unsigned bitmap)
+mono_gc_wbarrier_range_copy (gpointer _dest, gpointer _src, int size)
 {
        g_assert_not_reached ();
 }
 
+void*
+mono_gc_get_range_copy_func (void)
+{
+       return &mono_gc_wbarrier_range_copy;
+}
+
 guint8*
 mono_gc_get_card_table (int *shift_bits, gpointer *card_mask)
 {
index a67fc067263ca69b8714b0bb056b9c2fe4028e3d..fc379e52a8f47636618fea8f16a5cc35e64192f2 100644 (file)
@@ -181,9 +181,15 @@ mono_gc_wbarrier_set_field (MonoObject *obj, gpointer field_ptr, MonoObject* val
 }
 
 void
-mono_gc_wbarrier_value_copy_bitmap (gpointer _dest, gpointer _src, int size, unsigned bitmap)
+mono_gc_wbarrier_range_copy (gpointer _dest, gpointer _src, int size)
 {
-       sgen_wbarrier_value_copy_bitmap (_dest, _src, size, bitmap);
+       sgen_wbarrier_range_copy (_dest, _src, size);
+}
+
+void*
+mono_gc_get_range_copy_func (void)
+{
+       return sgen_get_remset ()->wbarrier_range_copy;
 }
 
 int
index 21fdfa8ce043e062bd8b4ec79f2ba0571c0fb131..c47792226c4e983bd2eb1332ff5495c43292e7a1 100644 (file)
@@ -3053,24 +3053,11 @@ mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4
        if (align < SIZEOF_VOID_P)
                return FALSE;
 
-       /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
-       if (size > 32 * SIZEOF_VOID_P)
+       if (size > 5 * SIZEOF_VOID_P)
                return FALSE;
 
        create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
 
-       /* We don't unroll more than 5 stores to avoid code bloat. */
-       if (size > 5 * SIZEOF_VOID_P) {
-               /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
-               size += (SIZEOF_VOID_P - 1);
-               size &= ~(SIZEOF_VOID_P - 1);
-
-               EMIT_NEW_ICONST (cfg, iargs [2], size);
-               EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
-               mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
-               return TRUE;
-       }
-
        destreg = iargs [0]->dreg;
        srcreg = iargs [1]->dreg;
        offset = 0;
@@ -3164,6 +3151,8 @@ mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *kla
        else
                n = mono_class_value_size (klass, &align);
 
+       if (!align)
+               align = SIZEOF_VOID_P;
        /* if native is true there should be no references in the struct */
        if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
                /* Avoid barriers when storing to the stack */
@@ -3179,19 +3168,27 @@ mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *kla
                        /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
                        if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
                                return;
-                       } else if (context_used) {
-                               iargs [2] = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
-                       }  else {
-                               iargs [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
-                               if (!cfg->compile_aot)
-                                       mono_class_compute_gc_descriptor (klass);
-                       }
+                       } else if (size_ins || align < SIZEOF_VOID_P) {
+                               if (context_used) {
+                                       iargs [2] = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
+                               }  else {
+                                       iargs [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
+                                       if (!cfg->compile_aot)
+                                               mono_class_compute_gc_descriptor (klass);
+                               }
+                               if (size_ins)
+                                       mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
+                               else
+                                       mono_emit_jit_icall (cfg, mono_value_copy, iargs);
+                       } else {
+                               /* We don't unroll more than 5 stores to avoid code bloat. */
+                               /*This is harmless and simplify mono_gc_get_range_copy_func */
+                               n += (SIZEOF_VOID_P - 1);
+                               n &= ~(SIZEOF_VOID_P - 1);
 
-                       if (size_ins)
-                               mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
-                       else
-                               mono_emit_jit_icall (cfg, mono_value_copy, iargs);
-                       return;
+                               EMIT_NEW_ICONST (cfg, iargs [2], n);
+                               mono_emit_jit_icall (cfg, mono_gc_get_range_copy_func (), iargs);
+                       }
                }
        }
 
index b245e264ce469a57417fe932769a3319ac9e8fa1..9efd7c34929b2b4f6766b183085e4852a9b83289 100644 (file)
@@ -4194,7 +4194,7 @@ register_icalls (void)
        register_icall (mono_gsharedvt_constrained_call, "mono_gsharedvt_constrained_call", "object ptr ptr ptr ptr ptr", FALSE);
        register_icall (mono_gsharedvt_value_copy, "mono_gsharedvt_value_copy", "void ptr ptr ptr", TRUE);
 
-       register_icall (mono_gc_wbarrier_value_copy_bitmap, "mono_gc_wbarrier_value_copy_bitmap", "void ptr ptr int int", FALSE);
+       register_icall_no_wrapper (mono_gc_get_range_copy_func (), "mono_gc_range_copy", "void ptr ptr int");
 
        register_icall (mono_object_castclass_with_cache, "mono_object_castclass_with_cache", "object object ptr ptr", FALSE);
        register_icall (mono_object_isinst_with_cache, "mono_object_isinst_with_cache", "object object ptr ptr", FALSE);
index a1fac4ada5da4a212f1f63b2fb19e7cbbf072216..4fd859ac9fe8e05835b1be0283b4c40b2a3c0d0b 100644 (file)
@@ -132,6 +132,36 @@ sgen_card_table_wbarrier_generic_nostore (gpointer ptr)
        sgen_card_table_mark_address ((mword)ptr);      
 }
 
+static void
+sgen_card_table_wbarrier_range_copy (gpointer _dest, gpointer _src, int size)
+{
+       GCObject **dest = (GCObject **)_dest;
+       GCObject **src = (GCObject **)_src;
+
+       size_t nursery_bits = DEFAULT_NURSERY_BITS;
+       char *start = sgen_nursery_start;
+       G_GNUC_UNUSED char *end = sgen_nursery_end;
+
+       /*
+        * It's cardtable theory time!
+        * Our cardtable scanning code supports marking any card that an object/valuetype belongs to.
+        * This function is supposed to be used to copy a range that fully belongs to a single type.
+        * It must not be used, for example, to copy 2 adjacent VTs in an array.
+       */
+       volatile guint8 *card_address = (volatile guint8 *)sgen_card_table_get_card_address ((mword)dest);
+       while (size) {
+               GCObject *value = *src;
+               *dest = value;
+               if (SGEN_PTR_IN_NURSERY (value, nursery_bits, start, end) || concurrent_collection_in_progress) {
+                       *card_address = 1;
+                       sgen_dummy_use (value);
+               }
+               ++src;
+               ++dest;
+               size -= SIZEOF_VOID_P;
+       }
+}
+
 #ifdef SGEN_HAVE_OVERLAPPING_CARDS
 
 guint8 *sgen_shadow_cardtable;
@@ -576,6 +606,7 @@ sgen_card_table_init (SgenRememberedSet *remset)
 
        remset->find_address = sgen_card_table_find_address;
        remset->find_address_with_cards = sgen_card_table_find_address_with_cards;
+       remset->wbarrier_range_copy = sgen_card_table_wbarrier_range_copy;
 
        need_mod_union = sgen_get_major_collector ()->is_concurrent;
 }
index e30fb2d48090214a16fb1259298b8e4946bdcd13..7f1a8c3d39d912bb35d060f9131d139c41a60d19 100644 (file)
@@ -357,7 +357,7 @@ static volatile mword highest_heap_address = 0;
 MonoCoopMutex sgen_interruption_mutex;
 
 int current_collection_generation = -1;
-static volatile gboolean concurrent_collection_in_progress = FALSE;
+volatile gboolean concurrent_collection_in_progress = FALSE;
 
 /* objects that are ready to be finalized */
 static SgenPointerQueue fin_ready_queue = SGEN_POINTER_QUEUE_INIT (INTERNAL_MEM_FINALIZE_READY);
@@ -2910,21 +2910,9 @@ mono_gc_wbarrier_generic_store_atomic (gpointer ptr, GCObject *value)
 }
 
 void
-sgen_wbarrier_value_copy_bitmap (gpointer _dest, gpointer _src, int size, unsigned bitmap)
+sgen_wbarrier_range_copy (gpointer _dest, gpointer _src, int size)
 {
-       GCObject **dest = (GCObject **)_dest;
-       GCObject **src = (GCObject **)_src;
-
-       while (size) {
-               if (bitmap & 0x1)
-                       mono_gc_wbarrier_generic_store (dest, *src);
-               else
-                       *dest = *src;
-               ++src;
-               ++dest;
-               size -= SIZEOF_VOID_P;
-               bitmap >>= 1;
-       }
+       remset.wbarrier_range_copy (_dest,_src, size);
 }
 
 /*
index 8cf5a46fa500f40683e1d916f7a8ac08807c2349..db2e35a292fb19d7ddf161eac6c4058747fe9993 100644 (file)
@@ -714,6 +714,7 @@ typedef struct _SgenRememberedSet {
        void (*wbarrier_object_copy) (GCObject* obj, GCObject *src);
        void (*wbarrier_generic_nostore) (gpointer ptr);
        void (*record_pointer) (gpointer ptr);
+       void (*wbarrier_range_copy) (gpointer dest, gpointer src, int count);
 
        void (*start_scan_remsets) (void);
 
@@ -734,7 +735,7 @@ void mono_gc_wbarrier_generic_nostore (gpointer ptr);
 void mono_gc_wbarrier_generic_store (gpointer ptr, GCObject* value);
 void mono_gc_wbarrier_generic_store_atomic (gpointer ptr, GCObject *value);
 
-void sgen_wbarrier_value_copy_bitmap (gpointer _dest, gpointer _src, int size, unsigned bitmap);
+void sgen_wbarrier_range_copy (gpointer _dest, gpointer _src, int size);
 
 static inline SgenDescriptor
 sgen_obj_get_descriptor (GCObject *obj)
@@ -1003,6 +1004,7 @@ extern mword total_promoted_size;
 extern mword total_allocated_major;
 extern volatile gboolean sgen_suspend_finalizers;
 extern MonoCoopMutex gc_mutex;
+extern volatile gboolean concurrent_collection_in_progress;
 
 /* Nursery helpers. */