[gsharedvt] Implement support for multi-dimensional arrays in gsharedvt methods.
authorZoltan Varga <vargaz@gmail.com>
Tue, 17 Feb 2015 11:57:43 +0000 (06:57 -0500)
committerZoltan Varga <vargaz@gmail.com>
Tue, 17 Feb 2015 11:57:43 +0000 (06:57 -0500)
mono/metadata/marshal.c
mono/mini/gshared.cs
mono/mini/method-to-ir.c
mono/mini/mini-codegen.c

index 0015944addc727142b261358d890d3b970ff6fb3..9307c0040fb4302892a37591034d8a96e6b9a6f1 100644 (file)
@@ -9544,10 +9544,11 @@ static int elem_addr_cache_next = 0;
  * @rank: rank of the array type
  * @elem_size: size in bytes of an element of an array.
  *
- * Returns a MonoMethd that implements the code to get the address
+ * Returns a MonoMethod that implements the code to get the address
  * of an element in a multi-dimenasional array of @rank dimensions.
  * The returned method takes an array as the first argument and then
  * @rank indexes for the @rank dimensions.
+ * If ELEM_SIZE is 0, read the array size from the array object.
  */
 MonoMethod*
 mono_marshal_get_array_address (int rank, int elem_size)
@@ -9556,6 +9557,7 @@ mono_marshal_get_array_address (int rank, int elem_size)
        MonoMethodBuilder *mb;
        MonoMethodSignature *sig;
        WrapperInfo *info;
+       char *name;
        int i, bounds, ind, realidx;
        int branch_pos, *branch_positions;
        int cached;
@@ -9583,7 +9585,9 @@ mono_marshal_get_array_address (int rank, int elem_size)
                sig->params [i + 1] = &mono_defaults.int32_class->byval_arg;
        }
 
-       mb = mono_mb_new (mono_defaults.object_class, "ElementAddr", MONO_WRAPPER_MANAGED_TO_MANAGED);
+       name = g_strdup_printf ("ElementAddr_%d", elem_size);
+       mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_MANAGED_TO_MANAGED);
+       g_free (name);
        
 #ifndef DISABLE_JIT
        bounds = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
@@ -9651,8 +9655,24 @@ mono_marshal_get_array_address (int rank, int elem_size)
        mono_mb_emit_ldarg (mb, 0);
        mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoArray, vector));
        mono_mb_emit_ldloc (mb, ind);
-       mono_mb_emit_icon (mb, elem_size);
-       mono_mb_emit_byte (mb, CEE_MUL);
+       if (elem_size) {
+               mono_mb_emit_icon (mb, elem_size);
+       } else {
+               /* Load arr->vtable->klass->sizes.element_class */
+               mono_mb_emit_ldarg (mb, 0);
+               mono_mb_emit_byte (mb, CEE_CONV_I);
+               mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoObject, vtable));
+               mono_mb_emit_byte (mb, CEE_ADD);
+               mono_mb_emit_byte (mb, CEE_LDIND_I);
+               mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoVTable, klass));
+               mono_mb_emit_byte (mb, CEE_ADD);
+               mono_mb_emit_byte (mb, CEE_LDIND_I);
+               /* sizes is an union, so this reads sizes.element_size */
+               mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoClass, sizes));
+               mono_mb_emit_byte (mb, CEE_ADD);
+               mono_mb_emit_byte (mb, CEE_LDIND_I4);
+       }
+               mono_mb_emit_byte (mb, CEE_MUL);
        mono_mb_emit_byte (mb, CEE_ADD);
        mono_mb_emit_byte (mb, CEE_RET);
 
index 31d1704491890c7f09f017e95117f2e87be7e5ed..ea146bda57d13777695b38460d3fa0c067173748 100644 (file)
@@ -1663,6 +1663,36 @@ public class Tests
                        return 1;
                return 0;
        }
+
+       interface IFoo4<T> {
+               T Get(T[,] arr, T t);
+       }
+
+       class Foo4<T> : IFoo4<T> {
+               public T Get(T[,] arr, T t) {
+                       arr [1, 1] = t;
+                       return arr [1, 1];
+               }
+       }
+
+       struct AStruct {
+               public int a, b;
+       }
+
+       public static int test_0_multi_dim_arrays_2 () {
+               IFoo4<int> foo = new Foo4<int> ();
+               var arr = new int [10, 10];
+               int res = foo.Get (arr, 10);
+               if (res != 10)
+                       return 1;
+
+               IFoo4<AStruct> foo2 = new Foo4<AStruct> ();
+               var arr2 = new AStruct [10, 10];
+               var res2 = foo2.Get (arr2, new AStruct () { a = 1, b = 2 });
+               if (res2.a != 1 || res2.b != 2)
+                       return 2;
+               return 0;
+       }
 }
 
 // #13191
index 56047489f80de54825131ade3e99a250399ce5ea..2fc0f49c9a9bb269b5d931bdb4619ff2bb11536c 100755 (executable)
@@ -5276,20 +5276,24 @@ mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, uns
        MonoInst *addr;
        MonoMethod *addr_method;
        int element_size;
+       MonoClass *eclass = cmethod->klass->element_class;
 
        rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
 
        if (rank == 1)
-               return mini_emit_ldelema_1_ins (cfg, cmethod->klass->element_class, sp [0], sp [1], TRUE);
+               return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
 
 #ifndef MONO_ARCH_EMULATE_MUL_DIV
        /* emit_ldelema_2 depends on OP_LMUL */
-       if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
-               return mini_emit_ldelema_2_ins (cfg, cmethod->klass->element_class, sp [0], sp [1], sp [2]);
+       if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (cfg, eclass)) {
+               return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
        }
 #endif
 
-       element_size = mono_class_array_element_size (cmethod->klass->element_class);
+       if (mini_is_gsharedvt_variable_klass (cfg, eclass))
+               element_size = 0;
+       else
+               element_size = mono_class_array_element_size (eclass);
        addr_method = mono_marshal_get_array_address (rank, element_size);
        addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
 
@@ -9160,7 +9164,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                         * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
                         * patching gshared method addresses into a gsharedvt method.
                         */
-                       if (cmethod && cfg->gsharedvt && (mini_is_gsharedvt_signature (cfg, fsig) || cmethod->is_inflated || cmethod->klass->generic_class)) {
+                       if (cmethod && cfg->gsharedvt && (mini_is_gsharedvt_signature (cfg, fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
+                               !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY)) {
                                MonoRgctxInfoType info_type;
 
                                if (virtual) {
@@ -9186,10 +9191,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        }
                                }
 
-                               if (cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY)
-                                       /* test_0_multi_dim_arrays () in gshared.cs */
-                                       GSHAREDVT_FAILURE (*ip);
-
                                if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
                                        keep_this_alive = sp [0];
 
@@ -9309,6 +9310,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
                                        if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
                                                emit_write_barrier (cfg, addr, val);
+                                       if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cfg, cmethod->klass))
+                                               GSHAREDVT_FAILURE (*ip);
                                } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
                                        addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
 
index 04b2ec30be4410daf07787972101d26be1eb25c5..92a22729dfa44dc0a75e8e150f19e8ce64ab78c5 100644 (file)
@@ -580,6 +580,7 @@ mono_print_ins_index (int i, MonoInst *ins)
        case OP_IOR_IMM:
        case OP_IXOR_IMM:
        case OP_SUB_IMM:
+       case OP_STORE_MEMBASE_IMM:
                printf (" [%d]", (int)ins->inst_imm);
                break;
        case OP_ADD_IMM: