#include <mono/metadata/mono-debug-debugger.h>
#include <mono/metadata/monitor.h>
#include <mono/metadata/security-manager.h>
+#include <mono/metadata/threads-types.h>
+#include <mono/metadata/rawbuffer.h>
#include <mono/utils/mono-math.h>
#include <mono/utils/mono-compiler.h>
#include <mono/os/gc_wrapper.h>
#include "jit-icalls.c"
+#include "aliasing.h"
+
/*
* this is used to determine when some branch optimizations are possible: we exclude FP compares
* because they have weird semantics with NaNs.
static int mini_verbose = 0;
+#define mono_jit_lock() EnterCriticalSection (&jit_mutex)
+#define mono_jit_unlock() LeaveCriticalSection (&jit_mutex)
static CRITICAL_SECTION jit_mutex;
static GHashTable *class_init_hash_addr = NULL;
return res;
}
+G_GNUC_UNUSED char *
+mono_pmip (void *ip)
+{
+ return get_method_from_ip (ip);
+}
+
/* debug function */
G_GNUC_UNUSED static void
print_method_from_ip (void *ip)
return mono_code_manager_reserve (global_codeman, size);
}
else {
- EnterCriticalSection (&jit_mutex);
+ mono_jit_lock ();
ptr = mono_code_manager_reserve (global_codeman, size);
- LeaveCriticalSection (&jit_mutex);
+ mono_jit_unlock ();
return ptr;
}
}
#define NEW_LOCLOADA(cfg,dest,num) do { \
(dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
- (dest)->ssa_op = MONO_SSA_MAYBE_LOAD; \
+ (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN; \
(dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)]; \
(dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
(dest)->opcode = OP_LDADDR; \
#define NEW_RETLOADA(cfg,dest) do { \
(dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
- (dest)->ssa_op = MONO_SSA_MAYBE_LOAD; \
+ (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN; \
(dest)->inst_i0 = (cfg)->ret; \
(dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
(dest)->opcode = cfg->ret_var_is_local ? OP_LDADDR : CEE_LDIND_I; \
#define NEW_ARGLOADA(cfg,dest,num) do { \
if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
(dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
- (dest)->ssa_op = MONO_SSA_MAYBE_LOAD; \
+ (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN; \
(dest)->inst_i0 = arg_array [(num)]; \
(dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
(dest)->opcode = OP_LDADDR; \
#define NEW_TEMPLOADA(cfg,dest,num) do { \
(dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
- (dest)->ssa_op = MONO_SSA_MAYBE_LOAD; \
+ (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN; \
(dest)->inst_i0 = (cfg)->varinfo [(num)]; \
(dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
(dest)->opcode = OP_LDADDR; \
int i;
array [*dfn] = start;
- /*g_print ("visit %d at %p\n", *dfn, start->cil_code);*/
+ /*g_print ("visit %d at %p (BB%ld)\n", *dfn, start->cil_code, start->block_num);*/
for (i = 0; i < start->out_count; ++i) {
if (start->out_bb [i]->dfn)
continue;
found = FALSE;
for (i = 0; i < bb->out_count; ++i) {
outb = bb->out_bb [i];
+ /* exception handlers are linked, but they should not be considered for stack args */
+ if (outb->flags & BB_EXCEPTION_HANDLER)
+ continue;
//g_print (" %d", outb->block_num);
if (outb->in_stack) {
found = TRUE;
for (i = 0; i < bb->out_count; ++i) {
outb = bb->out_bb [i];
- if (outb->in_scount)
+ /* exception handlers are linked, but they should not be considered for stack args */
+ if (outb->flags & BB_EXCEPTION_HANDLER)
+ continue;
+ if (outb->in_scount) {
+ if (outb->in_scount != bb->out_scount)
+ G_BREAKPOINT ();
continue; /* check they are the same locals */
+ }
outb->in_scount = count;
outb->in_stack = bb->out_stack;
}
found = FALSE;
while (bindex < bb->out_count) {
outb = bb->out_bb [bindex];
+ /* exception handlers are linked, but they should not be considered for stack args */
+ if (outb->flags & BB_EXCEPTION_HANDLER) {
+ bindex++;
+ continue;
+ }
if (outb->in_stack != locals) {
/*
* Instead of storing sp [i] to locals [i], we need to store
MonoMethodSignature *res;
int i;
- EnterCriticalSection (&jit_mutex);
+ mono_jit_lock ();
if (!sighash) {
sighash = g_hash_table_new (NULL, NULL);
}
res->ret = &mono_defaults.int_class->byval_arg;
g_hash_table_insert (sighash, GINT_TO_POINTER (arity), res);
- LeaveCriticalSection (&jit_mutex);
+ mono_jit_unlock ();
return res;
}
MonoMethodSignature *res;
int i;
- EnterCriticalSection (&jit_mutex);
+ mono_jit_lock ();
if (!sighash) {
sighash = g_hash_table_new (NULL, NULL);
}
else if ((res = g_hash_table_lookup (sighash, GINT_TO_POINTER (arity)))) {
- LeaveCriticalSection (&jit_mutex);
+ mono_jit_unlock ();
return res;
}
res->ret = &mono_defaults.int_class->byval_arg;
g_hash_table_insert (sighash, GINT_TO_POINTER (arity), res);
- LeaveCriticalSection (&jit_mutex);
+ mono_jit_unlock ();
return res;
}
return mono_emit_jit_icall (cfg, bblock, alloc_ftn, iargs, ip);
}
+
+/**
+ * Handles unbox of a Nullable<T>, returning a temp variable
+ * where the result is stored
+ */
+static int
+handle_unbox_nullable (MonoCompile* cfg, MonoBasicBlock* bblock, MonoInst* val, const guchar *ip, MonoClass* klass)
+{
+ MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
+ return mono_emit_method_call_spilled (cfg, bblock, method, mono_method_signature (method), &val, ip, NULL);
+}
+
+
+
static MonoInst *
handle_box (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const guchar *ip, MonoClass *klass)
{
MonoInst *dest, *vtoffset, *add, *vstore;
int temp;
+ if (mono_class_is_nullable (klass)) {
+ MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
+ temp = mono_emit_method_call_spilled (cfg, bblock, method, mono_method_signature (method), &val, ip, NULL);
+ NEW_TEMPLOAD (cfg, dest, temp);
+ return dest;
+ }
+
+
temp = handle_alloc (cfg, bblock, klass, TRUE, ip);
NEW_TEMPLOAD (cfg, dest, temp);
NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
name = g_strdup (icall_name);
info = mono_register_jit_icall (mono_array_new_va, name, esig, FALSE);
- EnterCriticalSection (&jit_mutex);
+ mono_jit_lock ();
g_hash_table_insert (jit_icall_name_hash, name, name);
- LeaveCriticalSection (&jit_mutex);
+ mono_jit_unlock ();
}
cfg->flags |= MONO_CFG_HAS_VARARGS;
name = g_strdup (icall_name);
info = mono_register_jit_icall (ves_array_element_address, name, esig, FALSE);
- EnterCriticalSection (&jit_mutex);
+ mono_jit_lock ();
g_hash_table_insert (jit_icall_name_hash, name, name);
- LeaveCriticalSection (&jit_mutex);
+ mono_jit_unlock ();
}
temp = mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, sp, ip, FALSE, FALSE);
return NULL;
}
+static MonoException*
+mini_loader_error_to_exception (MonoLoaderError *error)
+{
+ MonoException *ex = NULL;
+
+ switch (error->kind) {
+ case MONO_LOADER_ERROR_TYPE: {
+ MonoString *class_name = mono_string_new (mono_domain_get (), error->class_name);
+
+ ex = mono_get_exception_type_load (class_name, error->assembly_name);
+ break;
+ }
+ case MONO_LOADER_ERROR_METHOD:
+ case MONO_LOADER_ERROR_FIELD: {
+ char *class_name;
+
+ class_name = g_strdup_printf ("%s%s%s", error->klass->name_space, *error->klass->name_space ? "." : "", error->klass->name);
+
+ if (error->kind == MONO_LOADER_ERROR_METHOD)
+ ex = mono_get_exception_missing_method (class_name, error->member_name);
+ else
+ ex = mono_get_exception_missing_field (class_name, error->member_name);
+ g_free (class_name);
+ break;
+ }
+ default:
+ g_assert_not_reached ();
+ }
+
+ return ex;
+}
+
static MonoInst*
mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
{
ins->inst_i0 = args [0];
return ins;
#endif
+ } else if (strcmp (cmethod->name, ".ctor") == 0) {
+ MONO_INST_NEW (cfg, ins, CEE_NOP);
+ return ins;
} else
return NULL;
- } else if (mini_class_is_system_array (cmethod->klass)) {
+ } else if (cmethod->klass == mono_defaults.array_class) {
if (cmethod->name [0] != 'g')
return NULL;
} else if (cmethod->klass == mono_defaults.thread_class) {
if (strcmp (cmethod->name, "get_CurrentThread") == 0 && (ins = mono_arch_get_thread_intrinsic (cfg)))
return ins;
- return NULL;
}
return mono_arch_get_inst_for_method (cfg, cmethod, fsig, args);
MonoInst *store, *temp, *load;
if (ip_in_bb (cfg, bblock, ip_next) &&
- (CODE_IS_STLOC (ip_next) || *ip_next == CEE_BRTRUE || *ip_next == CEE_BRFALSE ||
- *ip_next == CEE_BRTRUE_S || *ip_next == CEE_BRFALSE_S || *ip_next == CEE_RET))
+ (CODE_IS_STLOC (ip_next) || *ip_next == CEE_RET))
return ins;
temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
method = mono_get_method_full (m->klass->image, token, klass, context);
- if (method->is_inflated)
+ if (method && method->is_inflated)
method = mono_get_inflated_method (method);
return method;
}
+static inline MonoClass*
+mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
+{
+ MonoClass *klass;
+
+ if (method->wrapper_type != MONO_WRAPPER_NONE)
+ klass = mono_method_get_wrapper_data (method, token);
+ else
+ klass = mono_class_get_full (method->klass->image, token, context);
+ if (klass)
+ mono_class_init (klass);
+ return klass;
+}
+
static
void check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee, MonoBasicBlock *bblock, unsigned char *ip)
{
image = method->klass->image;
header = mono_method_get_header (method);
- generic_container = ((MonoMethodNormal *)method)->generic_container;
+ generic_container = method->generic_container;
sig = mono_method_signature (method);
num_args = sig->hasthis + sig->param_count;
ip = (unsigned char*)header->code;
}
/* handle exception clauses */
for (i = 0; i < header->num_clauses; ++i) {
- //unsigned char *p = ip;
+ MonoBasicBlock *try_bb;
MonoExceptionClause *clause = &header->clauses [i];
- GET_BBLOCK (cfg, bbhash, tblock, ip + clause->try_offset);
- tblock->real_offset = clause->try_offset;
+ GET_BBLOCK (cfg, bbhash, try_bb, ip + clause->try_offset);
+ try_bb->real_offset = clause->try_offset;
GET_BBLOCK (cfg, bbhash, tblock, ip + clause->handler_offset);
tblock->real_offset = clause->handler_offset;
+ tblock->flags |= BB_EXCEPTION_HANDLER;
+
+ link_bblock (cfg, try_bb, tblock);
+
+ if (*(ip + clause->handler_offset) == CEE_POP)
+ tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
MONO_ADD_INS (tblock, ins);
+
+ /* todo: is a fault block unsafe to optimize? */
+ if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
+ tblock->flags |= BB_EXCEPTION_UNSAFE;
}
+
/*g_print ("clause try IL_%04x to IL_%04x handler %d at IL_%04x to IL_%04x\n", clause->try_offset, clause->try_offset + clause->try_len, clause->flags, clause->handler_offset, clause->handler_offset + clause->handler_len);
while (p < end) {
g_print ("%s", mono_disasm_code_one (NULL, method, p, &p));
/* FIXME: check the signature matches */
cmethod = mini_get_method (method, token, NULL, generic_context);
+ if (!cmethod)
+ goto load_error;
+
if (mono_use_security_manager) {
check_linkdemand (cfg, method, cmethod, bblock, ip);
}
cmethod = mini_get_method (method, token, NULL, generic_context);
}
- g_assert (cmethod);
+ if (!cmethod)
+ goto load_error;
if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
/* MS.NET seems to silently convert this to a callvirt */
}
if (cmethod && cmethod->klass->generic_container) {
- G_BREAKPOINT ();
+ // G_BREAKPOINT ();
goto unverified;
}
}
if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp)) {
- G_BREAKPOINT ();
+ // G_BREAKPOINT ();
goto unverified;
}
if (ip_in_bb (cfg, bblock, ip + 5)
&& (!MONO_TYPE_ISSTRUCT (fsig->ret))
&& (!MONO_TYPE_IS_VOID (fsig->ret) || cmethod->string_ctor)
- && (CODE_IS_STLOC (ip + 5) || ip [5] == CEE_POP || ip [5] == CEE_BRTRUE || ip [5] == CEE_BRFALSE ||
- ip [5] == CEE_BRTRUE_S || ip [5] == CEE_BRFALSE_S || ip [5] == CEE_RET)) {
+ && (CODE_IS_STLOC (ip + 5) || ip [5] == CEE_POP || ip [5] == CEE_RET)) {
/* no need to spill */
ins = (MonoInst*)mono_emit_method_call (cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL);
*sp++ = ins;
ins_flag = 0;
inline_costs += 1;
break;
+ case CEE_MUL:
+ CHECK_STACK (2);
+ ADD_BINOP (*ip);
+
+#ifdef MONO_ARCH_NO_EMULATE_MUL_IMM
+ /* FIXME: This breaks with ssapre (mono -O=ssapre loader.exe) */
+ if ((ins->inst_right->opcode == OP_ICONST) && !(cfg->opt & MONO_OPT_SSAPRE)) {
+ switch (ins->opcode) {
+ case CEE_MUL:
+ ins->opcode = OP_IMUL_IMM;
+ ins->inst_imm = ins->inst_right->inst_c0;
+ break;
+ case OP_LMUL:
+ ins->opcode = OP_LMUL_IMM;
+ ins->inst_imm = ins->inst_right->inst_c0;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ }
+#endif
+
+ if (mono_find_jit_opcode_emulation (ins->opcode)) {
+ --sp;
+ *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
+ mono_get_got_var (cfg);
+ }
+ ip++;
+ break;
case CEE_ADD:
case CEE_SUB:
- case CEE_MUL:
case CEE_DIV:
case CEE_DIV_UN:
case CEE_REM:
CHECK_OPSIZE (5);
CHECK_STACK (2);
token = read32 (ip + 1);
- if (method->wrapper_type != MONO_WRAPPER_NONE)
- klass = mono_method_get_wrapper_data (method, token);
- else
- klass = mono_class_get_full (image, token, generic_context);
-
- mono_class_init (klass);
+ klass = mini_get_class (method, token, generic_context);
+ if (!klass)
+ goto load_error;
sp -= 2;
if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
MonoInst *store, *load;
CHECK_STACK (1);
--sp;
token = read32 (ip + 1);
- if (method->wrapper_type != MONO_WRAPPER_NONE)
- klass = mono_method_get_wrapper_data (method, token);
- else
- klass = mono_class_get_full (image, token, generic_context);
-
- mono_class_init (klass);
+ klass = mini_get_class (method, token, generic_context);
+ if (!klass)
+ goto load_error;
if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
ins->cil_code = ip;
CHECK_OPSIZE (5);
token = read32 (ip + 1);
cmethod = mini_get_method (method, token, NULL, generic_context);
+ if (!cmethod)
+ goto load_error;
fsig = mono_method_get_signature (cmethod, image, token);
mono_class_init (cmethod->klass);
--sp;
CHECK_OPSIZE (5);
token = read32 (ip + 1);
- if (method->wrapper_type != MONO_WRAPPER_NONE)
- klass = mono_method_get_wrapper_data (method, token);
- else
- klass = mono_class_get_full (image, token, generic_context);
- mono_class_init (klass);
+ klass = mini_get_class (method, token, generic_context);
+ if (!klass)
+ goto load_error;
/* Needed by the code generated in inssel.brg */
mono_get_got_var (cfg);
--sp;
CHECK_OPSIZE (5);
token = read32 (ip + 1);
- if (method->wrapper_type != MONO_WRAPPER_NONE)
- klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
- else
- klass = mono_class_get_full (image, token, generic_context);
- mono_class_init (klass);
+ klass = mini_get_class (method, token, generic_context);
+ if (!klass)
+ goto load_error;
if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
/* CASTCLASS */
break;
}
+ if (mono_class_is_nullable (klass)) {
+ int v = handle_unbox_nullable (cfg, bblock, *sp, ip, klass);
+ NEW_TEMPLOAD (cfg, *sp, v);
+ sp ++;
+ ip += 5;
+ break;
+ }
+
MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
ins->type = STACK_OBJ;
ins->inst_left = *sp;
--sp;
CHECK_OPSIZE (5);
token = read32 (ip + 1);
- if (method->wrapper_type != MONO_WRAPPER_NONE)
- klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
- else
- klass = mono_class_get_full (image, token, generic_context);
- mono_class_init (klass);
+ klass = mini_get_class (method, token, generic_context);
+ if (!klass)
+ goto load_error;
+
+ if (mono_class_is_nullable (klass)) {
+ int v = handle_unbox_nullable (cfg, bblock, *sp, ip, klass);
+ NEW_TEMPLOAD (cfg, *sp, v);
+ sp ++;
+ ip += 5;
+ break;
+ }
/* Needed by the code generated in inssel.brg */
mono_get_got_var (cfg);
--sp;
CHECK_OPSIZE (5);
token = read32 (ip + 1);
- if (method->wrapper_type != MONO_WRAPPER_NONE)
- klass = mono_method_get_wrapper_data (method, token);
- else
- klass = mono_class_get_full (image, token, generic_context);
- mono_class_init (klass);
+ klass = mini_get_class (method, token, generic_context);
+ if (!klass)
+ goto load_error;
/* Needed by the code generated in inssel.brg */
mono_get_got_var (cfg);
ins->cil_code = ip - 1;
MONO_ADD_INS (bblock, ins);
sp = stack_start;
+
link_bblock (cfg, bblock, end_bblock);
start_new_bblock = 1;
mono_get_got_var (cfg);
CHECK_OPSIZE (5);
token = read32 (ip + 1);
field = mono_field_from_token (image, token, &klass, generic_context);
+ if (!field)
+ goto load_error;
mono_class_init (klass);
foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
}
} else {
if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
- MonoMethod *ldfld_wrapper = mono_marshal_get_ldfld_wrapper (field->type);
+ MonoMethod *wrapper = (*ip == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type);
MonoInst *iargs [4];
int temp;
NEW_CLASSCONST (cfg, iargs [1], klass);
NEW_FIELDCONST (cfg, iargs [2], field);
NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
- if ((cfg->opt & MONO_OPT_INLINE) && !MONO_TYPE_ISSTRUCT (mono_method_signature (ldfld_wrapper)->ret)) {
- costs = inline_method (cfg, ldfld_wrapper, mono_method_signature (ldfld_wrapper), bblock,
+ if ((cfg->opt & MONO_OPT_INLINE) && !MONO_TYPE_ISSTRUCT (mono_method_signature (wrapper)->ret)) {
+ costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), bblock,
iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
g_assert (costs > 0);
temp = iargs [0]->inst_i0->inst_c0;
- if (*ip == CEE_LDFLDA) {
- /* not sure howto handle this */
- NEW_TEMPLOADA (cfg, *sp, temp);
- } else {
- NEW_TEMPLOAD (cfg, *sp, temp);
- }
+ NEW_TEMPLOAD (cfg, *sp, temp);
sp++;
/* indicates start of a new block, and triggers a load of
inline_costs += costs;
break;
} else {
- temp = mono_emit_method_call_spilled (cfg, bblock, ldfld_wrapper, mono_method_signature (ldfld_wrapper), iargs, ip, NULL);
- if (*ip == CEE_LDFLDA) {
- /* not sure howto handle this */
- NEW_TEMPLOADA (cfg, *sp, temp);
- } else {
- NEW_TEMPLOAD (cfg, *sp, temp);
- }
+ temp = mono_emit_method_call_spilled (cfg, bblock, wrapper, mono_method_signature (wrapper), iargs, ip, NULL);
+ NEW_TEMPLOAD (cfg, *sp, temp);
sp++;
}
} else {
token = read32 (ip + 1);
field = mono_field_from_token (image, token, &klass, generic_context);
+ if (!field)
+ goto load_error;
mono_class_init (klass);
g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
sp -= 2;
CHECK_OPSIZE (5);
token = read32 (ip + 1);
- if (method->wrapper_type != MONO_WRAPPER_NONE)
- klass = mono_method_get_wrapper_data (method, token);
- else
- klass = mono_class_get_full (image, token, generic_context);
- mono_class_init (klass);
+ klass = mini_get_class (method, token, generic_context);
+ if (!klass)
+ goto load_error;
n = mono_type_to_stind (&klass->byval_arg);
if (n == CEE_STOBJ) {
handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE);
val = *sp;
CHECK_OPSIZE (5);
token = read32 (ip + 1);
- if (method->wrapper_type != MONO_WRAPPER_NONE)
- klass = mono_method_get_wrapper_data (method, token);
- else
- klass = mono_class_get_full (image, token, generic_context);
- mono_class_init (klass);
+ klass = mini_get_class (method, token, generic_context);
+ if (!klass)
+ goto load_error;
if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
*sp++ = val;
/* Ditto */
mono_get_got_var (cfg);
- if (method->wrapper_type != MONO_WRAPPER_NONE)
- klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
- else
- klass = mono_class_get_full (image, token, generic_context);
-
- mono_class_init (klass);
+ klass = mini_get_class (method, token, generic_context);
+ if (!klass)
+ goto load_error;
ins->inst_newa_class = klass;
ins->inst_newa_len = *sp;
ins->type = STACK_OBJ;
sp -= 2;
CHECK_OPSIZE (5);
- if (method->wrapper_type != MONO_WRAPPER_NONE)
- klass = (MonoClass*)mono_method_get_wrapper_data (method, read32 (ip + 1));
- else
- klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
-
+ klass = mini_get_class (method, read32 (ip + 1), generic_context);
+ if (!klass)
+ goto load_error;
/* we need to make sure that this array is exactly the type it needs
* to be for correctness. the wrappers are lax with their usage
* so we need to ignore them here
CHECK_OPSIZE (5);
token = read32 (ip + 1);
klass = mono_class_get_full (image, token, generic_context);
+ if (!klass)
+ goto load_error;
mono_class_init (klass);
NEW_LDELEMA (cfg, load, sp, klass);
load->cil_code = ip;
CHECK_OPSIZE (5);
token = read32 (ip + 1);
klass = mono_class_get_full (image, token, generic_context);
+ if (!klass)
+ goto load_error;
mono_class_init (klass);
if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
MonoMethod* helper = mono_marshal_get_stelemref ();
--sp;
CHECK_OPSIZE (5);
klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
+ if (!klass)
+ goto load_error;
mono_class_init (klass);
ins->type = STACK_MP;
ins->inst_left = *sp;
--sp;
CHECK_OPSIZE (5);
klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
+ if (!klass)
+ goto load_error;
mono_class_init (klass);
ins->cil_code = ip;
else {
handle = mono_ldtoken (image, n, &handle_class, generic_context);
}
+ if (!handle)
+ goto load_error;
mono_class_init (handle_class);
if (cfg->opt & MONO_OPT_SHARED) {
CHECK_OPSIZE (6);
n = read32 (ip + 2);
cmethod = mini_get_method (method, n, NULL, generic_context);
-
+ if (!cmethod)
+ goto load_error;
mono_class_init (cmethod->klass);
if (mono_use_security_manager) {
CHECK_OPSIZE (6);
n = read32 (ip + 2);
cmethod = mini_get_method (method, n, NULL, generic_context);
-
+ if (!cmethod)
+ goto load_error;
mono_class_init (cmethod->klass);
if (mono_use_security_manager) {
--sp;
CHECK_OPSIZE (6);
token = read32 (ip + 2);
- if (method->wrapper_type != MONO_WRAPPER_NONE)
- klass = mono_method_get_wrapper_data (method, token);
- else
- klass = mono_class_get_full (image, token, generic_context);
+ klass = mini_get_class (method, token, generic_context);
+ if (!klass)
+ goto load_error;
if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
MonoInst *store, *load;
NEW_PCONST (cfg, load, NULL);
CHECK_OPSIZE (6);
token = read32 (ip + 2);
constrained_call = mono_class_get_full (image, token, generic_context);
+ if (!constrained_call)
+ goto load_error;
ip += 6;
break;
case CEE_CPBLK:
handler_offset = clause->handler_offset;
}
+ bblock->flags |= BB_EXCEPTION_UNSAFE;
+
g_assert (handler_offset != -1);
NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
MonoType *type = mono_type_create_from_typespec (image, token);
token = mono_type_size (type, &align);
} else {
- MonoClass *szclass = mono_class_get_full (image, token, generic_context);
- mono_class_init (szclass);
- token = mono_class_value_size (szclass, &align);
+ MonoClass *klass = mono_class_get_full (image, token, generic_context);
+ if (!klass)
+ goto load_error;
+ mono_class_init (klass);
+ token = mono_class_value_size (klass, &align);
}
NEW_ICONST (cfg, ins, token);
ins->cil_code = ip;
dont_inline = g_list_remove (dont_inline, method);
return -1;
+ load_error:
+ if (cfg->method != method)
+ g_hash_table_destroy (bbhash);
+ g_slist_free (class_inits);
+ dont_inline = g_list_remove (dont_inline, method);
+ return -1;
+
unverified:
if (cfg->method != method)
g_hash_table_destroy (bbhash);
#endif
}
+static void
+mono_init_exceptions (void)
+{
+#ifndef CUSTOM_EXCEPTION_HANDLING
+ mono_arch_get_restore_context ();
+ mono_arch_get_call_filter ();
+ mono_arch_get_throw_exception ();
+ mono_arch_get_rethrow_exception ();
+#endif
+}
+
guint8 *
mono_get_trampoline_code (MonoTrampolineType tramp_type)
{
vtable, ptr);
mono_domain_unlock (vtable->domain);
- EnterCriticalSection (&jit_mutex);
+ mono_jit_lock ();
if (!class_init_hash_addr)
class_init_hash_addr = g_hash_table_new (NULL, NULL);
g_hash_table_insert (class_init_hash_addr, ptr, vtable);
- LeaveCriticalSection (&jit_mutex);
+ mono_jit_unlock ();
return ptr;
}
{
MonoVTable *res;
- EnterCriticalSection (&jit_mutex);
+ mono_jit_lock ();
if (class_init_hash_addr)
res = g_hash_table_lookup (class_init_hash_addr, addr);
else
res = NULL;
- LeaveCriticalSection (&jit_mutex);
+ mono_jit_unlock ();
return res;
}
} StackSlotInfo;
/*
- * mono_allocate_stack_slots:
+ * mono_allocate_stack_slots_full:
*
* Allocate stack slots for all non register allocated variables using a
* linear scan algorithm.
* STACK_ALIGN is set to the alignment needed by the locals area.
*/
gint32*
-mono_allocate_stack_slots (MonoCompile *m, guint32 *stack_size, guint32 *stack_align)
+mono_allocate_stack_slots_full (MonoCompile *m, gboolean backward, guint32 *stack_size, guint32 *stack_align)
{
int i, slot, offset, size, align;
MonoMethodVar *vmv;
if (t->type == MONO_TYPE_VALUETYPE)
align = sizeof (gpointer);
- offset += size;
- offset += align - 1;
- offset &= ~(align - 1);
- slot = offset;
+ if (backward) {
+ offset += size;
+ offset += align - 1;
+ offset &= ~(align - 1);
+ slot = offset;
+ }
+ else {
+ offset += align - 1;
+ offset &= ~(align - 1);
+ slot = offset;
+ offset += size;
+ }
if (*stack_align == 0)
*stack_align = align;
return offsets;
}
+gint32*
+mono_allocate_stack_slots (MonoCompile *m, guint32 *stack_size, guint32 *stack_align)
+{
+ return mono_allocate_stack_slots_full (m, TRUE, stack_size, stack_align);
+}
+
void
mono_register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpointer func, gboolean no_throw)
{
mono_arch_setup_jit_tls_data (jit_tls);
+#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
+ mono_setup_altstack (jit_tls);
+#endif
+
return jit_tls;
}
if (jit_tls) {
mono_arch_free_jit_tls_data (jit_tls);
+
+#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
+ mono_free_altstack (jit_tls);
+#endif
g_free (jit_tls->first_lmf);
g_free (jit_tls);
thread->jit_data = NULL;
case CEE_STIND_R4:
case CEE_STIND_R8:
case CEE_STOBJ:
- if (tree->ssa_op == MONO_SSA_NOP) {
+ if ((tree->ssa_op == MONO_SSA_NOP) || (tree->ssa_op & MONO_SSA_ADDRESS_TAKEN)) {
memset (acp, 0, sizeof (MonoInst *) * acp_size);
return;
}
mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gboolean run_cctors, gboolean compile_aot, int parts)
{
MonoMethodHeader *header = mono_method_get_header (method);
- guint8 *ip = (guint8 *)header->code;
+ guint8 *ip;
MonoCompile *cfg;
MonoJitInfo *jinfo;
int dfn = 0, i, code_size_ratio;
+ gboolean deadce_has_run = FALSE;
+
+ if (!header)
+ return NULL;
+
+ ip = (guint8 *)header->code;
mono_jit_stats.methods_compiled++;
if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
cfg->compile_aot = compile_aot;
cfg->intvars = mono_mempool_alloc0 (cfg->mempool, sizeof (guint16) * STACK_MAX *
mono_method_get_header (method)->max_stack);
-
+ cfg->aliasing_info = NULL;
+
if (cfg->verbose_level > 2)
g_print ("converting method %s\n", mono_method_full_name (method, TRUE));
#else
/* fixme: add all optimizations which requires SSA */
- if (cfg->opt & (MONO_OPT_DEADCE | MONO_OPT_ABCREM | MONO_OPT_SSAPRE)) {
+ if (cfg->opt & (MONO_OPT_SSA | MONO_OPT_ABCREM | MONO_OPT_SSAPRE)) {
if (!(cfg->comp_done & MONO_COMP_SSA) && !header->num_clauses && !cfg->disable_ssa) {
mono_local_cprop (cfg);
mono_ssa_compute (cfg);
}
if (cfg->comp_done & MONO_COMP_SSA) {
- mono_ssa_deadce (cfg);
+ //mono_ssa_deadce (cfg);
//mono_ssa_strength_reduction (cfg);
+ if (cfg->opt & MONO_OPT_SSAPRE) {
+ mono_perform_ssapre (cfg);
+ //mono_local_cprop (cfg);
+ }
+
+ if (cfg->opt & MONO_OPT_DEADCE) {
+ mono_ssa_deadce (cfg);
+ deadce_has_run = TRUE;
+ }
+
if ((cfg->flags & MONO_CFG_HAS_LDELEMA) && (cfg->opt & MONO_OPT_ABCREM))
mono_perform_abc_removal (cfg);
- if (cfg->opt & MONO_OPT_SSAPRE)
- mono_perform_ssapre (cfg);
-
mono_ssa_remove (cfg);
if (cfg->opt & MONO_OPT_BRANCH)
if (cfg->opt & MONO_OPT_LINEARS) {
GList *vars, *regs;
+
+ /* For now, compute aliasing info only if needed for deadce... */
+ if ((cfg->opt & MONO_OPT_DEADCE) && (! deadce_has_run) && (header->num_clauses == 0)) {
+ cfg->aliasing_info = mono_build_aliasing_information (cfg);
+ }
/* fixme: maybe we can avoid to compute livenesss here if already computed ? */
cfg->comp_done &= ~MONO_COMP_LIVENESS;
if (!(cfg->comp_done & MONO_COMP_LIVENESS))
mono_analyze_liveness (cfg);
+ if (cfg->aliasing_info != NULL) {
+ mono_aliasing_deadce (cfg->aliasing_info);
+ deadce_has_run = TRUE;
+ }
+
if ((vars = mono_arch_get_allocatable_int_vars (cfg))) {
regs = mono_arch_get_global_int_regs (cfg);
if (cfg->got_var)
regs = g_list_delete_link (regs, regs);
mono_linear_scan (cfg, vars, regs, &cfg->used_int_regs);
}
+
+ if (cfg->aliasing_info != NULL) {
+ mono_destroy_aliasing_information (cfg->aliasing_info);
+ cfg->aliasing_info = NULL;
+ }
}
//mono_print_code (cfg);
}
cfg->jit_info = jinfo;
+#if defined(__arm__)
+ mono_arch_fixup_jinfo (cfg);
+#endif
mono_domain_lock (cfg->domain);
mono_jit_info_table_add (cfg->domain, jinfo);
method = mono_get_inflated_method (method);
#ifdef MONO_USE_AOT_COMPILER
- if (!mono_compile_aot && (opt & MONO_OPT_AOT)) {
+ if (!mono_compile_aot && (opt & MONO_OPT_AOT) && !(mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)) {
MonoJitInfo *info;
MonoDomain *domain = mono_domain_get ();
cfg = mini_method_compile (method, opt, target_domain, TRUE, FALSE, 0);
+ if (!cfg) {
+ /* Throw a type load exception if needed */
+ MonoLoaderError *error = mono_loader_get_last_error ();
+
+ if (error) {
+ MonoException *ex = mini_loader_error_to_exception (error);
+ mono_loader_clear_error ();
+ mono_raise_exception (ex);
+ }
+ else
+ g_assert_not_reached ();
+ }
+
mono_domain_lock (target_domain);
/* Check if some other thread already did the job. In this case, we can
mono_domain_unlock (target_domain);
mono_jit_stats.methods_lookups++;
mono_runtime_class_init (mono_class_vtable (domain, method->klass));
- return mono_create_ftnptr (domain, info->code_start);
+ return mono_create_ftnptr (target_domain, info->code_start);
}
}
mono_domain_unlock (target_domain);
p = mono_jit_compile_method_inner (method, target_domain);
- return mono_create_ftnptr (domain, p);
+ return mono_create_ftnptr (target_domain, p);
}
static gpointer
#define GET_CONTEXT \
ucontext_t *uctx = context; \
struct sigcontext *ctx = (struct sigcontext *)&(uctx->uc_mcontext);
-#elif defined(__ppc__) || defined (__powerpc__) || defined (__s390__) || defined (MONO_ARCH_USE_SIGACTION)
+#elif defined (MONO_ARCH_USE_SIGACTION)
#define GET_CONTEXT \
void *ctx = context;
#else
SIG_HANDLER_SIGNATURE (sigill_signal_handler)
{
MonoException *exc;
- GET_CONTEXT
+ GET_CONTEXT;
+
exc = mono_get_exception_execution_engine ("SIGILL");
mono_arch_handle_exception (ctx, exc, FALSE);
SIG_HANDLER_SIGNATURE (sigsegv_signal_handler)
{
MonoException *exc = NULL;
+ MonoJitInfo *ji;
+
#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
#endif
- GET_CONTEXT
+ GET_CONTEXT;
+
+#ifdef MONO_ARCH_USE_SIGACTION
+ if (debug_options.collect_pagefault_stats) {
+ if (mono_raw_buffer_is_pagefault (info->si_addr)) {
+ mono_raw_buffer_handle_pagefault (info->si_addr);
+ return;
+ }
+ if (mono_aot_is_pagefault (info->si_addr)) {
+ mono_aot_handle_pagefault (info->si_addr);
+ return;
+ }
+ }
+#endif
#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
/* Can't allocate memory using Boehm GC on altstack */
exc = mono_domain_get ()->null_reference_ex;
#endif
- if (debug_options.abort_on_sigsegv) {
- MonoJitInfo *ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
- if (!ji) {
- fprintf (stderr, "Got SIGSEGV while in unmanaged code, and the 'abort-on-sigsegv' MONO_DEBUG option is set. Aborting...\n");
- /* Segfault in unmanaged code */
- abort ();
- }
+ ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
+ if (!ji) {
+ mono_handle_native_sigsegv (ctx);
}
mono_arch_handle_exception (ctx, exc, FALSE);
static void
SIG_HANDLER_SIGNATURE (sigquit_signal_handler)
{
- MonoException *exc;
- GET_CONTEXT
+ MonoException *exc;
+ GET_CONTEXT;
- exc = mono_get_exception_execution_engine ("Interrupted (SIGQUIT).");
+ exc = mono_get_exception_execution_engine ("Interrupted (SIGQUIT).");
- mono_arch_handle_exception (ctx, exc, FALSE);
+ mono_arch_handle_exception (ctx, exc, FALSE);
}
static void
SIG_HANDLER_SIGNATURE (sigint_signal_handler)
{
MonoException *exc;
- GET_CONTEXT
+ GET_CONTEXT;
exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
add_signal_handler (SIGUSR2, sigusr2_signal_handler);
add_signal_handler (mono_thread_get_abort_signal (), sigusr1_signal_handler);
+ signal (SIGPIPE, SIG_IGN);
/* catch SIGSEGV */
#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
debug_options.handle_sigint = TRUE;
else if (!strcmp (arg, "keep-delegates"))
debug_options.keep_delegates = TRUE;
- else if (!strcmp (arg, "abort-on-sigsegv"))
- debug_options.abort_on_sigsegv = TRUE;
+ else if (!strcmp (arg, "collect-pagefault-stats"))
+ debug_options.collect_pagefault_stats = TRUE;
else {
fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
- fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'abort-on-sigsegv'\n");
+ fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'collect-pagefault-stats'\n");
exit (1);
}
}
mono_init_trampolines ();
+ mono_init_exceptions ();
+
if (!g_thread_supported ())
g_thread_init (NULL);
if (getenv ("MONO_DEBUG") != NULL)
mini_parse_debug_options ();
-
+
+ if (mono_running_on_valgrind ()) {
+ gsize stack_bottom = (gsize)&domain;
+ stack_bottom += 4095;
+ stack_bottom &= ~4095;
+ GC_stackbottom = (char*)stack_bottom;
+ }
MONO_GC_PRE_INIT ();
mono_jit_tls_id = TlsAlloc ();
mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
+ if (debug_options.collect_pagefault_stats) {
+ mono_raw_buffer_set_make_unreadable (TRUE);
+ mono_aot_set_make_unreadable (TRUE);
+ }
+
domain = mono_init_from_assembly (filename, filename);
mono_icall_init ();
g_print ("LinkDemand (aptc) : %ld\n", mono_jit_stats.cas_linkdemand_aptc);
g_print ("Demand (code gen) : %ld\n", mono_jit_stats.cas_demand_generation);
}
+ if (debug_options.collect_pagefault_stats) {
+ g_print ("Metadata pagefaults : %d\n", mono_raw_buffer_get_n_pagefaults ());
+ g_print ("AOT pagefaults : %d\n", mono_aot_get_n_pagefaults ());
+ }
}
}