#include <signal.h>
#include <unistd.h>
#include <math.h>
+#include <sys/time.h>
#ifdef sun // Solaris x86
#include <sys/types.h>
#include <mono/metadata/mono-debug.h>
#include <mono/metadata/mono-debug-debugger.h>
#include <mono/metadata/monitor.h>
+#include <mono/metadata/security-manager.h>
+#include <mono/utils/mono-math.h>
#include <mono/os/gc_wrapper.h>
#include "mini.h"
#define MONO_CHECK_THIS(ins) (cfg->method->signature->hasthis && (ins)->ssa_op == MONO_SSA_LOAD && (ins)->inst_left->inst_c0 == 0)
+static void setup_stat_profiler (void);
gboolean mono_arch_print_tree(MonoInst *tree, int arity);
static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt);
static gpointer mono_jit_compile_method (MonoMethod *method);
static MonoMethodSignature *helper_sig_void_ptr_ptr = NULL;
static MonoMethodSignature *helper_sig_void_ptr_ptr_ptr = NULL;
static MonoMethodSignature *helper_sig_ptr_ptr_ptr = NULL;
+static MonoMethodSignature *helper_sig_ptr_ptr_ptr_ptr = NULL;
static MonoMethodSignature *helper_sig_ptr_obj = NULL;
static MonoMethodSignature *helper_sig_ptr_obj_int = NULL;
static MonoMethodSignature *helper_sig_ptr_int = NULL;
guint32 mono_jit_tls_id = -1;
MonoTraceSpec *mono_jit_trace_calls = NULL;
gboolean mono_break_on_exc = FALSE;
+#ifndef DISABLE_AOT
gboolean mono_compile_aot = FALSE;
+#endif
+gboolean mono_use_security_manager = FALSE;
static int mini_verbose = 0;
static GHashTable *class_init_hash_addr = NULL;
+static MonoCodeManager *global_codeman = NULL;
+
+static GHashTable *jit_icall_name_hash = NULL;
+
gboolean
mono_running_on_valgrind (void)
{
#endif
}
+/* 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 ();
+
+ ji = mono_jit_info_table_find (domain, ip);
+ if (!ji) {
+ return NULL;
+ }
+ method = mono_method_full_name (ji->method, TRUE);
+ source = mono_debug_source_location_from_address (ji->method, (int) ip, NULL, 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);
+ g_free (method);
+
+ return res;
+}
+
/* debug function */
G_GNUC_UNUSED static void
print_method_from_ip (void *ip)
method = mono_method_full_name (ji->method, TRUE);
source = mono_debug_source_location_from_address (ji->method, (int) ip, NULL, domain);
- g_print ("IP %p at offset 0x%x of method %s (%p %p)[domain %p - %s]\n", ip, (char*)ip - (char*)ji->code_start, method, ji->code_start, (char*)ji->code_start + ji->code_size, domain, domain->friendly_name);
+ 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_free (source);
g_free (method);
-
}
G_GNUC_UNUSED void
return TRUE;
}
+/*
+ * mono_global_codeman_reserve:
+ *
+ * Allocate code memory from the global code manager.
+ */
+void *mono_global_codeman_reserve (int size)
+{
+ void *ptr;
+
+ if (!global_codeman) {
+ /* This can happen during startup */
+ global_codeman = mono_code_manager_new ();
+ return mono_code_manager_reserve (global_codeman, size);
+ }
+ else {
+ EnterCriticalSection (&jit_mutex);
+ ptr = mono_code_manager_reserve (global_codeman, size);
+ LeaveCriticalSection (&jit_mutex);
+ return ptr;
+ }
+}
+
MonoJumpInfoToken *
mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
{
#define CHECK_BBLOCK(target,ip,tblock) do { \
if ((target) < (ip) && !(tblock)->code) { \
bb_recheck = g_list_prepend (bb_recheck, (tblock)); \
- if (cfg->verbose_level > 2) g_print ("queued block %d for check at IL%04x from IL%04x\n", (tblock)->block_num, (target) - header->code, (ip) - header->code); \
+ if (cfg->verbose_level > 2) g_print ("queued block %d for check at IL%04x from IL%04x\n", (tblock)->block_num, (int)((target) - header->code), (int)((ip) - header->code)); \
} \
} while (0)
(dest)->type = STACK_I4; \
} while (0)
-#if SIZEOF_VOID_P == 8
-#define NEW_PCONST(cfg,dest,val) do { \
- (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
- (dest)->opcode = OP_I8CONST; \
- (dest)->inst_p0 = (val); \
- (dest)->type = STACK_PTR; \
- } while (0)
-#else
#define NEW_PCONST(cfg,dest,val) do { \
(dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
- (dest)->opcode = OP_ICONST; \
+ (dest)->opcode = OP_PCONST; \
(dest)->inst_p0 = (val); \
(dest)->type = STACK_PTR; \
} while (0)
-#endif
-#if SIZEOF_VOID_P == 8
-#define OP_PCONST OP_I8CONST
-#else
-#define OP_PCONST OP_ICONST
-#endif
-#define NEW_CLASSCONST(cfg,dest,val) do { \
- (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
- (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_PCONST; \
- (dest)->inst_p0 = (val); \
- (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_CLASS; \
- (dest)->type = STACK_PTR; \
- } while (0)
+#ifdef MONO_ARCH_NEED_GOT_VAR
-#define NEW_IMAGECONST(cfg,dest,val) do { \
+#define NEW_PATCH_INFO(cfg,dest,el1,el2) do { \
(dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
- (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_PCONST; \
- (dest)->inst_p0 = (val); \
- (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_IMAGE; \
- (dest)->type = STACK_PTR; \
+ (dest)->opcode = OP_PATCH_INFO; \
+ (dest)->inst_left = (gpointer)(el1); \
+ (dest)->inst_right = (gpointer)(el2); \
} while (0)
-#define NEW_FIELDCONST(cfg,dest,field) do { \
+#define NEW_AOTCONST(cfg,dest,patch_type,cons) do { \
(dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
- (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_PCONST; \
- (dest)->inst_p0 = (field); \
- (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_FIELD; \
+ (dest)->opcode = cfg->compile_aot ? OP_GOT_ENTRY : OP_PCONST; \
+ if (cfg->compile_aot) { \
+ MonoInst *group, *got_var; \
+ NEW_TEMPLOAD ((cfg), got_var, mono_get_got_var (cfg)->inst_c0); \
+ NEW_PATCH_INFO ((cfg), group, cons, patch_type); \
+ (dest)->inst_p0 = got_var; \
+ (dest)->inst_p1 = group; \
+ } else { \
+ (dest)->inst_p0 = (cons); \
+ (dest)->inst_i1 = (gpointer)(patch_type); \
+ } \
(dest)->type = STACK_PTR; \
- } while (0)
+ } while (0)
-#define NEW_METHODCONST(cfg,dest,val) do { \
+#define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type) do { \
+ MonoInst *group, *got_var; \
(dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
- (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_PCONST; \
- (dest)->inst_p0 = (val); \
- (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_METHODCONST; \
- (dest)->type = STACK_PTR; \
- } while (0)
+ (dest)->opcode = OP_GOT_ENTRY; \
+ NEW_TEMPLOAD ((cfg), got_var, mono_get_got_var (cfg)->inst_c0); \
+ NEW_PATCH_INFO ((cfg), group, NULL, patch_type); \
+ 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); \
+ } while (0)
-#define NEW_VTABLECONST(cfg,dest,vtable) do { \
- (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
- (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_PCONST; \
- (dest)->inst_p0 = mono_compile_aot ? (gpointer)((vtable)->klass) : (vtable); \
- (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_VTABLE; \
- (dest)->type = STACK_PTR; \
- } while (0)
+#else
-#define NEW_SFLDACONST(cfg,dest,field) do { \
+#define NEW_AOTCONST(cfg,dest,patch_type,cons) do { \
(dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
- (dest)->opcode = mono_compile_aot ? OP_AOTCONST : OP_PCONST; \
- (dest)->inst_p0 = (field); \
- (dest)->inst_i1 = (gpointer)MONO_PATCH_INFO_SFLDA; \
+ (dest)->opcode = cfg->compile_aot ? OP_AOTCONST : OP_PCONST; \
+ (dest)->inst_p0 = (cons); \
+ (dest)->inst_i1 = (gpointer)(patch_type); \
(dest)->type = STACK_PTR; \
- } while (0)
+ } while (0)
-#define NEW_LDSTRCONST(cfg,dest,image,token) do { \
+#define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type) 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_i1 = (gpointer)MONO_PATCH_INFO_LDSTR; \
- (dest)->type = STACK_OBJ; \
- } while (0)
+ (dest)->inst_p1 = (gpointer)(patch_type); \
+ (dest)->type = (stack_type); \
+ } while (0)
-#define NEW_TYPE_FROM_HANDLE_CONST(cfg,dest,image,token) 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_i1 = (gpointer)MONO_PATCH_INFO_TYPE_FROM_HANDLE; \
- (dest)->type = STACK_OBJ; \
- } while (0)
+#endif
-#define NEW_LDTOKENCONST(cfg,dest,image,token) 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_i1 = (gpointer)MONO_PATCH_INFO_LDTOKEN; \
- (dest)->type = STACK_PTR; \
+#define NEW_CLASSCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_CLASS, (val))
+
+#define NEW_IMAGECONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_IMAGE, (val))
+
+#define NEW_FIELDCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_FIELD, (val))
+
+#define NEW_METHODCONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_METHODCONST, (val))
+
+#define NEW_VTABLECONST(cfg,dest,vtable) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_VTABLE, cfg->compile_aot ? (gpointer)((vtable)->klass) : (vtable))
+
+#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_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_LDTOKENCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDTOKEN, (image), (token), STACK_PTR)
+
+#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); \
+ } else { \
+ NEW_PCONST (cfg, args [0], (entry).blob); \
+ } \
} while (0)
#define NEW_DOMAINCONST(cfg,dest) do { \
(dest)->klass = (dest)->inst_i0->klass; \
} while (0)
+#define NEW_DUMMY_USE(cfg,dest,load) do { \
+ (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
+ (dest)->opcode = OP_DUMMY_USE; \
+ (dest)->inst_left = (load); \
+ } while (0)
+
+#define NEW_DUMMY_STORE(cfg,dest,num) do { \
+ (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
+ (dest)->inst_i0 = (cfg)->varinfo [(num)]; \
+ (dest)->opcode = OP_DUMMY_STORE; \
+ (dest)->klass = (dest)->inst_i0->klass; \
+ } while (0)
+
#define ADD_BINOP(op) do { \
MONO_INST_NEW (cfg, ins, (op)); \
ins->cil_code = ip; \
* that is in none of try/catch/filter.
*/
static int
-mono_find_block_region (MonoCompile *cfg, int offset, int *filter_lengths)
+mono_find_block_region (MonoCompile *cfg, int offset)
{
MonoMethod *method = cfg->method;
MonoMethodHeader *header = mono_method_get_header (method);
for (i = 0; i < header->num_clauses; ++i) {
clause = &header->clauses [i];
if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
- (offset < (clause->data.filter_offset + filter_lengths [i])))
+ (offset < (clause->handler_offset)))
return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
}
+static MonoInst *
+mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
+{
+ return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
+}
+
+static MonoInst*
+mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
+{
+ MonoInst *var;
+
+ var = g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
+ if (var)
+ return var;
+
+ var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
+ /* prevent it from being register allocated */
+ var->flags |= MONO_INST_INDIRECT;
+
+ g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
+
+ return var;
+}
+
static void
df_visit (MonoBasicBlock *start, int *dfn, MonoBasicBlock **array)
{
}
}
+static guint32
+reverse_branch_op (guint32 opcode)
+{
+ static const int reverse_map [] = {
+ CEE_BNE_UN, CEE_BLT, CEE_BLE, CEE_BGT, CEE_BGE,
+ CEE_BEQ, CEE_BLT_UN, CEE_BLE_UN, CEE_BGT_UN, CEE_BGE_UN
+ };
+ static const int reverse_fmap [] = {
+ OP_FBNE_UN, OP_FBLT, OP_FBLE, OP_FBGT, OP_FBGE,
+ OP_FBEQ, OP_FBLT_UN, OP_FBLE_UN, OP_FBGT_UN, OP_FBGE_UN
+ };
+ static const int reverse_lmap [] = {
+ OP_LBNE_UN, OP_LBLT, OP_LBLE, OP_LBGT, OP_LBGE,
+ OP_LBEQ, OP_LBLT_UN, OP_LBLE_UN, OP_LBGT_UN, OP_LBGE_UN
+ };
+ static const int reverse_imap [] = {
+ OP_IBNE_UN, OP_IBLT, OP_IBLE, OP_IBGT, OP_IBGE,
+ OP_IBEQ, OP_IBLT_UN, OP_IBLE_UN, OP_IBGT_UN, OP_IBGE_UN
+ };
+
+ if (opcode >= CEE_BEQ && opcode <= CEE_BLT_UN) {
+ opcode = reverse_map [opcode - CEE_BEQ];
+ } else if (opcode >= OP_FBEQ && opcode <= OP_FBLT_UN) {
+ opcode = reverse_fmap [opcode - OP_FBEQ];
+ } else if (opcode >= OP_LBEQ && opcode <= OP_LBLT_UN) {
+ opcode = reverse_lmap [opcode - OP_LBEQ];
+ } else if (opcode >= OP_IBEQ && opcode <= OP_IBLT_UN) {
+ opcode = reverse_imap [opcode - OP_IBEQ];
+ } else
+ g_assert_not_reached ();
+
+ return opcode;
+}
+
guint
mono_type_to_ldind (MonoType *type)
{
case MONO_TYPE_TYPEDBYREF:
return CEE_LDOBJ;
case MONO_TYPE_GENERICINST:
- type = type->data.generic_class->generic_type;
+ 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);
case MONO_TYPE_TYPEDBYREF:
return CEE_STOBJ;
case MONO_TYPE_GENERICINST:
- type = type->data.generic_class->generic_type;
+ 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);
handle_enum:
switch (type->type) {
+ case MONO_TYPE_VOID:
+ inst->type = STACK_INV;
+ return;
case MONO_TYPE_I1:
case MONO_TYPE_U1:
case MONO_TYPE_BOOLEAN:
inst->type = STACK_VTYPE;
return;
case MONO_TYPE_GENERICINST:
- type = type->data.generic_class->generic_type;
+ type = &type->data.generic_class->container_class->byval_arg;
goto handle_enum;
default:
g_error ("unknown type 0x%02x in eval stack type", type->type);
return cfg->domainvar;
}
+/*
+ * The got_var contains the address of the Global Offset Table when AOT
+ * compiling.
+ */
+inline static MonoInst *
+mono_get_got_var (MonoCompile *cfg)
+{
+#ifdef MONO_ARCH_NEED_GOT_VAR
+ if (!cfg->compile_aot)
+ return NULL;
+ if (!cfg->got_var) {
+ cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
+ }
+ return cfg->got_var;
+#else
+ return NULL;
+#endif
+}
+
MonoInst*
mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
{
mono_add_ins_to_end (bb, inst);
}
if (cfg->verbose_level > 3)
- g_print ("storing %d to temp %d\n", i, locals [i]->inst_c0);
+ g_print ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
}
/*
case MONO_TYPE_TYPEDBYREF:
return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
case MONO_TYPE_GENERICINST:
- type = type->data.generic_class->generic_type;
+ type = &type->data.generic_class->container_class->byval_arg;
goto handle_enum;
default:
g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
mono_create_jump_table (MonoCompile *cfg, MonoInst *label, MonoBasicBlock **bbs, int num_blocks)
{
MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
+ MonoJumpInfoBBTable *table;
+
+ table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
+ table->table = bbs;
+ table->table_size = num_blocks;
ji->ip.label = label;
ji->type = MONO_PATCH_INFO_SWITCH;
- ji->data.table = bbs;
+ ji->data.table = table;
ji->next = cfg->patch_info;
- ji->table_size = num_blocks;
cfg->patch_info = ji;
}
while (stack < sp) {
ins = *stack;
/* handle also other constants */
- if (ins->opcode != OP_ICONST) {
+ if ((ins->opcode != OP_ICONST) &&
+ /* temps never get written to again, so we can safely avoid duplicating them */
+ !(ins->ssa_op == MONO_SSA_LOAD && ins->inst_i0->opcode == OP_LOCAL && ins->inst_i0->flags & MONO_INST_IS_TEMP)) {
temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
+ temp->flags |= MONO_INST_IS_TEMP;
NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
store->cil_code = ins->cil_code;
if (store->opcode == CEE_STOBJ) {
}
for (i = 0; i < sig->param_count; ++i) {
if (sig->params [i]->byref) {
- /*
- * check the result of ldelema is only passed as an argument if the byref
- * type matches exactly the array element type.
- * FIXME: if the argument as been saved on the stack as part of the
- * interface variable code (the value was on the stack at a basic block boundary)
- * we need to add the check in that case, too.
- */
- if (args [i]->opcode == CEE_LDELEMA) {
- MonoInst *check;
- MonoClass *exact_class = mono_class_from_mono_type (sig->params [i]);
- if (!exact_class->valuetype) {
- MONO_INST_NEW (cfg, check, OP_CHECK_ARRAY_TYPE);
- check->cil_code = args [i]->cil_code;
- check->klass = exact_class;
- check->inst_left = args [i]->inst_left;
- check->type = STACK_OBJ;
- args [i]->inst_left = check;
- }
- }
if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
return 1;
continue;
return 1;
continue;
case MONO_TYPE_GENERICINST:
- simple_type = simple_type->data.generic_class->generic_type;
+ simple_type = &simple_type->data.generic_class->container_class->byval_arg;
goto handle_enum;
default:
type_to_eval_stack_type (ret, ins);
temp = mono_compile_create_var (cfg, ret, OP_LOCAL);
}
+
+ temp->flags |= MONO_INST_IS_TEMP;
if (MONO_TYPE_ISSTRUCT (ret)) {
- MonoInst *loada;
+ MonoInst *loada, *dummy_store;
+
+ /*
+ * Emit a dummy store to the local holding the result so the
+ * liveness info remains correct.
+ */
+ NEW_DUMMY_STORE (cfg, dummy_store, temp->inst_c0);
+ if (to_end)
+ mono_add_ins_to_end (bblock, dummy_store);
+ else
+ MONO_ADD_INS (bblock, dummy_store);
/* we use this to allocate native sized structs */
temp->unused = sig->pinvoke;
call->args = args;
call->signature = sig;
call = mono_arch_call_opcode (cfg, bblock, call, virtual);
-
+ type_to_eval_stack_type (sig->ret, &call->inst);
+
for (arg = call->out_args; arg;) {
MonoInst *narg = arg->next;
arg->next = NULL;
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)
+ /* Needed by the code generated in inssel.brg */
+ mono_get_got_var (cfg);
+
return call;
}
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;
NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
store->cil_code = tree->cil_code;
} else {
if (!sighash) {
sighash = g_hash_table_new (NULL, NULL);
}
- else if ((res = g_hash_table_lookup (sighash, (gpointer)arity))) {
+ else if ((res = g_hash_table_lookup (sighash, GINT_TO_POINTER (arity)))) {
LeaveCriticalSection (&jit_mutex);
return res;
}
res->ret = &mono_defaults.int_class->byval_arg;
- g_hash_table_insert (sighash, (gpointer)arity, res);
+ g_hash_table_insert (sighash, GINT_TO_POINTER (arity), res);
LeaveCriticalSection (&jit_mutex);
return res;
if (!sighash) {
sighash = g_hash_table_new (NULL, NULL);
}
- else if ((res = g_hash_table_lookup (sighash, (gpointer)arity))) {
+ else if ((res = g_hash_table_lookup (sighash, GINT_TO_POINTER (arity)))) {
LeaveCriticalSection (&jit_mutex);
return res;
}
res->ret = &mono_defaults.int_class->byval_arg;
- g_hash_table_insert (sighash, (gpointer)arity, res);
+ g_hash_table_insert (sighash, GINT_TO_POINTER (arity), res);
LeaveCriticalSection (&jit_mutex);
return res;
if ((cfg->opt & MONO_OPT_INTRINS) && !to_end && n <= sizeof (gpointer) * 5) {
MonoInst *inst;
+ if (dest->opcode == OP_LDADDR) {
+ /* Keep liveness info correct */
+ NEW_DUMMY_STORE (cfg, inst, dest->inst_i0->inst_c0);
+ MONO_ADD_INS (bblock, inst);
+ }
MONO_INST_NEW (cfg, inst, OP_MEMCPY);
inst->inst_left = dest;
inst->inst_right = src;
{
MonoMethodSignature *esig;
char icall_name [256];
+ char *name;
MonoJitICallInfo *info;
/* Need to register the icall so it gets an icall wrapper */
info = mono_find_jit_icall_by_name (icall_name);
if (info == NULL) {
esig = mono_get_array_new_va_signature (rank);
- info = mono_register_jit_icall (mono_array_new_va, g_strdup (icall_name), esig, FALSE);
+ name = g_strdup (icall_name);
+ info = mono_register_jit_icall (mono_array_new_va, name, esig, FALSE);
+
+ EnterCriticalSection (&jit_mutex);
+ g_hash_table_insert (jit_icall_name_hash, name, name);
+ LeaveCriticalSection (&jit_mutex);
}
cfg->flags |= MONO_CFG_HAS_VARARGS;
return mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, sp, ip, TRUE, FALSE);
}
+static void
+mono_emit_load_got_addr (MonoCompile *cfg)
+{
+ MonoInst *load, *store, *dummy_use;
+ MonoInst *get_got;
+
+ if (!cfg->got_var || cfg->got_var_allocated)
+ return;
+
+ MONO_INST_NEW (cfg, get_got, OP_LOAD_GOTADDR);
+ NEW_TEMPSTORE (cfg, store, cfg->got_var->inst_c0, get_got);
+
+ /* Add it to the start of the first bblock */
+ if (cfg->bb_entry->code) {
+ store->next = cfg->bb_entry->code;
+ cfg->bb_entry->code = store;
+ }
+ else
+ MONO_ADD_INS (cfg->bb_entry, store);
+
+ cfg->got_var_allocated = TRUE;
+
+ /*
+ * Add a dummy use to keep the got_var alive, since real uses might
+ * only be generated in the decompose or instruction selection phases.
+ * Add it to end_bblock, so the variable's lifetime covers the whole
+ * method.
+ */
+ NEW_TEMPLOAD (cfg, load, cfg->got_var->inst_c0);
+ NEW_DUMMY_USE (cfg, dummy_use, load);
+ MONO_ADD_INS (cfg->bb_exit, dummy_use);
+}
+
#define CODE_IS_STLOC(ip) (((ip) [0] >= CEE_STLOC_0 && (ip) [0] <= CEE_STLOC_3) || ((ip) [0] == CEE_STLOC_S))
static gboolean
MonoInst *addr;
MonoMethodSignature *esig;
char icall_name [256];
+ char *name;
MonoJitICallInfo *info;
rank = cmethod->signature->param_count - (is_set? 1: 0);
info = mono_find_jit_icall_by_name (icall_name);
if (info == NULL) {
esig = mono_get_element_address_signature (rank);
- info = mono_register_jit_icall (ves_array_element_address, g_strdup (icall_name), esig, FALSE);
+ name = g_strdup (icall_name);
+ info = mono_register_jit_icall (ves_array_element_address, name, esig, FALSE);
+
+ EnterCriticalSection (&jit_mutex);
+ g_hash_table_insert (jit_icall_name_hash, name, name);
+ LeaveCriticalSection (&jit_mutex);
}
temp = mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, sp, ip, FALSE, FALSE);
}
static MonoInst*
-mini_get_opcode_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
+mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
{
- int pc, op;
- MonoInst *ins;
+ MonoInst *ins = NULL;
static MonoClass *runtime_helpers_class = NULL;
if (! runtime_helpers_class)
if (cmethod->name [0] != 'g')
return NULL;
- if (strcmp (cmethod->name, "get_Chars") == 0)
- op = OP_GETCHR;
- else if (strcmp (cmethod->name, "get_Length") == 0)
- op = OP_STRLEN;
- else return NULL;
+ if (strcmp (cmethod->name, "get_Chars") == 0) {
+ MONO_INST_NEW (cfg, ins, OP_GETCHR);
+ ins->inst_i0 = args [0];
+ ins->inst_i1 = args [1];
+ return ins;
+ } else if (strcmp (cmethod->name, "get_Length") == 0) {
+ MONO_INST_NEW (cfg, ins, OP_STRLEN);
+ ins->inst_i0 = args [0];
+ return ins;
+ } else
+ return NULL;
} else if (cmethod->klass == mono_defaults.object_class) {
- if (strcmp (cmethod->name, "GetType") == 0)
- op = OP_GETTYPE;
- else
+ if (strcmp (cmethod->name, "GetType") == 0) {
+ MONO_INST_NEW (cfg, ins, OP_GETTYPE);
+ ins->inst_i0 = args [0];
+ return ins;
+ } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0) {
+ MONO_INST_NEW (cfg, ins, OP_GETHASHCODE);
+ ins->inst_i0 = args [0];
+ return ins;
+ } else
return NULL;
} else if (cmethod->klass == mono_defaults.array_class) {
- if (strcmp (cmethod->name, "get_Rank") == 0)
- op = OP_ARRAY_RANK;
- else if (strcmp (cmethod->name, "get_Length") == 0)
- op = CEE_LDLEN;
- else
+ if (cmethod->name [0] != 'g')
+ return NULL;
+
+ if (strcmp (cmethod->name, "get_Rank") == 0) {
+ MONO_INST_NEW (cfg, ins, OP_ARRAY_RANK);
+ ins->inst_i0 = args [0];
+ return ins;
+ } else if (strcmp (cmethod->name, "get_Length") == 0) {
+ MONO_INST_NEW (cfg, ins, CEE_LDLEN);
+ ins->inst_i0 = args [0];
+ return ins;
+ } else
return NULL;
} else if (cmethod->klass == runtime_helpers_class) {
if (strcmp (cmethod->name, "get_OffsetToStringData") == 0) {
if (strcmp (cmethod->name, "get_CurrentThread") == 0 && (ins = mono_arch_get_thread_intrinsic (cfg)))
return ins;
return NULL;
- } else {
- op = mono_arch_get_opcode_for_method (cfg, cmethod, fsig, args);
- if (op < 0)
- return NULL;
- }
- pc = fsig->param_count + fsig->hasthis;
- MONO_INST_NEW (cfg, ins, op);
-
- if (pc > 0) {
- ins->inst_i0 = args [0];
- if (pc > 1)
- ins->inst_i1 = args [1];
}
- return ins;
+ return mono_arch_get_inst_for_method (cfg, cmethod, fsig, args);
}
static void
/* offset from br.s -> br like opcodes */
#define BIG_BRANCH_OFFSET 13
+static gboolean
+ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
+{
+ MonoBasicBlock *b = g_hash_table_lookup (cfg->bb_hash, ip);
+
+ return b == NULL || b == bb;
+}
+
static int
get_basic_blocks (MonoCompile *cfg, GHashTable *bbhash, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
{
}
static MonoInst*
-emit_tree (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ins)
+emit_tree (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ins, const guint8* ip_next)
{
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))
+ return ins;
+
temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
+ temp->flags |= MONO_INST_IS_TEMP;
NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
store->cil_code = ins->cil_code;
MONO_ADD_INS (bblock, store);
return load;
}
+static inline MonoMethod *
+mini_get_method (MonoImage *image, guint32 token, MonoClass *klass, MonoGenericContext *context)
+{
+ MonoMethod *method = mono_get_method_full (image, token, klass, context);
+
+ if (method->is_inflated)
+ method = mono_get_inflated_method (method);
+
+ return method;
+}
+
/*
* mono_method_to_ir: translates IL into basic blocks containing trees
*/
GList *bb_recheck = NULL, *tmp;
int i, n, start_new_bblock, align;
int num_calls = 0, inline_costs = 0;
- int *filter_lengths = NULL;
int breakpoint_id = 0;
guint real_offset, num_args;
+ MonoBoolean security;
+ MonoDeclSecurityActions actions;
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);
arg_array [i] = cfg->varinfo [i];
if (header->num_clauses) {
- int size = sizeof (int) * header->num_clauses;
- filter_lengths = alloca (size);
- memset (filter_lengths, 0, size);
-
cfg->spvars = g_hash_table_new (NULL, NULL);
+ cfg->exvars = g_hash_table_new (NULL, NULL);
}
/* handle exception clauses */
for (i = 0; i < header->num_clauses; ++i) {
/* catch and filter blocks get the exception object on the stack */
if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
+ MonoInst *load, *dummy_use;
+
/* mostly like handle_stack_args (), but just sets the input args */
/* g_print ("handling clause at IL_%04x\n", clause->handler_offset); */
- if (!cfg->exvar) {
- cfg->exvar = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
- /* prevent it from being register allocated */
- cfg->exvar->flags |= MONO_INST_INDIRECT;
- }
tblock->in_scount = 1;
tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
- tblock->in_stack [0] = cfg->exvar;
+ tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
+
+ /*
+ * Add a dummy use for the exvar so its liveness info will be
+ * correct.
+ */
+ NEW_TEMPLOAD (cfg, load, tblock->in_stack [0]->inst_c0);
+ NEW_DUMMY_USE (cfg, dummy_use, load);
+ MONO_ADD_INS (tblock, dummy_use);
if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
GET_BBLOCK (cfg, bbhash, tblock, ip + clause->data.filter_offset);
tblock->real_offset = clause->data.filter_offset;
tblock->in_scount = 1;
tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
- tblock->in_stack [0] = cfg->exvar;
+ tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->data.filter_offset);
MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
MONO_ADD_INS (tblock, ins);
}
}
}
-
} else {
arg_array = alloca (sizeof (MonoInst *) * num_args);
mono_save_args (cfg, start_bblock, sig, inline_args, arg_array);
MONO_ADD_INS (bblock, ins);
}
}
+
+ security = mono_use_security_manager && mono_method_has_declsec (method);
+ /* at this point having security doesn't mean we have any code to generate */
+ if (security && (cfg->method == method)) {
+ /* Only Demand, NonCasDemand and DemandChoice requires code generation.
+ * And we do not want to enter the next section (with allocation) if we
+ * have nothing to generate */
+ security = mono_declsec_get_demands (method, &actions);
+ }
- if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || mono_compile_aot) {
+ if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || mono_compile_aot || security) {
/* we use a separate basic block for the initialization code */
cfg->bb_init = init_localsbb = NEW_BBLOCK (cfg);
init_localsbb->real_offset = real_offset;
link_bblock (cfg, start_bblock, bblock);
}
+ /* at this point we know, if security is TRUE, that some code needs to be generated */
+ if (security && (cfg->method == method)) {
+ MonoInst *args [2];
+ MonoSecurityManager* secman = mono_security_manager_get_methods ();
+
+ if (actions.demand.blob) {
+ /* Add code for SecurityAction.Demand */
+ NEW_DECLSECCONST (cfg, args[0], image, actions.demand);
+ NEW_ICONST (cfg, args [1], actions.demand.size);
+ /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
+ mono_emit_method_call_spilled (cfg, init_localsbb, secman->demand, secman->demand->signature, args, ip, NULL);
+ }
+ if (actions.noncasdemand.blob) {
+ /* CLR 1.x uses a .noncasdemand (but 2.x doesn't) */
+ /* For Mono we re-route non-CAS Demand to Demand (as the managed code must deal with it anyway) */
+ NEW_DECLSECCONST (cfg, args[0], image, actions.noncasdemand);
+ NEW_ICONST (cfg, args [1], actions.noncasdemand.size);
+ /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
+ mono_emit_method_call_spilled (cfg, init_localsbb, secman->demand, secman->demand->signature, args, ip, NULL);
+ }
+ if (actions.demandchoice.blob) {
+ /* New in 2.0, Demand must succeed for one of the permissions (i.e. not all) */
+ NEW_DECLSECCONST (cfg, args[0], image, actions.demandchoice);
+ NEW_ICONST (cfg, args [1], actions.demandchoice.size);
+ /* Calls static void SecurityManager.InternalDemandChoice (byte* permissions, int size); */
+ mono_emit_method_call_spilled (cfg, init_localsbb, secman->demandchoice, secman->demandchoice->signature, args, ip, NULL);
+ }
+ }
+
if (get_basic_blocks (cfg, bbhash, header, real_offset, ip, end, &err_pos)) {
ip = err_pos;
goto unverified;
}
- mono_debug_init_method (cfg, bblock, breakpoint_id);
+ if (cfg->method == method)
+ mono_debug_init_method (cfg, bblock, breakpoint_id);
param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
if (sig->hasthis)
start_new_bblock = 0;
for (i = 0; i < bblock->in_scount; ++i) {
if (cfg->verbose_level > 3)
- g_print ("loading %d from temp %d\n", i, bblock->in_stack [i]->inst_c0);
+ g_print ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);
NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
*sp++ = ins;
}
bblock = tblock;
for (i = 0; i < bblock->in_scount; ++i) {
if (cfg->verbose_level > 3)
- g_print ("loading %d from temp %d\n", i, bblock->in_stack [i]->inst_c0);
+ g_print ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);
NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
*sp++ = ins;
}
}
if (cfg->verbose_level > 3)
- g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, sp-stack_start, mono_disasm_code_one (NULL, method, ip, NULL));
+ g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
switch (*ip) {
case CEE_NOP:
++ip;
readr4 (ip, f);
ins->inst_p0 = f;
+
ip += 4;
*sp++ = ins;
break;
++ip;
readr8 (ip, d);
ins->inst_p0 = d;
+
ip += 8;
*sp++ = ins;
break;
temp->cil_code = ip;
*sp++ = temp;
} else {
- temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
- temp->cil_code = ip;
- NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
- store->cil_code = ip;
- if (store->opcode == CEE_STOBJ) {
- NEW_TEMPLOADA (cfg, store, temp->inst_c0);
- handle_stobj (cfg, bblock, store, ins, ins->cil_code, store->klass, TRUE, FALSE);
- } else
+ /* Common idiom: ... / dup / stloc.x */
+ int ins_len = 0;
+ if (ip_in_bb (cfg, bblock, ip + 1)) {
+ switch (ip [1]) {
+ case CEE_STLOC_0:
+ case CEE_STLOC_1:
+ case CEE_STLOC_2:
+ case CEE_STLOC_3:
+ n = (ip [1]) - CEE_STLOC_0;
+ ins_len = 1;
+ break;
+
+ case CEE_STLOC_S:
+ n = ip [2];
+ ins_len = 2;
+ break;
+
+ case CEE_PREFIX1:
+ if (ip [2] == CEE_LDLOC) {
+ n = read16 (ip + 3);
+ ins_len = 4;
+ }
+ }
+ }
+
+ if (ins_len) {
+ CHECK_LOCAL (n);
+ handle_loaded_temps (cfg, bblock, stack_start, sp - 1);
+ NEW_LOCSTORE (cfg, ins, n, *sp);
+ 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);
+ } else
+ MONO_ADD_INS (bblock, ins);
+
+ NEW_LOCLOAD (cfg, *sp, n);
+ (*sp)->cil_code = ip;
+ ip += ins_len;
+ sp++;
+ } else {
+ temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
+ temp->flags |= MONO_INST_IS_TEMP;
+ temp->cil_code = ip;
+ NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
+ store->cil_code = ip;
MONO_ADD_INS (bblock, store);
- NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
- *sp++ = ins;
- ins->cil_code = ip;
- NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
- *sp++ = ins;
- ins->cil_code = ip;
- }
- ++ip;
+ NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
+ *sp++ = ins;
+ ins->cil_code = ip;
+ NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
+ *sp++ = ins;
+ ins->cil_code = ip;
+ }
+ }
+ ++ip;
inline_costs += 2;
break;
}
MONO_INST_NEW (cfg, ins, CEE_JMP);
token = read32 (ip + 1);
/* FIXME: check the signature matches */
- cmethod = mono_get_method_full (image, token, NULL, generic_context);
+ cmethod = mini_get_method (image, token, NULL, generic_context);
ins->inst_p0 = cmethod;
MONO_ADD_INS (bblock, ins);
ip += 5;
cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
} else if (constrained_call) {
cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context);
+ cmethod = mono_get_inflated_method (cmethod);
} else {
- cmethod = mono_get_method_full (image, token, NULL, generic_context);
+ cmethod = mini_get_method (image, token, NULL, generic_context);
}
g_assert (cmethod);
mono_class_init (cmethod->klass);
if (cmethod->signature->pinvoke) {
- MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod);
- fsig = wrapper->signature;
+ MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod);
+ fsig = wrapper->signature;
+ } else if (constrained_call) {
+ fsig = cmethod->signature;
} else {
- fsig = mono_method_get_signature (cmethod, image, token);
+ fsig = mono_method_get_signature_full (cmethod, image, token, generic_context);
}
n = fsig->param_count + fsig->hasthis;
}
- if (cmethod && cmethod->klass->generic_container)
+ 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;
+ }
CHECK_STACK (n);
constrained_call = NULL;
}
- if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp))
+ if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp)) {
+ G_BREAKPOINT ();
goto unverified;
+ }
if (cmethod && virtual && cmethod->signature->generic_param_count) {
MonoInst *this_temp, *store;
ins->inst_p0 = cmethod;
ins->inst_p1 = arg_array [0];
MONO_ADD_INS (bblock, ins);
+ link_bblock (cfg, bblock, end_bblock);
start_new_bblock = 1;
/* skip CEE_RET as well */
ip += 6;
ins_flag = 0;
break;
}
- if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_get_opcode_for_method (cfg, cmethod, fsig, sp))) {
+ if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_get_inst_for_method (cfg, cmethod, fsig, sp))) {
ins->cil_code = ip;
if (MONO_TYPE_IS_VOID (fsig->ret)) {
}
} else {
- if (0 && CODE_IS_STLOC (ip + 5) && (!MONO_TYPE_ISSTRUCT (fsig->ret)) && (!MONO_TYPE_IS_VOID (fsig->ret) || cmethod->string_ctor)) {
+ 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)) {
/* no need to spill */
ins = (MonoInst*)mono_emit_method_call (cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL);
*sp++ = ins;
handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
sp = stack_start;
}
+ /* Needed by the code generated in inssel.brg */
+ mono_get_got_var (cfg);
inline_costs += 20;
break;
case CEE_LDIND_I1:
}
if (mono_find_jit_opcode_emulation (ins->opcode)) {
--sp;
- *sp++ = emit_tree (cfg, bblock, ins);
+ *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
}
ip++;
break;
ADD_UNOP (*ip);
if (mono_find_jit_opcode_emulation (ins->opcode)) {
--sp;
- *sp++ = emit_tree (cfg, bblock, ins);
+ *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
}
ip++;
break;
break;
case CEE_LDOBJ: {
MonoInst *iargs [3];
+ int loc_index = -1;
+ int stloc_len = 0;
CHECK_OPSIZE (5);
CHECK_STACK (1);
--sp;
ip += 5;
break;
}
+
+ /* Optimize the common ldobj+stloc combination */
+ switch (ip [5]) {
+ case CEE_STLOC_S:
+ loc_index = ip [6];
+ stloc_len = 2;
+ break;
+ case CEE_STLOC_0:
+ case CEE_STLOC_1:
+ case CEE_STLOC_2:
+ case CEE_STLOC_3:
+ loc_index = ip [5] - CEE_STLOC_0;
+ stloc_len = 1;
+ break;
+ default:
+ break;
+ }
+
+ if ((loc_index != -1) && ip_in_bb (cfg, bblock, ip + 5)) {
+ CHECK_LOCAL (loc_index);
+ NEW_LOCSTORE (cfg, ins, loc_index, *sp);
+
+ if (ins->opcode == CEE_STOBJ) {
+ handle_loaded_temps (cfg, bblock, stack_start, sp);
+ 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);
+ ip += 5;
+ ip += stloc_len;
+ break;
+ }
+ }
+
n = mono_class_value_size (klass, NULL);
ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
int temp;
MonoInst *iargs [3];
- if (mono_compile_aot) {
- cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, (gpointer)n);
+ if (cfg->compile_aot) {
+ cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
}
NEW_TEMPLOAD (cfg, iargs [0], mono_get_domainvar (cfg)->inst_c0);
NEW_TEMPLOAD (cfg, *sp, temp);
mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
} else {
- if (mono_compile_aot)
+ if (cfg->compile_aot)
NEW_LDSTRCONST (cfg, ins, image, n);
else {
NEW_PCONST (cfg, ins, NULL);
if (method->wrapper_type != MONO_WRAPPER_NONE) {
cmethod = mono_method_get_wrapper_data (method, token);
} else
- cmethod = mono_get_method_full (image, token, NULL, generic_context);
+ cmethod = mini_get_method (image, token, NULL, generic_context);
fsig = mono_method_get_signature (cmethod, image, token);
mono_class_init (cmethod->klass);
else
klass = mono_class_get_full (image, token, generic_context);
mono_class_init (klass);
-
+
+ /* Needed by the code generated in inssel.brg */
+ mono_get_got_var (cfg);
+
if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
MonoMethod *mono_isinst;
ins->inst_left = *sp;
ins->inst_newa_class = klass;
ins->cil_code = ip;
- *sp++ = emit_tree (cfg, bblock, ins);
+ *sp++ = emit_tree (cfg, bblock, ins, ip + 5);
ip += 5;
}
break;
ins->inst_newa_class = klass;
ins->cil_code = ip;
*sp++ = ins;
+ ip += 5;
}
- ip += 5;
break;
}
klass = mono_class_get_full (image, token, generic_context);
mono_class_init (klass);
+ /* Needed by the code generated in inssel.brg */
+ mono_get_got_var (cfg);
+
MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
ins->type = STACK_OBJ;
ins->inst_left = *sp;
else
klass = mono_class_get_full (image, token, generic_context);
mono_class_init (klass);
+
+ /* Needed by the code generated in inssel.brg */
+ mono_get_got_var (cfg);
if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
ins->klass = klass;
ins->inst_newa_class = klass;
ins->cil_code = ip;
- *sp++ = emit_tree (cfg, bblock, ins);
+ *sp++ = emit_tree (cfg, bblock, ins, ip + 5);
ip += 5;
}
break;
--sp;
ins->inst_left = *sp;
ins->cil_code = ip++;
+ bblock->out_of_line = TRUE;
MONO_ADD_INS (bblock, ins);
sp = stack_start;
+ link_bblock (cfg, bblock, end_bblock);
start_new_bblock = 1;
break;
case CEE_LDFLD:
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) {
+ if ((cfg->opt & MONO_OPT_INLINE) && !MONO_TYPE_ISSTRUCT (ldfld_wrapper->signature->ret)) {
costs = inline_method (cfg, ldfld_wrapper, ldfld_wrapper->signature, bblock,
iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
g_assert (costs > 0);
if ((*ip) == CEE_STSFLD)
handle_loaded_temps (cfg, bblock, stack_start, sp);
+ /* The special_static_fields field is init'd in mono_class_vtable, so it needs
+ * to be called here.
+ */
+ if (!(cfg->opt & MONO_OPT_SHARED))
+ mono_class_vtable (cfg->domain, klass);
+
if (cfg->domain->special_static_fields)
addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
- if ((cfg->opt & MONO_OPT_SHARED) || (mono_compile_aot && addr)) {
+ if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
int temp;
MonoInst *iargs [2];
g_assert (field->parent);
MonoVTable *vtable;
vtable = mono_class_vtable (cfg->domain, klass);
if (!addr) {
- if ((!vtable->initialized || mono_compile_aot) && !(klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && mono_class_needs_cctor_run (klass, method)) {
+ if ((!vtable->initialized || cfg->compile_aot) && !(klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && mono_class_needs_cctor_run (klass, method)) {
guint8 *tramp = mono_create_class_init_trampoline (vtable);
mono_emit_native_call (cfg, bblock, tramp,
helper_sig_class_init_trampoline,
}
addr = (char*)vtable->data + field->offset;
- if (mono_compile_aot)
+ if (cfg->compile_aot)
NEW_SFLDACONST (cfg, ins, field);
else
NEW_PCONST (cfg, ins, addr);
} else {
gboolean is_const = FALSE;
MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
- if (!((cfg->opt & MONO_OPT_SHARED) || mono_compile_aot) &&
+ if (!((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) &&
vtable->initialized && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY)) {
gpointer addr = (char*)vtable->data + field->offset;
+ int ro_type = field->type->type;
+ if (ro_type == MONO_TYPE_VALUETYPE && field->type->data.klass->enumtype) {
+ ro_type = field->type->data.klass->enum_basetype->type;
+ }
/* g_print ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, field->name);*/
is_const = TRUE;
- switch (field->type->type) {
+ switch (ro_type) {
case MONO_TYPE_BOOLEAN:
case MONO_TYPE_U1:
NEW_ICONST (cfg, *sp, *((guint8 *)addr));
/* LAME-IR: Mark it as used since otherwise it will be optimized away */
cfg->domainvar->flags |= MONO_INST_VOLATILE;
}
-
+
+ /* Ditto */
+ mono_get_got_var (cfg);
+
if (method->wrapper_type != MONO_WRAPPER_NONE)
klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
else
klass = (MonoClass*)mono_method_get_wrapper_data (method, read32 (ip + 1));
else
klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
+
+ /* 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
+ */
+ if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE) {
+ MonoInst* check;
+ MONO_INST_NEW (cfg, check, OP_CHECK_ARRAY_TYPE);
+ check->cil_code = ip;
+ check->klass = klass;
+ check->inst_left = sp [0];
+ check->type = STACK_OBJ;
+ sp [0] = check;
+ }
+
mono_class_init (klass);
NEW_LDELEMA (cfg, ins, sp, klass);
ins->cil_code = ip;
if (cfg->opt & MONO_OPT_SHARED) {
int temp;
- MonoInst *res, *store, *addr, *vtvar, *iargs [2];
+ MonoInst *res, *store, *addr, *vtvar, *iargs [3];
vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
NEW_IMAGECONST (cfg, iargs [0], image);
NEW_ICONST (cfg, iargs [1], n);
+ NEW_PCONST (cfg, iargs [2], generic_context);
temp = mono_emit_jit_icall (cfg, bblock, mono_ldtoken_wrapper, iargs, ip);
NEW_TEMPLOAD (cfg, res, temp);
NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
MONO_ADD_INS (bblock, store);
NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
} else {
- if ((ip [5] == CEE_CALL) && (cmethod = mono_get_method_full (image, read32 (ip + 6), NULL, generic_context)) &&
+ if ((ip [5] == CEE_CALL) && (cmethod = mini_get_method (image, read32 (ip + 6), NULL, generic_context)) &&
(cmethod->klass == mono_defaults.monotype_class->parent) &&
- (strcmp (cmethod->name, "GetTypeFromHandle") == 0) &&
- ((g_hash_table_lookup (bbhash, ip + 5) == NULL) ||
- (g_hash_table_lookup (bbhash, ip + 5) == bblock))) {
+ (strcmp (cmethod->name, "GetTypeFromHandle") == 0) && ip_in_bb (cfg, bblock, ip + 5)) {
MonoClass *tclass = mono_class_from_mono_type (handle);
mono_class_init (tclass);
- if (mono_compile_aot)
+ if (cfg->compile_aot)
NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n);
else
NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
} else {
MonoInst *store, *addr, *vtvar;
- if (mono_compile_aot)
+ if (cfg->compile_aot)
NEW_LDTOKENCONST (cfg, ins, image, n);
else
NEW_PCONST (cfg, ins, handle);
ADD_BINOP (*ip);
if (mono_find_jit_opcode_emulation (ins->opcode)) {
--sp;
- *sp++ = emit_tree (cfg, bblock, ins);
+ *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
}
ip++;
break;
case CEE_LEAVE:
case CEE_LEAVE_S: {
GList *handlers;
+
if (*ip == CEE_LEAVE) {
CHECK_OPSIZE (5);
target = ip + 5 + (gint32)read32(ip + 1);
*/
for (i = 0; i < header->num_clauses; ++i) {
MonoExceptionClause *clause = &header->clauses [i];
- if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code)) {
+
+ 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;
+
+ NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
+ load->cil_code = ip;
temp = mono_emit_jit_icall (cfg, bblock, mono_thread_get_pending_exception, NULL, ip);
NEW_TEMPLOAD (cfg, *sp, temp);
-
+
MONO_INST_NEW (cfg, ins, OP_THROW_OR_NULL);
ins->inst_left = *sp;
+ ins->inst_right = load;
ins->cil_code = ip;
MONO_ADD_INS (bblock, ins);
}
*sp++ = ins;
ip += 6;
inline_costs += 10 * num_calls++;
+ /* Can't embed random pointers into AOT code */
+ cfg->disable_aot = 1;
break;
case CEE_MONO_VTADDR:
CHECK_STACK (1);
ins->inst_left = *sp;
ins->inst_newa_class = klass;
ins->cil_code = ip;
- *sp++ = emit_tree (cfg, bblock, ins);
+ *sp++ = emit_tree (cfg, bblock, ins, ip + 6);
ip += 6;
break;
}
#endif
ip += 2;
break;
+ case CEE_MONO_CLASSCONST:
+ CHECK_STACK_OVF (1);
+ CHECK_OPSIZE (6);
+ token = read32 (ip + 2);
+ NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
+ ins->cil_code = ip;
+ *sp++ = ins;
+ ip += 6;
+ inline_costs += 10 * num_calls++;
+ break;
default:
g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
break;
*/
if (cmp->inst_left->type == STACK_I8) {
--sp;
- *sp++ = emit_tree (cfg, bblock, ins);
+ *sp++ = emit_tree (cfg, bblock, ins, ip + 2);
}
ip += 2;
break;
if (method->wrapper_type != MONO_WRAPPER_NONE)
cmethod = mono_method_get_wrapper_data (method, n);
else {
- cmethod = mono_get_method_full (image, n, NULL, generic_context);
+ cmethod = mini_get_method (image, n, NULL, generic_context);
}
mono_class_init (cmethod->klass);
if (method->wrapper_type != MONO_WRAPPER_NONE)
cmethod = mono_method_get_wrapper_data (method, n);
else
- cmethod = mono_get_method_full (image, n, NULL, generic_context);
+ cmethod = mini_get_method (image, n, NULL, generic_context);
mono_class_init (cmethod->klass);
handle_loaded_temps (cfg, bblock, stack_start, sp);
}
}
g_assert (nearest);
- filter_lengths [nearest_num] = (ip - header->code) - nearest->data.filter_offset;
+ if ((ip - header->code) != nearest->handler_offset)
+ goto unverified;
break;
}
break;
case CEE_RETHROW: {
MonoInst *load;
- /* FIXME: check we are in a catch handler */
- NEW_TEMPLOAD (cfg, load, cfg->exvar->inst_c0);
+ int handler_offset = -1;
+
+ 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_FINALLY))
+ handler_offset = clause->handler_offset;
+ }
+
+ g_assert (handler_offset != -1);
+
+ NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
load->cil_code = ip;
MONO_INST_NEW (cfg, ins, OP_RETHROW);
ins->inst_left = load;
ins->cil_code = ip;
MONO_ADD_INS (bblock, ins);
sp = stack_start;
+ link_bblock (cfg, bblock, end_bblock);
start_new_bblock = 1;
ip += 2;
break;
bblock->cil_length = ip - bblock->cil_code;
bblock->next_bb = end_bblock;
- link_bblock (cfg, bblock, end_bblock);
if (cfg->method == method && cfg->domainvar) {
-
-
MonoInst *store;
MonoInst *get_domain;
MONO_ADD_INS (init_localsbb, store);
}
+ if (cfg->method == method && cfg->got_var)
+ mono_emit_load_got_addr (cfg);
+
if (header->init_locals) {
MonoInst *store;
for (i = 0; i < header->num_locals; ++i) {
}
}
-
/* resolve backward branches in the middle of an existing basic block */
for (tmp = bb_recheck; tmp; tmp = tmp->next) {
bblock = tmp->data;
}
}
- /*
- * we compute regions here, because the length of filter clauses is not known in advance.
- * It is computed in the CEE_ENDFILTER case in the above switch statement
- */
if (cfg->method == method) {
MonoBasicBlock *bb;
for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
- bb->region = mono_find_block_region (cfg, bb->real_offset, filter_lengths);
+ bb->region = mono_find_block_region (cfg, bb->real_offset);
if (cfg->spvars)
mono_create_spvar_for_region (cfg, bb->region);
if (cfg->verbose_level > 2)
unverified:
if (cfg->method != method)
g_hash_table_destroy (bbhash);
- g_error ("Invalid IL code at IL%04x in %s: %s\n", ip - header->code,
+ g_error ("Invalid IL code at IL%04x in %s: %s\n", (int)(ip - header->code),
mono_method_full_name (method, TRUE), mono_disasm_code_one (NULL, method, ip, NULL));
dont_inline = g_list_remove (dont_inline, method);
return -1;
switch (tree->opcode) {
case OP_ICONST:
- printf ("[%d]", tree->inst_c0);
+ printf ("[%d]", (int)tree->inst_c0);
break;
case OP_I8CONST:
- printf ("[%lld]", tree->inst_l);
+ printf ("[%lld]", (long long)tree->inst_l);
break;
case OP_R8CONST:
printf ("[%f]", *(double*)tree->inst_p0);
break;
case OP_ARG:
case OP_LOCAL:
- printf ("[%d]", tree->inst_c0);
+ printf ("[%d]", (int)tree->inst_c0);
break;
case OP_REGOFFSET:
if (tree->inst_offset < 0)
- printf ("[-0x%x(%s)]", -tree->inst_offset, mono_arch_regname (tree->inst_basereg));
+ printf ("[-0x%x(%s)]", (int)(-tree->inst_offset), mono_arch_regname (tree->inst_basereg));
else
- printf ("[0x%x(%s)]", tree->inst_offset, mono_arch_regname (tree->inst_basereg));
+ printf ("[0x%x(%s)]", (int)(tree->inst_offset), mono_arch_regname (tree->inst_basereg));
break;
case OP_REGVAR:
printf ("[%s]", mono_arch_regname (tree->dreg));
}
case OP_PHI: {
int i;
- printf ("[%d (", tree->inst_c0);
+ printf ("[%d (", (int)tree->inst_c0);
for (i = 0; i < tree->inst_phi_args [0]; i++) {
if (i)
printf (", ");
case OP_LOADI1_MEMBASE:
case OP_LOADU2_MEMBASE:
case OP_LOADI2_MEMBASE:
- printf ("[%s] <- [%s + 0x%x]", mono_arch_regname (tree->dreg), mono_arch_regname (tree->inst_basereg), tree->inst_offset);
+ printf ("[%s] <- [%s + 0x%x]", mono_arch_regname (tree->dreg), mono_arch_regname (tree->inst_basereg), (int)tree->inst_offset);
break;
case CEE_BR:
case OP_CALL_HANDLER:
/* intptr amethod (intptr, intptr) */
helper_sig_ptr_ptr_ptr = make_icall_sig ("ptr ptr ptr");
+ helper_sig_ptr_ptr_ptr_ptr = make_icall_sig ("ptr ptr ptr ptr");
+
/* IntPtr amethod (object) */
helper_sig_ptr_obj = make_icall_sig ("ptr object");
/* previously created trampoline code */
mono_domain_lock (vtable->domain);
code =
- mono_g_hash_table_lookup (vtable->domain->class_init_trampoline_hash,
+ g_hash_table_lookup (vtable->domain->class_init_trampoline_hash,
vtable);
mono_domain_unlock (vtable->domain);
if (code)
/* store trampoline address */
mono_domain_lock (vtable->domain);
- mono_g_hash_table_insert (vtable->domain->class_init_trampoline_hash,
+ g_hash_table_insert (vtable->domain->class_init_trampoline_hash,
vtable, code);
mono_domain_unlock (vtable->domain);
return code;
mono_domain_lock (domain);
- code = mono_g_hash_table_lookup (domain->jump_trampoline_hash, method);
+ code = g_hash_table_lookup (domain->jump_trampoline_hash, method);
mono_domain_unlock (domain);
if (code)
return code;
mono_jit_info_table_add (mono_get_root_domain (), ji);
mono_domain_lock (domain);
- mono_g_hash_table_insert (domain->jump_trampoline_hash, method, ji->code_start);
+ g_hash_table_insert (domain->jump_trampoline_hash, method, ji->code_start);
mono_domain_unlock (domain);
return ji->code_start;
return res;
}
+typedef struct {
+ MonoClass *vtype;
+ GList *active;
+ GList *slots;
+} StackSlotInfo;
+
+/*
+ * mono_allocate_stack_slots:
+ *
+ * Allocate stack slots for all non register allocated variables using a
+ * linear scan algorithm.
+ * Returns: an array of stack offsets which the caller should free.
+ * STACK_SIZE is set to the amount of stack space needed.
+ * 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)
+{
+ int i, slot, offset, size, align;
+ MonoMethodVar *vmv;
+ MonoInst *inst;
+ gint32 *offsets;
+ GList *vars = NULL, *l;
+ StackSlotInfo *scalar_stack_slots, *vtype_stack_slots, *slot_info;
+ MonoType *t;
+ int nvtypes;
+
+ scalar_stack_slots = g_new0 (StackSlotInfo, MONO_TYPE_PINNED);
+ vtype_stack_slots = g_new0 (StackSlotInfo, 256);
+ nvtypes = 0;
+
+ offsets = g_new (guint32, m->num_varinfo);
+ for (i = 0; i < m->num_varinfo; ++i)
+ offsets [i] = -1;
+
+ for (i = m->locals_start; i < m->num_varinfo; i++) {
+ inst = m->varinfo [i];
+ vmv = MONO_VARINFO (m, i);
+
+ if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR || inst->opcode == OP_REGOFFSET)
+ continue;
+
+ vars = g_list_prepend (vars, vmv);
+ }
+
+ vars = mono_varlist_sort (m, vars, 0);
+ offset = 0;
+ *stack_align = 0;
+ for (l = vars; l; l = l->next) {
+ vmv = l->data;
+ inst = m->varinfo [vmv->idx];
+
+ /* inst->unused indicates native sized value types, this is used by the
+ * pinvoke wrappers when they call functions returning structures */
+ if (inst->unused && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
+ size = mono_class_native_size (inst->inst_vtype->data.klass, &align);
+ else
+ size = mono_type_size (inst->inst_vtype, &align);
+
+ t = mono_type_get_underlying_type (inst->inst_vtype);
+ switch (t->type) {
+ case MONO_TYPE_VALUETYPE:
+ for (i = 0; i < nvtypes; ++i)
+ if (t->data.klass == vtype_stack_slots [i].vtype)
+ break;
+ if (i < nvtypes)
+ slot_info = &vtype_stack_slots [i];
+ else {
+ g_assert (nvtypes < 256);
+ vtype_stack_slots [nvtypes].vtype = t->data.klass;
+ slot_info = &vtype_stack_slots [nvtypes];
+ nvtypes ++;
+ }
+ break;
+ default:
+ slot_info = &scalar_stack_slots [t->type];
+ }
+
+ slot = 0xffffff;
+ if (m->comp_done & MONO_COMP_LIVENESS) {
+ //printf ("START %2d %08x %08x\n", vmv->idx, vmv->range.first_use.abs_pos, vmv->range.last_use.abs_pos);
+
+ /* expire old intervals in active */
+ while (slot_info->active) {
+ MonoMethodVar *amv = (MonoMethodVar *)slot_info->active->data;
+
+ if (amv->range.last_use.abs_pos > vmv->range.first_use.abs_pos)
+ break;
+
+ //printf ("EXPIR %2d %08x %08x C%d R%d\n", amv->idx, amv->range.first_use.abs_pos, amv->range.last_use.abs_pos, amv->spill_costs, amv->reg);
+
+ slot_info->active = g_list_delete_link (slot_info->active, slot_info->active);
+ slot_info->slots = g_list_prepend (slot_info->slots, GINT_TO_POINTER (offsets [amv->idx]));
+ }
+
+ /*
+ * This also handles the case when the variable is used in an
+ * exception region, as liveness info is not computed there.
+ */
+ /*
+ * FIXME: All valuetypes are marked as INDIRECT because of LDADDR
+ * opcodes.
+ */
+ if (! (inst->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT))) {
+ if (slot_info->slots) {
+ slot = (int)slot_info->slots->data;
+
+ slot_info->slots = g_list_delete_link (slot_info->slots, slot_info->slots);
+ }
+
+ slot_info->active = mono_varlist_insert_sorted (m, slot_info->active, vmv, TRUE);
+ }
+ }
+
+ {
+ static int count = 0;
+ count ++;
+
+ /*
+ if (count == atoi (getenv ("COUNT")))
+ printf ("LAST: %s\n", mono_method_full_name (m->method, TRUE));
+ if (count > atoi (getenv ("COUNT")))
+ slot = 0xffffff;
+ else {
+ mono_print_tree_nl (inst);
+ }
+ */
+ }
+ if (slot == 0xffffff) {
+ offset += size;
+ offset += align - 1;
+ offset &= ~(align - 1);
+ slot = offset;
+
+ if (*stack_align == 0)
+ *stack_align = align;
+ }
+
+ offsets [vmv->idx] = slot;
+ }
+ g_list_free (vars);
+ for (i = 0; i < MONO_TYPE_PINNED; ++i) {
+ g_list_free (scalar_stack_slots [i].active);
+ g_list_free (scalar_stack_slots [i].slots);
+ }
+ for (i = 0; i < nvtypes; ++i) {
+ g_list_free (vtype_stack_slots [i].active);
+ g_list_free (vtype_stack_slots [i].slots);
+ }
+ g_free (scalar_stack_slots);
+ g_free (vtype_stack_slots);
+
+ *stack_size = offset;
+ return offsets;
+}
+
void
mono_register_opcode_emulation (int opcode, const char *name, MonoMethodSignature *sig, gpointer func, gboolean no_throw)
{
mono_regstate_free (cfg->rs);
if (cfg->spvars)
g_hash_table_destroy (cfg->spvars);
+ if (cfg->exvars)
+ g_hash_table_destroy (cfg->exvars);
mono_mempool_destroy (cfg->mempool);
g_list_free (cfg->ldstr_list);
thread = mono_thread_current ();
if (thread)
thread->jit_data = jit_tls;
+ if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
+ setup_stat_profiler ();
}
void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
int i;
if (method->dynamic) {
- jump_table = mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->table_size);
+ jump_table = mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
} else {
mono_domain_lock (domain);
- jump_table = mono_code_manager_reserve (domain->code_mp, sizeof (gpointer) * patch_info->table_size);
+ jump_table = mono_code_manager_reserve (domain->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
mono_domain_unlock (domain);
}
- for (i = 0; i < patch_info->table_size; i++) {
- jump_table [i] = code + (int)patch_info->data.table [i];
+ for (i = 0; i < patch_info->data.table->table_size; i++) {
+ jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
}
target = jump_table;
break;
break;
case MONO_PATCH_INFO_IID:
mono_class_init (patch_info->data.klass);
- target = (gpointer)patch_info->data.klass->interface_id;
+ target = GINT_TO_POINTER ((int)patch_info->data.klass->interface_id);
break;
case MONO_PATCH_INFO_VTABLE:
target = mono_class_vtable (domain, patch_info->data.klass);
target = handle;
break;
}
+ case MONO_PATCH_INFO_DECLSEC:
+ target = (mono_metadata_blob_heap (patch_info->data.token->image, patch_info->data.token->token) + 2);
+ break;
case MONO_PATCH_INFO_BB_OVF:
case MONO_PATCH_INFO_EXC_OVF:
+ case MONO_PATCH_INFO_GOT_OFFSET:
+ case MONO_PATCH_INFO_NONE:
break;
default:
g_assert_not_reached ();
}
}
+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;
+
+ for (inst = bb->code; inst != NULL; inst = inst->next) {
+ if (inst->opcode == OP_CALL_HANDLER) {
+ if (inst->inst_target_bb == orig) {
+ inst->inst_target_bb = repl;
+ }
+ }
+ }
+ if (bb->last_ins != NULL) {
+ switch (bb->last_ins->opcode) {
+ case CEE_BR:
+ if (bb->last_ins->inst_target_bb == orig) {
+ bb->last_ins->inst_target_bb = repl;
+ }
+ break;
+ case CEE_SWITCH: {
+ int i;
+ int n = GPOINTER_TO_INT (bb->last_ins->klass);
+ for (i = 0; i < n; i++ ) {
+ if (bb->last_ins->inst_many_bb [i] == orig) {
+ bb->last_ins->inst_many_bb [i] = repl;
+ }
+ }
+ break;
+ }
+ case CEE_BNE_UN:
+ case CEE_BEQ:
+ case CEE_BLT:
+ case CEE_BLT_UN:
+ case CEE_BGT:
+ case CEE_BGT_UN:
+ case CEE_BGE:
+ case CEE_BGE_UN:
+ case CEE_BLE:
+ case CEE_BLE_UN:
+ if (bb->last_ins->inst_true_bb == orig) {
+ bb->last_ins->inst_true_bb = repl;
+ }
+ if (bb->last_ins->inst_false_bb == orig) {
+ bb->last_ins->inst_false_bb = repl;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
static void
replace_basic_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
{
}
+/**
+ * Check if a bb is useless (is just made of NOPs and ends with an
+ * unconditional branch, or nothing).
+ * If it is so, unlink it from the CFG and nullify it, and return TRUE.
+ * Otherwise, return FALSE;
+ */
+static gboolean
+remove_block_if_useless (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *previous_bb) {
+ MonoBasicBlock *target_bb = NULL;
+ MonoInst *inst;
+
+ /* Do not touch handlers */
+ if (bb->region != -1) return FALSE;
+
+ for (inst = bb->code; inst != NULL; inst = inst->next) {
+ switch (inst->opcode) {
+ case CEE_NOP:
+ break;
+ case CEE_BR:
+ target_bb = inst->inst_target_bb;
+ break;
+ default:
+ return FALSE;
+ }
+ }
+
+ if (target_bb == NULL) {
+ if ((bb->out_count == 1) && (bb->out_bb [0] == bb->next_bb)) {
+ target_bb = bb->next_bb;
+ } else {
+ /* Do not touch empty BBs that do not "fall through" to their next BB (like the exit BB) */
+ return FALSE;
+ }
+ }
+
+ /* Do not touch BBs following a switch (they are the "default" branch) */
+ if ((previous_bb->last_ins != NULL) && (previous_bb->last_ins->opcode == CEE_SWITCH)) {
+ return FALSE;
+ }
+
+ /* Do not touch BBs following the entry BB and jumping to something that is not */
+ /* thiry "next" bb (the entry BB cannot contain the branch) */
+ if ((previous_bb == cfg->bb_entry) && (bb->next_bb != target_bb)) {
+ return FALSE;
+ }
+
+ if (target_bb != NULL) {
+ int i;
+
+ if (cfg->verbose_level > 0) {
+ 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);
+ 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);
+ }
+ }
+
+ if ((previous_bb != cfg->bb_entry) &&
+ (previous_bb->region == bb->region) &&
+ ((previous_bb->last_ins == NULL) ||
+ ((previous_bb->last_ins->opcode != CEE_BR) &&
+ (! (MONO_IS_COND_BRANCH_OP (previous_bb->last_ins))) &&
+ (previous_bb->last_ins->opcode != CEE_SWITCH)))) {
+ for (i = 0; i < previous_bb->out_count; i++) {
+ if (previous_bb->out_bb [i] == target_bb) {
+ MonoInst *jump;
+ MONO_INST_NEW (cfg, jump, CEE_BR);
+ MONO_ADD_INS (previous_bb, jump);
+ jump->cil_code = previous_bb->cil_code;
+ jump->inst_target_bb = target_bb;
+ break;
+ }
+ }
+ }
+
+ previous_bb->next_bb = bb->next_bb;
+ nullify_basic_block (bb);
+
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
static void
merge_basic_blocks (MonoBasicBlock *bb, MonoBasicBlock *bbn)
nullify_basic_block (bbn);
}
+static void
+move_basic_block_to_end (MonoCompile *cfg, MonoBasicBlock *bb)
+{
+ MonoBasicBlock *bbn;
+
+ /* Find the previous */
+ for (bbn = cfg->bb_entry; bbn->next_bb && bbn->next_bb != bb; bbn = bbn->next_bb)
+ ;
+ if (bbn->next_bb) {
+ bbn->next_bb = bb->next_bb;
+ }
+
+ /* Find the last */
+ for (bbn = cfg->bb_entry; bbn->next_bb; bbn = bbn->next_bb)
+ ;
+ bbn->next_bb = bb;
+ bb->next_bb = NULL;
+}
+
/*
* Optimizes the branches on the Control Flow Graph
*
*/
niterations = 1000;
do {
+ MonoBasicBlock *previous_bb;
changed = FALSE;
niterations --;
/* we skip the entry block (exit is handled specially instead ) */
- for (bb = cfg->bb_entry->next_bb; bb; bb = bb->next_bb) {
+ for (previous_bb = cfg->bb_entry, bb = cfg->bb_entry->next_bb; bb; previous_bb = bb, bb = bb->next_bb) {
/* dont touch code inside exception clauses */
if (bb->region != -1)
continue;
+ if (remove_block_if_useless (cfg, bb, previous_bb)) {
+ changed = TRUE;
+ continue;
+ }
+
if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
if (cfg->verbose_level > 2)
g_print ("nullify block triggered %d\n", bbn->block_num);
/* conditional branches where true and false targets are the same can be also replaced with CEE_BR */
if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins)) {
+ MonoInst *pop;
+ MONO_INST_NEW (cfg, pop, CEE_POP);
+ pop->inst_left = bb->last_ins->inst_left->inst_left;
+ mono_add_ins_to_end (bb, pop);
+ MONO_INST_NEW (cfg, pop, CEE_POP);
+ pop->inst_left = bb->last_ins->inst_left->inst_right;
+ mono_add_ins_to_end (bb, pop);
bb->last_ins->opcode = CEE_BR;
bb->last_ins->inst_target_bb = bb->last_ins->inst_true_bb;
changed = TRUE;
}
} else if (bb->out_count == 2) {
if (bb->last_ins && MONO_IS_COND_BRANCH_NOFP (bb->last_ins)) {
+ int branch_result = mono_eval_cond_branch (bb->last_ins);
+ MonoBasicBlock *taken_branch_target = NULL, *untaken_branch_target = NULL;
+ if (branch_result == BRANCH_TAKEN) {
+ taken_branch_target = bb->last_ins->inst_true_bb;
+ untaken_branch_target = bb->last_ins->inst_false_bb;
+ } else if (branch_result == BRANCH_NOT_TAKEN) {
+ taken_branch_target = bb->last_ins->inst_false_bb;
+ untaken_branch_target = bb->last_ins->inst_true_bb;
+ }
+ if (taken_branch_target) {
+ /* if mono_eval_cond_branch () is ever taken to handle
+ * non-constant values to compare, issue a pop here.
+ */
+ 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);
+ changed = TRUE;
+ break;
+ }
bbn = bb->last_ins->inst_true_bb;
if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
bbn->code->inst_target_bb->region == bb->region) {
break;
}
}
+
+#ifdef MONO_ARCH_HAVE_OUT_OF_LINE_BBLOCKS
+ if (bb->last_ins && MONO_IS_COND_BRANCH_NOFP (bb->last_ins)) {
+ if (bb->last_ins->inst_false_bb->out_of_line) {
+ /* Reverse the branch */
+ bb->last_ins->opcode = reverse_branch_op (bb->last_ins->opcode);
+ bbn = bb->last_ins->inst_false_bb;
+ bb->last_ins->inst_false_bb = bb->last_ins->inst_true_bb;
+ bb->last_ins->inst_true_bb = bbn;
+
+ move_basic_block_to_end (cfg, bb->last_ins->inst_true_bb);
+ if (cfg->verbose_level > 2)
+ g_print ("cbranch to throw block triggered %d.\n",
+ bb->block_num);
+ }
+ }
+#endif
}
}
} while (changed && (niterations > 0));
static void
mini_select_instructions (MonoCompile *cfg)
{
- static const int reverse_map [] = {
- CEE_BNE_UN, CEE_BLT, CEE_BLE, CEE_BGT, CEE_BGE,
- CEE_BEQ, CEE_BLT_UN, CEE_BLE_UN, CEE_BGT_UN, CEE_BGE_UN
- };
- static const int reverse_fmap [] = {
- OP_FBNE_UN, OP_FBLT, OP_FBLE, OP_FBGT, OP_FBGE,
- OP_FBEQ, OP_FBLT_UN, OP_FBLE_UN, OP_FBGT_UN, OP_FBGE_UN
- };
- static const int reverse_lmap [] = {
- OP_LBNE_UN, OP_LBLT, OP_LBLE, OP_LBGT, OP_LBGE,
- OP_LBEQ, OP_LBLT_UN, OP_LBLE_UN, OP_LBGT_UN, OP_LBGE_UN
- };
- static const int reverse_imap [] = {
- OP_IBNE_UN, OP_IBLT, OP_IBLE, OP_IBGT, OP_IBGE,
- OP_IBEQ, OP_IBLT_UN, OP_IBLE_UN, OP_IBGT_UN, OP_IBGE_UN
- };
-
MonoBasicBlock *bb;
cfg->state_pool = mono_mempool_new ();
MonoBasicBlock *tmp = bb->last_ins->inst_true_bb;
bb->last_ins->inst_true_bb = bb->last_ins->inst_false_bb;
bb->last_ins->inst_false_bb = tmp;
-
- if (bb->last_ins->opcode >= CEE_BEQ && bb->last_ins->opcode <= CEE_BLT_UN) {
- bb->last_ins->opcode = reverse_map [bb->last_ins->opcode - CEE_BEQ];
- } else if (bb->last_ins->opcode >= OP_FBEQ && bb->last_ins->opcode <= OP_FBLT_UN) {
- bb->last_ins->opcode = reverse_fmap [bb->last_ins->opcode - OP_FBEQ];
- } else if (bb->last_ins->opcode >= OP_LBEQ && bb->last_ins->opcode <= OP_LBLT_UN) {
- bb->last_ins->opcode = reverse_lmap [bb->last_ins->opcode - OP_LBEQ];
- } else if (bb->last_ins->opcode >= OP_IBEQ && bb->last_ins->opcode <= OP_IBLT_UN) {
- bb->last_ins->opcode = reverse_imap [bb->last_ins->opcode - OP_IBEQ];
- }
+
+ bb->last_ins->opcode = reverse_branch_op (bb->last_ins->opcode);
} else {
MonoInst *inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
inst->opcode = CEE_BR;
for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
bb->native_offset = cfg->code_len;
mono_arch_output_basic_block (cfg, bb);
+
+#ifdef MONO_ARCH_HAVE_OUT_OF_LINE_BBLOCKS
+ if (bb == cfg->bb_exit) {
+ cfg->epilog_begin = cfg->code_len;
+
+ if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
+ code = cfg->native_code + cfg->code_len;
+ code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
+ cfg->code_len = code - cfg->native_code;
+ }
+
+ mono_arch_emit_epilog (cfg);
+ }
+#endif
}
+
+#ifndef MONO_ARCH_HAVE_OUT_OF_LINE_BBLOCKS
cfg->bb_exit->native_offset = cfg->code_len;
+ max_epilog_size = mono_arch_max_epilog_size (cfg);
+#else
+ mono_arch_emit_exceptions (cfg);
- code = cfg->native_code + cfg->code_len;
+ max_epilog_size = 0;
+#endif
- max_epilog_size = mono_arch_max_epilog_size (cfg);
+ code = cfg->native_code + cfg->code_len;
/* we always allocate code in cfg->domain->code_mp to increase locality */
cfg->code_size = cfg->code_len + max_epilog_size;
/* g_assert (((int)cfg->native_code & (MONO_ARCH_CODE_ALIGNMENT - 1)) == 0); */
+#ifndef MONO_ARCH_HAVE_OUT_OF_LINE_BBLOCKS
cfg->epilog_begin = cfg->code_len;
if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
cfg->code_len = code - cfg->native_code;
mono_arch_emit_epilog (cfg);
+#endif
for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
switch (patch_info->type) {
case MONO_PATCH_INFO_SWITCH: {
gpointer *table;
if (cfg->method->dynamic) {
- table = mono_code_manager_reserve (cfg->dynamic_info->code_mp, sizeof (gpointer) * patch_info->table_size);
+ table = mono_code_manager_reserve (cfg->dynamic_info->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
} else {
mono_domain_lock (cfg->domain);
- table = mono_code_manager_reserve (cfg->domain->code_mp, sizeof (gpointer) * patch_info->table_size);
+ table = mono_code_manager_reserve (cfg->domain->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
mono_domain_unlock (cfg->domain);
}
-
- patch_info->ip.i = patch_info->ip.label->inst_c0;
- for (i = 0; i < patch_info->table_size; i++) {
- table [i] = (gpointer)patch_info->data.table [i]->native_offset;
+
+ if (!cfg->compile_aot)
+ /* In the aot case, the patch already points to the correct location */
+ patch_info->ip.i = patch_info->ip.label->inst_c0;
+ for (i = 0; i < patch_info->data.table->table_size; i++) {
+ table [i] = GINT_TO_POINTER (patch_info->data.table->table [i]->native_offset);
}
- patch_info->data.target = table;
+ patch_info->data.table->table = (MonoBasicBlock**)table;
break;
}
default:
static void
remove_critical_edges (MonoCompile *cfg) {
MonoBasicBlock *bb;
+ MonoBasicBlock *previous_bb;
if (cfg->verbose_level > 3) {
for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
}
}
- for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
- if (bb->out_count > 1) {
- int out_bb_index;
- for (out_bb_index = 0; out_bb_index < bb->out_count; out_bb_index++) {
- MonoBasicBlock *out_bb = bb->out_bb [out_bb_index];
- if (out_bb->in_count > 1) {
- MonoInst *inst;
+ for (previous_bb = cfg->bb_entry, bb = previous_bb->next_bb; bb != NULL; previous_bb = previous_bb->next_bb, bb = bb->next_bb) {
+ if (bb->in_count > 1) {
+ int in_bb_index;
+ for (in_bb_index = 0; in_bb_index < bb->in_count; in_bb_index++) {
+ MonoBasicBlock *in_bb = bb->in_bb [in_bb_index];
+ if (in_bb->out_count > 1) {
MonoBasicBlock *new_bb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
new_bb->block_num = cfg->num_bblocks++;
- new_bb->next_bb = bb->next_bb;
- bb->next_bb = new_bb;
- new_bb->in_bb = mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
- new_bb->in_bb [0] = bb;
- new_bb->in_count = 1;
- new_bb->out_bb = mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
- new_bb->out_bb [0] = out_bb;
- new_bb->out_count = 1;
- replace_out_block (bb, out_bb, new_bb);
- replace_in_block (out_bb, bb, new_bb);
- for (inst = bb->code; inst != NULL; inst = inst->next) {
- if (inst->opcode == OP_CALL_HANDLER) {
- if (inst->inst_target_bb == out_bb) {
- inst->inst_target_bb = new_bb;
- }
- }
- }
- if (bb->last_ins != NULL) {
- switch (bb->last_ins->opcode) {
- case CEE_BR:
- if (bb->last_ins->inst_target_bb == out_bb) {
- bb->last_ins->inst_target_bb = new_bb;
- }
- break;
- case CEE_SWITCH: {
- int i;
- int n = GPOINTER_TO_INT (bb->last_ins->klass);
- for (i = 0; i < n; i++ ) {
- if (bb->last_ins->inst_many_bb [i] == out_bb) {
- bb->last_ins->inst_many_bb [i] = new_bb;
- break;
+// new_bb->real_offset = bb->real_offset;
+ new_bb->region = bb->region;
+
+ /* Do not alter the CFG while altering the BB list */
+ if (previous_bb->region == bb->region) {
+ if (previous_bb != cfg->bb_entry) {
+ /* If previous_bb "followed through" to bb, */
+ /* keep it linked with a CEE_BR */
+ if ((previous_bb->last_ins == NULL) ||
+ ((previous_bb->last_ins->opcode != CEE_BR) &&
+ (! (MONO_IS_COND_BRANCH_OP (previous_bb->last_ins))) &&
+ (previous_bb->last_ins->opcode != CEE_SWITCH))) {
+ int i;
+ /* Make sure previous_bb really falls through bb */
+ for (i = 0; i < previous_bb->out_count; i++) {
+ if (previous_bb->out_bb [i] == bb) {
+ MonoInst *jump;
+ MONO_INST_NEW (cfg, jump, CEE_BR);
+ MONO_ADD_INS (previous_bb, jump);
+ jump->cil_code = previous_bb->cil_code;
+ jump->inst_target_bb = bb;
+ break;
+ }
}
}
- break;
- }
- case CEE_BNE_UN:
- case CEE_BEQ:
- case CEE_BLT:
- case CEE_BLT_UN:
- case CEE_BGT:
- case CEE_BGT_UN:
- case CEE_BGE:
- case CEE_BGE_UN:
- case CEE_BLE:
- case CEE_BLE_UN:
- if (bb->last_ins->inst_true_bb == out_bb) {
- bb->last_ins->inst_true_bb = new_bb;
- }
- if (bb->last_ins->inst_false_bb == out_bb) {
- bb->last_ins->inst_false_bb = new_bb;
+ } else {
+ /* We cannot add any inst to the entry BB, so we must */
+ /* put a new BB in the middle to hold the CEE_BR */
+ MonoInst *jump;
+ MonoBasicBlock *new_bb_after_entry = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
+ new_bb_after_entry->block_num = cfg->num_bblocks++;
+// new_bb_after_entry->real_offset = bb->real_offset;
+ new_bb_after_entry->region = bb->region;
+
+ MONO_INST_NEW (cfg, jump, CEE_BR);
+ MONO_ADD_INS (new_bb_after_entry, jump);
+ jump->cil_code = bb->cil_code;
+ jump->inst_target_bb = bb;
+
+ previous_bb->next_bb = new_bb_after_entry;
+ previous_bb = new_bb_after_entry;
+
+ if (cfg->verbose_level > 2) {
+ printf ("remove_critical_edges %s, added helper BB%d jumping to BB%d\n", mono_method_full_name (cfg->method, TRUE), new_bb_after_entry->block_num, bb->block_num);
}
- break;
- default:
- break;
}
}
-// new_bb->real_offset = bb->real_offset;
- new_bb->region = bb->region;
- if (new_bb->next_bb != out_bb) {
- MonoInst *jump;
- MONO_INST_NEW (cfg, jump, CEE_BR);
- MONO_ADD_INS (new_bb, jump);
- jump->cil_code = bb->cil_code;
- jump->inst_target_bb = out_bb;
- }
+ /* Insert new_bb in the BB list */
+ previous_bb->next_bb = new_bb;
+ new_bb->next_bb = bb;
+ previous_bb = new_bb;
+
+ /* Setup in_bb and out_bb */
+ new_bb->in_bb = mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
+ new_bb->in_bb [0] = in_bb;
+ new_bb->in_count = 1;
+ new_bb->out_bb = mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
+ new_bb->out_bb [0] = bb;
+ new_bb->out_count = 1;
+
+ /* Relink in_bb and bb to (from) new_bb */
+ replace_out_block (in_bb, bb, new_bb);
+ replace_out_block_in_code (in_bb, bb, new_bb);
+ replace_in_block (bb, in_bb, new_bb);
if (cfg->verbose_level > 2) {
- printf ("remove_critical_edges %s, removed critical edge from BB%d to BB%d (added BB%d)\n", mono_method_full_name (cfg->method, TRUE), bb->block_num, out_bb->block_num, new_bb->block_num);
+ printf ("remove_critical_edges %s, removed critical edge from BB%d to BB%d (added BB%d)\n", mono_method_full_name (cfg->method, TRUE), in_bb->block_num, bb->block_num, new_bb->block_num);
}
}
}
}
}
-
MonoCompile*
-mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gboolean run_cctors, int parts)
+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;
cfg->bb_hash = g_hash_table_new (NULL, NULL);
cfg->domain = domain;
cfg->verbose_level = mini_verbose;
+ cfg->compile_aot = compile_aot;
cfg->intvars = mono_mempool_alloc0 (cfg->mempool, sizeof (guint16) * STACK_MAX *
mono_method_get_header (method)->max_stack);
mono_jit_stats.basic_blocks += cfg->num_bblocks;
mono_jit_stats.max_basic_blocks = MAX (cfg->num_bblocks, mono_jit_stats.max_basic_blocks);
- if (cfg->num_varinfo > 2000) {
+ if ((cfg->num_varinfo > 2000) && !mono_compile_aot) {
/*
* we disable some optimizations if there are too many variables
* because JIT time may become too expensive. The actual number needs
cfg->opt &= ~ (MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP);
cfg->disable_ssa = TRUE;
}
+
/*g_print ("numblocks = %d\n", cfg->num_bblocks);*/
if (cfg->opt & MONO_OPT_BRANCH)
optimize_branches (cfg);
- if ((cfg->opt & MONO_OPT_SSAPRE) && ! (cfg->opt & (MONO_OPT_CONSPROP|MONO_OPT_COPYPROP))) {
+ if (cfg->opt & MONO_OPT_SSAPRE) {
remove_critical_edges (cfg);
}
if ((cfg->flags & MONO_CFG_HAS_LDELEMA) && (cfg->opt & MONO_OPT_ABCREM))
mono_perform_abc_removal (cfg);
- if ((cfg->opt & MONO_OPT_SSAPRE) && ! (cfg->opt & (MONO_OPT_CONSPROP|MONO_OPT_COPYPROP)))
+ if (cfg->opt & MONO_OPT_SSAPRE)
mono_perform_ssapre (cfg);
mono_ssa_remove (cfg);
decompose_pass (cfg);
+ if (cfg->got_var) {
+ GList *regs;
+
+ /* The decompose pass may create calls which need the got var */
+ mono_emit_load_got_addr (cfg);
+
+ /*
+ * Allways allocate the GOT var to a register, because keeping it
+ * in memory will increase the number of live temporaries in some
+ * code created by inssel.brg, leading to the well known spills+
+ * branches problem. Testcase: mcs crash in
+ * System.MonoCustomAttrs:GetCustomAttributes.
+ */
+ regs = mono_arch_get_global_int_regs (cfg);
+ g_assert (regs);
+ cfg->got_var->opcode = OP_REGVAR;
+ cfg->got_var->dreg = GPOINTER_TO_INT (regs->data);
+ cfg->used_int_regs |= 1LL << cfg->got_var->dreg;
+
+ g_list_free (regs);
+ }
+
if (cfg->opt & MONO_OPT_LINEARS) {
GList *vars, *regs;
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);
}
}
//mono_print_code (cfg);
- //print_dfn (cfg);
+ //print_dfn (cfg);
/* variables are allocated after decompose, since decompose could create temps */
mono_arch_allocate_vars (cfg);
jinfo->code_size = cfg->code_len;
jinfo->used_regs = cfg->used_int_regs;
jinfo->domain_neutral = (cfg->opt & MONO_OPT_SHARED) != 0;
+ jinfo->cas_inited = FALSE; /* initialization delayed at the first stalk walk using this method */
if (header->num_clauses) {
int i;
- jinfo->exvar_offset = cfg->exvar? cfg->exvar->inst_offset: 0;
jinfo->num_clauses = header->num_clauses;
jinfo->clauses = mono_mempool_alloc0 (cfg->domain->mp,
sizeof (MonoJitExceptionInfo) * header->num_clauses);
MonoExceptionClause *ec = &header->clauses [i];
MonoJitExceptionInfo *ei = &jinfo->clauses [i];
MonoBasicBlock *tblock;
+ MonoInst *exvar;
ei->flags = ec->flags;
+ exvar = mono_find_exvar_for_offset (cfg, ec->handler_offset);
+ ei->exvar_offset = exvar ? exvar->inst_offset : 0;
+
if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->data.filter_offset);
g_assert (tblock);
return NULL;
}
- cfg = mini_method_compile (method, opt, target_domain, TRUE, 0);
+ cfg = mini_method_compile (method, opt, target_domain, TRUE, FALSE, 0);
mono_domain_lock (target_domain);
mono_arch_handle_exception (ctx, exc, FALSE);
}
+static void
+SIG_HANDLER_SIGNATURE (sigprof_signal_handler)
+{
+ GET_CONTEXT;
+
+ mono_profiler_stat_hit (mono_arch_ip_from_context (ctx), ctx);
+}
+
static void
SIG_HANDLER_SIGNATURE (sigquit_signal_handler)
{
#endif /* PLATFORM_WIN32 */
}
+
+#ifdef HAVE_LINUX_RTC_H
+#include <linux/rtc.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+static int rtc_fd = -1;
+
+static int
+enable_rtc_timer (gboolean enable)
+{
+ int flags;
+ flags = fcntl (rtc_fd, F_GETFL);
+ if (flags < 0) {
+ perror ("getflags");
+ return 0;
+ }
+ if (enable)
+ flags |= FASYNC;
+ else
+ flags &= ~FASYNC;
+ if (fcntl (rtc_fd, F_SETFL, flags) == -1) {
+ perror ("setflags");
+ return 0;
+ }
+ return 1;
+}
+#endif
+
+static void
+setup_stat_profiler (void)
+{
+#ifdef ITIMER_PROF
+ struct itimerval itval;
+ static int inited = 0;
+#ifdef HAVE_LINUX_RTC_H
+ const char *rtc_freq;
+ if (!inited && (rtc_freq = g_getenv ("MONO_RTC"))) {
+ int freq = 0;
+ inited = 1;
+ if (*rtc_freq)
+ freq = atoi (rtc_freq);
+ if (!freq)
+ freq = 1024;
+ rtc_fd = open ("/dev/rtc", O_RDONLY);
+ if (rtc_fd == -1) {
+ perror ("open /dev/rtc");
+ return;
+ }
+ add_signal_handler (SIGPROF, sigprof_signal_handler);
+ if (ioctl (rtc_fd, RTC_IRQP_SET, freq) == -1) {
+ perror ("set rtc freq");
+ return;
+ }
+ if (ioctl (rtc_fd, RTC_PIE_ON, 0) == -1) {
+ perror ("start rtc");
+ return;
+ }
+ if (fcntl (rtc_fd, F_SETSIG, SIGPROF) == -1) {
+ perror ("setsig");
+ return;
+ }
+ if (fcntl (rtc_fd, F_SETOWN, getpid ()) == -1) {
+ perror ("setown");
+ return;
+ }
+ enable_rtc_timer (TRUE);
+ return;
+ }
+ if (rtc_fd >= 0)
+ return;
+#endif
+
+ itval.it_interval.tv_usec = 999;
+ itval.it_interval.tv_sec = 0;
+ itval.it_value = itval.it_interval;
+ setitimer (ITIMER_PROF, &itval, NULL);
+ if (inited)
+ return;
+ inited = 1;
+ add_signal_handler (SIGPROF, sigprof_signal_handler);
+#endif
+}
+
/* mono_jit_create_remoting_trampoline:
* @method: pointer to the method info
*
{
MonoDomain *domain;
+ InitializeCriticalSection (&jit_mutex);
+
+ global_codeman = mono_code_manager_new ();
+ jit_icall_name_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
mono_arch_cpu_init ();
if (!g_thread_supported ())
mono_jit_tls_id = TlsAlloc ();
setup_jit_tls_data ((gpointer)-1, mono_thread_abort);
- InitializeCriticalSection (&jit_mutex);
-
mono_burg_init ();
if (default_opt & MONO_OPT_AOT)
mono_install_stack_walk (mono_jit_walk_stack);
domain = mono_init_from_assembly (filename, filename);
- mono_init_icall ();
+ mono_icall_init ();
mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info",
ves_icall_get_frame_info);
mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace",
ves_icall_get_trace);
+ mono_add_internal_call ("System.Security.SecurityFrame::_GetSecurityFrame",
+ ves_icall_System_Security_SecurityFrame_GetSecurityFrame);
+ mono_add_internal_call ("System.Security.SecurityFrame::_GetSecurityStack",
+ ves_icall_System_Security_SecurityFrame_GetSecurityStack);
mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers",
mono_runtime_install_handlers);
mono_register_jit_icall (mono_arch_get_rethrow_exception (), "mono_arch_rethrow_exception", helper_sig_void_obj, TRUE);
mono_register_jit_icall (mono_arch_get_throw_exception_by_name (), "mono_arch_throw_exception_by_name",
helper_sig_void_ptr, TRUE);
+#if MONO_ARCH_HAVE_THROW_CORLIB_EXCEPTION
+ mono_register_jit_icall (mono_arch_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception",
+ helper_sig_void_ptr, TRUE);
+#endif
mono_register_jit_icall (mono_thread_get_pending_exception, "mono_thread_get_pending_exception", helper_sig_obj_void, FALSE);
mono_register_jit_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", helper_sig_void_void, FALSE);
mono_register_jit_icall (mono_thread_force_interruption_checkpoint, "mono_thread_force_interruption_checkpoint", helper_sig_void_void, FALSE);
/* other jit icalls */
mono_register_jit_icall (mono_class_static_field_address , "mono_class_static_field_address",
helper_sig_ptr_ptr_ptr, FALSE);
- mono_register_jit_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", helper_sig_ptr_ptr_ptr, FALSE);
+ mono_register_jit_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", helper_sig_ptr_ptr_ptr_ptr, FALSE);
mono_register_jit_icall (mono_get_special_static_data, "mono_get_special_static_data", helper_sig_ptr_int, FALSE);
mono_register_jit_icall (mono_ldstr, "mono_ldstr", helper_sig_ldstr, FALSE);
mono_register_jit_icall (helper_memcpy, "helper_memcpy", helper_sig_memcpy, FALSE);
g_print ("VTable data size: %ld\n", mono_stats.class_vtable_size);
g_print ("\nGeneric instances: %ld\n", mono_stats.generic_instance_count);
- g_print ("Inflated methods: %ld\n", mono_stats.inflated_method_count);
+ g_print ("Initialized classes: %ld\n", mono_stats.generic_class_count);
+ g_print ("Inflated methods: %ld / %ld\n", mono_stats.inflated_method_count_2,
+ mono_stats.inflated_method_count);
g_print ("Inflated types: %ld\n", mono_stats.inflated_type_count);
g_print ("Generics metadata size: %ld\n", mono_stats.generics_metadata_size);
}
void
mini_cleanup (MonoDomain *domain)
{
+#ifdef HAVE_LINUX_RTC_H
+ if (rtc_fd >= 0)
+ enable_rtc_timer (FALSE);
+#endif
+
/*
* mono_runtime_cleanup() and mono_domain_finalize () need to
* be called early since they need the execution engine still
mono_debug_cleanup ();
+ mono_icall_cleanup ();
+
#ifdef PLATFORM_WIN32
win32_seh_cleanup();
#endif
mono_domain_free (domain, TRUE);
+ mono_code_manager_destroy (global_codeman);
+ g_hash_table_destroy (jit_icall_name_hash);
+ if (class_init_hash_addr)
+ g_hash_table_destroy (class_init_hash_addr);
+
print_jit_stats ();
}