* @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)
MonoMethodBuilder *mb;
MonoMethodSignature *sig;
WrapperInfo *info;
+ char *name;
int i, bounds, ind, realidx;
int branch_pos, *branch_positions;
int cached;
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);
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);
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
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);
* 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) {
}
}
- 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];
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);
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: