Skip to content

Commit

Permalink
Compute the MonoGenericSharingContext from the caller of the rgctx fe…
Browse files Browse the repository at this point in the history
…tch trampoline instead of the context, since the latter contains the types used by the instantiation while we need the types used to compile the gsharedvt method. Fix gsharedvt support in CEE_BOX.
  • Loading branch information
vargaz committed Jan 30, 2013
1 parent 6e3e95a commit 6269547
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 60 deletions.
10 changes: 8 additions & 2 deletions mono/mini/gshared.cs
Expand Up @@ -141,7 +141,7 @@ public class Tests
}

[MethodImplAttribute (MethodImplOptions.NoInlining)]
private static void box<T> (T [] array, object[] arr) {
private static void box<T1, T> (T [] array, object[] arr) {
object x = array [0];
arr [0] = x;
}
Expand All @@ -151,12 +151,18 @@ public class Tests
arr [0] = new Foo () { i = 1, j = 2 };

object[] arr2 = new object [16];
box<Foo> (arr, arr2);
box<int, Foo> (arr, arr2);
if (arr2 [0].GetType () != typeof (Foo))
return 1;
Foo f = (Foo)arr2 [0];
if (f.i != 1 || f.j != 2)
return 2;
string[] arr3 = new string [16];
object[] arr4 = new object [16];
arr3 [0] = "OK";
box<int, string> (arr3, arr4);
if (arr4 [0] != (object)arr3 [0])
return 3;
return 0;
}

Expand Down
52 changes: 46 additions & 6 deletions mono/mini/method-to-ir.c
Expand Up @@ -3410,18 +3410,55 @@ handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
}
}

alloc = handle_alloc (cfg, klass, TRUE, context_used);
if (!alloc)
return NULL;

if (mini_is_gsharedvt_klass (cfg, klass)) {
MonoBasicBlock *is_ref_bb, *end_bb;
MonoInst *res, *is_ref, *src_var, *addr;
int addr_reg, dreg;

dreg = alloc_ireg (cfg);

NEW_BBLOCK (cfg, is_ref_bb);
NEW_BBLOCK (cfg, end_bb);
is_ref = emit_get_rgctx_klass (cfg, context_used, klass,
MONO_RGCTX_INFO_CLASS_IS_REF);
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);

/* Non-ref case */
alloc = handle_alloc (cfg, klass, TRUE, context_used);
if (!alloc)
return NULL;
EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
ins->opcode = OP_STOREV_MEMBASE;

EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
res->type = STACK_OBJ;
res->klass = klass;
MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);

/* Ref case */
MONO_START_BB (cfg, is_ref_bb);
addr_reg = alloc_ireg (cfg);

/* val is a vtype, so has to load the value manually */
src_var = get_vreg_to_inst (cfg, val->dreg);
if (!src_var)
src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);

MONO_START_BB (cfg, end_bb);

return res;
} else {
alloc = handle_alloc (cfg, klass, TRUE, context_used);
if (!alloc)
return NULL;

EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
return alloc;
}

return alloc;
}


Expand Down Expand Up @@ -7147,6 +7184,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
ins->klass = constrained_call;
sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call));
bblock = cfg->cbb;
CHECK_CFG_EXCEPTION;
} else if (!constrained_call->valuetype) {
int dreg = alloc_ireg_ref (cfg);
Expand Down Expand Up @@ -7181,6 +7219,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
ins->klass = constrained_call;
sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call));
bblock = cfg->cbb;
CHECK_CFG_EXCEPTION;
}
}
Expand Down Expand Up @@ -9043,6 +9082,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
}

*sp++ = handle_box (cfg, val, klass, context_used);
bblock = cfg->cbb;

CHECK_CFG_EXCEPTION;
ip += 5;
Expand Down
29 changes: 1 addition & 28 deletions mono/mini/mini-codegen.c
Expand Up @@ -411,33 +411,6 @@ typedef struct {

#ifndef DISABLE_LOGGING

static const char*
info_type_to_str (MonoRgctxInfoType type)
{
switch (type) {
case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
case MONO_RGCTX_INFO_KLASS: return "KLASS";
case MONO_RGCTX_INFO_VTABLE: return "VTABLE";
case MONO_RGCTX_INFO_TYPE: return "TYPE";
case MONO_RGCTX_INFO_REFLECTION_TYPE: return "REFLECTION_TYPE";
case MONO_RGCTX_INFO_METHOD: return "METHOD";
case MONO_RGCTX_INFO_GENERIC_METHOD_CODE: return "GENERIC_METHOD_CODE";
case MONO_RGCTX_INFO_CLASS_FIELD: return "CLASS_FIELD";
case MONO_RGCTX_INFO_METHOD_RGCTX: return "METHOD_RGCTX";
case MONO_RGCTX_INFO_METHOD_CONTEXT: return "METHOD_CONTEXT";
case MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK: return "REMOTING_INVOKE_WITH_CHECK";
case MONO_RGCTX_INFO_METHOD_DELEGATE_CODE: return "METHOD_DELEGATE_CODE";
case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
default:
return "<UNKNOWN RGCTX INFO TYPE>";
}
}

static void
print_ji (MonoJumpInfo *ji)
{
Expand All @@ -447,7 +420,7 @@ print_ji (MonoJumpInfo *ji)

printf ("[RGCTX_FETCH ");
print_ji (entry->data);
printf (" - %s]", info_type_to_str (entry->info_type));
printf (" - %s]", mono_rgctx_info_type_to_str (entry->info_type));
break;
}
case MONO_PATCH_INFO_METHODCONST: {
Expand Down
55 changes: 34 additions & 21 deletions mono/mini/mini-generic-sharing.c
Expand Up @@ -520,7 +520,8 @@ inflate_info (MonoRuntimeGenericContextInfoTemplate *oti, MonoGenericContext *co
case MONO_RGCTX_INFO_REFLECTION_TYPE:
case MONO_RGCTX_INFO_CAST_CACHE:
case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
case MONO_RGCTX_INFO_VALUE_SIZE: {
case MONO_RGCTX_INFO_VALUE_SIZE:
case MONO_RGCTX_INFO_CLASS_IS_REF: {
gpointer result = mono_class_inflate_generic_type_with_mempool (temporary ? NULL : class->image,
data, context, &error);
g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
Expand Down Expand Up @@ -863,6 +864,11 @@ class_type_info (MonoDomain *domain, MonoClass *class, MonoRgctxInfoType info_ty
return GUINT_TO_POINTER (sizeof (gpointer));
else
return GUINT_TO_POINTER (mono_class_value_size (class, NULL));
case MONO_RGCTX_INFO_CLASS_IS_REF:
if (MONO_TYPE_IS_REFERENCE (&class->byval_arg))
return GUINT_TO_POINTER (1);
else
return GUINT_TO_POINTER (0);
default:
g_assert_not_reached ();
}
Expand All @@ -882,7 +888,7 @@ ji_is_gsharedvt (MonoJitInfo *ji)

static gpointer
instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti,
MonoGenericContext *context, MonoClass *class)
MonoGenericContext *context, MonoClass *class, guint8 *caller)
{
gpointer data;
gboolean temporary;
Expand All @@ -909,7 +915,8 @@ instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti
case MONO_RGCTX_INFO_VTABLE:
case MONO_RGCTX_INFO_CAST_CACHE:
case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
case MONO_RGCTX_INFO_VALUE_SIZE: {
case MONO_RGCTX_INFO_VALUE_SIZE:
case MONO_RGCTX_INFO_CLASS_IS_REF: {
MonoClass *arg_class = mono_class_from_mono_type (data);

free_inflated_info (oti->info_type, data);
Expand Down Expand Up @@ -974,9 +981,10 @@ instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti
MonoMethod *caller_method = oti->data;
MonoMethod *method = data;
gpointer addr;
MonoJitInfo *ji;
MonoJitInfo *caller_ji, *ji;
gboolean virtual = oti->info_type == MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
gint32 vcall_offset;
MonoGenericJitInfo *gji;

g_assert (method->is_inflated);

Expand All @@ -1001,6 +1009,12 @@ instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti
vcall_offset = -1;
}

g_assert (caller);
caller_ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (caller), NULL);
g_assert (caller_ji);
gji = mono_jit_info_get_generic_jit_info (caller_ji);
g_assert (gji);

/*
* For gsharedvt calls made out of gsharedvt methods, the callee could end up being a gsharedvt method, or a normal
* non-shared method. The latter call cannot be patched, so instead of using a normal call, we make an indirect
Expand All @@ -1018,7 +1032,6 @@ instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti
static gpointer tramp_addr;
gpointer info;
MonoMethod *wrapper;
MonoGenericSharingContext gsctx;
MonoMethod *gm;

g_assert (method->is_inflated);
Expand All @@ -1029,9 +1042,7 @@ instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti

gm = caller_method;

mini_init_gsctx (context, &gsctx);

info = mono_arch_get_gsharedvt_call_info (addr, method, gm, &gsctx, FALSE, vcall_offset);
info = mono_arch_get_gsharedvt_call_info (addr, method, gm, gji->generic_sharing_context, FALSE, vcall_offset);

if (!tramp_addr) {
wrapper = mono_marshal_get_gsharedvt_out_wrapper ();
Expand All @@ -1057,20 +1068,17 @@ instantiate_info (MonoDomain *domain, MonoRuntimeGenericContextInfoTemplate *oti
static gpointer tramp_addr;
gpointer info;
MonoMethod *wrapper;
MonoGenericSharingContext gsctx;

//
// FIXME:
// This is a combination of the normal in and out cases, since the caller is a gsharedvt method.
// A trampoline is not always needed, but its hard to determine when it can be omitted.
//

mini_init_gsctx (context, &gsctx);

// FIXME: This is just a workaround
if (caller_method == method) {
} else {
info = mono_arch_get_gsharedvt_call_info (ji->code_start, method, ji->method, &gsctx, TRUE, -1);
info = mono_arch_get_gsharedvt_call_info (ji->code_start, method, ji->method, gji->generic_sharing_context, TRUE, -1);

if (!tramp_addr) {
wrapper = mono_marshal_get_gsharedvt_in_wrapper ();
Expand Down Expand Up @@ -1130,8 +1138,8 @@ fill_in_rgctx_template_slot (MonoClass *class, int type_argc, int index, gpointe
}
}

G_GNUC_UNUSED static const char*
info_type_to_str (MonoRgctxInfoType type)
const char*
mono_rgctx_info_type_to_str (MonoRgctxInfoType type)
{
switch (type) {
case MONO_RGCTX_INFO_STATIC_DATA: return "STATIC_DATA";
Expand All @@ -1149,9 +1157,12 @@ info_type_to_str (MonoRgctxInfoType type)
case MONO_RGCTX_INFO_CAST_CACHE: return "CAST_CACHE";
case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE: return "ARRAY_ELEMENT_SIZE";
case MONO_RGCTX_INFO_VALUE_SIZE: return "VALUE_SIZE";
case MONO_RGCTX_INFO_CLASS_IS_REF: return "CLASS_IS_REF";
case MONO_RGCTX_INFO_FIELD_OFFSET: return "FIELD_OFFSET";
case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE";
case MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT: return "METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT";
default:
return "<>";
return "<UNKNOWN RGCTX INFO TYPE>";
}
}

Expand Down Expand Up @@ -1182,7 +1193,7 @@ register_info (MonoClass *class, int type_argc, gpointer data, MonoRgctxInfoType
break;
}

DEBUG (printf ("set slot %s, infos [%d] = %s, %s\n", mono_type_get_full_name (class), i, info_type_to_str (info_type), rgctx_info_to_str (info_type, data)));
DEBUG (printf ("set slot %s, infos [%d] = %s, %s\n", mono_type_get_full_name (class), i, mono_rgctx_info_type_to_str (info_type), rgctx_info_to_str (info_type, data)));

/* Mark the slot as used in all parent classes (until we find
a parent class which already has it marked used). */
Expand Down Expand Up @@ -1225,6 +1236,7 @@ info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type)
case MONO_RGCTX_INFO_CAST_CACHE:
case MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE:
case MONO_RGCTX_INFO_VALUE_SIZE:
case MONO_RGCTX_INFO_CLASS_IS_REF:
return mono_class_from_mono_type (data1) == mono_class_from_mono_type (data2);
case MONO_RGCTX_INFO_METHOD:
case MONO_RGCTX_INFO_GENERIC_METHOD_CODE:
Expand Down Expand Up @@ -1389,7 +1401,7 @@ alloc_rgctx_array (MonoDomain *domain, int n, gboolean is_mrgctx)
}

static gpointer
fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint32 slot,
fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContext *rgctx, guint8 *caller, guint32 slot,
MonoGenericInst *method_inst)
{
gpointer info;
Expand Down Expand Up @@ -1444,7 +1456,7 @@ fill_runtime_generic_context (MonoVTable *class_vtable, MonoRuntimeGenericContex
oti = class_get_rgctx_template_oti (get_shared_class (class),
method_inst ? method_inst->type_argc : 0, slot, TRUE, TRUE, &do_free);
/* This might take the loader lock */
info = instantiate_info (domain, &oti, &context, class);
info = instantiate_info (domain, &oti, &context, class, caller);

/*
if (method_inst)
Expand Down Expand Up @@ -1502,7 +1514,7 @@ mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot)

mono_domain_unlock (domain);

info = fill_runtime_generic_context (class_vtable, rgctx, slot, 0);
info = fill_runtime_generic_context (class_vtable, rgctx, NULL, slot, 0);

DEBUG (printf ("get rgctx slot: %s %d -> %p\n", mono_type_full_name (&class_vtable->klass->byval_arg), slot, info));

Expand All @@ -1512,16 +1524,17 @@ mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot)
/*
* mono_method_fill_runtime_generic_context:
* @mrgctx: an MRGCTX
* @caller: caller method address
* @slot: a slot index to be instantiated
*
* Instantiates a slot in the MRGCTX.
*/
gpointer
mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot)
mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint8* caller, guint32 slot)
{
gpointer info;

info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, slot,
info = fill_runtime_generic_context (mrgctx->class_vtable, (MonoRuntimeGenericContext*)mrgctx, caller, slot,
mrgctx->method_inst);

return info;
Expand Down
2 changes: 1 addition & 1 deletion mono/mini/mini-trampolines.c
Expand Up @@ -947,7 +947,7 @@ mono_rgctx_lazy_fetch_trampoline (mgreg_t *regs, guint8 *code, gpointer data, gu
num_lookups++;

if (mrgctx)
return mono_method_fill_runtime_generic_context (arg, index);
return mono_method_fill_runtime_generic_context (arg, code, index);
else
return mono_class_fill_runtime_generic_context (arg, index);
#else
Expand Down
8 changes: 6 additions & 2 deletions mono/mini/mini.h
Expand Up @@ -1054,7 +1054,8 @@ typedef enum {
/* Either the code for a gsharedvt method, or the address for a gsharedvt-out trampoline for the method */
MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE,
/* Same for virtual calls */
MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT
MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT,
MONO_RGCTX_INFO_CLASS_IS_REF
} MonoRgctxInfoType;

typedef struct _MonoRuntimeGenericContextInfoTemplate {
Expand Down Expand Up @@ -2373,11 +2374,14 @@ gpointer
mono_class_fill_runtime_generic_context (MonoVTable *class_vtable, guint32 slot) MONO_INTERNAL;

gpointer
mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint32 slot) MONO_INTERNAL;
mono_method_fill_runtime_generic_context (MonoMethodRuntimeGenericContext *mrgctx, guint8 *caller, guint32 slot) MONO_INTERNAL;

MonoMethodRuntimeGenericContext*
mono_method_lookup_rgctx (MonoVTable *class_vtable, MonoGenericInst *method_inst) MONO_INTERNAL;

const char*
mono_rgctx_info_type_to_str (MonoRgctxInfoType type) MONO_INTERNAL;

gboolean
mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars) MONO_INTERNAL;

Expand Down

0 comments on commit 6269547

Please sign in to comment.