#include <sys/time.h>
#endif
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
+
#ifdef HAVE_VALGRIND_MEMCHECK_H
#include <valgrind/memcheck.h>
#endif
return OP_FMOVE;
case MONO_TYPE_VALUETYPE:
if (type->data.klass->enumtype) {
- type = type->data.klass->enum_basetype;
+ type = mono_class_enum_basetype (type->data.klass);
goto handle_enum;
}
if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
return;
case MONO_TYPE_VALUETYPE:
if (type->data.klass->enumtype) {
- type = type->data.klass->enum_basetype;
+ type = mono_class_enum_basetype (type->data.klass);
goto handle_enum;
} else {
inst->klass = klass;
return calli? OP_FCALL_REG: virt? OP_FCALLVIRT: OP_FCALL;
case MONO_TYPE_VALUETYPE:
if (type->data.klass->enumtype) {
- type = type->data.klass->enum_basetype;
+ type = mono_class_enum_basetype (type->data.klass);
goto handle_enum;
} else
return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
continue;
case MONO_TYPE_VALUETYPE:
if (simple_type->data.klass->enumtype) {
- simple_type = simple_type->data.klass->enum_basetype;
+ simple_type = mono_class_enum_basetype (simple_type->data.klass);
goto handle_enum;
}
if (args [i]->type != STACK_VTYPE)
if (method->string_ctor) {
/* Create the real signature */
/* FIXME: Cache these */
- MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_full (cfg->mempool, sig);
+ MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
ctor_sig->ret = &mono_defaults.string_class->byval_arg;
sig = ctor_sig;
EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
alloc_ftn = mono_object_new;
- } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib) {
+ } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
/* This happens often in argument checking code, eg. throw new FooException... */
/* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
static gboolean
mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
{
- MonoMethodHeader *header = mono_method_get_header (method);
+ MonoMethodHeader *header;
MonoVTable *vtable;
#ifdef MONO_ARCH_SOFT_FLOAT
MonoMethodSignature *sig = mono_method_signature (method);
return TRUE;
#endif
+ if (method->is_inflated)
+ /* Avoid inflating the header */
+ header = mono_method_get_header (((MonoMethodInflated*)method)->declaring);
+ else
+ header = mono_method_get_header (method);
+
if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
(method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
index2_reg = alloc_preg (cfg);
MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
#else
- index2_reg = index_reg;
+ if (index->type == STACK_I8) {
+ index2_reg = alloc_preg (cfg);
+ MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
+ } else {
+ index2_reg = index_reg;
+ }
#endif
MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
guint32 prev_cil_offset_to_bb_len;
MonoMethod *prev_current_method;
MonoGenericContext *prev_generic_context;
+ gboolean ret_var_set, prev_ret_var_set;
g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
prev_cbb = cfg->cbb;
prev_current_method = cfg->current_method;
prev_generic_context = cfg->generic_context;
+ prev_ret_var_set = cfg->ret_var_set;
costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, dont_inline, sp, real_offset, *ip == CEE_CALLVIRT);
+ ret_var_set = cfg->ret_var_set;
+
cfg->inlined_method = prev_inlined_method;
cfg->real_offset = prev_real_offset;
cfg->cbb_hash = prev_cbb_hash;
cfg->arg_types = prev_arg_types;
cfg->current_method = prev_current_method;
cfg->generic_context = prev_generic_context;
+ cfg->ret_var_set = prev_ret_var_set;
if ((costs >= 0 && costs < 60) || inline_allways) {
if (cfg->verbose_level > 2)
* If the inlined method contains only a throw, then the ret var is not
* set, so set it to a dummy value.
*/
- if (!cfg->ret_var_set) {
+ if (!ret_var_set) {
static double r8_0 = 0.0;
switch (rvar->type) {
restart = TRUE;
break;
}
+ case OP_CKFINITE: {
+ MonoInst *iargs [2];
+ MonoInst *call, *cmp;
+
+ /* Convert to icall+icompare+cond_exc+move */
+
+ /* Create dummy MonoInst's for the arguments */
+ MONO_INST_NEW (cfg, iargs [0], OP_ARG);
+ iargs [0]->dreg = ins->sreg1;
+
+ call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
+
+ MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
+ cmp->sreg1 = call->dreg;
+ cmp->inst_imm = 1;
+ MONO_ADD_INS (cfg->cbb, cmp);
+
+ MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
+
+ /* Do the assignment if the value is finite */
+ MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
+
+ restart = TRUE;
+ break;
+ }
default:
if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
mono_print_ins (ins);
{
MonoInst *ins;
guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
- if ((opcode == OP_MOVE) && ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
+ if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0] &&
+ ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
/* Optimize reg-reg moves away */
/*
* Can't optimize other opcodes, since sp[0] might point to
return NULL;
}
+static gboolean
+is_exception_class (MonoClass *class)
+{
+ while (class) {
+ if (class == mono_defaults.exception_class)
+ return TRUE;
+ class = class->parent;
+ }
+ return FALSE;
+}
+
/*
* mono_method_to_ir:
*
}
}
} else {
- arg_array = alloca (sizeof (MonoInst *) * num_args);
+ arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
cfg->cbb = start_bblock;
cfg->args = arg_array;
mono_save_args (cfg, sig, inline_args);
case CEE_LDC_R4: {
float *f;
/* FIXME: we should really allocate this only late in the compilation process */
- mono_domain_lock (cfg->domain);
f = mono_domain_alloc (cfg->domain, sizeof (float));
- mono_domain_unlock (cfg->domain);
CHECK_OPSIZE (5);
CHECK_STACK_OVF (1);
MONO_INST_NEW (cfg, ins, OP_R4CONST);
case CEE_LDC_R8: {
double *d;
/* FIXME: we should really allocate this only late in the compilation process */
- mono_domain_lock (cfg->domain);
d = mono_domain_alloc (cfg->domain, sizeof (double));
- mono_domain_unlock (cfg->domain);
CHECK_OPSIZE (9);
CHECK_STACK_OVF (1);
MONO_INST_NEW (cfg, ins, OP_R8CONST);
cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
cil_method = cmethod;
} else if (constrained_call) {
- cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
+ 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);
+ } 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;
CHECK_CFG_EXCEPTION;
}
- if (cmethod->string_ctor)
+ if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
g_assert_not_reached ();
}
* Generate smaller code for the common newobj <exception> instruction in
* argument checking code.
*/
- if (bblock->out_of_line && cmethod->klass->image == mono_defaults.corlib && n <= 2 &&
+ if (bblock->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
+ is_exception_class (cmethod->klass) && n <= 2 &&
((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) &&
((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
MonoInst *iargs [3];
mono_emit_rgctx_calli (cfg, fsig, sp, cmethod_addr, vtable_arg);
} else {
INLINE_FAILURE;
- mono_emit_rgctx_method_call_full (cfg, cmethod, fsig, sp,
- callvirt_this_arg, NULL, vtable_arg);
+ ins = mono_emit_rgctx_method_call_full (cfg, cmethod, fsig, sp,
+ callvirt_this_arg, NULL, vtable_arg);
+ if (mono_method_is_generic_sharable_impl (cmethod, TRUE) && ((MonoCallInst*)ins)->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)
+ GENERIC_SHARING_FAILURE (*ip);
}
}
gpointer addr = (char*)vtable->data + field->offset;
int ro_type = field->type->type;
if (ro_type == MONO_TYPE_VALUETYPE && field->type->data.klass->enumtype) {
- ro_type = field->type->data.klass->enum_basetype->type;
+ ro_type = mono_class_enum_basetype (field->type->data.klass)->type;
}
/* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
is_const = TRUE;
dreg = cfg->locals [i]->dreg;
if (t == MONO_TYPE_VALUETYPE && ptype->data.klass->enumtype)
- t = ptype->data.klass->enum_basetype->type;
+ t = mono_class_enum_basetype (ptype->data.klass)->type;
if (ptype->byref) {
MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
} else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
guint32 i, lvregs_len;
gboolean dest_has_lvreg = FALSE;
guint32 stacktypes [128];
+ MonoInst **live_range_start, **live_range_end;
+ MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
*need_local_opts = FALSE;
vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
lvregs_len = 0;
+
+ /*
+ * These arrays contain the first and last instructions accessing a given
+ * variable.
+ * Since we emit bblocks in the same order we process them here, and we
+ * don't split live ranges, these will precisely describe the live range of
+ * the variable, i.e. the instruction range where a valid value can be found
+ * in the variables location.
+ */
+ /* FIXME: Only do this if debugging info is requested */
+ live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
+ live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
+ live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
+ live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
/* Add spill loads/stores */
for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
MonoInst *store_ins;
int store_opcode;
+ MonoInst *def_ins = ins;
+ int dreg = ins->dreg; /* The original vreg */
store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
g_assert (var->opcode == OP_REGOFFSET);
if (ins->opcode == OP_MOVE) {
NULLIFY_INS (ins);
+ def_ins = NULL;
} else {
ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
ins->inst_basereg = var->inst_basereg;
mono_bblock_insert_after_ins (bb, ins, store_ins);
NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
mono_bblock_insert_after_ins (bb, ins, store_ins);
+ def_ins = store_ins;
}
else {
g_assert (store_opcode != OP_STOREV_MEMBASE);
/* Insert it after the instruction */
mono_bblock_insert_after_ins (bb, ins, store_ins);
+ def_ins = store_ins;
+
/*
* We can't assign ins->dreg to var->dreg here, since the
* sregs could use it. So set a flag, and do it after
}
}
}
+
+ if (def_ins && !live_range_start [dreg]) {
+ live_range_start [dreg] = def_ins;
+ live_range_start_bb [dreg] = bb;
+ }
}
/************/
g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
MonoInst *var = get_vreg_to_inst (cfg, sreg);
+ MonoInst *use_ins = ins;
MonoInst *load_ins;
guint32 load_opcode;
ins->sreg1 = var->dreg;
else
ins->sreg2 = var->dreg;
+ live_range_end [var->dreg] = use_ins;
+ live_range_end_bb [var->dreg] = bb;
continue;
}
mono_bblock_insert_before_ins (bb, ins, load_ins);
NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
mono_bblock_insert_before_ins (bb, ins, load_ins);
+ use_ins = load_ins;
}
else {
#if SIZEOF_REGISTER == 4
#endif
NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
mono_bblock_insert_before_ins (bb, ins, load_ins);
+ use_ins = load_ins;
}
}
+
+ if (var->dreg < orig_next_vreg) {
+ live_range_end [var->dreg] = use_ins;
+ live_range_end_bb [var->dreg] = bb;
+ }
}
}
mono_print_ins_index (1, ins);
}
}
+
+#ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
+ /*
+ * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
+ * by storing the current native offset into MonoMethodVar->live_range_start/end.
+ */
+ for (i = 0; i < cfg->num_varinfo; ++i) {
+ int vreg = MONO_VARINFO (cfg, i)->vreg;
+ MonoInst *ins;
+
+ if (live_range_start [vreg]) {
+ MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
+ ins->inst_c0 = i;
+ mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
+ }
+ if (live_range_end [vreg]) {
+ MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
+ ins->inst_c0 = i;
+ mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
+ }
+ }
+#endif
+
+ g_free (live_range_start);
+ g_free (live_range_end);
+ g_free (live_range_start_bb);
+ g_free (live_range_end_bb);
}
/**