*/
#include <config.h>
+
+#ifndef DISABLE_JIT
+
#include <signal.h>
#ifdef HAVE_UNISTD_H
goto exception_exit; \
} \
} while (0)
+#define GSHAREDVT_FAILURE(opcode) do { \
+ if (cfg->gsharedvt) { \
+ cfg->exception_message = g_strdup_printf ("gsharedvt failed for method %s.%s.%s/%d opcode %s %s:%d", method->klass->name_space, method->klass->name, method->name, method->signature->param_count, mono_opcode_name ((opcode)), __FILE__, __LINE__); \
+ if (cfg->verbose_level >= 2) \
+ printf ("%s\n", cfg->exception_message); \
+ mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
+ goto exception_exit; \
+ } \
+ } while (0)
#define OUT_OF_MEMORY_FAILURE do { \
mono_cfg_set_exception (cfg, MONO_EXCEPTION_OUT_OF_MEMORY); \
goto exception_exit; \
int mono_op_to_op_imm_noemul (int opcode);
MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
-void mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native);
-void mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass);
/* helper methods signatures */
static MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
#define FREG 'f'
#define VREG 'v'
#define XREG 'x'
-#if SIZEOF_REGISTER == 8
+#if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOIDP
#define LREG IREG
#else
#define LREG 'l'
case MONO_TYPE_VAR:
case MONO_TYPE_MVAR:
g_assert (cfg->generic_sharing_context);
- return OP_MOVE;
+ if (mini_type_var_is_vt (cfg, type))
+ return OP_VMOVE;
+ else
+ return OP_MOVE;
default:
g_error ("unknown type 0x%02x in type_to_regstore", type->type);
}
helper_sig_monitor_enter_exit_trampoline_llvm = mono_create_icall_signature ("void object");
}
-/*
- * Can't put this at the beginning, since other files reference stuff from this
- * file.
+/*
+ * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e.
+ * foo<T> (int i) { ldarg.0; box T; }
*/
-#ifndef DISABLE_JIT
-
-#define UNVERIFIED do { if (mini_get_debug_options ()->break_on_unverified) G_BREAKPOINT (); else goto unverified; } while (0)
+#define UNVERIFIED do { \
+ if (cfg->gsharedvt) { \
+ if (cfg->verbose_level > 2) \
+ printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
+ mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
+ goto exception_exit; \
+ } \
+ if (mini_get_debug_options ()->break_on_unverified) \
+ G_BREAKPOINT (); \
+ else \
+ goto unverified; \
+} while (0)
#define LOAD_ERROR do { if (mini_get_debug_options ()->break_on_unverified) G_BREAKPOINT (); else goto load_error; } while (0)
case MONO_TYPE_GENERICINST:
type = &type->data.generic_class->container_class->byval_arg;
goto handle_enum;
- case MONO_TYPE_VAR :
- case MONO_TYPE_MVAR :
- /* FIXME: all the arguments must be references for now,
- * later look inside cfg and see if the arg num is
- * really a reference
- */
+ case MONO_TYPE_VAR:
+ case MONO_TYPE_MVAR:
g_assert (cfg->generic_sharing_context);
- inst->type = STACK_OBJ;
+ if (mini_is_gsharedvt_type (cfg, type)) {
+ g_assert (cfg->gsharedvt);
+ inst->type = STACK_VTYPE;
+ } else {
+ inst->type = STACK_OBJ;
+ }
return;
default:
g_error ("unknown type 0x%02x in eval stack type", type->type);
}
case MONO_TYPE_VAR:
case MONO_TYPE_MVAR:
- /* FIXME: all the arguments must be references for now,
- * later look inside cfg and see if the arg num is
- * really a reference
- */
g_assert (cfg->generic_sharing_context);
- if (arg->type != STACK_OBJ)
- return 1;
+ if (mini_type_var_is_vt (cfg, simple_type)) {
+ if (arg->type != STACK_VTYPE)
+ return 1;
+ } else {
+ if (arg->type != STACK_OBJ)
+ return 1;
+ }
return 0;
default:
g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
}
#ifdef MONO_ARCH_HAVE_IMT
+/* Either METHOD or IMT_ARG needs to be set */
static void
-emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoInst *imt_arg)
+emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
{
int method_reg;
if (imt_arg) {
MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
} else if (cfg->compile_aot) {
- MONO_EMIT_NEW_AOTCONST (cfg, method_reg, call->method, MONO_PATCH_INFO_METHODCONST);
+ MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
} else {
MonoInst *ins;
MONO_INST_NEW (cfg, ins, OP_PCONST);
- ins->inst_p0 = call->method;
+ ins->inst_p0 = method;
ins->dreg = method_reg;
MONO_ADD_INS (cfg->cbb, ins);
}
if (imt_arg) {
MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
} else if (cfg->compile_aot) {
- MONO_EMIT_NEW_AOTCONST (cfg, method_reg, call->method, MONO_PATCH_INFO_METHODCONST);
+ MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
} else {
MonoInst *ins;
MONO_INST_NEW (cfg, ins, OP_PCONST);
- ins->inst_p0 = call->method;
+ ins->inst_p0 = method;
ins->dreg = method_reg;
MONO_ADD_INS (cfg->cbb, ins);
}
return ji;
}
+static int
+mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
+{
+ if (cfg->generic_sharing_context)
+ return mono_class_check_context_used (klass);
+ else
+ return 0;
+}
+
+static int
+mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
+{
+ if (cfg->generic_sharing_context)
+ return mono_method_check_context_used (method);
+ else
+ return 0;
+}
+
inline static MonoCallInst *
mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig,
MonoInst **args, int calli, int virtual, int tail, int rgctx, int unbox_trampoline)
type_to_eval_stack_type ((cfg), sig->ret, &call->inst);
if (tail) {
- if (MONO_TYPE_ISSTRUCT (sig->ret)) {
+ if (mini_type_is_vtype (cfg, sig->ret)) {
call->vret_var = cfg->vret_addr;
//g_assert_not_reached ();
}
- } else if (MONO_TYPE_ISSTRUCT (sig->ret)) {
+ } else if (mini_type_is_vtype (cfg, sig->ret)) {
MonoInst *temp = mono_compile_create_var (cfg, sig->ret, OP_LOCAL);
MonoInst *loada;
}
inline static MonoInst*
-mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *rgctx_arg)
+mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
{
MonoCallInst *call;
int rgctx_reg = -1;
call->inst.sreg1 = addr->dreg;
+ if (imt_arg)
+ emit_imt_argument (cfg, call, NULL, imt_arg);
+
MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
if (rgctx_arg)
mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig,
MonoInst **args, MonoInst *this, MonoInst *imt_arg, MonoInst *rgctx_arg)
{
- gboolean might_be_remote;
+ gboolean might_be_remote = FALSE;
gboolean virtual = this != NULL;
gboolean enable_for_aot = TRUE;
int context_used;
sig = ctor_sig;
}
- context_used = mono_method_check_context_used (method);
+ context_used = mini_method_check_context_used (cfg, method);
+#ifndef DISABLE_REMOTING
might_be_remote = this && sig->hasthis &&
- (method->klass->marshalbyref || method->klass == mono_defaults.object_class) &&
+ (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this) || context_used);
if (might_be_remote && context_used) {
addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
- return mono_emit_calli (cfg, sig, args, addr, NULL);
+ return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
}
+#endif
need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
call = mono_emit_call_args (cfg, sig, args, FALSE, virtual, FALSE, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
+#ifndef DISABLE_REMOTING
if (might_be_remote)
call->method = mono_marshal_get_remoting_invoke_with_check (method);
else
+#endif
call->method = method;
call->inst.flags |= MONO_INST_HAS_METHOD;
call->inst.inst_left = this;
(!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
(MONO_METHOD_IS_FINAL (method) &&
method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
- !(method->klass->marshalbyref && context_used)) {
+ !(mono_class_is_marshalbyref (method->klass) && context_used)) {
/*
* the method is not virtual, we just need to ensure this is not null
* and then we can call the method directly.
*/
- if (method->klass->marshalbyref || method->klass == mono_defaults.object_class) {
+#ifndef DISABLE_REMOTING
+ if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
/*
* The check above ensures method is not gshared, this is needed since
* gshared methods can't have wrappers.
*/
method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
}
+#endif
if (!method->string_ctor)
MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
#ifdef MONO_ARCH_HAVE_IMT
if (mono_use_imt) {
guint32 imt_slot = mono_method_get_imt_slot (method);
- emit_imt_argument (cfg, call, imt_arg);
+ emit_imt_argument (cfg, call, call->method, imt_arg);
slot_reg = vtable_reg;
call->inst.inst_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
}
#ifdef MONO_ARCH_HAVE_IMT
if (imt_arg) {
g_assert (mono_method_signature (method)->generic_param_count);
- emit_imt_argument (cfg, call, imt_arg);
+ emit_imt_argument (cfg, call, call->method, imt_arg);
}
#endif
}
mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
{
MonoInst *iargs [4];
- int n;
+ int context_used, n;
guint32 align = 0;
MonoMethod *memcpy_method;
+ MonoInst *size_ins = NULL;
g_assert (klass);
/*
* g_assert (klass && klass == src->klass && klass == dest->klass);
*/
+ if (mini_is_gsharedvt_klass (cfg, klass)) {
+ g_assert (!native);
+ context_used = mini_class_check_context_used (cfg, klass);
+ size_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_VALUE_SIZE);
+ }
+
if (native)
n = mono_class_native_size (klass, &align);
else
/* Avoid barriers when storing to the stack */
if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
(dest->opcode == OP_LDADDR))) {
- int context_used = 0;
+ int context_used;
iargs [0] = dest;
iargs [1] = src;
- if (cfg->generic_sharing_context)
- context_used = mono_class_check_context_used (klass);
+ context_used = mini_class_check_context_used (cfg, klass);
/* It's ok to intrinsify under gsharing since shared code types are layout stable. */
- if ((cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
+ 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] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
}
}
- if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
+ if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
/* FIXME: Optimize the case when src/dest is OP_LDADDR */
mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
} else {
iargs [0] = dest;
iargs [1] = src;
- EMIT_NEW_ICONST (cfg, iargs [2], n);
+ if (size_ins)
+ iargs [2] = size_ins;
+ else
+ EMIT_NEW_ICONST (cfg, iargs [2], n);
memcpy_method = get_memcpy_method ();
mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
{
MonoInst *iargs [3];
- int n;
+ int n, context_used;
guint32 align;
MonoMethod *memset_method;
+ MonoInst *size_ins = NULL;
/* FIXME: Optimize this for the case when dest is an LDADDR */
mono_class_init (klass);
- n = mono_class_value_size (klass, &align);
+ if (mini_is_gsharedvt_klass (cfg, klass)) {
+ context_used = mini_class_check_context_used (cfg, klass);
+ size_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_VALUE_SIZE);
+ n = -1;
+ } else {
+ n = mono_class_value_size (klass, &align);
+ }
- if (n <= sizeof (gpointer) * 5) {
+ if (!size_ins && n <= sizeof (gpointer) * 5) {
mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
}
else {
memset_method = get_memset_method ();
iargs [0] = dest;
EMIT_NEW_ICONST (cfg, iargs [1], 0);
- EMIT_NEW_ICONST (cfg, iargs [2], n);
+ if (size_ins)
+ iargs [2] = size_ins;
+ else
+ EMIT_NEW_ICONST (cfg, iargs [2], n);
mono_emit_method_call (cfg, memset_method, iargs, NULL);
}
}
return emit_rgctx_fetch (cfg, rgctx, entry);
}
+static MonoInst*
+emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
+ MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
+{
+ MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_SIGNATURE, sig, rgctx_type);
+ MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
+
+ return emit_rgctx_fetch (cfg, rgctx, entry);
+}
+
+static MonoInst*
+emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
+ MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
+{
+ MonoJumpInfoGSharedVtCall *call_info;
+ MonoJumpInfoRgctxEntry *entry;
+ MonoInst *rgctx;
+
+ call_info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
+ call_info->sig = sig;
+ call_info->method = cmethod;
+
+ entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_GSHAREDVT_CALL, call_info, rgctx_type);
+ rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
+
+ return emit_rgctx_fetch (cfg, rgctx, entry);
+}
+
/*
* emit_get_rgctx_method:
*
{
MonoInst *vtable_arg;
MonoCallInst *call;
- int context_used = 0;
+ int context_used;
- if (cfg->generic_sharing_context)
- context_used = mono_class_check_context_used (klass);
+ context_used = mini_class_check_context_used (cfg, klass);
if (context_used) {
vtable_arg = emit_get_rgctx_klass (cfg, context_used,
mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
{
int vtable_reg = alloc_preg (cfg);
- int context_used = 0;
+ int context_used;
- if (cfg->generic_sharing_context)
- context_used = mono_class_check_context_used (array_class);
+ context_used = mini_class_check_context_used (cfg, array_class);
save_cast_details (cfg, array_class, obj->dreg);
rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
- return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, rgctx);
+ return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
} else {
return mono_emit_method_call (cfg, method, &val, NULL);
}
MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
- return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, rgctx);
+ return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
} else {
return mono_emit_method_call (cfg, method, &val, NULL);
}
}
- 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);
- EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
+ MONO_START_BB (cfg, end_bb);
- return alloc;
+ 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;
+ }
}
}
// FIXME: This doesn't work yet (class libs tests fail?)
-#define is_complex_isinst(klass) (TRUE || (klass->flags & TYPE_ATTRIBUTE_INTERFACE) || klass->rank || mono_class_is_nullable (klass) || klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_SEALED) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
+#define is_complex_isinst(klass) (TRUE || (klass->flags & TYPE_ATTRIBUTE_INTERFACE) || klass->rank || mono_class_is_nullable (klass) || mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_SEALED) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
/*
* Returns NULL and set the cfg exception on error.
2) if the object is a proxy whose type cannot be determined */
MonoInst *ins;
+#ifndef DISABLE_REMOTING
MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
+#else
+ MonoBasicBlock *true_bb, *false_bb, *end_bb;
+#endif
int obj_reg = src->dreg;
int dreg = alloc_ireg (cfg);
int tmp_reg;
+#ifndef DISABLE_REMOTING
int klass_reg = alloc_preg (cfg);
+#endif
NEW_BBLOCK (cfg, true_bb);
NEW_BBLOCK (cfg, false_bb);
- NEW_BBLOCK (cfg, false2_bb);
NEW_BBLOCK (cfg, end_bb);
+#ifndef DISABLE_REMOTING
+ NEW_BBLOCK (cfg, false2_bb);
NEW_BBLOCK (cfg, no_proxy_bb);
+#endif
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+#ifndef DISABLE_REMOTING
NEW_BBLOCK (cfg, interface_fail_bb);
+#endif
tmp_reg = alloc_preg (cfg);
MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
+#ifndef DISABLE_REMOTING
mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
MONO_START_BB (cfg, interface_fail_bb);
MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);
+#else
+ mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
+#endif
} else {
+#ifndef DISABLE_REMOTING
tmp_reg = alloc_preg (cfg);
MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
MONO_START_BB (cfg, no_proxy_bb);
mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
+#else
+ g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
+#endif
}
MONO_START_BB (cfg, false_bb);
MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
+#ifndef DISABLE_REMOTING
MONO_START_BB (cfg, false2_bb);
MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
+#endif
MONO_START_BB (cfg, true_bb);
an InvalidCastException exception is thrown otherwhise*/
MonoInst *ins;
+#ifndef DISABLE_REMOTING
MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
+#else
+ MonoBasicBlock *ok_result_bb;
+#endif
int obj_reg = src->dreg;
int dreg = alloc_ireg (cfg);
int tmp_reg = alloc_preg (cfg);
- int klass_reg = alloc_preg (cfg);
+#ifndef DISABLE_REMOTING
+ int klass_reg = alloc_preg (cfg);
NEW_BBLOCK (cfg, end_bb);
+#endif
+
NEW_BBLOCK (cfg, ok_result_bb);
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
save_cast_details (cfg, klass, obj_reg);
if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+#ifndef DISABLE_REMOTING
NEW_BBLOCK (cfg, interface_fail_bb);
MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
-
+#else
+ MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
+ mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
+ MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
+#endif
} else {
+#ifndef DISABLE_REMOTING
NEW_BBLOCK (cfg, no_proxy_bb);
MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
MONO_START_BB (cfg, no_proxy_bb);
mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
+#else
+ g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
+#endif
}
MONO_START_BB (cfg, ok_result_bb);
MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
+#ifndef DISABLE_REMOTING
MONO_START_BB (cfg, end_bb);
+#endif
/* FIXME: */
MONO_INST_NEW (cfg, ins, OP_ICONST);
return;
MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
+ getaddr->cil_code = cfg->header->code;
getaddr->dreg = cfg->got_var->dreg;
/* Add it to the start of the first bblock */
/*runtime, icall and pinvoke are checked by summary call*/
if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
- (method->klass->marshalbyref) ||
+ (mono_class_is_marshalbyref (method->klass)) ||
header.has_clauses)
return FALSE;
MonoInst *ins;
guint32 size;
int mult_reg, add_reg, array_reg, index_reg, index2_reg;
+ int context_used;
- mono_class_init (klass);
- size = mono_class_array_element_size (klass);
+ if (mini_is_gsharedvt_klass (cfg, klass)) {
+ size = -1;
+ } else {
+ mono_class_init (klass);
+ size = mono_class_array_element_size (klass);
+ }
mult_reg = alloc_preg (cfg);
array_reg = arr->dreg;
add_reg = alloc_ireg_mp (cfg);
- MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
+ if (size == -1) {
+ MonoInst *rgctx_ins;
+
+ /* gsharedvt */
+ g_assert (cfg->generic_sharing_context);
+ context_used = mini_class_check_context_used (cfg, klass);
+ g_assert (context_used);
+ rgctx_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
+ MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
+ } else {
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
+ }
MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, G_STRUCT_OFFSET (MonoArray, vector));
ins->klass = mono_class_get_element_class (klass);
return mono_emit_method_call (cfg, helper, iargs, sp [0]);
} else {
MonoInst *ins;
- if (sp [1]->opcode == OP_ICONST) {
+
+ if (mini_is_gsharedvt_klass (cfg, klass)) {
+ MonoInst *addr;
+
+ // FIXME-VT: OP_ICONST optimization
+ addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
+ EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
+ ins->opcode = OP_STOREV_MEMBASE;
+ } else if (sp [1]->opcode == OP_ICONST) {
int array_reg = sp [0]->dreg;
int index_reg = sp [1]->dreg;
int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + G_STRUCT_OFFSET (MonoArray, vector);
}
#endif /* MONO_ARCH_HAVE_ATOMIC_CAS */
+ if (strcmp (cmethod->name, "MemoryBarrier") == 0)
+ ins = emit_memory_barrier (cfg, FullBarrier);
+
if (ins)
return ins;
} else if (cmethod->klass->image == mono_defaults.corlib) {
}
return 0;
unverified:
+exception_exit:
*pos = ip;
return 1;
}
{
MonoMethod *method;
- if (m->wrapper_type != MONO_WRAPPER_NONE)
- return mono_method_get_wrapper_data (m, token);
-
- method = mono_get_method_full (m->klass->image, token, klass, context);
+ if (m->wrapper_type != MONO_WRAPPER_NONE) {
+ method = mono_method_get_wrapper_data (m, token);
+ if (context)
+ method = mono_class_inflate_generic_method (method, context);
+ } else {
+ method = mono_get_method_full (m->klass->image, token, klass, context);
+ }
return method;
}
{
MonoClass *klass;
- if (method->wrapper_type != MONO_WRAPPER_NONE)
+ if (method->wrapper_type != MONO_WRAPPER_NONE) {
klass = mono_method_get_wrapper_data (method, token);
- else
+ if (context)
+ klass = mono_class_inflate_generic_class (klass, context);
+ } else {
klass = mono_class_get_full (method->klass->image, token, context);
+ }
if (klass)
mono_class_init (klass);
return klass;
}
+static inline MonoMethodSignature*
+mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
+{
+ MonoMethodSignature *fsig;
+
+ if (method->wrapper_type != MONO_WRAPPER_NONE) {
+ MonoError error;
+
+ fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
+ if (context) {
+ fsig = mono_inflate_generic_signature (fsig, context, &error);
+ // FIXME:
+ g_assert (mono_error_ok (&error));
+ }
+ } else {
+ fsig = mono_metadata_parse_signature (method->klass->image, token);
+ }
+ return fsig;
+}
+
/*
* Returns TRUE if the JIT should abort inlining because "callee"
* is influenced by security attributes.
init_locals = header->init_locals;
seq_points = cfg->gen_seq_points && cfg->method == method;
+#ifdef PLATFORM_ANDROID
+ seq_points &= cfg->method->wrapper_type == MONO_WRAPPER_NONE;
+#endif
+
+ if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
+ /* We could hit a seq point before attaching to the JIT (#8338) */
+ seq_points = FALSE;
+ }
if (cfg->gen_seq_points && cfg->method == method) {
minfo = mono_debug_lookup_method (method);
MonoCallInst *call;
INLINE_FAILURE ("jmp");
+ GSHAREDVT_FAILURE (*ip);
CHECK_OPSIZE (5);
if (stack_start != sp)
int calli = *ip == CEE_CALLI;
gboolean pass_imt_from_rgctx = FALSE;
MonoInst *imt_arg = NULL;
+ MonoInst *keep_this_alive = NULL;
gboolean pass_vtable = FALSE;
gboolean pass_mrgctx = FALSE;
MonoInst *vtable_arg = NULL;
gboolean check_this = FALSE;
gboolean supported_tail_call = FALSE;
gboolean need_seq_point = FALSE;
+ guint32 call_opcode = *ip;
+ gboolean emit_widen = TRUE;
+ gboolean push_res = TRUE;
+ gboolean skip_ret = FALSE;
+ gboolean delegate_invoke = FALSE;
CHECK_OPSIZE (5);
token = read32 (ip + 1);
+ ins = NULL;
+
if (calli) {
+ //GSHAREDVT_FAILURE (*ip);
cmethod = NULL;
CHECK_STACK (1);
--sp;
addr = *sp;
- if (method->wrapper_type != MONO_WRAPPER_NONE)
- fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
- else
- fsig = mono_metadata_parse_signature (image, token);
-
+ fsig = mini_get_signature (method, token, generic_context);
n = fsig->param_count + fsig->hasthis;
if (method->dynamic && fsig->pinvoke) {
}
} else {
MonoMethod *cil_method;
-
- if (method->wrapper_type != MONO_WRAPPER_NONE) {
- if (constrained_call && cfg->verbose_level > 2)
- printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_call));
- cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
- cil_method = cmethod;
- if (constrained_call && !((constrained_call->byval_arg.type == MONO_TYPE_VAR ||
- constrained_call->byval_arg.type == MONO_TYPE_MVAR) &&
- cfg->generic_sharing_context)) {
- cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_call, generic_context);
- }
- } else if (constrained_call) {
- if (cfg->verbose_level > 2)
- printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_call));
- if ((constrained_call->byval_arg.type == MONO_TYPE_VAR || constrained_call->byval_arg.type == MONO_TYPE_MVAR) && cfg->generic_sharing_context) {
- /*
- * This is needed since get_method_constrained can't find
- * the method in klass representing a type var.
- * The type var is guaranteed to be a reference type in this
- * case.
- */
- cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
- cil_method = cmethod;
- g_assert (!cmethod->klass->valuetype);
+ cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
+ cil_method = cmethod;
+
+ if (constrained_call) {
+ if (method->wrapper_type != MONO_WRAPPER_NONE) {
+ if (cfg->verbose_level > 2)
+ printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_call));
+ if (!((constrained_call->byval_arg.type == MONO_TYPE_VAR ||
+ constrained_call->byval_arg.type == MONO_TYPE_MVAR) &&
+ cfg->generic_sharing_context)) {
+ cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_call, generic_context);
+ }
} else {
- cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
+ if (cfg->verbose_level > 2)
+ printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_call));
+
+ if ((constrained_call->byval_arg.type == MONO_TYPE_VAR || constrained_call->byval_arg.type == MONO_TYPE_MVAR) && cfg->generic_sharing_context) {
+ /*
+ * This is needed since get_method_constrained can't find
+ * the method in klass representing a type var.
+ * The type var is guaranteed to be a reference type in this
+ * case.
+ */
+ if (!mini_is_gsharedvt_klass (cfg, constrained_call))
+ g_assert (!cmethod->klass->valuetype);
+ } else {
+ cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
+ }
}
- } else {
- cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
- cil_method = cmethod;
}
if (!cmethod || mono_loader_get_last_error ())
*/
const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
- if (!virtual && cmethod->klass->marshalbyref && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
+ if (!virtual && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
virtual = 1;
}
n = fsig->param_count + fsig->hasthis;
+ /* Don't support calls made using type arguments for now */
+ /*
+ if (cfg->gsharedvt) {
+ if (mini_is_gsharedvt_signature (cfg, fsig))
+ GSHAREDVT_FAILURE (*ip);
+ }
+ */
+
if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
if (check_linkdemand (cfg, method, cmethod))
INLINE_FAILURE ("linkdemand");
sp -= n;
if (constrained_call) {
+ if (mini_is_gsharedvt_klass (cfg, constrained_call)) {
+ /*
+ * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
+ */
+ /* Special case Object:ToString () as its easy to implement */
+ if (cmethod->klass == mono_defaults.object_class && !strcmp (cmethod->name, "ToString")) {
+ MonoInst *args [3];
+
+ args [0] = sp [0];
+ EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
+ args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_call), constrained_call, MONO_RGCTX_INFO_KLASS);
+ ins = mono_emit_jit_icall (cfg, mono_object_tostring_gsharedvt, args);
+ goto call_end;
+ } else if (cmethod->klass == mono_defaults.object_class && !strcmp (cmethod->name, "GetHashCode")) {
+ MonoInst *args [3];
+
+ args [0] = sp [0];
+ EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
+ args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_call), constrained_call, MONO_RGCTX_INFO_KLASS);
+ ins = mono_emit_jit_icall (cfg, mono_object_gethashcode_gsharedvt, args);
+ goto call_end;
+ } else if (constrained_call->valuetype && cmethod->klass->valuetype) {
+ /* The 'Own method' case below */
+ } else {
+ GSHAREDVT_FAILURE (*ip);
+ }
+ }
/*
* We have the `constrained.' prefix opcode.
*/
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);
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;
}
}
constrained_call = NULL;
}
- if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp))
+ if (!calli && check_call_signature (cfg, fsig, sp))
UNVERIFIED;
+#ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
+ if (cmethod && (cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
+ delegate_invoke = TRUE;
+#endif
+
if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
bblock = cfg->cbb;
if (!MONO_TYPE_IS_VOID (fsig->ret)) {
type_to_eval_stack_type ((cfg), fsig->ret, ins);
- *sp = ins;
- sp++;
+ emit_widen = FALSE;
}
- CHECK_CFG_EXCEPTION;
-
- ip += 5;
- ins_flag = 0;
- if (need_seq_point)
- emit_seq_point (cfg, method, ip, FALSE);
- break;
+ goto call_end;
}
/*
if (cmethod && ((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
(cmethod->klass->generic_class || cmethod->klass->generic_container)) {
- gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
- MonoGenericContext *context = mini_class_get_context (cmethod->klass);
- gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
+ gboolean sharable = FALSE;
+
+ if (mono_method_is_generic_sharable_impl (cmethod, TRUE)) {
+ sharable = TRUE;
+ } else {
+ gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
+ MonoGenericContext *context = mini_class_get_context (cmethod->klass);
+ gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
+
+ sharable = sharing_enabled && context_sharable;
+ }
/*
* Pass vtable iff target method might
* context is sharable (and it's not a
* generic method).
*/
- if (sharing_enabled && context_sharable &&
- !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
+ if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
pass_vtable = TRUE;
}
if (cmethod && mini_method_get_context (cmethod) &&
mini_method_get_context (cmethod)->method_inst) {
- gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
- MonoGenericContext *context = mini_method_get_context (cmethod);
- gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
-
g_assert (!pass_vtable);
- if (sharing_enabled && context_sharable)
- pass_mrgctx = TRUE;
+ if (mono_method_is_generic_sharable_impl (cmethod, TRUE)) {
+ pass_mrgctx = TRUE;
+ } else {
+ gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
+ MonoGenericContext *context = mini_method_get_context (cmethod);
+ gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
+
+ if (sharing_enabled && context_sharable)
+ pass_mrgctx = TRUE;
+ if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
+ pass_mrgctx = TRUE;
+ }
}
if (cfg->generic_sharing_context && cmethod) {
MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
- context_used = mono_method_check_context_used (cmethod);
+ context_used = mini_method_check_context_used (cfg, cmethod);
if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
/* Generic method interface
/* !marshalbyref is needed to properly handle generic methods + remoting */
if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
MONO_METHOD_IS_FINAL (cmethod)) &&
- !cmethod->klass->marshalbyref) {
+ !mono_class_is_marshalbyref (cmethod->klass)) {
if (virtual)
check_this = TRUE;
virtual = 0;
(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
!(MONO_METHOD_IS_FINAL (cmethod) &&
cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
- mono_method_signature (cmethod)->generic_param_count) {
+ fsig->generic_param_count &&
+ !(cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))) {
MonoInst *this_temp, *this_arg_temp, *store;
MonoInst *iargs [4];
+ gboolean use_imt = FALSE;
- g_assert (mono_method_signature (cmethod)->is_inflated);
+ g_assert (fsig->is_inflated);
/* Prevent inlining of methods that contain indirect calls */
INLINE_FAILURE ("virtual generic call");
+ if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
+ GSHAREDVT_FAILURE (*ip);
+
#if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK && defined(MONO_ARCH_GSHARED_SUPPORTED)
- if (cmethod->wrapper_type == MONO_WRAPPER_NONE && mono_use_imt) {
+ if (cmethod->wrapper_type == MONO_WRAPPER_NONE && mono_use_imt)
+ use_imt = TRUE;
+#endif
+
+ if (use_imt) {
g_assert (!imt_arg);
if (!context_used)
g_assert (cmethod->is_inflated);
imt_arg = emit_get_rgctx_method (cfg, context_used,
cmethod, MONO_RGCTX_INFO_METHOD);
ins = mono_emit_method_call_full (cfg, cmethod, fsig, sp, sp [0], imt_arg, NULL);
- } else
-#endif
- {
+ } else {
this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
MONO_ADD_INS (bblock, store);
EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
- ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL);
+ ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
}
- if (!MONO_TYPE_IS_VOID (fsig->ret))
- *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
-
- CHECK_CFG_EXCEPTION;
-
- ip += 5;
- ins_flag = 0;
- if (need_seq_point)
- emit_seq_point (cfg, method, ip, FALSE);
- break;
+ goto call_end;
}
/*
bblock = cfg->cbb;
if (!MONO_TYPE_IS_VOID (fsig->ret)) {
type_to_eval_stack_type ((cfg), fsig->ret, ins);
- *sp = ins;
- sp++;
+ emit_widen = FALSE;
}
-
- CHECK_CFG_EXCEPTION;
-
- ip += 5;
- ins_flag = 0;
- if (need_seq_point)
- emit_seq_point (cfg, method, ip, FALSE);
- break;
+ goto call_end;
}
/* Inlining */
- if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
+ if (cmethod && (cfg->opt & MONO_OPT_INLINE) &&
(!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
!disable_inline && mono_method_check_inlining (cfg, cmethod) &&
!g_list_find (dont_inline, cmethod)) {
always = TRUE;
}
- if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, always))) {
- ip += 5;
+ costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, always);
+ if (costs) {
cfg->real_offset += 5;
bblock = cfg->cbb;
if (!MONO_TYPE_IS_VOID (fsig->ret)) {
/* *sp is already set by inline_method */
sp++;
+ push_res = FALSE;
}
inline_costs += costs;
- ins_flag = 0;
- if (need_seq_point)
- emit_seq_point (cfg, method, ip, FALSE);
- break;
+
+ goto call_end;
}
}
-
- inline_costs += 10 * num_calls++;
/* Tail recursion elimination */
- if ((cfg->opt & MONO_OPT_TAILC) && *ip == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
+ if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
gboolean has_vtargs = FALSE;
int i;
/* skip the CEE_RET, too */
if (ip_in_bb (cfg, bblock, ip + 5))
- ip += 6;
- else
- ip += 5;
+ skip_ret = TRUE;
+ push_res = FALSE;
+ goto call_end;
+ }
+ }
- ins_flag = 0;
- break;
+ inline_costs += 10 * num_calls++;
+
+ /*
+ * Making generic calls out of gsharedvt methods.
+ */
+ if (cmethod && cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
+ MonoRgctxInfoType info_type;
+
+ if (virtual) {
+ //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
+ //GSHAREDVT_FAILURE (*ip);
+ // disable for possible remoting calls
+ if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
+ GSHAREDVT_FAILURE (*ip);
+ if (fsig->generic_param_count) {
+ /* virtual generic call */
+ g_assert (mono_use_imt);
+ g_assert (!imt_arg);
+ /* Same as the virtual generic case above */
+ imt_arg = emit_get_rgctx_method (cfg, context_used,
+ cmethod, MONO_RGCTX_INFO_METHOD);
+ /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
+ vtable_arg = NULL;
+ }
}
+
+ 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];
+
+ if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
+ info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
+ else
+ info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
+ addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
+
+ ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
+ goto call_end;
+ } else if (calli && cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
+ /*
+ * We pass the address to the gsharedvt trampoline in the rgctx reg
+ */
+ MonoInst *callee = addr;
+
+ if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
+ /* Not tested */
+ GSHAREDVT_FAILURE (*ip);
+
+ addr = emit_get_rgctx_sig (cfg, context_used,
+ fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
+ ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
+ goto call_end;
}
/* Generic sharing */
/* FIXME: only do this for generic methods if
they are not shared! */
- if (context_used && !imt_arg && !array_rank &&
- (!mono_method_is_generic_sharable_impl (cmethod, TRUE) ||
- !mono_class_generic_sharing_enabled (cmethod->klass)) &&
- (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
- !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
+ if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
+ (!mono_method_is_generic_sharable_impl (cmethod, TRUE) ||
+ !mono_class_generic_sharing_enabled (cmethod->klass)) &&
+ (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
+ !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
INLINE_FAILURE ("gshared");
g_assert (cfg->generic_sharing_context && cmethod);
* the method in the rgctx and do an
* indirect call.
*/
+ if (fsig->hasthis)
+ MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
+
addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
+ ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
+ goto call_end;
}
/* Indirect calls */
if (addr) {
- g_assert (!imt_arg);
-
- if (*ip == CEE_CALL)
+ if (call_opcode == CEE_CALL)
g_assert (context_used);
- else if (*ip == CEE_CALLI)
+ else if (call_opcode == CEE_CALLI)
g_assert (!vtable_arg);
else
/* FIXME: what the hell is this??? */
/* Prevent inlining of methods with indirect calls */
INLINE_FAILURE ("indirect call");
- if (vtable_arg) {
- ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, vtable_arg);
- } else {
- if (addr->opcode == OP_AOTCONST && addr->inst_c1 == MONO_PATCH_INFO_ICALL_ADDR) {
- /*
- * Instead of emitting an indirect call, emit a direct call
- * with the contents of the aotconst as the patch info.
- */
- ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR, addr->inst_p0, fsig, sp);
- NULLIFY_INS (addr);
- } else if (addr->opcode == OP_GOT_ENTRY && addr->inst_right->inst_c1 == MONO_PATCH_INFO_ICALL_ADDR) {
- ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR, addr->inst_right->inst_left, fsig, sp);
- NULLIFY_INS (addr);
+ if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
+ int info_type;
+ gpointer info_data;
+
+ /*
+ * Instead of emitting an indirect call, emit a direct call
+ * with the contents of the aotconst as the patch info.
+ */
+ if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
+ info_type = addr->inst_c1;
+ info_data = addr->inst_p0;
} else {
- ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL);
+ info_type = addr->inst_right->inst_c1;
+ info_data = addr->inst_right->inst_left;
+ }
+
+ if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
+ ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
+ NULLIFY_INS (addr);
+ goto call_end;
}
}
- if (!MONO_TYPE_IS_VOID (fsig->ret))
- *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
-
- CHECK_CFG_EXCEPTION;
-
- ip += 5;
- ins_flag = 0;
- if (need_seq_point)
- emit_seq_point (cfg, method, ip, FALSE);
- break;
+ ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
+ goto call_end;
}
/* Array methods */
addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
-
- *sp++ = ins;
} else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
if (!cmethod->klass->element_class->valuetype && !readonly)
mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
readonly = FALSE;
addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
- *sp++ = addr;
+ ins = addr;
} else {
g_assert_not_reached ();
}
- CHECK_CFG_EXCEPTION;
-
- ip += 5;
- ins_flag = 0;
- emit_seq_point (cfg, method, ip, FALSE);
- break;
+ emit_widen = FALSE;
+ goto call_end;
}
ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
- if (ins) {
- if (!MONO_TYPE_IS_VOID (fsig->ret))
- *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
-
- CHECK_CFG_EXCEPTION;
-
- ip += 5;
- ins_flag = 0;
- if (need_seq_point)
- emit_seq_point (cfg, method, ip, FALSE);
- break;
- }
+ if (ins)
+ goto call_end;
/* Tail prefix / tail call optimization */
/* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
/* FIXME: runtime generic context pointer for jumps? */
/* FIXME: handle this for generic sharing eventually */
- supported_tail_call = cmethod &&
- ((((ins_flag & MONO_INST_TAILCALL) && (*ip == CEE_CALL))
+ if (cmethod &&
+ ((((ins_flag & MONO_INST_TAILCALL) && (call_opcode == CEE_CALL))
))//|| ((cfg->opt & MONO_OPT_TAILC) && *ip == CEE_CALL && ip [5] == CEE_RET))
- && !vtable_arg && !cfg->generic_sharing_context && is_supported_tail_call (cfg, method, cmethod, fsig);
-
+ && !vtable_arg && !cfg->generic_sharing_context && is_supported_tail_call (cfg, method, cmethod, fsig))
+ supported_tail_call = TRUE;
if (supported_tail_call) {
MonoCallInst *call;
link_bblock (cfg, bblock, end_bblock);
start_new_bblock = 1;
- CHECK_CFG_EXCEPTION;
-
- ip += 5;
- ins_flag = 0;
-
// FIXME: Eliminate unreachable epilogs
/*
* OP_TAILCALL has no return value, so skip the CEE_RET if it is
* only reachable from this call.
*/
- GET_BBLOCK (cfg, tblock, ip);
+ GET_BBLOCK (cfg, tblock, ip + 5);
if (tblock == bblock || tblock->in_count == 0)
- ip += 1;
- break;
+ skip_ret = TRUE;
+ push_res = FALSE;
+
+ goto call_end;
}
/*
* change the called method to a dummy wrapper, and resolve that wrapper
* to the real method in mono_jit_compile_method ().
*/
- if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED && mono_marshal_method_from_wrapper (cfg->method) == cmethod) {
+ if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED && mono_marshal_method_from_wrapper (cfg->method) == cmethod)
cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
- }
/* Common call */
INLINE_FAILURE ("call");
ins = mono_emit_method_call_full (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL,
imt_arg, vtable_arg);
- if (!MONO_TYPE_IS_VOID (fsig->ret))
- *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
+ call_end:
+
+ /* End of call, INS should contain the result of the call, if any */
+
+ if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
+ g_assert (ins);
+ if (emit_widen)
+ *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
+ else
+ *sp++ = ins;
+ }
+
+ if (keep_this_alive) {
+ MonoInst *dummy_use;
+
+ /* See mono_emit_method_call_full () */
+ EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
+ }
CHECK_CFG_EXCEPTION;
ip += 5;
+ if (skip_ret) {
+ g_assert (*ip == CEE_RET);
+ ip += 1;
+ }
ins_flag = 0;
+ constrained_call = NULL;
if (need_seq_point)
emit_seq_point (cfg, method, ip, FALSE);
break;
ip++;
break;
case CEE_CPOBJ:
+ GSHAREDVT_FAILURE (*ip);
CHECK_OPSIZE (5);
CHECK_STACK (2);
token = read32 (ip + 1);
if (!mono_class_init (cmethod->klass))
TYPE_LOAD_ERROR (cmethod->klass);
- if (cfg->generic_sharing_context)
- context_used = mono_method_check_context_used (cmethod);
+ context_used = mini_method_check_context_used (cfg, cmethod);
if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
if (check_linkdemand (cfg, method, cmethod))
CHECK_TYPELOAD (cmethod->klass);
}
+ /*
+ if (cfg->gsharedvt) {
+ if (mini_is_gsharedvt_variable_signature (sig))
+ GSHAREDVT_FAILURE (*ip);
+ }
+ */
+
if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
mono_method_is_generic_sharable_impl (cmethod, TRUE)) {
if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
else if (fsig->param_count == 3)
alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
+ else if (fsig->param_count == 4)
+ alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
else
alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
} else if (cmethod->string_ctor) {
/* Now call the actual ctor */
/* Avoid virtual calls to ctors if possible */
- if (cmethod->klass->marshalbyref)
+ if (mono_class_is_marshalbyref (cmethod->klass))
callvirt_this_arg = sp [0];
inline_costs += costs - 5;
} else {
INLINE_FAILURE ("inline failure");
+ // FIXME-VT: Clean this up
+ if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
+ GSHAREDVT_FAILURE(*ip);
mono_emit_method_call_full (cfg, cmethod, fsig, sp, callvirt_this_arg, NULL, NULL);
}
+ } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
+ MonoInst *addr;
+
+ addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
+ mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
} else if (context_used &&
(!mono_method_is_generic_sharable_impl (cmethod, TRUE) ||
!mono_class_generic_sharing_enabled (cmethod->klass))) {
cmethod_addr = emit_get_rgctx_method (cfg, context_used,
cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
- mono_emit_calli (cfg, fsig, sp, cmethod_addr, vtable_arg);
+ mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
} else {
INLINE_FAILURE ("ctor call");
ins = mono_emit_method_call_full (cfg, cmethod, fsig, sp,
if (sp [0]->type != STACK_OBJ)
UNVERIFIED;
- if (cfg->generic_sharing_context)
- context_used = mono_class_check_context_used (klass);
+ context_used = mini_class_check_context_used (cfg, klass);
if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
*sp++ = mono_emit_method_call (cfg, mono_castclass, args, NULL);
ip += 5;
inline_costs += 2;
- } else if (!context_used && (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
+ } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
MonoMethod *mono_castclass;
MonoInst *iargs [1];
int costs;
if (sp [0]->type != STACK_OBJ)
UNVERIFIED;
- if (cfg->generic_sharing_context)
- context_used = mono_class_check_context_used (klass);
+ context_used = mini_class_check_context_used (cfg, klass);
if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
*sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
ip += 5;
inline_costs += 2;
- } else if (!context_used && (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
+ } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
MonoMethod *mono_isinst;
MonoInst *iargs [1];
int costs;
mono_save_token_info (cfg, image, token, klass);
- if (cfg->generic_sharing_context)
- context_used = mono_class_check_context_used (klass);
+ context_used = mini_class_check_context_used (cfg, klass);
+
+ if (mini_is_gsharedvt_klass (cfg, klass)) {
+ MonoInst *obj, *addr, *klass_inst, *args[16];
+ int dreg;
+
+ /* Need to check for nullable types at runtime, but those are disabled in mini_is_gsharedvt_sharable_method*/
+ if (mono_class_is_nullable (klass))
+ GSHAREDVT_FAILURE (*ip);
+
+ obj = *sp;
+
+ klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
+
+ /* obj */
+ args [0] = obj;
+
+ /* klass */
+ args [1] = klass_inst;
+
+ /* CASTCLASS */
+ obj = mono_emit_jit_icall (cfg, mono_object_castclass, args);
+
+ /* UNBOX */
+ dreg = alloc_dreg (cfg, STACK_MP);
+ NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, dreg, obj->dreg, sizeof (MonoObject));
+ MONO_ADD_INS (cfg->cbb, addr);
+
+ /* LDOBJ */
+ EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
+ *sp++ = ins;
+
+ ip += 5;
+ inline_costs += 2;
+ break;
+ }
if (generic_class_is_reference_type (cfg, klass)) {
/* CASTCLASS FIXME kill this huge slice of duplicated code*/
*sp++ = mono_emit_method_call (cfg, mono_castclass, args, NULL);
ip += 5;
inline_costs += 2;
- } else if (!context_used && (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
+ } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
MonoMethod *mono_castclass;
MonoInst *iargs [1];
int costs;
mono_save_token_info (cfg, image, token, klass);
- if (cfg->generic_sharing_context)
- context_used = mono_class_check_context_used (klass);
+ context_used = mini_class_check_context_used (cfg, klass);
if (generic_class_is_reference_type (cfg, klass)) {
*sp++ = val;
}
*sp++ = handle_box (cfg, val, klass, context_used);
+ bblock = cfg->cbb;
CHECK_CFG_EXCEPTION;
ip += 5;
mono_save_token_info (cfg, image, token, klass);
- if (cfg->generic_sharing_context)
- context_used = mono_class_check_context_used (klass);
+ context_used = mini_class_check_context_used (cfg, klass);
if (mono_class_is_nullable (klass)) {
MonoInst *val;
is_instance = FALSE;
}
+ context_used = mini_class_check_context_used (cfg, klass);
+
/* INSTANCE CASE */
foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
if (op == CEE_STFLD) {
if (target_type_is_incompatible (cfg, field->type, sp [1]))
UNVERIFIED;
- if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
+#ifndef DISABLE_REMOTING
+ if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type);
MonoInst *iargs [5];
+ GSHAREDVT_FAILURE (op);
+
iargs [0] = sp [0];
EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
} else {
mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
}
- } else {
+ } else
+#endif
+ {
MonoInst *store;
MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
- EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
+ if (mini_is_gsharedvt_klass (cfg, klass)) {
+ MonoInst *offset_ins;
+
+ context_used = mini_class_check_context_used (cfg, klass);
+
+ offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
+ dreg = alloc_ireg_mp (cfg);
+ EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
+ EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
+ // FIXME-VT: wbarriers ?
+ } else {
+ EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
+ }
if (sp [0]->opcode != OP_LDADDR)
store->flags |= MONO_INST_FAULT;
break;
}
- if (is_instance && ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class)) {
+#ifndef DISABLE_REMOTING
+ if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type);
MonoInst *iargs [4];
+ GSHAREDVT_FAILURE (op);
+
iargs [0] = sp [0];
EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
*sp++ = ins;
}
- } else if (is_instance) {
+ } else
+#endif
+ if (is_instance) {
if (sp [0]->type == STACK_VTYPE) {
MonoInst *var;
if (op == CEE_LDFLDA) {
if (is_magic_tls_access (field)) {
+ GSHAREDVT_FAILURE (*ip);
ins = sp [0];
*sp++ = create_magic_tls_access (cfg, field, &cached_tls_addr, ins);
} else {
dreg = alloc_ireg_mp (cfg);
- EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
+ if (mini_is_gsharedvt_klass (cfg, klass)) {
+ MonoInst *offset_ins;
+
+ offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
+ EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
+ } else {
+ EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
+ }
ins->klass = mono_class_from_mono_type (field->type);
ins->type = STACK_MP;
*sp++ = ins;
MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
- EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
+ if (mini_is_gsharedvt_klass (cfg, klass)) {
+ MonoInst *offset_ins;
+
+ offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
+ dreg = alloc_ireg_mp (cfg);
+ EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
+ EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
+ } else {
+ EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
+ }
load->flags |= ins_flag;
if (sp [0]->opcode != OP_LDADDR)
load->flags |= MONO_INST_FAULT;
GENERIC_SHARING_FAILURE (op);
#endif
- if (cfg->generic_sharing_context)
- context_used = mono_class_check_context_used (klass);
+ context_used = mini_class_check_context_used (cfg, klass);
ftype = mono_field_get_type (field);
int idx, static_data_reg, array_reg, dreg;
MonoInst *thread_ins;
+ GSHAREDVT_FAILURE (op);
+
// offset &= 0x7fffffff;
// idx = (offset >> 24) - 1;
// return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
static_data = emit_get_rgctx_klass (cfg, context_used,
klass, MONO_RGCTX_INFO_STATIC_DATA);
- if (field->offset == 0) {
+ if (mini_is_gsharedvt_klass (cfg, klass)) {
+ MonoInst *offset_ins;
+
+ offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
+ dreg = alloc_ireg_mp (cfg);
+ EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
+ } else if (field->offset == 0) {
ins = static_data;
} else {
int addr_reg = mono_alloc_preg (cfg);
if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
}
+
+ GSHAREDVT_FAILURE (op);
+
/* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
is_const = TRUE;
switch (ro_type) {
klass = mini_get_class (method, token, generic_context);
CHECK_TYPELOAD (klass);
- if (cfg->generic_sharing_context)
- context_used = mono_class_check_context_used (klass);
+ context_used = mini_class_check_context_used (cfg, klass);
if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
MONO_INST_NEW (cfg, ins, OP_LCONV_TO_I4);
if (context_used) {
MonoInst *args [3];
MonoClass *array_class = mono_array_class_get (klass, 1);
- /* FIXME: we cannot get a managed
- allocator because we can't get the
- open generic class's vtable. We
- have the same problem in
- handle_alloc(). This
- needs to be solved so that we can
- have managed allocs of shared
- generic classes. */
- /*
- MonoVTable *array_class_vtable = mono_class_vtable (cfg->domain, array_class);
- MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class_vtable, 1);
- */
- MonoMethod *managed_alloc = NULL;
+ MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
- /* FIXME: Decompose later to help abcrem */
+ /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
/* vtable */
args [0] = emit_get_rgctx_klass (cfg, context_used,
cfg->flags |= MONO_CFG_HAS_LDELEMA;
- if (sp [1]->opcode == OP_ICONST) {
+ if (mini_is_gsharedvt_klass (cfg, klass)) {
+ // FIXME-VT: OP_ICONST optimization
+ addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
+ EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
+ ins->opcode = OP_LOADV_MEMBASE;
+ } else if (sp [1]->opcode == OP_ICONST) {
int array_reg = sp [0]->dreg;
int index_reg = sp [1]->dreg;
int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + G_STRUCT_OFFSET (MonoArray, vector);
int klass_reg = alloc_preg (cfg);
int dreg = alloc_preg (cfg);
+ GSHAREDVT_FAILURE (*ip);
+
CHECK_STACK (1);
MONO_INST_NEW (cfg, ins, *ip);
--sp;
CHECK_TYPELOAD (klass);
mono_class_init (klass);
- if (cfg->generic_sharing_context)
- context_used = mono_class_check_context_used (klass);
+ context_used = mini_class_check_context_used (cfg, klass);
// FIXME:
src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
case CEE_MKREFANY: {
MonoInst *loc, *addr;
+ GSHAREDVT_FAILURE (*ip);
+
CHECK_STACK (1);
MONO_INST_NEW (cfg, ins, *ip);
--sp;
CHECK_TYPELOAD (klass);
mono_class_init (klass);
- if (cfg->generic_sharing_context)
- context_used = mono_class_check_context_used (klass);
+ context_used = mini_class_check_context_used (cfg, klass);
loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
if (mono_type_get_type (handle) == MONO_TYPE_CLASS)
context_used = 0;
else
- context_used = mono_class_check_context_used (mono_class_from_mono_type (handle));
+ context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type (handle));
} else if (handle_class == mono_defaults.fieldhandle_class)
- context_used = mono_class_check_context_used (((MonoClassField*)handle)->parent);
+ context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
else if (handle_class == mono_defaults.methodhandle_class)
- context_used = mono_method_check_context_used (handle);
+ context_used = mini_method_check_context_used (cfg, handle);
else
g_assert_not_reached ();
}
MonoInst *addr, *vtvar, *iargs [3];
int method_context_used;
- if (cfg->generic_sharing_context)
- method_context_used = mono_method_check_context_used (method);
- else
- method_context_used = 0;
+ method_context_used = mini_method_check_context_used (cfg, method);
vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
token = read32 (ip + 2);
ptr = mono_method_get_wrapper_data (method, token);
- if (cfg->compile_aot && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && (strstr (method->name, "__icall_wrapper_") == method->name)) {
- MonoJitICallInfo *callinfo;
- const char *icall_name;
-
- icall_name = method->name + strlen ("__icall_wrapper_");
- g_assert (icall_name);
- callinfo = mono_find_jit_icall_by_name (icall_name);
- g_assert (callinfo);
-
- if (ptr == callinfo->func) {
- /* Will be transformed into an AOTCONST later */
- EMIT_NEW_PCONST (cfg, ins, ptr);
- *sp++ = ins;
- ip += 6;
- break;
- }
- }
/* FIXME: Generalize this */
if (cfg->compile_aot && ptr == mono_thread_interruption_request_flag ()) {
EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
cfg->disable_aot = 1;
break;
}
+ case CEE_MONO_JIT_ICALL_ADDR: {
+ MonoJitICallInfo *callinfo;
+ gpointer ptr;
+
+ CHECK_STACK_OVF (1);
+ CHECK_OPSIZE (6);
+ token = read32 (ip + 2);
+
+ ptr = mono_method_get_wrapper_data (method, token);
+ callinfo = mono_find_jit_icall_by_addr (ptr);
+ g_assert (callinfo);
+ EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
+ *sp++ = ins;
+ ip += 6;
+ inline_costs += 10 * num_calls++;
+ break;
+ }
case CEE_MONO_ICALL_ADDR: {
MonoMethod *cmethod;
gpointer ptr;
mono_save_token_info (cfg, image, n, cmethod);
- if (cfg->generic_sharing_context)
- context_used = mono_method_check_context_used (cmethod);
+ context_used = mini_method_check_context_used (cfg, cmethod);
cil_method = cmethod;
if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
MonoInst *target_ins;
MonoMethod *invoke;
- int invoke_context_used = 0;
+ int invoke_context_used;
invoke = mono_get_delegate_invoke (ctor_method->klass);
if (!invoke || !mono_method_signature (invoke))
LOAD_ERROR;
- if (cfg->generic_sharing_context)
- invoke_context_used = mono_method_check_context_used (invoke);
+ invoke_context_used = mini_method_check_context_used (cfg, invoke);
target_ins = sp [-1];
LOAD_ERROR;
mono_class_init (cmethod->klass);
- if (cfg->generic_sharing_context)
- context_used = mono_method_check_context_used (cmethod);
+ context_used = mini_method_check_context_used (cfg, cmethod);
if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
if (check_linkdemand (cfg, method, cmethod))
case CEE_CONSTRAINED_:
CHECK_OPSIZE (6);
token = read32 (ip + 2);
- if (method->wrapper_type != MONO_WRAPPER_NONE)
- constrained_call = (MonoClass *)mono_method_get_wrapper_data (method, token);
- else
- constrained_call = mono_class_get_full (image, token, generic_context);
+ constrained_call = mini_get_class (method, token, generic_context);
CHECK_TYPELOAD (constrained_call);
ip += 6;
break;
guint32 val;
int ialign;
+ GSHAREDVT_FAILURE (*ip);
+
CHECK_STACK_OVF (1);
CHECK_OPSIZE (6);
token = read32 (ip + 2);
case CEE_REFANYTYPE: {
MonoInst *src_var, *src;
+ GSHAREDVT_FAILURE (*ip);
+
CHECK_STACK (1);
--sp;
} else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (ptype))) {
MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (ptype));
+ } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (cfg, ptype)) {
+ MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (ptype));
} else {
MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
}
return -1;
}
-#endif /* DISABLE_JIT */
-
int
mono_op_to_op_imm (int opcode)
{
}
}
-#ifndef DISABLE_JIT
-
/**
* mono_handle_global_vregs:
*
ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
+#if SIZEOF_REGISTER != 8
if (regtype == 'l') {
NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
mono_bblock_insert_after_ins (bb, ins, store_ins);
mono_bblock_insert_after_ins (bb, ins, store_ins);
def_ins = store_ins;
}
- else {
+ else
+#endif
+ {
g_assert (store_opcode != OP_STOREV_MEMBASE);
/* Try to fuse the store into the instruction itself */
sregs [srcindex] = sreg;
//mono_inst_set_src_registers (ins, sregs);
+#if SIZEOF_REGISTER != 8
if (regtype == 'l') {
NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
mono_bblock_insert_before_ins (bb, ins, load_ins);
mono_bblock_insert_before_ins (bb, ins, load_ins);
use_ins = load_ins;
}
- else {
+ else
+#endif
+ {
#if SIZEOF_REGISTER == 4
g_assert (load_opcode != OP_LOADI8_MEMBASE);
#endif