#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);
#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)
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)
{
(dest)->type = STACK_I4; \
} while (0)
-#if SIZEOF_VOID_P == 8
-#define OP_PCONST OP_I8CONST
-#else
-#define OP_PCONST OP_ICONST
-#endif
-
#define NEW_PCONST(cfg,dest,val) do { \
(dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
(dest)->opcode = OP_PCONST; \
#define NEW_AOTCONST(cfg,dest,patch_type,cons) do { \
(dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
- (dest)->opcode = mono_compile_aot ? OP_GOT_ENTRY : OP_PCONST; \
- if (mono_compile_aot) { \
+ (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); \
#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)->opcode = cfg->compile_aot ? OP_AOTCONST : OP_PCONST; \
(dest)->inst_p0 = (cons); \
(dest)->inst_i1 = (gpointer)(patch_type); \
(dest)->type = STACK_PTR; \
#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, mono_compile_aot ? (gpointer)((vtable)->klass) : (vtable))
+#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_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 { \
if (cfg->opt & MONO_OPT_SHARED) { \
NEW_TEMPLOAD (cfg, dest, mono_get_domainvar (cfg)->inst_c0); \
(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)
{
mono_get_got_var (MonoCompile *cfg)
{
#ifdef MONO_ARCH_NEED_GOT_VAR
- if (!mono_compile_aot)
+ 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);
}
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;
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->inst.flags |= MONO_INST_HAS_METHOD;
call->inst.inst_left = this;
- if (virtual && (call->method->klass->flags & TYPE_ATTRIBUTE_INTERFACE))
+ 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);
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;
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);
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) {
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);
}
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;
++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;
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);
}
- 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;
int temp;
MonoInst *iargs [3];
- if (mono_compile_aot) {
+ if (cfg->compile_aot) {
cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
}
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);
ins->inst_newa_class = klass;
ins->cil_code = ip;
*sp++ = 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);
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 (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));
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;
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) && 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);
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);
#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 (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;
MONO_ADD_INS (init_localsbb, store);
}
- if (cfg->method == method && cfg->got_var) {
- MonoInst *load, *store, *dummy_use;
- MonoInst *get_got;
- MONO_INST_NEW (cfg, get_got, OP_LOAD_GOTADDR);
- NEW_TEMPSTORE (cfg, store, cfg->got_var->inst_c0, get_got);
- MONO_ADD_INS (init_localsbb, store);
-
- /*
- * 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 (end_bblock, dummy_use);
- }
+ if (cfg->method == method && cfg->got_var)
+ mono_emit_load_got_addr (cfg);
if (header->init_locals) {
MonoInst *store;
}
}
-
/* 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)
/* 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;
break;
case MONO_PATCH_INFO_IID:
mono_class_init (patch_info->data.klass);
- target = GINT_TO_POINTER (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:
}
}
+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) {
mono_domain_unlock (cfg->domain);
}
- if (!mono_compile_aot)
+ 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++) {
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)
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);
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);
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 ();
}