#include <mono/utils/memcheck.h>
#include <mono/metadata/assembly.h>
+#include <mono/metadata/attrdefs.h>
#include <mono/metadata/loader.h>
#include <mono/metadata/tabledefs.h>
#include <mono/metadata/class.h>
#define METHOD_ACCESS_FAILURE do { \
char *method_fname = mono_method_full_name (method, TRUE); \
char *cil_method_fname = mono_method_full_name (cil_method, TRUE); \
- cfg->exception_type = MONO_EXCEPTION_METHOD_ACCESS; \
+ mono_cfg_set_exception (cfg, MONO_EXCEPTION_METHOD_ACCESS); \
cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname); \
g_free (method_fname); \
g_free (cil_method_fname); \
#define FIELD_ACCESS_FAILURE do { \
char *method_fname = mono_method_full_name (method, TRUE); \
char *field_fname = mono_field_full_name (field); \
- cfg->exception_type = MONO_EXCEPTION_FIELD_ACCESS; \
+ mono_cfg_set_exception (cfg, MONO_EXCEPTION_FIELD_ACCESS); \
cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname); \
g_free (method_fname); \
g_free (field_fname); \
if (cfg->generic_sharing_context) { \
if (cfg->verbose_level > 2) \
printf ("sharing failed for method %s.%s.%s/%d opcode %s line %d\n", method->klass->name_space, method->klass->name, method->name, method->signature->param_count, mono_opcode_name ((opcode)), __LINE__); \
- cfg->exception_type = MONO_EXCEPTION_GENERIC_SHARING_FAILED; \
+ 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; \
+ } 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))
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 signature */
-extern MonoMethodSignature *helper_sig_class_init_trampoline;
-extern MonoMethodSignature *helper_sig_domain_get;
-extern MonoMethodSignature *helper_sig_generic_class_init_trampoline;
-extern MonoMethodSignature *helper_sig_generic_class_init_trampoline_llvm;
-extern MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
-extern MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline;
-extern MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline_llvm;
+/* helper methods signatures */
+static MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
+static MonoMethodSignature *helper_sig_domain_get = NULL;
+static MonoMethodSignature *helper_sig_generic_class_init_trampoline = NULL;
+static MonoMethodSignature *helper_sig_generic_class_init_trampoline_llvm = NULL;
+static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline = NULL;
+static MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline = NULL;
+static MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline_llvm = NULL;
/*
* Instruction metadata
#define UNVERIFIED do { 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)
+
#define GET_BBLOCK(cfg,tblock,ip) do { \
(tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
if (!(tblock)) { \
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 (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
- if (card_table) {
+ } else if (card_table) {
int offset_reg = alloc_preg (cfg);
int card_reg = alloc_preg (cfg);
MonoInst *ins;
/*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
* IMM's larger than 32bits.
*/
- MONO_INST_NEW (cfg, ins, OP_PCONST);
- ins->inst_p0 = card_table;
- ins->dreg = card_reg;
- MONO_ADD_INS (cfg->cbb, ins);
+ if (cfg->compile_aot) {
+ MONO_EMIT_NEW_AOTCONST (cfg, card_reg, NULL, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR);
+ } else {
+ MONO_INST_NEW (cfg, ins, OP_PCONST);
+ ins->inst_p0 = card_table;
+ ins->dreg = card_reg;
+ MONO_ADD_INS (cfg->cbb, ins);
+ }
MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
- }
-#endif
- else {
+ } else {
MonoMethod *write_barrier = mono_gc_get_write_barrier ();
mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
}
dummy_use->sreg1 = value_reg;
MONO_ADD_INS (cfg->cbb, dummy_use);
}
-#endif
}
static gboolean
#endif
}
+static void
+save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg)
+{
+ if (mini_get_debug_options ()->better_cast_details) {
+ int to_klass_reg = alloc_preg (cfg);
+ int vtable_reg = alloc_preg (cfg);
+ int klass_reg = alloc_preg (cfg);
+ MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
+
+ if (!tls_get) {
+ fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
+ exit (1);
+ }
+
+ MONO_ADD_INS (cfg->cbb, tls_get);
+ MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
+ MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
+
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
+ MONO_EMIT_NEW_PCONST (cfg, to_klass_reg, klass);
+ MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
+ }
+}
+
+static void
+reset_cast_details (MonoCompile *cfg)
+{
+ /* Reset the variables holding the cast details */
+ if (mini_get_debug_options ()->better_cast_details) {
+ MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
+
+ MONO_ADD_INS (cfg->cbb, tls_get);
+ /* It is enough to reset the from field */
+ MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
+ }
+}
+
/*
* On return the caller must check @array_class for load errors
*/
if (cfg->generic_sharing_context)
context_used = mono_class_check_context_used (array_class);
+ save_cast_details (cfg, array_class, obj->dreg);
+
MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
-
+
if (cfg->opt & MONO_OPT_SHARED) {
int class_reg = alloc_preg (cfg);
MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
}
MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
-}
-static void
-save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg)
-{
- if (mini_get_debug_options ()->better_cast_details) {
- int to_klass_reg = alloc_preg (cfg);
- int vtable_reg = alloc_preg (cfg);
- int klass_reg = alloc_preg (cfg);
- MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
-
- if (!tls_get) {
- fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
- exit (1);
- }
-
- MONO_ADD_INS (cfg->cbb, tls_get);
- MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
- MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
-
- MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
- MONO_EMIT_NEW_PCONST (cfg, to_klass_reg, klass);
- MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
- }
-}
-
-static void
-reset_cast_details (MonoCompile *cfg)
-{
- /* Reset the variables holding the cast details */
- if (mini_get_debug_options ()->better_cast_details) {
- MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
-
- MONO_ADD_INS (cfg->cbb, tls_get);
- /* It is enough to reset the from field */
- MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
- }
+ reset_cast_details (cfg);
}
/**
gboolean pass_lw;
if (!vtable) {
- cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
+ mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
cfg->exception_ptr = klass;
return NULL;
}
return alloc;
}
+
+static gboolean
+mini_class_has_reference_variant_generic_argument (MonoClass *klass, int context_used)
+{
+ int i;
+ MonoGenericContainer *container;
+ MonoGenericInst *ginst;
+
+ if (klass->generic_class) {
+ container = klass->generic_class->container_class->generic_container;
+ ginst = klass->generic_class->context.class_inst;
+ } else if (klass->generic_container && context_used) {
+ container = klass->generic_container;
+ ginst = container->context.class_inst;
+ } else {
+ return FALSE;
+ }
+
+ for (i = 0; i < container->type_argc; ++i) {
+ MonoType *type;
+ if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
+ continue;
+ type = ginst->type_argv [i];
+ if (MONO_TYPE_IS_REFERENCE (type))
+ return TRUE;
+
+ if (context_used && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
+ return TRUE;
+ }
+ return FALSE;
+}
+
// 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) || mono_class_has_variant_generic_params (klass) || 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) || klass->marshalbyref || (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.
MonoInst *klass_inst = NULL;
if (context_used) {
- MonoInst *args [2];
+ MonoInst *args [3];
+
+ if(mini_class_has_reference_variant_generic_argument (klass, context_used)) {
+ MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
+ MonoInst *cache_ins;
- klass_inst = emit_get_rgctx_klass (cfg, context_used,
- klass, MONO_RGCTX_INFO_KLASS);
+ cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
+
+ /* obj */
+ args [0] = src;
+
+ /* klass - it's the second element of the cache entry*/
+ EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
+
+ /* cache */
+ args [2] = cache_ins;
+
+ return mono_emit_method_call (cfg, mono_castclass, args, NULL);
+ }
+
+ klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
if (is_complex_isinst (klass)) {
/* Complex case, handle by an icall */
if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
if (!vt) {
- cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
+ mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
cfg->exception_ptr = klass;
return NULL;
}
MonoInst *klass_inst = NULL;
if (context_used) {
+ MonoInst *args [3];
+
+ if(mini_class_has_reference_variant_generic_argument (klass, context_used)) {
+ MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
+ MonoInst *cache_ins;
+
+ cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
+
+ /* obj */
+ args [0] = src;
+
+ /* klass - it's the second element of the cache entry*/
+ EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
+
+ /* cache */
+ args [2] = cache_ins;
+
+ return mono_emit_method_call (cfg, mono_isinst, args, NULL);
+ }
+
klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
if (is_complex_isinst (klass)) {
- MonoInst *args [2];
-
/* Complex case, handle by an icall */
/* obj */
if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
if (!vt) {
- cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
+ mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
cfg->exception_ptr = klass;
return NULL;
}
static G_GNUC_UNUSED MonoInst*
handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used)
{
+ MonoInst *ptr;
+ int dreg;
gpointer *trampoline;
MonoInst *obj, *method_ins, *tramp_ins;
MonoDomain *domain;
/* Set target field */
/* Optimize away setting of NULL target */
- if (!(target->opcode == OP_PCONST && target->inst_p0 == 0))
+ if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
+ if (cfg->gen_write_barriers) {
+ dreg = alloc_preg (cfg);
+ EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, target));
+ emit_write_barrier (cfg, ptr, target, 0);
+ }
+ }
/* Set method field */
method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
-
+ if (cfg->gen_write_barriers) {
+ dreg = alloc_preg (cfg);
+ EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method));
+ emit_write_barrier (cfg, ptr, method_ins, 0);
+ }
/*
* To avoid looking up the compiled code belonging to the target method
* in mono_delegate_trampoline (), we allocate a per-domain memory slot to
}
} else if (cmethod->klass == mono_defaults.monitor_class) {
#if defined(MONO_ARCH_MONITOR_OBJECT_REG)
- /* The trampolines don't work under SGEN */
- gboolean is_moving_gc = mono_gc_is_moving ();
-
- if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 1 && !is_moving_gc) {
+ if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 1) {
MonoCallInst *call;
if (COMPILE_LLVM (cfg)) {
}
return (MonoInst*)call;
- } else if (strcmp (cmethod->name, "Exit") == 0 && !is_moving_gc) {
+ } else if (strcmp (cmethod->name, "Exit") == 0) {
MonoCallInst *call;
if (COMPILE_LLVM (cfg)) {
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;
}
+ /*Must verify before creating locals as it can cause the JIT to assert.*/
+ if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
+ mono_metadata_free_mh (cheader);
+ return 0;
+ }
+
/* allocate space to store the return value */
if (!MONO_TYPE_IS_VOID (fsig->ret)) {
rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
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));
#define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
#define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
#define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
-#define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) {cfg->exception_ptr = klass; goto load_error;}
+#define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) {cfg->exception_ptr = klass; LOAD_ERROR;}
/* offset from br.s -> br like opcodes */
#define BIG_BRANCH_OFFSET 13
mono_emit_method_call (cfg, secman->linkdemandsecurityexception, args, NULL);
} else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
/* don't hide previous results */
- cfg->exception_type = MONO_EXCEPTION_SECURITY_LINKDEMAND;
+ mono_cfg_set_exception (cfg, MONO_EXCEPTION_SECURITY_LINKDEMAND);
cfg->exception_data = result;
return TRUE;
}
method_code = g_strdup ("method body is empty.");
else
method_code = mono_disasm_code_one (NULL, method, ip, NULL);
- cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
+ mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
g_free (method_fname);
g_free (method_code);
static void
set_exception_object (MonoCompile *cfg, MonoException *exception)
{
- cfg->exception_type = MONO_EXCEPTION_OBJECT_SUPPLIED;
- MONO_GC_REGISTER_ROOT (cfg->exception_ptr);
+ mono_cfg_set_exception (cfg, MONO_EXCEPTION_OBJECT_SUPPLIED);
+ MONO_GC_REGISTER_ROOT_SINGLE (cfg->exception_ptr);
cfg->exception_ptr = exception;
}
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;
MonoLoaderError *error;
if ((error = mono_loader_get_last_error ())) {
- cfg->exception_type = error->exception_type;
+ mono_cfg_set_exception (cfg, error->exception_type);
} else {
- cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
+ mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
}
goto exception_exit;
dont_verify_stloc = TRUE;
}
- if (!dont_verify && mini_method_verify (cfg, method_definition))
- goto exception_exit;
-
if (mono_debug_using_mono_debugger ())
cfg->keep_cil_nops = TRUE;
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);
cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
if (!cmethod || mono_loader_get_last_error ())
- goto load_error;
+ LOAD_ERROR;
if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
GENERIC_SHARING_FAILURE (CEE_JMP);
}
if (!cmethod || mono_loader_get_last_error ())
- goto load_error;
+ LOAD_ERROR;
if (!dont_verify && !cfg->skip_visibility) {
MonoMethod *target_method = cil_method;
if (method->is_inflated) {
if (!cmethod->klass->inited)
if (!mono_class_init (cmethod->klass))
- goto load_error;
+ LOAD_ERROR;
if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
mini_class_is_system_array (cmethod->klass)) {
fsig = mono_method_signature (cmethod);
if (!fsig)
- goto load_error;
+ LOAD_ERROR;
if (fsig->pinvoke) {
MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod,
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);
}
token = read32 (ip + 1);
cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
if (!cmethod || mono_loader_get_last_error ())
- goto load_error;
+ LOAD_ERROR;
fsig = mono_method_get_signature (cmethod, image, token);
if (!fsig)
- goto load_error;
+ LOAD_ERROR;
mono_save_token_info (cfg, image, token, cmethod);
if (!mono_class_init (cmethod->klass))
- goto load_error;
+ LOAD_ERROR;
if (cfg->generic_sharing_context)
context_used = mono_method_check_context_used (cmethod);
}
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;
if (cfg->generic_sharing_context)
context_used = mono_class_check_context_used (klass);
- if (!context_used && mono_class_has_variant_generic_params (klass)) {
- MonoInst *args [2];
+ if (!context_used && mini_class_has_reference_variant_generic_argument (klass, context_used)) {
+ MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
+ MonoInst *args [3];
/* obj */
args [0] = *sp;
/* klass */
EMIT_NEW_CLASSCONST (cfg, args [1], klass);
- ins = mono_emit_jit_icall (cfg, mono_object_castclass, args);
- *sp ++ = ins;
+ /* inline cache*/
+ /*FIXME AOT support*/
+ EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
+
+ /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
+ *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)) {
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;
if (cfg->generic_sharing_context)
context_used = mono_class_check_context_used (klass);
- if (!context_used && mono_class_has_variant_generic_params (klass)) {
- MonoInst *args [2];
+ if (!context_used && mini_class_has_reference_variant_generic_argument (klass, context_used)) {
+ MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
+ MonoInst *args [3];
/* obj */
args [0] = *sp;
/* klass */
EMIT_NEW_CLASSCONST (cfg, args [1], klass);
- *sp = mono_emit_jit_icall (cfg, mono_object_isinst, args);
- sp++;
+ /* inline cache*/
+ /*FIXME AOT support*/
+ EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
+
+ *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)) {
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;
if (generic_class_is_reference_type (cfg, klass)) {
/* CASTCLASS FIXME kill this huge slice of duplicated code*/
- if (!context_used && (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
+ if (!context_used && mini_class_has_reference_variant_generic_argument (klass, context_used)) {
+ MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
+ MonoInst *args [3];
+
+ /* obj */
+ args [0] = *sp;
+
+ /* klass */
+ EMIT_NEW_CLASSCONST (cfg, args [1], klass);
+
+ /* inline cache*/
+ /*FIXME AOT support*/
+ EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
+
+ /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
+ *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)) {
MonoMethod *mono_castclass;
MonoInst *iargs [1];
int costs;
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;
field = mono_field_from_token (image, token, &klass, generic_context);
}
if (!field)
- goto load_error;
+ LOAD_ERROR;
if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
FIELD_ACCESS_FAILURE;
mono_class_init (klass);
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);
else
field = mono_field_from_token (image, token, &klass, generic_context);
if (!field)
- goto load_error;
+ LOAD_ERROR;
mono_class_init (klass);
if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
FIELD_ACCESS_FAILURE;
/* storing a NULL doesn't need any of the complex checks in stelemref */
if (generic_class_is_reference_type (cfg, klass) &&
!(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
- MonoMethod* helper = mono_marshal_get_stelemref ();
+ MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
+ MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
MonoInst *iargs [3];
+ if (!helper->slot)
+ mono_class_setup_vtable (obj_array);
+ g_assert (helper->slot);
+
if (sp [0]->type != STACK_OBJ)
UNVERIFIED;
if (sp [2]->type != STACK_OBJ)
iargs [2] = sp [2];
iargs [1] = sp [1];
iargs [0] = sp [0];
-
- mono_emit_method_call (cfg, helper, iargs, NULL);
+
+ mono_emit_method_call (cfg, helper, iargs, sp [0]);
} else {
if (sp [1]->opcode == OP_ICONST) {
int array_reg = sp [0]->dreg;
handle = mono_ldtoken (image, n, &handle_class, generic_context);
}
if (!handle)
- goto load_error;
+ LOAD_ERROR;
mono_class_init (handle_class);
if (cfg->generic_sharing_context) {
if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
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.
n = read32 (ip + 2);
cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
if (!cmethod || mono_loader_get_last_error ())
- goto load_error;
+ LOAD_ERROR;
mono_class_init (cmethod->klass);
mono_save_token_info (cfg, image, n, cmethod);
if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
+ MonoInst *target_ins;
MonoMethod *invoke;
int invoke_context_used = 0;
invoke = mono_get_delegate_invoke (ctor_method->klass);
if (!invoke || !mono_method_signature (invoke))
- goto load_error;
+ LOAD_ERROR;
if (cfg->generic_sharing_context)
invoke_context_used = mono_method_check_context_used (invoke);
+ target_ins = sp [-1];
+
+ if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
+ /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
+ if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
+ MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
+ MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
+ }
+ }
+
#if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE)
/* FIXME: SGEN support */
- if (!cfg->gen_write_barriers && invoke_context_used == 0) {
- MonoInst *target_ins;
-
+ if (invoke_context_used == 0) {
ip += 6;
if (cfg->verbose_level > 3)
g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
- target_ins = sp [-1];
sp --;
*sp = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used);
CHECK_CFG_EXCEPTION;
n = read32 (ip + 2);
cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
if (!cmethod || mono_loader_get_last_error ())
- goto load_error;
+ LOAD_ERROR;
mono_class_init (cmethod->klass);
if (cfg->generic_sharing_context)
/* Method is too large */
mname = mono_method_full_name (method, TRUE);
- cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
+ mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
g_free (mname);
cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
goto cleanup;
load_error:
- cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
+ mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
goto cleanup;
unverified:
g_free (live_range_end_bb);
}
+void
+mono_create_helper_signatures (void)
+{
+ helper_sig_domain_get = mono_create_icall_signature ("ptr");
+ helper_sig_class_init_trampoline = mono_create_icall_signature ("void");
+ helper_sig_generic_class_init_trampoline = mono_create_icall_signature ("void");
+ helper_sig_generic_class_init_trampoline_llvm = mono_create_icall_signature ("void ptr");
+ helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
+ helper_sig_monitor_enter_exit_trampoline = mono_create_icall_signature ("void");
+ helper_sig_monitor_enter_exit_trampoline_llvm = mono_create_icall_signature ("void object");
+}
+
/**
* FIXME:
* - use 'iadd' instead of 'int_add'