goto exception_exit; \
} \
} while (0)
-
+#define OUT_OF_MEMORY_FAILURE do { \
+ mono_cfg_set_exception (cfg, MONO_EXCEPTION_OUT_OF_MEMORY); \
+ goto exception_exit; \
+ } while (0)
/* Determine whenever 'ins' represents a load of the 'this' argument */
#define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
static void
emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value, int value_reg)
{
-#ifdef HAVE_SGEN_GC
int card_table_shift_bits;
gpointer card_table_mask;
- guint8 *card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
+ guint8 *card_table;
MonoInst *dummy_use;
-
-#ifdef MONO_ARCH_HAVE_CARD_TABLE_WBARRIER
int nursery_shift_bits;
size_t nursery_size;
+ gboolean has_card_table_wb = FALSE;
+
+ if (!cfg->gen_write_barriers)
+ return;
+
+ card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
- if (!cfg->compile_aot && card_table && nursery_shift_bits > 0) {
+#ifdef MONO_ARCH_HAVE_CARD_TABLE_WBARRIER
+ has_card_table_wb = TRUE;
+#endif
+
+ if (has_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0) {
MonoInst *wbarrier;
MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
else
wbarrier->sreg2 = value_reg;
MONO_ADD_INS (cfg->cbb, wbarrier);
- } else
-#endif
- if (card_table) {
+ } else if (card_table) {
int offset_reg = alloc_preg (cfg);
int card_reg = alloc_preg (cfg);
MonoInst *ins;
dummy_use->sreg1 = value_reg;
MONO_ADD_INS (cfg->cbb, dummy_use);
}
-#endif
}
static gboolean
static int
inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
- guchar *ip, guint real_offset, GList *dont_inline, gboolean inline_allways)
+ guchar *ip, guint real_offset, GList *dont_inline, gboolean inline_always)
{
MonoInst *ins, *rvar = NULL;
MonoMethodHeader *cheader;
g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
#if (MONO_INLINE_CALLED_LIMITED_METHODS)
- if ((! inline_allways) && ! check_inline_called_method_name_limit (cmethod))
+ if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
return 0;
#endif
#if (MONO_INLINE_CALLER_LIMITED_METHODS)
- if ((! inline_allways) && ! check_inline_caller_method_name_limit (cfg->method))
+ if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
return 0;
#endif
cheader = mono_method_get_header (cmethod);
if (cheader == NULL || mono_loader_get_last_error ()) {
+ MonoLoaderError *error = mono_loader_get_last_error ();
+
if (cheader)
mono_metadata_free_mh (cheader);
+ if (inline_always && error)
+ mono_cfg_set_exception (cfg, error->exception_type);
+
mono_loader_clear_error ();
return 0;
}
cfg->ret_var_set = prev_ret_var_set;
cfg->inline_depth --;
- if ((costs >= 0 && costs < 60) || inline_allways) {
+ if ((costs >= 0 && costs < 60) || inline_always) {
if (cfg->verbose_level > 2)
printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
return FALSE;
}
+/*
+ * is_jit_optimizer_disabled:
+ *
+ * Determine whenever M's assembly has a DebuggableAttribute with the
+ * IsJITOptimizerDisabled flag set.
+ */
+static gboolean
+is_jit_optimizer_disabled (MonoMethod *m)
+{
+ MonoAssembly *ass = m->klass->image->assembly;
+ MonoCustomAttrInfo* attrs;
+ static MonoClass *klass;
+ int i;
+ gboolean val = FALSE;
+
+ g_assert (ass);
+ if (ass->jit_optimizer_disabled_inited)
+ return ass->jit_optimizer_disabled;
+
+ klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
+
+ attrs = mono_custom_attrs_from_assembly (ass);
+ if (attrs) {
+ for (i = 0; i < attrs->num_attrs; ++i) {
+ MonoCustomAttrEntry *attr = &attrs->attrs [i];
+ const gchar *p;
+ int len;
+ MonoMethodSignature *sig;
+
+ if (!attr->ctor || attr->ctor->klass != klass)
+ continue;
+ /* Decode the attribute. See reflection.c */
+ len = attr->data_size;
+ p = (const char*)attr->data;
+ g_assert (read16 (p) == 0x0001);
+ p += 2;
+
+ // FIXME: Support named parameters
+ sig = mono_method_signature (attr->ctor);
+ if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
+ continue;
+ /* Two boolean arguments */
+ p ++;
+ val = *p;
+ }
+ }
+
+ ass->jit_optimizer_disabled = val;
+ mono_memory_barrier ();
+ ass->jit_optimizer_disabled_inited = TRUE;
+
+ return val;
+}
+
/*
* mono_method_to_ir:
*
gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
int context_used;
gboolean init_locals, seq_points, skip_dead_blocks;
+ gboolean disable_inline;
+
+ disable_inline = is_jit_optimizer_disabled (method);
/* serialization and xdomain stuff may need access to private fields and methods */
dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
MonoExceptionClause *clause = &header->clauses [i];
GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
try_bb->real_offset = clause->try_offset;
+ try_bb->try_start = TRUE;
+ try_bb->region = ((i + 1) << 8) | clause->flags;
GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
tblock->real_offset = clause->handler_offset;
tblock->flags |= BB_EXCEPTION_HANDLER;
if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
+ if (seq_points) {
+ NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
+ MONO_ADD_INS (tblock, ins);
+ }
MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
MONO_ADD_INS (tblock, ins);
break;
}
+ /*
+ * Implement a workaround for the inherent races involved in locking:
+ * Monitor.Enter ()
+ * try {
+ * } finally {
+ * Monitor.Exit ()
+ * }
+ * If a thread abort happens between the call to Monitor.Enter () and the start of the
+ * try block, the Exit () won't be executed, see:
+ * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
+ * To work around this, we extend such try blocks to include the last x bytes
+ * of the Monitor.Enter () call.
+ */
+ if (cmethod && cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
+ MonoBasicBlock *tbb;
+
+ GET_BBLOCK (cfg, tbb, ip + 5);
+ /*
+ * Only extend try blocks with a finally, to avoid catching exceptions thrown
+ * from Monitor.Enter like ArgumentNullException.
+ */
+ if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
+ /* Mark this bblock as needing to be extended */
+ tbb->extend_try_block = TRUE;
+ }
+ }
+
/* Conversion to a JIT intrinsic */
if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
bblock = cfg->cbb;
/* Inlining */
if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
(!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
- mono_method_check_inlining (cfg, cmethod) &&
+ !disable_inline && mono_method_check_inlining (cfg, cmethod) &&
!g_list_find (dont_inline, cmethod)) {
int costs;
- gboolean allways = FALSE;
+ gboolean always = FALSE;
if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
(cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
/* Prevent inlining of methods that call wrappers */
INLINE_FAILURE;
cmethod = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc, FALSE);
- allways = TRUE;
+ always = TRUE;
}
- if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, allways))) {
+ if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, always))) {
ip += 5;
cfg->real_offset += 5;
bblock = cfg->cbb;
NEW_PCONST (cfg, ins, NULL);
ins->type = STACK_OBJ;
ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
+ if (!ins->inst_p0)
+ OUT_OF_MEMORY_FAILURE;
+
*sp = ins;
MONO_ADD_INS (bblock, ins);
}
}
CHECK_CFG_EXCEPTION;
- } else
-
-
-
- if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
- mono_method_check_inlining (cfg, cmethod) &&
+ } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
+ !disable_inline && mono_method_check_inlining (cfg, cmethod) &&
!mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
!g_list_find (dont_inline, cmethod)) {
int costs;
iargs [0] = sp [0];
costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass),
- iargs, ip, cfg->real_offset, dont_inline, TRUE);
+ iargs, ip, cfg->real_offset, dont_inline, TRUE);
+ CHECK_CFG_EXCEPTION;
g_assert (costs > 0);
ip += 5;
iargs [0] = sp [0];
costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst),
- iargs, ip, cfg->real_offset, dont_inline, TRUE);
+ iargs, ip, cfg->real_offset, dont_inline, TRUE);
+ CHECK_CFG_EXCEPTION;
g_assert (costs > 0);
ip += 5;
costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass),
iargs, ip, cfg->real_offset, dont_inline, TRUE);
-
+ CHECK_CFG_EXCEPTION;
g_assert (costs > 0);
ip += 5;
if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper),
iargs, ip, cfg->real_offset, dont_inline, TRUE);
+ CHECK_CFG_EXCEPTION;
g_assert (costs > 0);
cfg->real_offset += 5;
if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
costs = inline_method (cfg, wrapper, mono_method_signature (wrapper),
iargs, ip, cfg->real_offset, dont_inline, TRUE);
+ CHECK_CFG_EXCEPTION;
bblock = cfg->cbb;
g_assert (costs > 0);
NEW_BBLOCK (cfg, dont_throw);
/*
- * Currently, we allways rethrow the abort exception, despite the
+ * Currently, we always rethrow the abort exception, despite the
* fact that this is not correct. See thread6.cs for an example.
* But propagating the abort exception is more important than
* getting the sematics right.