#include <mono/metadata/rawbuffer.h>
#include <mono/utils/mono-math.h>
#include <mono/utils/mono-compiler.h>
+#include <mono/utils/mono-counters.h>
+#include <mono/utils/mono-logger.h>
#include <mono/os/gc_wrapper.h>
#include "mini.h"
#include "inssel.h"
#include "trace.h"
-#include "jit-icalls.c"
+#include "jit-icalls.h"
#include "aliasing.h"
+#define BRANCH_COST 100
+#define INLINE_LENGTH_LIMIT 20
+#define INLINE_FAILURE do {\
+ if ((cfg->method != method) && (method->wrapper_type == MONO_WRAPPER_NONE))\
+ goto inline_failure;\
+ } while (0)
+
/*
* this is used to determine when some branch optimizations are possible: we exclude FP compares
* because they have weird semantics with NaNs.
#define MONO_IS_COND_BRANCH_OP(ins) (((ins)->opcode >= CEE_BEQ && (ins)->opcode <= CEE_BLT_UN) || ((ins)->opcode >= OP_LBEQ && (ins)->opcode <= OP_LBLT_UN) || ((ins)->opcode >= OP_FBEQ && (ins)->opcode <= OP_FBLT_UN) || ((ins)->opcode >= OP_IBEQ && (ins)->opcode <= OP_IBLT_UN))
#define MONO_IS_COND_BRANCH_NOFP(ins) (MONO_IS_COND_BRANCH_OP(ins) && (ins)->inst_left->inst_left->type != STACK_R8)
+#define MONO_IS_BRANCH_OP(ins) (MONO_IS_COND_BRANCH_OP(ins) || ((ins)->opcode == CEE_BR) || ((ins)->opcode == OP_BR_REG) || ((ins)->opcode == CEE_SWITCH))
+
#define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && (ins)->ssa_op == MONO_SSA_LOAD && (ins)->inst_left->inst_c0 == 0)
static void setup_stat_profiler (void);
static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt);
static gpointer mono_jit_compile_method (MonoMethod *method);
static gpointer mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method);
+static gpointer mono_create_jit_trampoline_in_domain (MonoDomain *domain, MonoMethod *method);
static void handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src,
- const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native);
+ const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native, gboolean write_barrier);
static void dec_foreach (MonoInst *tree, MonoCompile *cfg);
static MonoMethodSignature *helper_sig_domain_get = NULL;
static guint32 default_opt = 0;
+static gboolean default_opt_set = FALSE;
guint32 mono_jit_tls_id = -1;
MonoTraceSpec *mono_jit_trace_calls = NULL;
#endif
}
+typedef struct {
+ void *ip;
+ MonoMethod *method;
+} FindTrampUserData;
+
+static void
+find_tramp (gpointer key, gpointer value, gpointer user_data)
+{
+ FindTrampUserData *ud = (FindTrampUserData*)user_data;
+
+ if (value == ud->ip)
+ ud->method = (MonoMethod*)key;
+}
+
/* debug function */
G_GNUC_UNUSED static char*
get_method_from_ip (void *ip)
{
MonoJitInfo *ji;
char *method;
- char *source;
char *res;
MonoDomain *domain = mono_domain_get ();
+ MonoDebugSourceLocation *location;
+ FindTrampUserData user_data;
ji = mono_jit_info_table_find (domain, ip);
if (!ji) {
- return NULL;
+ user_data.ip = ip;
+ user_data.method = NULL;
+ mono_domain_lock (domain);
+ g_hash_table_foreach (domain->jit_trampoline_hash, find_tramp, &user_data);
+ mono_domain_unlock (domain);
+ if (user_data.method) {
+ char *mname = mono_method_full_name (user_data.method, TRUE);
+ res = g_strdup_printf ("<%p - JIT trampoline for %s>", ip, mname);
+ g_free (mname);
+ return res;
+ }
+ else
+ return NULL;
}
method = mono_method_full_name (ji->method, TRUE);
- source = mono_debug_source_location_from_address (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), NULL, domain);
+ /* FIXME: unused ? */
+ location = mono_debug_lookup_source_location (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
res = g_strdup_printf (" %s + 0x%x (%p %p) [%p - %s]", method, (int)((char*)ip - (char*)ji->code_start), ji->code_start, (char*)ji->code_start + ji->code_size, domain, domain->friendly_name);
- g_free (source);
+ mono_debug_free_source_location (location);
g_free (method);
return res;
}
/* debug function */
-G_GNUC_UNUSED static void
-print_method_from_ip (void *ip)
+void
+mono_print_method_from_ip (void *ip)
{
MonoJitInfo *ji;
char *method;
- char *source;
+ MonoDebugSourceLocation *source;
MonoDomain *domain = mono_domain_get ();
+ FindTrampUserData user_data;
ji = mono_jit_info_table_find (domain, ip);
if (!ji) {
- g_print ("No method at %p\n", ip);
+ user_data.ip = ip;
+ user_data.method = NULL;
+ mono_domain_lock (domain);
+ g_hash_table_foreach (domain->jit_trampoline_hash, find_tramp, &user_data);
+ mono_domain_unlock (domain);
+ if (user_data.method) {
+ char *mname = mono_method_full_name (user_data.method, TRUE);
+ printf ("IP %p is a JIT trampoline for %s\n", ip, mname);
+ g_free (mname);
+ }
+ else
+ g_print ("No method at %p\n", ip);
return;
}
method = mono_method_full_name (ji->method, TRUE);
- source = mono_debug_source_location_from_address (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), NULL, domain);
+ source = mono_debug_lookup_source_location (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
g_print ("IP %p at offset 0x%x of method %s (%p %p)[domain %p - %s]\n", ip, (int)((char*)ip - (char*)ji->code_start), method, ji->code_start, (char*)ji->code_start + ji->code_size, domain, domain->friendly_name);
if (source)
- g_print ("%s\n", source);
+ g_print ("%s:%d\n", source->source_file, source->row);
- g_free (source);
+ mono_debug_free_source_location (source);
g_free (method);
}
-
-G_GNUC_UNUSED void
-mono_print_method_from_ip (void *ip)
-{
- print_method_from_ip (ip);
-}
/*
* mono_method_same_domain:
(vi)->idx = (id); \
} while (0)
+//#define UNVERIFIED do { G_BREAKPOINT (); goto unverified; } while (0)
+#define UNVERIFIED do { goto unverified; } while (0)
+
/*
* Basic blocks have two numeric identifiers:
* dfn: Depth First Number
#define GET_BBLOCK(cfg,bbhash,tblock,ip) do { \
(tblock) = g_hash_table_lookup (bbhash, (ip)); \
if (!(tblock)) { \
- if ((ip) >= end || (ip) < header->code) goto unverified; \
+ if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
(tblock) = NEW_BBLOCK (cfg); \
(tblock)->cil_code = (ip); \
ADD_BBLOCK (cfg, (bbhash), (tblock)); \
(dest)->type = STACK_PTR; \
} while (0)
-#define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type) do { \
+#define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type,stack_class) do { \
MonoInst *group, *got_var, *got_loc; \
(dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
(dest)->opcode = OP_GOT_ENTRY; \
group->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token)); \
(dest)->inst_p0 = got_var; \
(dest)->inst_p1 = group; \
- (dest)->type = (stack_type); \
+ (dest)->type = (stack_type); \
+ (dest)->klass = (stack_class); \
} while (0)
#else
(dest)->type = STACK_PTR; \
} while (0)
-#define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type) do { \
+#define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type,stack_class) do { \
(dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
(dest)->opcode = OP_AOTCONST; \
(dest)->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token)); \
(dest)->inst_p1 = (gpointer)(patch_type); \
(dest)->type = (stack_type); \
+ (dest)->klass = (stack_class); \
} while (0)
#endif
#define NEW_SFLDACONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_SFLDA, (val))
-#define NEW_LDSTRCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDSTR, (image), (token), STACK_OBJ)
+#define NEW_LDSTRCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDSTR, (image), (token), STACK_OBJ, mono_defaults.string_class)
-#define NEW_TYPE_FROM_HANDLE_CONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_TYPE_FROM_HANDLE, (image), (token), STACK_OBJ)
+#define NEW_TYPE_FROM_HANDLE_CONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_TYPE_FROM_HANDLE, (image), (token), STACK_OBJ, mono_defaults.monotype_class)
-#define NEW_LDTOKENCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDTOKEN, (image), (token), STACK_PTR)
+#define NEW_LDTOKENCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDTOKEN, (image), (token), STACK_PTR, NULL)
#define NEW_DECLSECCONST(cfg,dest,image,entry) do { \
if (cfg->compile_aot) { \
- NEW_AOTCONST_TOKEN (cfg, dest, MONO_PATCH_INFO_DECLSEC, image, (entry).index, STACK_OBJ); \
+ NEW_AOTCONST_TOKEN (cfg, dest, MONO_PATCH_INFO_DECLSEC, image, (entry).index, STACK_OBJ, NULL); \
} else { \
NEW_PCONST (cfg, args [0], (entry).blob); \
} \
}
}
+/**
+ * mono_unlink_bblock:
+ *
+ * Unlink two basic blocks.
+ */
+static void
+mono_unlink_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
+{
+ int i, pos;
+ gboolean found;
+
+ found = FALSE;
+ for (i = 0; i < from->out_count; ++i) {
+ if (to == from->out_bb [i]) {
+ found = TRUE;
+ break;
+ }
+ }
+ if (found) {
+ pos = 0;
+ for (i = 0; i < from->out_count; ++i) {
+ if (from->out_bb [i] != to)
+ from->out_bb [pos ++] = from->out_bb [i];
+ }
+ g_assert (pos == from->out_count - 1);
+ from->out_count--;
+ }
+
+ found = FALSE;
+ for (i = 0; i < to->in_count; ++i) {
+ if (from == to->in_bb [i]) {
+ found = TRUE;
+ break;
+ }
+ }
+ if (found) {
+ pos = 0;
+ for (i = 0; i < to->in_count; ++i) {
+ if (to->in_bb [i] != from)
+ to->in_bb [pos ++] = to->in_bb [i];
+ }
+ g_assert (pos == to->in_count - 1);
+ to->in_count--;
+ }
+}
+
/**
* mono_find_block_region:
*
return opcode;
}
-guint
-mono_type_to_ldind (MonoType *type)
-{
- if (type->byref)
- return CEE_LDIND_I;
-
-handle_enum:
- switch (type->type) {
- case MONO_TYPE_I1:
- return CEE_LDIND_I1;
- case MONO_TYPE_U1:
- case MONO_TYPE_BOOLEAN:
- return CEE_LDIND_U1;
- case MONO_TYPE_I2:
- return CEE_LDIND_I2;
- case MONO_TYPE_U2:
- case MONO_TYPE_CHAR:
- return CEE_LDIND_U2;
- case MONO_TYPE_I4:
- return CEE_LDIND_I4;
- case MONO_TYPE_U4:
- return CEE_LDIND_U4;
- case MONO_TYPE_I:
- case MONO_TYPE_U:
- case MONO_TYPE_PTR:
- case MONO_TYPE_FNPTR:
- return CEE_LDIND_I;
- case MONO_TYPE_CLASS:
- case MONO_TYPE_STRING:
- case MONO_TYPE_OBJECT:
- case MONO_TYPE_SZARRAY:
- case MONO_TYPE_ARRAY:
- return CEE_LDIND_REF;
- case MONO_TYPE_I8:
- case MONO_TYPE_U8:
- return CEE_LDIND_I8;
- case MONO_TYPE_R4:
- return CEE_LDIND_R4;
- case MONO_TYPE_R8:
- return CEE_LDIND_R8;
- case MONO_TYPE_VALUETYPE:
- if (type->data.klass->enumtype) {
- type = type->data.klass->enum_basetype;
- goto handle_enum;
- }
- return CEE_LDOBJ;
- case MONO_TYPE_TYPEDBYREF:
- return CEE_LDOBJ;
- case MONO_TYPE_GENERICINST:
- type = &type->data.generic_class->container_class->byval_arg;
- goto handle_enum;
- default:
- g_error ("unknown type 0x%02x in type_to_ldind", type->type);
- }
- return -1;
-}
-
-guint
-mono_type_to_stind (MonoType *type)
-{
- if (type->byref)
- return CEE_STIND_I;
-
-handle_enum:
- switch (type->type) {
- case MONO_TYPE_I1:
- case MONO_TYPE_U1:
- case MONO_TYPE_BOOLEAN:
- return CEE_STIND_I1;
- case MONO_TYPE_I2:
- case MONO_TYPE_U2:
- case MONO_TYPE_CHAR:
- return CEE_STIND_I2;
- case MONO_TYPE_I4:
- case MONO_TYPE_U4:
- return CEE_STIND_I4;
- case MONO_TYPE_I:
- case MONO_TYPE_U:
- case MONO_TYPE_PTR:
- case MONO_TYPE_FNPTR:
- return CEE_STIND_I;
- case MONO_TYPE_CLASS:
- case MONO_TYPE_STRING:
- case MONO_TYPE_OBJECT:
- case MONO_TYPE_SZARRAY:
- case MONO_TYPE_ARRAY:
- return CEE_STIND_REF;
- case MONO_TYPE_I8:
- case MONO_TYPE_U8:
- return CEE_STIND_I8;
- case MONO_TYPE_R4:
- return CEE_STIND_R4;
- case MONO_TYPE_R8:
- return CEE_STIND_R8;
- case MONO_TYPE_VALUETYPE:
- if (type->data.klass->enumtype) {
- type = type->data.klass->enum_basetype;
- goto handle_enum;
- }
- return CEE_STOBJ;
- case MONO_TYPE_TYPEDBYREF:
- return CEE_STOBJ;
- case MONO_TYPE_GENERICINST:
- type = &type->data.generic_class->container_class->byval_arg;
- goto handle_enum;
- default:
- g_error ("unknown type 0x%02x in type_to_stind", type->type);
- }
- return -1;
-}
-
/*
* Returns the type used in the eval stack when @type is loaded.
* FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
{
MonoClass *klass;
+ inst->klass = klass = mono_class_from_mono_type (type);
if (type->byref) {
inst->type = STACK_MP;
return;
}
- klass = mono_class_from_mono_type (type);
-
handle_enum:
switch (type->type) {
case MONO_TYPE_VOID:
case STACK_I8: return &mono_defaults.int64_class->byval_arg;
case STACK_PTR: return &mono_defaults.int_class->byval_arg;
case STACK_R8: return &mono_defaults.double_class->byval_arg;
- case STACK_MP: return &mono_defaults.int_class->byval_arg;
+ case STACK_MP:
+ /*
+ * FIXME: This doesn't work because mono_class_from_mono_type ()
+ * returns the original klass for a byref type, not a 'byref' class,
+ * causing the JIT to create variables with the wrong type, for
+ * example.
+ */
+ /*
+ if (ins->klass)
+ return &ins->klass->this_arg;
+ else
+ */
+ return &mono_defaults.object_class->this_arg;
case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
case STACK_VTYPE: return &ins->klass->byval_arg;
default:
NEW_TEMPSTORE (cfg, inst, dest, load);
if (inst->opcode == CEE_STOBJ) {
NEW_TEMPLOADA (cfg, inst, dest);
- handle_stobj (cfg, bb, inst, load, NULL, inst->klass, TRUE, FALSE);
+ handle_stobj (cfg, bb, inst, load, NULL, inst->klass, TRUE, FALSE, FALSE);
} else {
inst->cil_code = NULL;
mono_add_ins_to_end (bb, inst);
return res;
}
+/*
+ * merge_stacks:
+ *
+ * Merge stack state between two basic blocks according to Ecma 335, Partition III,
+ * section 1.8.1.1. Store the resulting stack state into stack_2.
+ * Returns: TRUE, if verification succeeds, FALSE otherwise.
+ * FIXME: We should store the stack state in a dedicated structure instead of in
+ * MonoInst's.
+ */
+static gboolean
+merge_stacks (MonoCompile *cfg, MonoStackSlot *state_1, MonoStackSlot *state_2, guint32 size)
+{
+ int i;
+
+ if (cfg->dont_verify_stack_merge)
+ return TRUE;
+
+ /* FIXME: Implement all checks from the spec */
+
+ for (i = 0; i < size; ++i) {
+ MonoStackSlot *slot1 = &state_1 [i];
+ MonoStackSlot *slot2 = &state_2 [i];
+
+ if (slot1->type != slot2->type)
+ return FALSE;
+
+ switch (slot1->type) {
+ case STACK_PTR:
+ /* FIXME: Perform merge ? */
+ /* klass == NULL means a native int */
+ if (slot1->klass && slot2->klass) {
+ if (slot1->klass != slot2->klass)
+ return FALSE;
+ }
+ break;
+ case STACK_MP:
+ /* FIXME: Change this to an assert and fix the JIT to allways fill this */
+ if (slot1->klass && slot2->klass) {
+ if (slot1->klass != slot2->klass)
+ return FALSE;
+ }
+ break;
+ case STACK_OBJ: {
+ MonoClass *klass1 = slot1->klass;
+ MonoClass *klass2 = slot2->klass;
+
+ if (!klass1) {
+ /* slot1 is ldnull */
+ } else if (!klass2) {
+ /* slot2 is ldnull */
+ slot2->klass = slot1->klass;
+ }
+ break;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
/*
* This function is called to handle items that are left on the evaluation stack
* at basic block boundaries. What happens is that we save the values to local variables
* which case its old value should be used.
* A single joint point will use the same variables (stored in the array bb->out_stack or
* bb->in_stack, if the basic block is before or after the joint point).
+ * If the stack merge fails at a join point, cfg->unverifiable is set.
*/
static int
handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int count) {
int i, bindex;
MonoBasicBlock *outb;
MonoInst *inst, **locals;
+ MonoStackSlot *stack_state;
gboolean found;
if (!count)
return 0;
if (cfg->verbose_level > 3)
g_print ("%d item(s) on exit from B%d\n", count, bb->block_num);
+
+ stack_state = mono_mempool_alloc (cfg->mempool, sizeof (MonoStackSlot) * count);
+ for (i = 0; i < count; ++i) {
+ stack_state [i].type = sp [i]->type;
+ stack_state [i].klass = sp [i]->klass;
+
+ /* Check that instructions other than ldnull have ins->klass set */
+ if (!cfg->dont_verify_stack_merge && (sp [i]->type == STACK_OBJ) && !((sp [i]->opcode == OP_PCONST) && sp [i]->inst_c0 == 0))
+ g_assert (sp [i]->klass);
+ }
+
+ /* Perform verification and stack state merge */
+ 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;
+ if (outb->stack_state) {
+ gboolean verified;
+
+ if (count != outb->in_scount) {
+ cfg->unverifiable = TRUE;
+ return 0;
+ }
+ verified = merge_stacks (cfg, stack_state, outb->stack_state, count);
+ if (!verified) {
+ cfg->unverifiable = TRUE;
+ return 0;
+ }
+
+ if (cfg->verbose_level > 3) {
+ int j;
+
+ for (j = 0; j < count; ++j)
+ printf ("\tStack state of BB%d, slot %d=%d\n", outb->block_num, j, outb->stack_state [j].type);
+ }
+ } else {
+ /* Make a copy of the stack state */
+ outb->stack_state = mono_mempool_alloc (cfg->mempool, sizeof (MonoStackSlot) * count);
+ memcpy (outb->stack_state, stack_state, sizeof (MonoStackSlot) * count);
+ }
+ }
+
if (!bb->out_scount) {
bb->out_scount = count;
//g_print ("bblock %d has out:", bb->block_num);
NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
if (inst->opcode == CEE_STOBJ) {
NEW_TEMPLOADA (cfg, inst, locals [i]->inst_c0);
- handle_stobj (cfg, bb, inst, sp [i], sp [i]->cil_code, inst->klass, TRUE, FALSE);
+ handle_stobj (cfg, bb, inst, sp [i], sp [i]->cil_code, inst->klass, TRUE, FALSE, FALSE);
} else {
inst->cil_code = sp [i]->cil_code;
mono_add_ins_to_end (bb, inst);
store->cil_code = ins->cil_code;
if (store->opcode == CEE_STOBJ) {
NEW_TEMPLOADA (cfg, store, temp->inst_c0);
- handle_stobj (cfg, bblock, store, ins, ins->cil_code, temp->klass, FALSE, FALSE);
+ handle_stobj (cfg, bblock, store, ins, ins->cil_code, temp->klass, FALSE, FALSE, FALSE);
} else
MONO_ADD_INS (bblock, store);
NEW_TEMPLOAD (cfg, load, temp->inst_c0);
if (target->byref) {
/* FIXME: check that the pointed to types match */
- if (arg->type == STACK_MP && arg->type == STACK_PTR)
+ if (arg->type == STACK_MP)
+ return arg->klass != mono_class_from_mono_type (target);
+ if (arg->type == STACK_PTR)
return 0;
return 1;
}
if (arg->type != STACK_I4 && arg->type != STACK_PTR)
return 1;
return 0;
+ case MONO_TYPE_PTR:
+ /* STACK_MP is needed when setting pinned locals */
+ if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
+ return 1;
+ return 0;
case MONO_TYPE_I:
case MONO_TYPE_U:
- case MONO_TYPE_PTR:
case MONO_TYPE_FNPTR:
if (arg->type != STACK_I4 && arg->type != STACK_PTR)
return 1;
call->inst.flags |= MONO_INST_HAS_METHOD;
call->inst.inst_left = this;
- if (!virtual)
- mono_get_got_var (cfg);
- else if (call->method->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
+ if (call->method->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
/* Needed by the code generated in inssel.brg */
mono_get_got_var (cfg);
call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, FALSE, ip, to_end);
call->fptr = func;
- mono_get_got_var (cfg);
-
return mono_spill_call (cfg, bblock, call, sig, ret_object, ip, to_end);
}
g_assert_not_reached ();
}
- mono_get_got_var (cfg);
return mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, args, ip, FALSE, FALSE);
}
call = mono_arch_call_opcode (cfg, cfg->cbb, call, FALSE);
- mono_get_got_var (cfg);
-
if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
temp = mono_compile_create_var (cfg, info->sig->ret, OP_LOCAL);
temp->flags |= MONO_INST_IS_TEMP;
}
static void
-handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native) {
+handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native, gboolean write_barrier) {
MonoInst *iargs [3];
int n;
guint32 align = 0;
else
n = mono_class_value_size (klass, &align);
+#if HAVE_WRITE_BARRIERS
+ /* if native is true there should be no references in the struct */
+ if (write_barrier && klass->has_references && !native) {
+ iargs [0] = dest;
+ iargs [1] = src;
+ NEW_PCONST (cfg, iargs [2], klass);
+
+ mono_emit_jit_icall (cfg, bblock, mono_value_copy, iargs, ip);
+ return;
+ }
+#endif
+
+ /* FIXME: add write barrier handling */
if ((cfg->opt & MONO_OPT_INTRINS) && !to_end && n <= sizeof (gpointer) * 5) {
MonoInst *inst;
if (dest->opcode == OP_LDADDR) {
NEW_CLASSCONST (cfg, iargs [1], klass);
alloc_ftn = mono_object_new;
+ } else if (cfg->compile_aot && bblock->out_of_line && klass->type_token && klass->image == mono_defaults.corlib) {
+ /* This happens often in argument checking code, eg. throw new FooException... */
+ /* Avoid relocations by calling a helper function specialized to mscorlib */
+ NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
+ return mono_emit_jit_icall (cfg, bblock, mono_helper_newobj_mscorlib, iargs, ip);
} else {
MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
gboolean pass_lw;
-
+
alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
if (pass_lw) {
guint32 lw = vtable->klass->instance_size;
vstore->inst_right = val;
if (vstore->opcode == CEE_STOBJ) {
- handle_stobj (cfg, bblock, add, val, ip, klass, FALSE, FALSE);
+ handle_stobj (cfg, bblock, add, val, ip, klass, FALSE, FALSE, TRUE);
} else
MONO_ADD_INS (bblock, vstore);
if (!(cfg->opt & MONO_OPT_SHARED)) {
vtable = mono_class_vtable (cfg->domain, method->klass);
if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
- if (cfg->run_cctors)
+ if (cfg->run_cctors) {
+ /* This makes so that inline cannot trigger */
+ /* .cctors: too many apps depend on them */
+ /* running with a specific order... */
+ if (! vtable->initialized)
+ return FALSE;
mono_runtime_class_init (vtable);
+ }
}
else if (!vtable->initialized && mono_class_needs_cctor_run (method->klass, NULL))
return FALSE;
if (header->code_size < atoi (getenv ("MONO_INLINELIMIT"))) {
return TRUE;
}
- } else if (header->code_size < 20)
+ } else if (header->code_size < INLINE_LENGTH_LIMIT)
return TRUE;
return FALSE;
return addr;
}
-static MonoJitICallInfo **emul_opcode_map = NULL;
+MonoJitICallInfo **emul_opcode_map = NULL;
-static inline MonoJitICallInfo *
+MonoJitICallInfo *
mono_find_jit_opcode_emulation (int opcode)
{
if (emul_opcode_map)
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)
{
MONO_INST_NEW (cfg, ins, OP_GETTYPE);
ins->inst_i0 = args [0];
return ins;
- } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0) {
-#ifdef MONO_ARCH_EMULATE_MUL_DIV
/* The OP_GETHASHCODE rule depends on OP_MUL */
-#else
+#if !defined(MONO_ARCH_EMULATE_MUL_DIV) && !defined(HAVE_MOVING_COLLECTOR)
+ } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0) {
MONO_INST_NEW (cfg, ins, OP_GETHASHCODE);
ins->inst_i0 = args [0];
return ins;
} else if (cmethod->klass == mono_defaults.thread_class) {
if (strcmp (cmethod->name, "get_CurrentThread") == 0 && (ins = mono_arch_get_thread_intrinsic (cfg)))
return ins;
+ } else if (mini_class_is_system_array (cmethod->klass) &&
+ strcmp (cmethod->name, "GetGenericValueImpl") == 0) {
+ MonoInst *sp [2];
+ MonoInst *ldelem, *store, *load;
+ MonoClass *eklass = mono_class_from_mono_type (fsig->params [1]);
+ int n;
+ n = mono_type_to_stind (&eklass->byval_arg);
+ if (n == CEE_STOBJ)
+ return NULL;
+ sp [0] = args [0];
+ sp [1] = args [1];
+ NEW_LDELEMA (cfg, ldelem, sp, eklass);
+ ldelem->flags |= MONO_INST_NORANGECHECK;
+ MONO_INST_NEW (cfg, store, n);
+ n = mono_type_to_ldind (&eklass->byval_arg);
+ MONO_INST_NEW (cfg, load, mono_type_to_ldind (&eklass->byval_arg));
+ type_to_eval_stack_type (&eklass->byval_arg, load);
+ load->inst_left = ldelem;
+ store->inst_left = args [2];
+ store->inst_right = load;
+ return store;
}
return mono_arch_get_inst_for_method (cfg, cmethod, fsig, args);
store->cil_code = sp [0]->cil_code;
if (store->opcode == CEE_STOBJ) {
NEW_TEMPLOADA (cfg, store, temp->inst_c0);
- handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, temp->klass, FALSE, FALSE);
+ handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, temp->klass, FALSE, FALSE, FALSE);
} else {
MONO_ADD_INS (bblock, store);
}
sp++;
}
}
+#define MONO_INLINE_CALLED_LIMITED_METHODS 0
+#define MONO_INLINE_CALLER_LIMITED_METHODS 0
+
+#if (MONO_INLINE_CALLED_LIMITED_METHODS)
+static char*
+mono_inline_called_method_name_limit = NULL;
+static gboolean check_inline_called_method_name_limit (MonoMethod *called_method) {
+ char *called_method_name = mono_method_full_name (called_method, TRUE);
+ int strncmp_result;
+
+ if (mono_inline_called_method_name_limit == NULL) {
+ char *limit_string = getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
+ if (limit_string != NULL) {
+ mono_inline_called_method_name_limit = limit_string;
+ } else {
+ mono_inline_called_method_name_limit = (char *) "";
+ }
+ }
+
+ strncmp_result = strncmp (called_method_name, mono_inline_called_method_name_limit, strlen (mono_inline_called_method_name_limit));
+ g_free (called_method_name);
+
+ //return (strncmp_result <= 0);
+ return (strncmp_result == 0);
+}
+#endif
+
+#if (MONO_INLINE_CALLER_LIMITED_METHODS)
+static char*
+mono_inline_caller_method_name_limit = NULL;
+static gboolean check_inline_caller_method_name_limit (MonoMethod *caller_method) {
+ char *caller_method_name = mono_method_full_name (caller_method, TRUE);
+ int strncmp_result;
+
+ if (mono_inline_caller_method_name_limit == NULL) {
+ char *limit_string = getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
+ if (limit_string != NULL) {
+ mono_inline_caller_method_name_limit = limit_string;
+ } else {
+ mono_inline_caller_method_name_limit = (char *) "";
+ }
+ }
+
+ strncmp_result = strncmp (caller_method_name, mono_inline_caller_method_name_limit, strlen (mono_inline_caller_method_name_limit));
+ g_free (caller_method_name);
+
+ //return (strncmp_result <= 0);
+ return (strncmp_result == 0);
+}
+#endif
static int
inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoBasicBlock *bblock, MonoInst **sp,
MonoBasicBlock *ebblock, *sbblock;
int i, costs, new_locals_offset;
MonoMethod *prev_inlined_method;
+#if (MONO_INLINE_CALLED_LIMITED_METHODS)
+ if ((! inline_allways) && ! 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))
+ return 0;
+#endif
if (cfg->verbose_level > 2)
g_print ("INLINE START %p %s -> %s\n", cmethod, mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
* * consider using an array instead of an hash table (bb_hash)
*/
-#define CHECK_TYPE(ins) if (!(ins)->type) goto unverified
-#define CHECK_STACK(num) if ((sp - stack_start) < (num)) goto unverified
-#define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) goto unverified
-#define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) goto unverified
-#define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) goto unverified
-#define CHECK_OPSIZE(size) if (ip + size > end) goto unverified
-
+#define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
+#define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
+#define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
+#define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
+#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
/* offset from br.s -> br like opcodes */
#define BIG_BRANCH_OFFSET 13
cli_addr = ip - start;
i = mono_opcode_value ((const guint8 **)&ip, end);
if (i < 0)
- goto unverified;
+ UNVERIFIED;
opcode = &mono_opcodes [i];
switch (opcode->argument) {
case MonoInlineNone:
/* Find the start of the bblock containing the throw */
bblock = NULL;
- while ((bb_start > start) && !bblock) {
+ while ((bb_start >= start) && !bblock) {
bblock = g_hash_table_lookup (bbhash, (bb_start));
bb_start --;
}
return klass;
}
+/*
+ * Returns TRUE if the JIT should abort inlining because "callee"
+ * is influenced by security attributes.
+ */
static
-void check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee, MonoBasicBlock *bblock, unsigned char *ip)
+gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee, MonoBasicBlock *bblock, unsigned char *ip)
{
- guint32 result = mono_declsec_linkdemand (cfg->domain, caller, callee);
+ guint32 result;
+
+ if ((cfg->method != caller) && mono_method_has_declsec (callee)) {
+ return TRUE;
+ }
+
+ result = mono_declsec_linkdemand (cfg->domain, caller, callee);
if (result == MONO_JIT_SECURITY_OK)
- return;
+ return FALSE;
if (result == MONO_JIT_LINKDEMAND_ECMA) {
/* Generate code to throw a SecurityException before the actual call/link */
cfg->exception_type = MONO_EXCEPTION_SECURITY_LINKDEMAND;
cfg->exception_data = result;
}
+
+ return FALSE;
+}
+
+static gboolean
+can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed)
+{
+ GSList *tmp;
+ if (accessing == accessed)
+ return TRUE;
+ if (!accessed || !accessing)
+ return FALSE;
+ for (tmp = accessed->friend_assembly_names; tmp; tmp = tmp->next) {
+ MonoAssemblyName *friend = tmp->data;
+ /* Be conservative with checks */
+ if (!friend->name)
+ continue;
+ if (strcmp (accessing->aname.name, friend->name))
+ continue;
+ if (friend->public_key_token [0]) {
+ if (!accessing->aname.public_key_token [0])
+ continue;
+ if (strcmp ((char*)friend->public_key_token, (char*)accessing->aname.public_key_token))
+ continue;
+ }
+ return TRUE;
+ }
+ return FALSE;
}
+/* FIXME: check visibility of type, too */
+static gboolean
+can_access_member (MonoClass *access_klass, MonoClass *member_klass, int access_level)
+{
+ /* Partition I 8.5.3.2 */
+ /* the access level values are the same for fields and methods */
+ switch (access_level) {
+ case FIELD_ATTRIBUTE_COMPILER_CONTROLLED:
+ /* same compilation unit */
+ return access_klass->image == member_klass->image;
+ case FIELD_ATTRIBUTE_PRIVATE:
+ return access_klass == member_klass;
+ case FIELD_ATTRIBUTE_FAM_AND_ASSEM:
+ if (mono_class_has_parent (access_klass, member_klass) &&
+ can_access_internals (access_klass->image->assembly, member_klass->image->assembly))
+ return TRUE;
+ return FALSE;
+ case FIELD_ATTRIBUTE_ASSEMBLY:
+ return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
+ case FIELD_ATTRIBUTE_FAMILY:
+ if (mono_class_has_parent (access_klass, member_klass))
+ return TRUE;
+ return FALSE;
+ case FIELD_ATTRIBUTE_FAM_OR_ASSEM:
+ if (mono_class_has_parent (access_klass, member_klass))
+ return TRUE;
+ return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
+ case FIELD_ATTRIBUTE_PUBLIC:
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static gboolean
+can_access_field (MonoMethod *method, MonoClassField *field)
+{
+ /* FIXME: check all overlapping fields */
+ int can = can_access_member (method->klass, field->parent, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
+ if (!can) {
+ MonoClass *nested = method->klass->nested_in;
+ while (nested) {
+ can = can_access_member (nested, field->parent, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
+ if (can)
+ return TRUE;
+ nested = nested->nested_in;
+ }
+ }
+ return can;
+}
+
+static gboolean
+can_access_method (MonoMethod *method, MonoMethod *called)
+{
+ int can = can_access_member (method->klass, called->klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
+ if (!can) {
+ MonoClass *nested = method->klass->nested_in;
+ while (nested) {
+ can = can_access_member (nested, called->klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
+ if (can)
+ return TRUE;
+ nested = nested->nested_in;
+ }
+ }
+ /*
+ * FIXME:
+ * with generics calls to explicit interface implementations can be expressed
+ * directly: the method is private, but we must allow it. This may be opening
+ * a hole or the generics code should handle this differently.
+ * Maybe just ensure the interface type is public.
+ */
+ if ((called->flags & METHOD_ATTRIBUTE_VIRTUAL) && (called->flags & METHOD_ATTRIBUTE_FINAL))
+ return TRUE;
+ return can;
+}
/*
* mono_method_to_ir: translates IL into basic blocks containing trees
MonoSecurityManager* secman = NULL;
MonoDeclSecurityActions actions;
GSList *class_inits = NULL;
+ gboolean dont_verify, dont_verify_stloc;
+
+ /* serialization and xdomain stuff may need access to private fields and methods */
+ dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
+ dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
+ dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
+ dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
+
+ /* still some type unsefety issues in marshal wrappers... (unknown is PtrToStructure) */
+ dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
+ dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
+ dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
+
+ /* Not turned on yet */
+ cfg->dont_verify_stack_merge = TRUE;
image = method->klass->image;
header = mono_method_get_header (method);
dont_inline = g_list_prepend (dont_inline, method);
if (cfg->method == method) {
- if (cfg->method->save_lmf)
- /* Needed by the prolog code */
- mono_get_got_var (cfg);
-
if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
tblock->in_scount = 1;
tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
+ tblock->stack_state = mono_mempool_alloc (cfg->mempool, sizeof (MonoStackSlot));
+ tblock->stack_state [0].type = STACK_OBJ;
+ /* FIXME? */
+ tblock->stack_state [0].klass = mono_defaults.object_class;
/*
* Add a dummy use for the exvar so its liveness info will be
tblock->real_offset = clause->data.filter_offset;
tblock->in_scount = 1;
tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
+ tblock->stack_state = mono_mempool_alloc (cfg->mempool, sizeof (MonoStackSlot));
+ tblock->stack_state [0].type = STACK_OBJ;
+ /* FIXME? */
+ tblock->stack_state [0].klass = mono_defaults.object_class;
+
/* The filter block shares the exvar with the handler block */
tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
if (get_basic_blocks (cfg, bbhash, header, real_offset, ip, end, &err_pos)) {
ip = err_pos;
- goto unverified;
+ UNVERIFIED;
}
if (cfg->method == method)
param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
for (n = 0; n < sig->param_count; ++n)
param_types [n + sig->hasthis] = sig->params [n];
+ for (n = 0; n < header->num_locals; ++n) {
+ if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
+ UNVERIFIED;
+ }
class_inits = NULL;
/* do this somewhere outside - not here */
if (sp != stack_start) {
handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
sp = stack_start;
+ CHECK_UNVERIFIABLE (cfg);
}
bblock->next_bb = tblock;
bblock = tblock;
handle_loaded_temps (cfg, bblock, stack_start, sp);
NEW_LOCSTORE (cfg, ins, n, *sp);
ins->cil_code = ip;
+ if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
+ UNVERIFIED;
if (ins->opcode == CEE_STOBJ) {
NEW_LOCLOADA (cfg, ins, n);
- handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
+ handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
} else
MONO_ADD_INS (bblock, ins);
++ip;
NEW_ARGSTORE (cfg, ins, ip [1], *sp);
handle_loaded_temps (cfg, bblock, stack_start, sp);
ins->cil_code = ip;
+ if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
+ UNVERIFIED;
if (ins->opcode == CEE_STOBJ) {
NEW_ARGLOADA (cfg, ins, ip [1]);
- handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
+ handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
} else
MONO_ADD_INS (bblock, ins);
ip += 2;
CHECK_LOCAL (ip [1]);
NEW_LOCSTORE (cfg, ins, ip [1], *sp);
ins->cil_code = ip;
+ if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
+ UNVERIFIED;
if (ins->opcode == CEE_STOBJ) {
NEW_LOCLOADA (cfg, ins, ip [1]);
- handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
+ handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
} else
MONO_ADD_INS (bblock, ins);
ip += 2;
store->cil_code = ip;
if (store->opcode == CEE_STOBJ) {
NEW_TEMPLOADA (cfg, store, temp->inst_c0);
- handle_stobj (cfg, bblock, store, sp [0], sp [0]->cil_code, store->klass, TRUE, FALSE);
+ handle_stobj (cfg, bblock, store, sp [0], sp [0]->cil_code, store->klass, TRUE, FALSE, FALSE);
} else {
MONO_ADD_INS (bblock, store);
}
case CEE_JMP:
CHECK_OPSIZE (5);
if (stack_start != sp)
- goto unverified;
+ UNVERIFIED;
MONO_INST_NEW (cfg, ins, CEE_JMP);
token = read32 (ip + 1);
/* FIXME: check the signature matches */
goto load_error;
if (mono_use_security_manager) {
- check_linkdemand (cfg, method, cmethod, bblock, ip);
+ if (check_linkdemand (cfg, method, cmethod, bblock, ip))
+ INLINE_FAILURE;
}
ins->inst_p0 = cmethod;
if (!cmethod)
goto load_error;
+ if (!dont_verify && !can_access_method (method, cmethod))
+ UNVERIFIED;
if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
/* MS.NET seems to silently convert this to a callvirt */
virtual = 1;
- if (!cmethod->klass->inited)
- mono_class_init (cmethod->klass);
+ if (!cmethod->klass->inited){
+ if (!mono_class_init (cmethod->klass))
+ goto load_error;
+ }
if (mono_method_signature (cmethod)->pinvoke) {
MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod);
n = fsig->param_count + fsig->hasthis;
if (mono_use_security_manager) {
- check_linkdemand (cfg, method, cmethod, bblock, ip);
+ if (check_linkdemand (cfg, method, cmethod, bblock, ip))
+ INLINE_FAILURE;
}
if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
}
- if (!virtual) {
- mono_get_got_var (cfg);
- } else {
- /* code in inssel.brg might transform a virtual call to a normal call */
- if (!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
- ((cmethod->flags & METHOD_ATTRIBUTE_FINAL) &&
- cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK))
- mono_get_got_var (cfg);
- }
-
- if (cmethod && cmethod->klass->generic_container) {
- // G_BREAKPOINT ();
- goto unverified;
- }
+ if (cmethod && cmethod->klass->generic_container)
+ UNVERIFIED;
CHECK_STACK (n);
ins->cil_code = ip;
ins->inst_i0 = sp [0];
ins->type = STACK_OBJ;
+ ins->klass = mono_class_from_mono_type (&constrained_call->byval_arg);
sp [0] = ins;
} else if (cmethod->klass->valuetype)
virtual = 0;
constrained_call = NULL;
}
- if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp)) {
- // G_BREAKPOINT ();
- goto unverified;
- }
+ if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp))
+ UNVERIFIED;
if (cmethod && virtual &&
(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
MonoInst *iargs [3];
g_assert (mono_method_signature (cmethod)->is_inflated);
+ /* Prevent inlining of methods that contain indirect calls */
+ INLINE_FAILURE;
this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
this_temp->cil_code = ip;
NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
NEW_PCONST (cfg, iargs [1], cmethod);
NEW_PCONST (cfg, iargs [2], ((MonoMethodInflated *) cmethod)->context);
- temp = mono_emit_jit_icall (cfg, bblock, helper_compile_generic_method, iargs, ip);
+ temp = mono_emit_jit_icall (cfg, bblock, mono_helper_compile_generic_method, iargs, ip);
NEW_TEMPLOAD (cfg, addr, temp);
NEW_TEMPLOAD (cfg, sp [0], this_temp->inst_c0);
if ((ins_flag & MONO_INST_TAILCALL) && cmethod && (*ip == CEE_CALL) &&
(mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)))) {
int i;
+ /* Prevent inlining of methods with tail calls (the call stack would be altered) */
+ INLINE_FAILURE;
/* FIXME: This assumes the two methods has the same number and type of arguments */
for (i = 0; i < n; ++i) {
/* Check if argument is the same */
ins->cil_code = ip;
if (ins->opcode == CEE_STOBJ) {
NEW_ARGLOADA (cfg, ins, i);
- handle_stobj (cfg, bblock, ins, sp [i], sp [i]->cil_code, ins->klass, FALSE, FALSE);
+ handle_stobj (cfg, bblock, ins, sp [i], sp [i]->cil_code, ins->klass, FALSE, FALSE, FALSE);
}
else
MONO_ADD_INS (bblock, ins);
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);
allways = TRUE;
}
gboolean has_vtargs = FALSE;
int i;
+ /* Prevent inlining of methods with tail calls (the call stack would be altered) */
+ INLINE_FAILURE;
/* keep it simple */
for (i = fsig->param_count - 1; i >= 0; i--) {
if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i]))
}
if (*ip == CEE_CALLI) {
-
+ /* Prevent inlining of methods with indirect calls */
+ INLINE_FAILURE;
if ((temp = mono_emit_calli (cfg, bblock, fsig, sp, addr, ip)) != -1) {
NEW_TEMPLOAD (cfg, *sp, temp);
sp++;
- }
-
+ }
} else if (array_rank) {
MonoInst *addr;
* the same MonoInst is added to two different trees and this is not
* allowed by burg.
*/
- mono_emit_jit_icall (cfg, bblock, helper_stelem_ref_check, iargs, ip);
+ mono_emit_jit_icall (cfg, bblock, mono_helper_stelem_ref_check, iargs, ip);
NEW_TEMPLOAD (cfg, sp [0], array->inst_c0);
NEW_TEMPLOAD (cfg, sp [fsig->param_count], to_store->inst_c0);
NEW_INDSTORE (cfg, ins, addr, sp [fsig->param_count], fsig->params [fsig->param_count - 1]);
ins->cil_code = ip;
if (ins->opcode == CEE_STOBJ) {
- handle_stobj (cfg, bblock, addr, sp [fsig->param_count], ip, mono_class_from_mono_type (fsig->params [fsig->param_count-1]), FALSE, FALSE);
+ handle_stobj (cfg, bblock, addr, sp [fsig->param_count], ip, mono_class_from_mono_type (fsig->params [fsig->param_count-1]), FALSE, FALSE, TRUE);
} else {
MONO_ADD_INS (bblock, ins);
}
}
} else {
+ /* Prevent inlining of methods which call other methods */
+ INLINE_FAILURE;
if (ip_in_bb (cfg, bblock, ip + 5)
&& (!MONO_TYPE_ISSTRUCT (fsig->ret))
&& (!MONO_TYPE_IS_VOID (fsig->ret) || cmethod->string_ctor)
if (store->opcode == CEE_STOBJ) {
g_assert_not_reached ();
NEW_TEMPLOADA (cfg, store, return_var->inst_c0);
- handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, return_var->klass, FALSE, FALSE);
+ /* FIXME: it is possible some optimization will pass the a heap pointer for the struct address, so we'll need the write barrier */
+ handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, return_var->klass, FALSE, FALSE, FALSE);
} else
MONO_ADD_INS (bblock, store);
}
ins->opcode = mono_type_to_stind (mono_method_signature (method)->ret);
if (ins->opcode == CEE_STOBJ) {
NEW_RETLOADA (cfg, ins);
- handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
+ /* FIXME: it is possible some optimization will pass the a heap pointer for the struct address, so we'll need the write barrier */
+ handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
} else {
ins->opcode = OP_SETRET;
ins->cil_code = ip;
}
}
if (sp != stack_start)
- goto unverified;
+ UNVERIFIED;
MONO_INST_NEW (cfg, ins, CEE_BR);
ins->cil_code = ip++;
ins->inst_target_bb = end_bblock;
if (sp != stack_start) {
handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
sp = stack_start;
+ CHECK_UNVERIFIABLE (cfg);
}
start_new_bblock = 1;
- inline_costs += 10;
+ inline_costs += BRANCH_COST;
break;
case CEE_BRFALSE_S:
case CEE_BRTRUE_S:
CHECK_OPSIZE (2);
CHECK_STACK (1);
if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
- goto unverified;
+ UNVERIFIED;
MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
ins->cil_code = ip++;
target = ip + 1 + *(signed char*)ip;
if (sp != stack_start) {
handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
sp = stack_start;
+ CHECK_UNVERIFIABLE (cfg);
}
- inline_costs += 10;
+ inline_costs += BRANCH_COST;
break;
case CEE_BEQ_S:
case CEE_BGE_S:
if (sp != stack_start) {
handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
sp = stack_start;
+ CHECK_UNVERIFIABLE (cfg);
}
- inline_costs += 10;
+ inline_costs += BRANCH_COST;
break;
case CEE_BR:
CHECK_OPSIZE (5);
if (sp != stack_start) {
handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
sp = stack_start;
+ CHECK_UNVERIFIABLE (cfg);
}
start_new_bblock = 1;
- inline_costs += 10;
+ inline_costs += BRANCH_COST;
break;
case CEE_BRFALSE:
case CEE_BRTRUE:
CHECK_OPSIZE (5);
CHECK_STACK (1);
if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
- goto unverified;
+ UNVERIFIED;
MONO_INST_NEW (cfg, ins, *ip);
ins->cil_code = ip++;
target = ip + 4 + (gint32)read32(ip);
if (sp != stack_start) {
handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
sp = stack_start;
+ CHECK_UNVERIFIABLE (cfg);
}
- inline_costs += 10;
+ inline_costs += BRANCH_COST;
break;
case CEE_BEQ:
case CEE_BGE:
if (sp != stack_start) {
handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
sp = stack_start;
+ CHECK_UNVERIFIABLE (cfg);
}
- inline_costs += 10;
+ inline_costs += BRANCH_COST;
break;
case CEE_SWITCH:
CHECK_OPSIZE (5);
--sp;
ins->inst_left = *sp;
if ((ins->inst_left->type != STACK_I4) && (ins->inst_left->type != STACK_PTR))
- goto unverified;
+ UNVERIFIED;
ins->cil_code = ip;
ip += 5;
CHECK_OPSIZE (n * sizeof (guint32));
if (sp != stack_start) {
handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
sp = stack_start;
+ CHECK_UNVERIFIABLE (cfg);
}
/* Needed by the code generated in inssel.brg */
mono_get_got_var (cfg);
- inline_costs += 20;
+ inline_costs += (BRANCH_COST * 2);
break;
case CEE_LDIND_I1:
case CEE_LDIND_U1:
ins->type = ldind_type [*ip - CEE_LDIND_I1];
ins->flags |= ins_flag;
ins_flag = 0;
+ if (ins->type == STACK_OBJ)
+ ins->klass = mono_defaults.object_class;
++ip;
break;
case CEE_STIND_REF:
case CEE_STIND_R4:
case CEE_STIND_R8:
CHECK_STACK (2);
+#if HAVE_WRITE_BARRIERS
+ if (*ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER) {
+ /* insert call to write barrier */
+ MonoMethod *write_barrier = mono_marshal_get_write_barrier ();
+ sp -= 2;
+ mono_emit_method_call_spilled (cfg, bblock, write_barrier, mono_method_signature (write_barrier), sp, ip, NULL);
+ ip++;
+ break;
+ }
+#endif
MONO_INST_NEW (cfg, ins, *ip);
ins->cil_code = ip++;
sp -= 2;
if (mono_find_jit_opcode_emulation (ins->opcode)) {
--sp;
*sp++ = emit_tree (cfg, bblock, ins, ip + 1);
- mono_get_got_var (cfg);
}
ip++;
break;
if (mono_find_jit_opcode_emulation (ins->opcode)) {
--sp;
*sp++ = emit_tree (cfg, bblock, ins, ip + 1);
- mono_get_got_var (cfg);
}
ip++;
break;
if (mono_find_jit_opcode_emulation (ins->opcode)) {
--sp;
*sp++ = emit_tree (cfg, bblock, ins, ip + 1);
- mono_get_got_var (cfg);
}
ip++;
break;
load->cil_code = ip;
load->inst_i0 = sp [1];
load->type = STACK_OBJ;
+ load->klass = klass;
load->flags |= ins_flag;
MONO_INST_NEW (cfg, store, CEE_STIND_REF);
store->cil_code = ip;
ins->cil_code = ip;
ins->inst_i0 = sp [0];
ins->type = STACK_OBJ;
+ ins->klass = klass;
ins->flags |= ins_flag;
ins_flag = 0;
*sp++ = ins;
ins->cil_code = ip;
g_assert (ins->opcode == CEE_STOBJ);
NEW_LOCLOADA (cfg, ins, loc_index);
- handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
+ handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
ip += 5;
ip += stloc_len;
break;
NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
ins->cil_code = ip;
ins->type = STACK_OBJ;
+ ins->klass = mono_defaults.string_class;
*sp = ins;
}
else if (method->wrapper_type != MONO_WRAPPER_NONE) {
MonoInst *iargs [2];
int temp;
- /* Avoid creating the string object */
- NEW_IMAGECONST (cfg, iargs [0], image);
- NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
- temp = mono_emit_jit_icall (cfg, bblock, helper_ldstr, iargs, ip);
+ if (cfg->compile_aot && cfg->method->klass->image == mono_defaults.corlib) {
+ /*
+ * Avoid relocations by using a version of helper_ldstr
+ * specialized to mscorlib.
+ */
+ NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
+ temp = mono_emit_jit_icall (cfg, bblock, mono_helper_ldstr_mscorlib, iargs, ip);
+ } else {
+ /* Avoid creating the string object */
+ NEW_IMAGECONST (cfg, iargs [0], image);
+ NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
+ temp = mono_emit_jit_icall (cfg, bblock, mono_helper_ldstr, iargs, ip);
+ }
NEW_TEMPLOAD (cfg, *sp, temp);
}
else
ins->cil_code = ip;
ins->type = STACK_OBJ;
ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
+ ins->klass = mono_defaults.string_class;
*sp = ins;
}
}
goto load_error;
fsig = mono_method_get_signature (cmethod, image, token);
- mono_class_init (cmethod->klass);
+ if (!mono_class_init (cmethod->klass))
+ goto load_error;
if (mono_use_security_manager) {
- check_linkdemand (cfg, method, cmethod, bblock, ip);
+ if (check_linkdemand (cfg, method, cmethod, bblock, ip))
+ INLINE_FAILURE;
}
n = fsig->param_count;
/*
* The code generated by mini_emit_virtual_call () expects
* iargs [0] to be a boxed instance, but luckily the vcall
- * will be transformed into a normal call there. The AOT
- * case needs an already allocate got_var.
+ * will be transformed into a normal call there.
*/
- mono_get_got_var (cfg);
} else {
temp = handle_alloc (cfg, bblock, cmethod->klass, FALSE, ip);
NEW_TEMPLOAD (cfg, *sp, temp);
break;
} else {
+ /* Prevent inlining of methods which call other methods */
+ INLINE_FAILURE;
mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, callvirt_this_arg);
}
} else {
+ /* Prevent inlining of methods which call other methods */
+ INLINE_FAILURE;
/* now call the actual ctor */
mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, callvirt_this_arg);
}
if (!klass)
goto load_error;
if (sp [0]->type != STACK_OBJ)
- goto unverified;
+ UNVERIFIED;
/* Needed by the code generated in inssel.brg */
mono_get_got_var (cfg);
add->inst_left = ins;
add->inst_right = vtoffset;
add->type = STACK_MP;
+ add->klass = mono_defaults.object_class;
*sp = add;
ip += 5;
/* LDOBJ impl */
add->inst_left = ins;
add->inst_right = vtoffset;
add->type = STACK_MP;
+ add->klass = klass;
*sp++ = add;
ip += 5;
inline_costs += 2;
if (!klass)
goto load_error;
if (sp [0]->type != STACK_OBJ)
- goto unverified;
+ UNVERIFIED;
/* Needed by the code generated in inssel.brg */
mono_get_got_var (cfg);
link_bblock (cfg, bblock, end_bblock);
start_new_bblock = 1;
- mono_get_got_var (cfg);
break;
case CEE_LDFLD:
case CEE_LDFLDA:
--sp;
}
if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
- goto unverified;
+ UNVERIFIED;
if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
- goto unverified;
+ UNVERIFIED;
CHECK_OPSIZE (5);
token = read32 (ip + 1);
if (method->wrapper_type != MONO_WRAPPER_NONE) {
if (!field)
goto load_error;
mono_class_init (klass);
+ if (!dont_verify && !can_access_field (method, field))
+ UNVERIFIED;
foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
/* FIXME: mark instructions for use in SSA */
if (*ip == CEE_STFLD) {
if (target_type_is_incompatible (cfg, field->type, sp [1]))
- goto unverified;
+ UNVERIFIED;
if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type);
MonoInst *iargs [5];
} else {
mono_emit_method_call_spilled (cfg, bblock, stfld_wrapper, mono_method_signature (stfld_wrapper), iargs, ip, NULL);
}
+#if HAVE_WRITE_BARRIERS
+ } else if (mono_type_to_stind (field->type) == CEE_STIND_REF) {
+ /* insert call to write barrier */
+ MonoMethod *write_barrier = mono_marshal_get_write_barrier ();
+ MonoInst *iargs [2];
+ NEW_ICONST (cfg, offset_ins, foffset);
+ MONO_INST_NEW (cfg, ins, OP_PADD);
+ ins->cil_code = ip;
+ ins->inst_left = *sp;
+ ins->inst_right = offset_ins;
+ ins->type = STACK_MP;
+ ins->klass = mono_defaults.object_class;
+ iargs [0] = ins;
+ iargs [1] = sp [1];
+ mono_emit_method_call_spilled (cfg, bblock, write_barrier, mono_method_signature (write_barrier), iargs, ip, NULL);
+#endif
} else {
MonoInst *store;
NEW_ICONST (cfg, offset_ins, foffset);
ins_flag = 0;
if (store->opcode == CEE_STOBJ) {
handle_stobj (cfg, bblock, ins, sp [1], ip,
- mono_class_from_mono_type (field->type), FALSE, FALSE);
+ mono_class_from_mono_type (field->type), FALSE, FALSE, TRUE);
} else
MONO_ADD_INS (bblock, store);
}
ins->type = STACK_MP;
if (*ip == CEE_LDFLDA) {
+ ins->klass = mono_class_from_mono_type (field->type);
*sp++ = ins;
} else {
MonoInst *load;
g_print ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, field->name);
class_inits = g_slist_prepend (class_inits, vtable);
} else {
- if (cfg->run_cctors)
+ if (cfg->run_cctors) {
+ /* This makes so that inline cannot trigger */
+ /* .cctors: too many apps depend on them */
+ /* running with a specific order... */
+ if (! vtable->initialized)
+ INLINE_FAILURE;
mono_runtime_class_init (vtable);
+ }
}
addr = (char*)vtable->data + field->offset;
/* FIXME: mark instructions for use in SSA */
if (*ip == CEE_LDSFLDA) {
+ ins->klass = mono_class_from_mono_type (field->type);
*sp++ = ins;
} else if (*ip == CEE_STSFLD) {
MonoInst *store;
ins_flag = 0;
if (store->opcode == CEE_STOBJ) {
- handle_stobj (cfg, bblock, ins, sp [0], ip, mono_class_from_mono_type (field->type), FALSE, FALSE);
+ handle_stobj (cfg, bblock, ins, sp [0], ip, mono_class_from_mono_type (field->type), FALSE, FALSE, FALSE);
} else
MONO_ADD_INS (bblock, store);
} else {
NEW_ICONST (cfg, *sp, *((guint32 *)addr));
sp++;
break;
+#ifndef HAVE_MOVING_COLLECTOR
case MONO_TYPE_I:
case MONO_TYPE_U:
case MONO_TYPE_STRING:
type_to_eval_stack_type (field->type, *sp);
sp++;
break;
+#endif
case MONO_TYPE_I8:
case MONO_TYPE_U8:
MONO_INST_NEW (cfg, *sp, OP_I8CONST);
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);
+ handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE, TRUE);
} else {
/* FIXME: should check item at sp [1] is compatible with the type of the store. */
MonoInst *store;
ip += 5;
break;
}
+ if (klass == mono_defaults.void_class)
+ UNVERIFIED;
if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
- goto unverified;
+ UNVERIFIED;
/* frequent check in generic code: box (struct), brtrue */
- if (ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) && (ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S)) {
+ if (!mono_class_is_nullable (klass) &&
+ ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) && (ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S)) {
/*g_print ("box-brtrue opt at 0x%04x in %s\n", real_offset, method->name);*/
MONO_INST_NEW (cfg, ins, CEE_POP);
MONO_ADD_INS (bblock, ins);
if (sp != stack_start) {
handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
sp = stack_start;
+ CHECK_UNVERIFIABLE (cfg);
}
start_new_bblock = 1;
break;
ins->inst_newa_class = klass;
ins->inst_newa_len = *sp;
ins->type = STACK_OBJ;
+ ins->klass = klass;
ip += 5;
*sp++ = ins;
/*
CHECK_STACK (1);
--sp;
if (sp [0]->type != STACK_OBJ)
- goto unverified;
+ UNVERIFIED;
MONO_INST_NEW (cfg, ins, *ip);
ins->cil_code = ip++;
ins->inst_left = *sp;
sp -= 2;
CHECK_OPSIZE (5);
if (sp [0]->type != STACK_OBJ)
- goto unverified;
+ UNVERIFIED;
klass = mini_get_class (method, read32 (ip + 1), generic_context);
if (!klass)
check->klass = klass;
check->inst_left = sp [0];
check->type = STACK_OBJ;
+ check->klass = klass;
sp [0] = check;
}
CHECK_STACK (2);
sp -= 2;
if (sp [0]->type != STACK_OBJ)
- goto unverified;
+ UNVERIFIED;
CHECK_OPSIZE (5);
token = read32 (ip + 1);
klass = mono_class_get_full (image, token, generic_context);
CHECK_STACK (2);
sp -= 2;
if (sp [0]->type != STACK_OBJ)
- goto unverified;
+ UNVERIFIED;
klass = array_access_to_klass (*ip);
NEW_LDELEMA (cfg, load, sp, klass);
load->cil_code = ip;
ins->inst_left = load;
*sp++ = ins;
ins->type = ldind_type [ins->opcode - CEE_LDIND_I1];
+ ins->klass = klass;
++ip;
break;
}
CHECK_STACK (3);
sp -= 3;
if (sp [0]->type != STACK_OBJ)
- goto unverified;
+ UNVERIFIED;
klass = array_access_to_klass (*ip);
NEW_LDELEMA (cfg, load, sp, klass);
load->cil_code = ip;
CHECK_STACK (3);
sp -= 3;
if (sp [0]->type != STACK_OBJ)
- goto unverified;
+ UNVERIFIED;
CHECK_OPSIZE (5);
token = read32 (ip + 1);
klass = mono_class_get_full (image, token, generic_context);
n = mono_type_to_stind (&klass->byval_arg);
if (n == CEE_STOBJ)
- handle_stobj (cfg, bblock, load, sp [2], ip, klass, FALSE, FALSE);
+ handle_stobj (cfg, bblock, load, sp [2], ip, klass, FALSE, FALSE, TRUE);
else {
MONO_INST_NEW (cfg, ins, n);
ins->cil_code = ip;
CHECK_STACK (3);
sp -= 3;
if (sp [0]->type != STACK_OBJ)
- goto unverified;
+ UNVERIFIED;
if (sp [2]->type != STACK_OBJ)
- goto unverified;
+ UNVERIFIED;
handle_loaded_temps (cfg, bblock, stack_start, sp);
if (mono_find_jit_opcode_emulation (ins->opcode)) {
--sp;
*sp++ = emit_tree (cfg, bblock, ins, ip + 1);
- mono_get_got_var (cfg);
}
ip++;
break;
for (i = 0; i < header->num_clauses; ++i) {
MonoExceptionClause *clause = &header->clauses [i];
- if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) && (ip - header->code + ((*ip == CEE_LEAVE) ? 5 : 2)) == (clause->handler_offset + clause->handler_len)) {
+ /*
+ * Use <= in the final comparison to handle clauses with multiple
+ * leave statements, like in bug #78024.
+ * The ordering of the exception clauses guarantees that we find the
+ * innermost clause.
+ */
+ if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) && (ip - header->code + ((*ip == CEE_LEAVE) ? 5 : 2)) <= (clause->handler_offset + clause->handler_len)) {
int temp;
MonoInst *load;
klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
NEW_RETLOADA (cfg, ins);
- handle_stobj (cfg, bblock, ins, *sp, ip, klass, FALSE, TRUE);
+ handle_stobj (cfg, bblock, ins, *sp, ip, klass, FALSE, TRUE, FALSE);
if (sp != stack_start)
- goto unverified;
+ UNVERIFIED;
MONO_INST_NEW (cfg, ins, CEE_BR);
ins->cil_code = ip;
mono_class_init (cmethod->klass);
if (mono_use_security_manager) {
- check_linkdemand (cfg, method, cmethod, bblock, ip);
+ if (check_linkdemand (cfg, method, cmethod, bblock, ip))
+ INLINE_FAILURE;
}
handle_loaded_temps (cfg, bblock, stack_start, sp);
mono_class_init (cmethod->klass);
if (mono_use_security_manager) {
- check_linkdemand (cfg, method, cmethod, bblock, ip);
+ if (check_linkdemand (cfg, method, cmethod, bblock, ip))
+ INLINE_FAILURE;
}
handle_loaded_temps (cfg, bblock, stack_start, sp);
CHECK_ARG (n);
NEW_ARGSTORE (cfg, ins, n, *sp);
ins->cil_code = ip;
+ if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
+ UNVERIFIED;
if (ins->opcode == CEE_STOBJ) {
NEW_ARGLOADA (cfg, ins, n);
- handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
+ handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
} else
MONO_ADD_INS (bblock, ins);
ip += 4;
CHECK_LOCAL (n);
handle_loaded_temps (cfg, bblock, stack_start, sp);
NEW_LOCSTORE (cfg, ins, n, *sp);
+ if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
+ UNVERIFIED;
ins->cil_code = ip;
if (ins->opcode == CEE_STOBJ) {
NEW_LOCLOADA (cfg, ins, n);
- handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
+ handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
} else
MONO_ADD_INS (bblock, ins);
ip += 4;
CHECK_STACK (1);
--sp;
if (sp != stack_start)
- goto unverified;
+ UNVERIFIED;
if (cfg->method != method)
/*
* Inlining this into a loop in a parent could lead to
MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
ins->inst_left = *sp;
ins->cil_code = ip;
- ins->type = STACK_MP;
+ ins->type = STACK_PTR;
cfg->flags |= MONO_CFG_HAS_ALLOCA;
if (header->init_locals)
CHECK_STACK (1);
--sp;
if ((sp != stack_start) || (sp [0]->type != STACK_I4))
- goto unverified;
+ UNVERIFIED;
MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
ins->inst_left = *sp;
ins->cil_code = ip;
}
g_assert (nearest);
if ((ip - header->code) != nearest->handler_offset)
- goto unverified;
+ UNVERIFIED;
break;
}
NEW_PCONST (cfg, load, NULL);
load->cil_code = ip;
load->type = STACK_OBJ;
+ load->klass = klass;
MONO_INST_NEW (cfg, store, CEE_STIND_REF);
store->cil_code = ip;
handle_loaded_temps (cfg, bblock, stack_start, sp);
link_bblock (cfg, bblock, end_bblock);
start_new_bblock = 1;
ip += 2;
- mono_get_got_var (cfg);
break;
}
case CEE_SIZEOF:
}
}
if (start_new_bblock != 1)
- goto unverified;
+ UNVERIFIED;
bblock->cil_length = ip - bblock->cil_code;
bblock->next_bb = end_bblock;
g_slist_free (class_inits);
dont_inline = g_list_remove (dont_inline, method);
+
+ if (inline_costs < 0) {
+ char *mname;
+
+ /* Method is too large */
+ mname = mono_method_full_name (method, TRUE);
+ cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
+ cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
+ g_free (mname);
+ return -1;
+ }
+
return inline_costs;
inline_failure:
{
char *name;
MonoMethod *wrapper;
- gconstpointer code;
- if (callinfo->wrapper)
+ if (callinfo->wrapper) {
return callinfo->wrapper;
-
+ }
+
+ if (callinfo->trampoline)
+ return callinfo->trampoline;
+
name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func);
- /* Must be domain neutral since there is only one copy */
- code = mono_jit_compile_method_with_opt (wrapper, default_opt | MONO_OPT_SHARED);
+ g_free (name);
- if (!callinfo->wrapper) {
- callinfo->wrapper = code;
- mono_register_jit_icall_wrapper (callinfo, code);
- mono_debug_add_icall_wrapper (wrapper, callinfo);
- }
+ callinfo->trampoline = mono_create_ftnptr (mono_get_root_domain (), mono_create_jit_trampoline_in_domain (mono_get_root_domain (), wrapper));
+ mono_register_jit_icall_wrapper (callinfo, callinfo->trampoline);
- g_free (name);
- return callinfo->wrapper;
+ return callinfo->trampoline;
}
static void
mono_trampoline_code [MONO_TRAMPOLINE_CLASS_INIT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT);
#ifdef MONO_ARCH_HAVE_PIC_AOT
mono_trampoline_code [MONO_TRAMPOLINE_AOT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_AOT);
+ mono_trampoline_code [MONO_TRAMPOLINE_AOT_PLT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_AOT_PLT);
#endif
#ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
mono_trampoline_code [MONO_TRAMPOLINE_DELEGATE] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_DELEGATE);
#ifdef MONO_ARCH_HAVE_CREATE_SPECIFIC_TRAMPOLINE
code = mono_arch_create_specific_trampoline (method, MONO_TRAMPOLINE_JUMP, mono_domain_get (), &code_size);
- ji = g_new0 (MonoJitInfo, 1);
+ mono_domain_lock (domain);
+ ji = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
+ mono_domain_unlock (domain);
ji->code_start = code;
ji->code_size = code_size;
ji->method = method;
return ji->code_start;
}
-gpointer
-mono_create_jit_trampoline (MonoMethod *method)
+static gpointer
+mono_create_jit_trampoline_in_domain (MonoDomain *domain, MonoMethod *method)
{
- MonoDomain *domain = mono_domain_get ();
gpointer tramp;
mono_domain_lock (domain);
return mono_create_jit_trampoline (mono_marshal_get_synchronized_wrapper (method));
#ifdef MONO_ARCH_HAVE_CREATE_SPECIFIC_TRAMPOLINE
- tramp = mono_arch_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC, mono_domain_get (), NULL);
+ tramp = mono_arch_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC, domain, NULL);
#else
tramp = mono_arch_create_jit_trampoline (method);
#endif
return tramp;
}
+gpointer
+mono_create_jit_trampoline (MonoMethod *method)
+{
+ return mono_create_jit_trampoline_in_domain (mono_domain_get (), method);
+}
+
#ifdef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN
gpointer
mono_create_jit_trampoline_from_token (MonoImage *image, guint32 token)
}
#endif
-gpointer
+static gpointer
mono_create_delegate_trampoline (MonoMethod *method, gpointer addr)
{
#ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
* efficient copying (and to work around the fact that OP_MEMCPY
* and OP_MEMSET ignores alignment).
*/
- if (t->type == MONO_TYPE_VALUETYPE)
+ if (MONO_TYPE_ISSTRUCT (t))
align = sizeof (gpointer);
if (backward) {
g_free (jit_tls->first_lmf);
g_free (jit_tls);
thread->jit_data = NULL;
+ TlsSetValue (mono_jit_tls_id, NULL);
}
}
mono_class_init (patch_info->data.klass);
target = GINT_TO_POINTER ((int)patch_info->data.klass->interface_id);
break;
+ case MONO_PATCH_INFO_ADJUSTED_IID:
+ mono_class_init (patch_info->data.klass);
+ target = GINT_TO_POINTER ((int)(-((patch_info->data.klass->interface_id + 1) * SIZEOF_VOID_P)));
+ break;
case MONO_PATCH_INFO_VTABLE:
target = mono_class_vtable (domain, patch_info->data.klass);
break;
}
}
-static void
-replace_or_add_in_block (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
-{
- gboolean found = FALSE;
- int i;
-
- for (i = 0; i < bb->in_count; i++) {
- MonoBasicBlock *ib = bb->in_bb [i];
- if (ib == orig) {
- if (!repl) {
- if (bb->in_count > 1) {
- bb->in_bb [i] = bb->in_bb [bb->in_count - 1];
- }
- bb->in_count--;
- } else {
- bb->in_bb [i] = repl;
- }
- found = TRUE;
- }
- }
-
- if (! found) {
- MonoBasicBlock **new_in_bb = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (bb->in_count + 1));
- for (i = 0; i < bb->in_count; i++) {
- new_in_bb [i] = bb->in_bb [i];
- }
- new_in_bb [i] = repl;
- bb->in_count++;
- bb->in_bb = new_in_bb;
- }
-}
-
-
static void
replace_out_block_in_code (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl) {
MonoInst *inst;
MonoInst *inst;
/* Do not touch handlers */
- if (bb->region != -1) return FALSE;
+ if (bb->region != -1) {
+ bb->not_useless = TRUE;
+ return FALSE;
+ }
for (inst = bb->code; inst != NULL; inst = inst->next) {
switch (inst->opcode) {
target_bb = inst->inst_target_bb;
break;
default:
+ bb->not_useless = TRUE;
return FALSE;
}
}
if ((previous_bb == cfg->bb_entry) && (bb->next_bb != target_bb)) {
return FALSE;
}
+
+ /*
+ * Do not touch BBs following a try block as the code in
+ * mini_method_compile needs them to compute the length of the try block.
+ */
+ if (MONO_BBLOCK_IS_IN_REGION (previous_bb, MONO_REGION_TRY))
+ return FALSE;
/* Check that there is a target BB, and that bb is not an empty loop (Bug 75061) */
if ((target_bb != NULL) && (target_bb != bb)) {
printf ("remove_block_if_useless %s, removed BB%d\n", mono_method_full_name (cfg->method, TRUE), bb->block_num);
}
- for (i = 0; i < bb->in_count; i++) {
- MonoBasicBlock *in_bb = bb->in_bb [i];
- replace_out_block (in_bb, bb, target_bb);
+ /* unlink_bblock () modifies the bb->in_bb array so can't use a for loop here */
+ while (bb->in_count) {
+ MonoBasicBlock *in_bb = bb->in_bb [0];
+ mono_unlink_bblock (cfg, in_bb, bb);
+ link_bblock (cfg, in_bb, target_bb);
replace_out_block_in_code (in_bb, bb, target_bb);
- if (bb->in_count == 1) {
- replace_in_block (target_bb, bb, in_bb);
- } else {
- replace_or_add_in_block (cfg, target_bb, bb, in_bb);
- }
}
+ mono_unlink_bblock (cfg, bb, target_bb);
+
if ((previous_bb != cfg->bb_entry) &&
(previous_bb->region == bb->region) &&
((previous_bb->last_ins == NULL) ||
replace_basic_block (bb, bbn, bb);
+ /* Nullify branch at the end of bb */
+ if (bb->last_ins && MONO_IS_BRANCH_OP (bb->last_ins)) {
+ bb->last_ins->opcode = CEE_NOP;
+ }
+
if (bb->last_ins) {
if (bbn->code) {
bb->last_ins->next = bbn->code;
if (bb->region != -1)
continue;
- if (remove_block_if_useless (cfg, bb, previous_bb)) {
+ if (!bb->not_useless && remove_block_if_useless (cfg, bb, previous_bb)) {
changed = TRUE;
continue;
}
g_print ("block merge triggered %d -> %d\n", bb->block_num, bbn->block_num);
merge_basic_blocks (bb, bbn);
changed = TRUE;
+ continue;
}
//mono_print_bb_code (bb);
nullify_basic_block (bbn);
changed = TRUE;
- break;
+ continue;
}
-
if (bb->out_count == 1) {
bbn = bb->out_bb [0];
link_bblock (cfg, bb, bbn->code->inst_target_bb);
bb->last_ins->inst_target_bb = bbn->code->inst_target_bb;
changed = TRUE;
- break;
+ continue;
}
}
} else if (bb->out_count == 2) {
*/
bb->last_ins->opcode = CEE_BR;
bb->last_ins->inst_target_bb = taken_branch_target;
- replace_out_block (bb, untaken_branch_target, NULL);
- replace_in_block (untaken_branch_target, bb, NULL);
+ mono_unlink_bblock (cfg, bb, untaken_branch_target);
changed = TRUE;
- break;
+ continue;
}
bbn = bb->last_ins->inst_true_bb;
if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num,
bbn->code->opcode);
- bb->last_ins->inst_true_bb = bbn->code->inst_target_bb;
+ /*
+ * Unlink, then relink bblocks to avoid various
+ * tricky situations when the two targets of the branch
+ * are equal, or will become equal after the change.
+ */
+ mono_unlink_bblock (cfg, bb, bb->last_ins->inst_true_bb);
+ mono_unlink_bblock (cfg, bb, bb->last_ins->inst_false_bb);
- replace_in_block (bbn, bb, NULL);
- if (!bbn->in_count)
- replace_in_block (bbn->code->inst_target_bb, bbn, bb);
- replace_out_block (bb, bbn, bbn->code->inst_target_bb);
+ bb->last_ins->inst_true_bb = bbn->code->inst_target_bb;
- link_bblock (cfg, bb, bbn->code->inst_target_bb);
+ link_bblock (cfg, bb, bb->last_ins->inst_true_bb);
+ link_bblock (cfg, bb, bb->last_ins->inst_false_bb);
changed = TRUE;
- break;
+ continue;
}
bbn = bb->last_ins->inst_false_bb;
bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num,
bbn->code->opcode);
- bb->last_ins->inst_false_bb = bbn->code->inst_target_bb;
+ mono_unlink_bblock (cfg, bb, bb->last_ins->inst_true_bb);
+ mono_unlink_bblock (cfg, bb, bb->last_ins->inst_false_bb);
- replace_in_block (bbn, bb, NULL);
- if (!bbn->in_count)
- replace_in_block (bbn->code->inst_target_bb, bbn, bb);
- replace_out_block (bb, bbn, bbn->code->inst_target_bb);
+ bb->last_ins->inst_false_bb = bbn->code->inst_target_bb;
- link_bblock (cfg, bb, bbn->code->inst_target_bb);
+ link_bblock (cfg, bb, bb->last_ins->inst_true_bb);
+ link_bblock (cfg, bb, bb->last_ins->inst_false_bb);
changed = TRUE;
- break;
+ continue;
}
}
if (try_unsigned_compare (cfg, bb)) {
/*g_print ("applied in bb %d (->%d) %s\n", bb->block_num, bb->last_ins->inst_target_bb->block_num, mono_method_full_name (cfg->method, TRUE));*/
changed = TRUE;
- break;
+ continue;
}
}
*/
;
else {
- patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
- patch_info->data.name = info->name;
+ /* for these array methods we currently register the same function pointer
+ * since it's a vararg function. But this means that mono_find_jit_icall_by_addr ()
+ * will return the incorrect one depending on the order they are registered.
+ * See tests/test-arr.cs
+ */
+ if (strstr (info->name, "ves_array_new_va_") == NULL && strstr (info->name, "ves_array_element_address_") == NULL) {
+ patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
+ patch_info->data.name = info->name;
+ }
}
}
else {
if (cfg->verbose_level > 0) {
char* nm = mono_method_full_name (cfg->method, TRUE);
- g_print ("Method %s emitted at %p to %p [%s]\n",
+ g_print ("Method %s emitted at %p to %p (code length %d) [%s]\n",
nm,
- cfg->native_code, cfg->native_code + cfg->code_len, cfg->domain->friendly_name);
+ cfg->native_code, cfg->native_code + cfg->code_len, cfg->code_len, cfg->domain->friendly_name);
g_free (nm);
}
mono_debug_close_method (cfg);
}
-static void
-mono_cprop_copy_values (MonoCompile *cfg, MonoInst *tree, MonoInst **acp)
-{
- MonoInst *cp;
- int arity;
-
- if (tree->ssa_op == MONO_SSA_LOAD && (tree->inst_i0->opcode == OP_LOCAL || tree->inst_i0->opcode == OP_ARG) &&
- (cp = acp [tree->inst_i0->inst_c0]) && !tree->inst_i0->flags) {
-
- if (cp->opcode == OP_ICONST) {
- if (cfg->opt & MONO_OPT_CONSPROP) {
- //{ static int c = 0; printf ("CCOPY %d %d %s\n", c++, cp->inst_c0, mono_method_full_name (cfg->method, TRUE)); }
- *tree = *cp;
- }
- } else {
- if (tree->inst_i0->inst_vtype->type == cp->inst_vtype->type) {
- if (cfg->opt & MONO_OPT_COPYPROP) {
- //{ static int c = 0; printf ("VCOPY %d\n", ++c); }
- tree->inst_i0 = cp;
- }
- }
- }
- } else {
- arity = mono_burg_arity [tree->opcode];
-
- if (arity) {
- mono_cprop_copy_values (cfg, tree->inst_i0, acp);
- if (cfg->opt & MONO_OPT_CFOLD)
- mono_constant_fold_inst (tree, NULL);
- /* The opcode may have changed */
- if (mono_burg_arity [tree->opcode] > 1) {
- mono_cprop_copy_values (cfg, tree->inst_i1, acp);
- if (cfg->opt & MONO_OPT_CFOLD)
- mono_constant_fold_inst (tree, NULL);
- }
- mono_constant_fold_inst (tree, NULL);
- }
- }
-}
-
-static void
-mono_cprop_invalidate_values (MonoInst *tree, MonoInst **acp, int acp_size)
-{
- int arity;
-
- switch (tree->opcode) {
- case CEE_STIND_I:
- case CEE_STIND_I1:
- case CEE_STIND_I2:
- case CEE_STIND_I4:
- case CEE_STIND_REF:
- case CEE_STIND_I8:
- case CEE_STIND_R4:
- case CEE_STIND_R8:
- case CEE_STOBJ:
- if ((tree->ssa_op == MONO_SSA_NOP) || (tree->ssa_op & MONO_SSA_ADDRESS_TAKEN)) {
- memset (acp, 0, sizeof (MonoInst *) * acp_size);
- return;
- }
-
- break;
- case CEE_CALL:
- case OP_CALL_REG:
- case CEE_CALLVIRT:
- case OP_LCALL_REG:
- case OP_LCALLVIRT:
- case OP_LCALL:
- case OP_FCALL_REG:
- case OP_FCALLVIRT:
- case OP_FCALL:
- case OP_VCALL_REG:
- case OP_VCALLVIRT:
- case OP_VCALL:
- case OP_VOIDCALL_REG:
- case OP_VOIDCALLVIRT:
- case OP_VOIDCALL: {
- MonoCallInst *call = (MonoCallInst *)tree;
- MonoMethodSignature *sig = call->signature;
- int i, byref = FALSE;
-
- for (i = 0; i < sig->param_count; i++) {
- if (sig->params [i]->byref) {
- byref = TRUE;
- break;
- }
- }
-
- if (byref)
- memset (acp, 0, sizeof (MonoInst *) * acp_size);
-
- return;
- }
- default:
- break;
- }
-
- arity = mono_burg_arity [tree->opcode];
-
- switch (arity) {
- case 0:
- break;
- case 1:
- mono_cprop_invalidate_values (tree->inst_i0, acp, acp_size);
- break;
- case 2:
- mono_cprop_invalidate_values (tree->inst_i0, acp, acp_size);
- mono_cprop_invalidate_values (tree->inst_i1, acp, acp_size);
- break;
- default:
- g_assert_not_reached ();
- }
-}
-
-static void
-mono_local_cprop_bb (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **acp, int acp_size)
-{
- MonoInst *tree = bb->code;
- int i;
-
- if (!tree)
- return;
-
- for (; tree; tree = tree->next) {
-
- mono_cprop_copy_values (cfg, tree, acp);
-
- mono_cprop_invalidate_values (tree, acp, acp_size);
-
- if (tree->ssa_op == MONO_SSA_STORE &&
- (tree->inst_i0->opcode == OP_LOCAL || tree->inst_i0->opcode == OP_ARG)) {
- MonoInst *i1 = tree->inst_i1;
-
- acp [tree->inst_i0->inst_c0] = NULL;
-
- for (i = 0; i < acp_size; i++) {
- if (acp [i] && acp [i]->opcode != OP_ICONST &&
- acp [i]->inst_c0 == tree->inst_i0->inst_c0) {
- acp [i] = NULL;
- }
- }
-
- if (i1->opcode == OP_ICONST) {
- acp [tree->inst_i0->inst_c0] = i1;
- //printf ("DEF1 BB%d %d\n", bb->block_num,tree->inst_i0->inst_c0);
- }
- if (i1->ssa_op == MONO_SSA_LOAD &&
- (i1->inst_i0->opcode == OP_LOCAL || i1->inst_i0->opcode == OP_ARG) &&
- (i1->inst_i0->inst_c0 != tree->inst_i0->inst_c0)) {
- acp [tree->inst_i0->inst_c0] = i1->inst_i0;
- //printf ("DEF2 BB%d %d %d\n", bb->block_num,tree->inst_i0->inst_c0,i1->inst_i0->inst_c0);
- }
- }
-
- /*
- if (tree->opcode == CEE_BEQ) {
- g_assert (tree->inst_i0->opcode == OP_COMPARE);
- if (tree->inst_i0->inst_i0->opcode == OP_ICONST &&
- tree->inst_i0->inst_i1->opcode == OP_ICONST) {
-
- tree->opcode = CEE_BR;
- if (tree->inst_i0->inst_i0->opcode == tree->inst_i0->inst_i1->opcode) {
- tree->inst_target_bb = tree->inst_true_bb;
- } else {
- tree->inst_target_bb = tree->inst_false_bb;
- }
- }
- }
- */
- }
-}
-
-static void
-mono_local_cprop (MonoCompile *cfg)
-{
- MonoBasicBlock *bb;
- MonoInst **acp;
-
- acp = alloca (sizeof (MonoInst *) * cfg->num_varinfo);
- for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
- memset (acp, 0, sizeof (MonoInst *) * cfg->num_varinfo);
- mono_local_cprop_bb (cfg, bb, acp, cfg->num_varinfo);
- }
-}
static void
remove_critical_edges (MonoCompile *cfg) {
if (bbn && bbn->region == -1 && !bbn->dfn) {
if (cfg->verbose_level > 1)
- g_print ("found unreachabel code in BB%d\n", bbn->block_num);
+ g_print ("found unreachable code in BB%d\n", bbn->block_num);
bb->next_bb = bbn->next_bb;
nullify_basic_block (bbn);
} else {
if (parts == 3)
return cfg;
+ if (cfg->verbose_level > 4) {
+ printf ("BEFORE DECOMPSE START\n");
+ mono_print_code (cfg);
+ printf ("BEFORE DECOMPSE END\n");
+ }
+
decompose_pass (cfg);
if (cfg->got_var) {
}
static gpointer
-mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain)
+mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, int opt)
{
MonoCompile *cfg;
GHashTable *jit_code_hash;
gpointer code = NULL;
- guint32 opt;
MonoJitInfo *info;
- opt = default_opt;
-
jit_code_hash = target_domain->jit_code_hash;
method = mono_get_inflated_method (method);
mono_destroy_compile (cfg);
if (error) {
- MonoException *ex = mini_loader_error_to_exception (error);
- mono_loader_clear_error ();
+ MonoException *ex = mono_loader_error_prepare_exception (error);
mono_raise_exception (ex);
} else {
g_assert_not_reached ();
static gpointer
mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt)
{
- /* FIXME: later copy the code from mono */
MonoDomain *target_domain, *domain = mono_domain_get ();
MonoJitInfo *info;
gpointer p;
+ MonoJitICallInfo *callinfo = NULL;
+
+ /*
+ * ICALL wrappers are handled specially, since there is only one copy of them
+ * shared by all appdomains.
+ */
+ if ((method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && (strstr (method->name, "__icall_wrapper_") == method->name)) {
+ const char *icall_name;
+
+ icall_name = method->name + strlen ("__icall_wrapper_");
+ g_assert (icall_name);
+ callinfo = mono_find_jit_icall_by_name (icall_name);
+ g_assert (callinfo);
+
+ /* Must be domain neutral since there is only one copy */
+ opt |= MONO_OPT_SHARED;
+ }
if (opt & MONO_OPT_SHARED)
target_domain = mono_get_root_domain ();
}
mono_domain_unlock (target_domain);
- p = mono_jit_compile_method_inner (method, target_domain);
- return mono_create_ftnptr (target_domain, p);
+ p = mono_create_ftnptr (target_domain, mono_jit_compile_method_inner (method, target_domain, opt));
+
+ if (callinfo) {
+ mono_jit_lock ();
+ if (!callinfo->wrapper) {
+ callinfo->wrapper = p;
+ mono_register_jit_icall_wrapper (callinfo, p);
+ mono_debug_add_icall_wrapper (method, callinfo);
+ }
+ mono_jit_unlock ();
+ }
+
+ return p;
}
static gpointer
mono_domain_lock (domain);
g_hash_table_remove (domain->dynamic_code_hash, method);
g_hash_table_remove (domain->jit_code_hash, method);
+ g_hash_table_remove (domain->jump_trampoline_hash, method);
mono_domain_unlock (domain);
#ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
if (!ji) {
- mono_handle_native_sigsegv (ctx);
+ mono_handle_native_sigsegv (SIGSEGV, ctx);
}
mono_arch_handle_exception (ctx, exc, FALSE);
}
+static void
+SIG_HANDLER_SIGNATURE (sigabrt_signal_handler)
+{
+ MonoJitInfo *ji;
+ GET_CONTEXT;
+
+ ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
+ if (!ji) {
+ mono_handle_native_sigsegv (SIGABRT, ctx);
+ }
+}
+
static void
SIG_HANDLER_SIGNATURE (sigusr1_signal_handler)
{
add_signal_handler (mono_thread_get_abort_signal (), sigusr1_signal_handler);
signal (SIGPIPE, SIG_IGN);
+ add_signal_handler (SIGABRT, sigabrt_signal_handler);
+
/* catch SIGSEGV */
#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
sa.sa_sigaction = sigsegv_signal_handler;
#else
add_signal_handler (SIGSEGV, sigsegv_signal_handler);
#endif
-
#endif /* PLATFORM_WIN32 */
}
MonoDomain *domain;
/* Happens when using the embedding interface */
- if (default_opt == 0)
+ if (!default_opt_set)
default_opt = mono_parse_default_optimizations (NULL);
InitializeCriticalSection (&jit_mutex);
if (getenv ("MONO_DEBUG") != NULL)
mini_parse_debug_options ();
- /* we used to do this only when running on valgrind,
+ /*
+ * Handle the case when we are called from a thread different from the main thread,
+ * confusing libgc.
+ * FIXME: Move this to libgc where it belongs.
+ *
+ * we used to do this only when running on valgrind,
* but it happens also in other setups.
*/
#if defined(HAVE_BOEHM_GC)
pthread_attr_t attr;
pthread_getattr_np (pthread_self (), &attr);
pthread_attr_getstack (&attr, &sstart, &size);
+ pthread_attr_destroy (&attr);
/*g_print ("stackbottom pth is: %p\n", (char*)sstart + size);*/
+#ifdef __ia64__
+ /*
+ * The calculation above doesn't seem to work on ia64, also we need to set
+ * GC_register_stackbottom as well, but don't know how.
+ */
+#else
GC_stackbottom = (char*)sstart + size;
+#endif
}
#elif defined(HAVE_PTHREAD_GET_STACKSIZE_NP) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
GC_stackbottom = (char*)pthread_get_stackaddr_np (pthread_self ());
register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
register_icall (mono_ldstr, "mono_ldstr", "object ptr ptr int32", FALSE);
- register_icall (helper_stelem_ref, "helper_stelem_ref", "void ptr int32 object", FALSE);
- register_icall (helper_stelem_ref_check, "helper_stelem_ref_check", "void object object", FALSE);
+ register_icall (mono_helper_stelem_ref, "helper_stelem_ref", "void ptr int32 object", FALSE);
+ register_icall (mono_helper_stelem_ref_check, "helper_stelem_ref_check", "void object object", FALSE);
register_icall (mono_object_new, "mono_object_new", "object ptr ptr", FALSE);
register_icall (mono_object_new_specific, "mono_object_new_specific", "object ptr", FALSE);
register_icall (mono_array_new, "mono_array_new", "object ptr ptr int32", FALSE);
register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
register_icall (mono_ldftn_nosync, "mono_ldftn_nosync", "ptr ptr", FALSE);
register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
- register_icall (helper_compile_generic_method, "compile_generic_method", "ptr object ptr ptr", FALSE);
- register_icall (helper_ldstr, "helper_ldstr", "object ptr int", FALSE);
+ register_icall (mono_helper_compile_generic_method, "compile_generic_method", "ptr object ptr ptr", FALSE);
+ register_icall (mono_helper_ldstr, "helper_ldstr", "object ptr int", FALSE);
+ register_icall (mono_helper_ldstr_mscorlib, "helper_ldstr_mscorlib", "object int", FALSE);
+ register_icall (mono_helper_newobj_mscorlib, "helper_newobj_mscorlib", "object int", FALSE);
+ register_icall (mono_value_copy, "mono_value_copy", "void ptr ptr ptr", FALSE);
#endif
#define JIT_RUNTIME_WORKS
*/
mono_domain_finalize (domain, 2000);
+ /* This accesses metadata so needs to be called before runtime shutdown */
+ print_jit_stats ();
+
mono_runtime_cleanup (domain);
mono_profiler_shutdown ();
g_hash_table_destroy (jit_icall_name_hash);
if (class_init_hash_addr)
g_hash_table_destroy (class_init_hash_addr);
+ g_free (emul_opcode_map);
- print_jit_stats ();
+ mono_cleanup ();
+
+ mono_trace_cleanup ();
+
+ mono_counters_dump (-1, stdout);
}
void
{
mini_verbose = verbose_level;
default_opt = opts;
+ default_opt_set = TRUE;
}
static void