#include <mono/metadata/security-core-clr.h>
#include <mono/metadata/verify.h>
#include <mono/metadata/verify-internals.h>
+#include <mono/metadata/mempool-internals.h>
+#include <mono/metadata/attach.h>
#include <mono/utils/mono-math.h>
#include <mono/utils/mono-compiler.h>
#include <mono/utils/mono-counters.h>
goto exception_exit; \
} \
} while (0)
-#define GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD(opcode) do { \
- if (method->klass->valuetype) \
- GENERIC_SHARING_FAILURE ((opcode)); \
- } while (0)
#define GET_RGCTX(rgctx, context_used) do { \
MonoInst *this = NULL; \
g_assert (context_used); \
- GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD(*ip); \
if (!(method->flags & METHOD_ATTRIBUTE_STATIC) && \
- !((context_used) & MONO_GENERIC_CONTEXT_USED_METHOD)) \
+ !((context_used) & MONO_GENERIC_CONTEXT_USED_METHOD) && \
+ !method->klass->valuetype) \
NEW_ARGLOAD (cfg, this, 0); \
(rgctx) = get_runtime_generic_context (cfg, method, (context_used), this, ip); \
} while (0)
MonoTraceSpec *mono_jit_trace_calls = NULL;
gboolean mono_break_on_exc = FALSE;
-#ifndef DISABLE_AOT
gboolean mono_compile_aot = FALSE;
-#endif
/* If this is set, no code is generated dynamically, everything is taken from AOT files */
gboolean mono_aot_only = FALSE;
/* Whenever to use IMT */
/* Whenever to disable passing/returning small valuetypes in registers for managed methods */
gboolean disable_vtypes_in_regs = FALSE;
+gboolean mono_dont_free_global_codeman;
+
+#ifdef DISABLE_JIT
+/* Define this here, since many files reference it */
+const guint8 mono_burg_arity [MBMAX_OPCODES] = {
+};
+#endif
+
gboolean
mono_running_on_valgrind (void)
{
user_data.ip = ip;
user_data.method = NULL;
mono_domain_lock (domain);
- g_hash_table_foreach (domain->jit_trampoline_hash, find_tramp, &user_data);
+ g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
mono_domain_unlock (domain);
if (user_data.method) {
char *mname = mono_method_full_name (user_data.method, TRUE);
user_data.ip = ip;
user_data.method = NULL;
mono_domain_lock (domain);
- g_hash_table_foreach (domain->jit_trampoline_hash, find_tramp, &user_data);
+ g_hash_table_foreach (domain_jit_info (domain)->jit_trampoline_hash, find_tramp, &user_data);
mono_domain_unlock (domain);
if (user_data.method) {
char *mname = mono_method_full_name (user_data.method, TRUE);
*
* Return whenever BB1 and BB2 are linked in the CFG.
*/
-static gboolean
+gboolean
mono_bblocks_linked (MonoBasicBlock *bb1, MonoBasicBlock *bb2)
{
int i;
}
}
-static guint32
-reverse_branch_op (guint32 opcode)
+guint32
+mono_reverse_branch_op (guint32 opcode)
{
static const int reverse_map [] = {
CEE_BNE_UN, CEE_BLT, CEE_BLE, CEE_BGT, CEE_BGE,
}
#endif
-/*
- * Returns the type used in the eval stack when @type is loaded.
- * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
- */
-static void
-type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
-{
- MonoClass *klass;
-
- inst->klass = klass = mono_class_from_mono_type (type);
- if (type->byref) {
- inst->type = STACK_MP;
- return;
- }
-
-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:
- case MONO_TYPE_I2:
- case MONO_TYPE_U2:
- case MONO_TYPE_CHAR:
- case MONO_TYPE_I4:
- case MONO_TYPE_U4:
- inst->type = STACK_I4;
- return;
- case MONO_TYPE_I:
- case MONO_TYPE_U:
- case MONO_TYPE_PTR:
- case MONO_TYPE_FNPTR:
- inst->type = STACK_PTR;
- return;
- case MONO_TYPE_CLASS:
- case MONO_TYPE_STRING:
- case MONO_TYPE_OBJECT:
- case MONO_TYPE_SZARRAY:
- case MONO_TYPE_ARRAY:
- inst->type = STACK_OBJ;
- return;
- case MONO_TYPE_I8:
- case MONO_TYPE_U8:
- inst->type = STACK_I8;
- return;
- case MONO_TYPE_R4:
- case MONO_TYPE_R8:
- inst->type = STACK_R8;
- return;
- case MONO_TYPE_VALUETYPE:
- if (type->data.klass->enumtype) {
- type = type->data.klass->enum_basetype;
- goto handle_enum;
- } else {
- inst->klass = klass;
- inst->type = STACK_VTYPE;
- return;
- }
- case MONO_TYPE_TYPEDBYREF:
- inst->klass = mono_defaults.typed_reference_class;
- inst->type = STACK_VTYPE;
- return;
- case MONO_TYPE_GENERICINST:
- type = &type->data.generic_class->container_class->byval_arg;
- goto handle_enum;
- case MONO_TYPE_VAR :
- case MONO_TYPE_MVAR :
- /* FIXME: all the arguments must be references for now,
- * later look inside cfg and see if the arg num is
- * really a reference
- */
- g_assert (cfg->generic_sharing_context);
- inst->type = STACK_OBJ;
- return;
- default:
- g_error ("unknown type 0x%02x in eval stack type", type->type);
- }
-}
-
/*
* The following tables are used to quickly validate the IL code in type_from_op ().
*/
printf (" Create LVAR R%d (R%d, R%d)\n", inst->dreg, inst->dreg + 1, inst->dreg + 2);
}
+#ifdef MONO_ARCH_SOFT_FLOAT
+ if (cfg->opt & MONO_OPT_SSA) {
+ if (mono_type_is_float (type))
+ inst->flags = MONO_INST_VOLATILE;
+ }
+#endif
+
/* Allocate a dummy MonoInst for the first vreg */
MONO_INST_NEW (cfg, tree, OP_LOCAL);
tree->dreg = inst->dreg + 1;
MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
return ins;
}
+ if (strcmp (cmethod->name, "SpinWait_nop") == 0) {
+ MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
+ return ins;
+ }
} else if (mini_class_is_system_array (cmethod->klass) &&
strcmp (cmethod->name, "GetGenericValueImpl") == 0) {
MonoInst *sp [2];
static MonoInst*
get_runtime_generic_context (MonoCompile *cfg, MonoMethod *method, int context_used, MonoInst *this, unsigned char *ip)
{
- g_assert (!method->klass->valuetype);
+ g_assert (cfg->generic_sharing_context);
+
+ if (method->klass->valuetype)
+ g_assert (!this);
if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
MonoInst *mrgctx_loc, *mrgctx_var;
NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
return mrgctx_var;
- } else if (method->flags & METHOD_ATTRIBUTE_STATIC) {
+ } else if ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype) {
MonoInst *vtable_loc, *vtable_var;
g_assert (!this);
MonoMethodSignature *signature = mono_method_signature (method);
if (rgctx) {
+ /* FIXME: What if the class is shared? We might not
+ have to get the address of the method from the
+ RGCTX. */
MonoInst *addr = get_runtime_generic_context_method (cfg, caller_method, context_used, bblock, method,
generic_context, rgctx, MONO_RGCTX_INFO_GENERIC_METHOD_CODE, ip);
g_assert (mono_class_is_nullable (klass));
+ /* FIXME: What if the class is shared? We might not have to
+ get the method address from the RGCTX. */
method_addr = get_runtime_generic_context_method (cfg, caller_method, context_used, bblock, method,
generic_context, rgctx, MONO_RGCTX_INFO_GENERIC_METHOD_CODE, ip);
temp = mono_emit_rgctx_calli_spilled (cfg, bblock, mono_method_signature (method), &val,
*_inline_costs = inline_costs;
*_real_offset = real_offset;
return return_value;
-exception_exit:
- return_value = -2;
- goto do_return;
unverified:
return_value = -1;
goto do_return;
add->klass = klass;
*sp = add;
-do_return:
*_bblock = bblock;
*_ip = ip;
*_sp = sp;
*_inline_costs = inline_costs;
*_real_offset = real_offset;
return return_value;
-exception_exit:
- return_value = -2;
- goto do_return;
}
gboolean
* methods) are live.
*/
if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
- mini_method_get_context (method)->method_inst) {
+ mini_method_get_context (method)->method_inst ||
+ method->klass->valuetype) {
mono_get_vtable_var (cfg);
} else {
MonoInst *this, *dummy_use;
float *f;
/* we should really allocate this only late in the compilation process */
mono_domain_lock (cfg->domain);
- f = mono_mempool_alloc (cfg->domain->mp, sizeof (float));
+ f = mono_domain_alloc (cfg->domain, sizeof (float));
mono_domain_unlock (cfg->domain);
CHECK_OPSIZE (5);
CHECK_STACK_OVF (1);
case CEE_LDC_R8: {
double *d;
mono_domain_lock (cfg->domain);
- d = mono_mempool_alloc (cfg->domain->mp, sizeof (double));
+ d = mono_domain_alloc (cfg->domain, sizeof (double));
mono_domain_unlock (cfg->domain);
CHECK_OPSIZE (9);
CHECK_STACK_OVF (1);
if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp))
UNVERIFIED;
- if (cmethod && (cmethod->flags & METHOD_ATTRIBUTE_STATIC) &&
+ if (cmethod && ((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
(cmethod->klass->generic_class || cmethod->klass->generic_container)) {
gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
MonoGenericContext *context = mini_class_get_context (cmethod->klass);
* should be a flag in the cfg to
* request a generic sharing context.
*/
- if (context_used && method->flags & METHOD_ATTRIBUTE_STATIC)
+ if (context_used && ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
mono_get_vtable_var (cfg);
}
else
no_spill = FALSE;
- /* FIXME: only do this for generic methods if
- they are not shared! */
- if (context_used &&
- (cmethod->klass->valuetype ||
- (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst && !pass_mrgctx) ||
- ((cmethod->flags & METHOD_ATTRIBUTE_STATIC) &&
- mono_class_generic_sharing_enabled (cmethod->klass)) ||
- (!imt_arg && !mono_method_is_generic_sharable_impl (cmethod, TRUE) &&
- (!virtual || cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
- !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))))) {
+ if (context_used && !imt_arg &&
+ (!mono_method_is_generic_sharable_impl (cmethod, TRUE) ||
+ !mono_class_generic_sharing_enabled (cmethod->klass)) &&
+ (!virtual || cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
+ !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
MonoInst *rgctx;
INLINE_FAILURE;
MonoMethodSignature *fsig;
MonoInst this_ins;
int temp;
+ MonoInst *vtable_arg = NULL;
CHECK_OPSIZE (5);
token = read32 (ip + 1);
ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
}
+ if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
+ mono_method_is_generic_sharable_impl (cmethod, TRUE)) {
+ if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
+ if (context_used) {
+ MonoInst *rgctx;
+
+ GET_RGCTX (rgctx, context_used);
+ vtable_arg = get_runtime_generic_context_method_rgctx (cfg, method,
+ context_used, bblock, cmethod, generic_context, rgctx, ip);
+ } else {
+ MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
+ MonoMethodRuntimeGenericContext *mrgctx;
+
+ mrgctx = mono_method_lookup_rgctx (vtable,
+ mini_method_get_context (cmethod)->method_inst);
+
+ NEW_PCONST (cfg, vtable_arg, mrgctx);
+ }
+ } else {
+ if (context_used) {
+ MonoInst *rgctx;
+
+ GET_RGCTX (rgctx, context_used);
+ vtable_arg = get_runtime_generic_context_ptr (cfg, method, context_used,
+ bblock, cmethod->klass, generic_context,
+ rgctx, MONO_RGCTX_INFO_VTABLE, ip);
+ } else {
+ MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
+
+ CHECK_TYPELOAD (cmethod->klass);
+ NEW_VTABLECONST (cfg, vtable_arg, vtable);
+ }
+ }
+ }
+
n = fsig->param_count;
CHECK_STACK (n);
((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
MonoInst *iargs [3];
int temp;
-
+
+ g_assert (!vtable_arg);
+
sp -= n;
NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
if (mini_class_is_system_array (cmethod->klass)) {
g_assert (!context_used);
+ g_assert (!vtable_arg);
NEW_METHODCONST (cfg, *sp, cmethod);
temp = handle_array_new (cfg, bblock, fsig->param_count, sp, ip);
} else if (cmethod->string_ctor) {
g_assert (!context_used);
+ g_assert (!vtable_arg);
/* we simply pass a null pointer */
NEW_PCONST (cfg, *sp, NULL);
if (cmethod->klass->marshalbyref)
callvirt_this_arg = sp [0];
- if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used &&
+ if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
mono_method_check_inlining (cfg, cmethod) &&
!mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
!g_list_find (dont_inline, cmethod)) {
mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, callvirt_this_arg);
}
} else if (context_used &&
- (cmethod->klass->valuetype ||
- !mono_method_is_generic_sharable_impl (cmethod, TRUE))) {
+ (!mono_method_is_generic_sharable_impl (cmethod, TRUE) ||
+ !mono_class_generic_sharing_enabled (cmethod->klass))) {
MonoInst *rgctx, *cmethod_addr;
g_assert (!callvirt_this_arg);
bblock, cmethod,
generic_context, rgctx, MONO_RGCTX_INFO_GENERIC_METHOD_CODE, ip);
- mono_emit_calli_spilled (cfg, bblock, fsig, sp, cmethod_addr, ip);
+ mono_emit_rgctx_calli_spilled (cfg, bblock, fsig, sp, cmethod_addr, vtable_arg, ip);
} else {
/* Prevent inlining of methods which call other methods */
INLINE_FAILURE;
/* now call the actual ctor */
- mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, callvirt_this_arg);
+ mono_emit_rgctx_method_call_spilled (cfg, bblock, cmethod, fsig, sp,
+ vtable_arg, NULL, ip, callvirt_this_arg);
}
}
call = mono_emit_call_args (cfg, bblock, sig, NULL, FALSE, FALSE, ip, FALSE);
call->inst.opcode = OP_TRAMPCALL_VTABLE;
- call->fptr = mono_get_trampoline_code (MONO_TRAMPOLINE_GENERIC_CLASS_INIT);
+ call->fptr = mono_create_generic_class_init_trampoline ();
call->inst.inst_left = vtable;
if (sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL) {
MonoInst *load;
NEW_LDELEMA (cfg, load, sp, mono_defaults.object_class);
- MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
+ MONO_INST_NEW (cfg, ins, CEE_STIND_REF);
ins->inst_left = load;
ins->inst_right = sp [2];
MONO_ADD_INS (bblock, ins);
MonoInst *argconst;
MonoMethod *cil_method, *ctor_method;
int temp;
- gboolean is_shared = FALSE;
+ gboolean needs_static_rgctx_invoke;
CHECK_STACK_OVF (1);
CHECK_OPSIZE (6);
if (cfg->generic_sharing_context)
context_used = mono_method_check_context_used (cmethod);
- if (mono_class_generic_sharing_enabled (cmethod->klass)) {
- if ((cmethod->flags & METHOD_ATTRIBUTE_STATIC) &&
- (cmethod->klass->generic_class ||
- cmethod->klass->generic_container)) {
- is_shared = TRUE;
- }
- if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst)
- is_shared = TRUE;
- }
+ needs_static_rgctx_invoke = mono_method_needs_static_rgctx_invoke (cmethod, TRUE);
cil_method = cmethod;
if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
/* FIXME: SGEN support */
/* FIXME: handle shared static generic methods */
/* FIXME: handle this in shared code */
- if (!is_shared && !context_used && (sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ) && (ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context)) && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
+ if (!needs_static_rgctx_invoke && !context_used && (sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ) && (ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context)) && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
MonoInst *target_ins;
ip += 6;
if (context_used) {
MonoInst *rgctx;
- if (is_shared)
+ if (needs_static_rgctx_invoke)
cmethod = mono_marshal_get_static_rgctx_invoke (cmethod);
GET_RGCTX (rgctx, context_used);
argconst = get_runtime_generic_context_method (cfg, method, context_used,
bblock, cmethod,
generic_context, rgctx, MONO_RGCTX_INFO_METHOD, ip);
- } else if (is_shared) {
+ } else if (needs_static_rgctx_invoke) {
NEW_METHODCONST (cfg, argconst, mono_marshal_get_static_rgctx_invoke (cmethod));
} else {
NEW_METHODCONST (cfg, argconst, cmethod);
}
- if (method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED)
- temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn, &argconst, ip);
- else
- temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn_nosync, &argconst, ip);
+ temp = mono_emit_jit_icall (cfg, bblock, mono_ldftn, &argconst, ip);
NEW_TEMPLOAD (cfg, *sp, temp);
sp ++;
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))
+ if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
handler_offset = clause->handler_offset;
+ break;
+ }
}
bblock->flags |= BB_EXCEPTION_UNSAFE;
helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
}
-gconstpointer
-mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
+static gconstpointer
+mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile)
{
char *name;
MonoMethod *wrapper;
wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func, check_for_pending_exc);
g_free (name);
- trampoline = mono_create_ftnptr (domain, mono_create_jit_trampoline_in_domain (domain, wrapper, TRUE));
+ if (do_compile)
+ trampoline = mono_compile_method (wrapper);
+ else
+ trampoline = mono_create_ftnptr (domain, mono_create_jit_trampoline_in_domain (domain, wrapper));
mono_register_jit_icall_wrapper (callinfo, trampoline);
callinfo->trampoline = trampoline;
return callinfo->trampoline;
}
+gconstpointer
+mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
+{
+ return mono_icall_get_wrapper_full (callinfo, FALSE);
+}
+
static void
mono_dynamic_code_hash_insert (MonoDomain *domain, MonoMethod *method, MonoJitDynamicMethodInfo *ji)
{
- if (!domain->dynamic_code_hash)
- domain->dynamic_code_hash = g_hash_table_new (NULL, NULL);
- g_hash_table_insert (domain->dynamic_code_hash, method, ji);
+ if (!domain_jit_info (domain)->dynamic_code_hash)
+ domain_jit_info (domain)->dynamic_code_hash = g_hash_table_new (NULL, NULL);
+ g_hash_table_insert (domain_jit_info (domain)->dynamic_code_hash, method, ji);
}
static MonoJitDynamicMethodInfo*
{
MonoJitDynamicMethodInfo *res;
- if (domain->dynamic_code_hash)
- res = g_hash_table_lookup (domain->dynamic_code_hash, method);
+ if (domain_jit_info (domain)->dynamic_code_hash)
+ res = g_hash_table_lookup (domain_jit_info (domain)->dynamic_code_hash, method);
else
res = NULL;
return res;
GSList *slots;
} StackSlotInfo;
-static inline GSList*
-g_slist_prepend_mempool (MonoMemPool *mp, GSList *list,
- gpointer data)
-{
- GSList *new_list;
-
- new_list = mono_mempool_alloc (mp, sizeof (GSList));
- new_list->data = data;
- new_list->next = list;
-
- return new_list;
-}
-
static gint
compare_by_interval_start_pos_func (gconstpointer a, gconstpointer b)
{
return 1;
}
+#ifndef DISABLE_JIT
+
#if 0
#define LSCAN_DEBUG(a) do { a; } while (0)
#else
return mono_allocate_stack_slots_full (m, TRUE, stack_size, stack_align);
}
+#else
+
+gint32*
+mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *stack_size, guint32 *stack_align)
+{
+ g_assert_not_reached ();
+ return NULL;
+}
+
+#endif /* DISABLE_JIT */
+
void
mono_register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpointer func, gboolean no_throw)
{
mono_mempool_destroy (cfg->mempool);
g_list_free (cfg->ldstr_list);
g_hash_table_destroy (cfg->token_info_hash);
-
- g_free (cfg->reverse_inst_list);
+ if (cfg->abs_patches)
+ g_hash_table_destroy (cfg->abs_patches);
g_free (cfg->varinfo);
g_free (cfg->vars);
return NULL;
MONO_INST_NEW (cfg, ins, OP_TLS_GET);
- ins->dreg = mono_regstate_next_int (cfg->rs);
+ ins->dreg = cfg->new_ir ? mono_alloc_preg (cfg) : mono_regstate_next_int (cfg->rs);
ins->inst_offset = offset;
return ins;
#else
res->data.table = mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
break;
+ case MONO_PATCH_INFO_RGCTX_FETCH:
+ res->data.rgctx_entry = mono_mempool_alloc (mp, sizeof (MonoJumpInfoRgctxEntry));
+ memcpy (res->data.rgctx_entry, patch_info->data.rgctx_entry, sizeof (MonoJumpInfoRgctxEntry));
+ res->data.rgctx_entry->data = mono_patch_info_dup_mp (mp, res->data.rgctx_entry->data);
+ break;
default:
break;
}
case MONO_PATCH_INFO_IMAGE:
case MONO_PATCH_INFO_INTERNAL_METHOD:
case MONO_PATCH_INFO_JIT_ICALL_ADDR:
- case MONO_PATCH_INFO_WRAPPER:
case MONO_PATCH_INFO_FIELD:
case MONO_PATCH_INFO_SFLDA:
return (ji->type << 8) | (gssize)ji->data.target;
break;
}
case MONO_PATCH_INFO_METHOD_JUMP:
- target = mono_create_jump_trampoline (domain, patch_info->data.method, TRUE);
+ target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE);
break;
case MONO_PATCH_INFO_METHOD:
if (patch_info->data.method == method) {
/* get the trampoline to the method from the domain */
if (method && method->wrapper_type == MONO_WRAPPER_STATIC_RGCTX_INVOKE) {
target = mono_create_jit_trampoline_in_domain (mono_domain_get (),
- patch_info->data.method, FALSE);
+ patch_info->data.method);
} else {
target = mono_create_jit_trampoline (patch_info->data.method);
}
} else {
mono_domain_lock (domain);
if (mono_aot_only)
- jump_table = mono_mempool_alloc (domain->mp, sizeof (gpointer) * patch_info->data.table->table_size);
+ jump_table = mono_domain_alloc (domain, sizeof (gpointer) * patch_info->data.table->table_size);
else
jump_table = mono_code_manager_reserve (domain->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
mono_domain_unlock (domain);
case MONO_PATCH_INFO_GOT_OFFSET:
case MONO_PATCH_INFO_NONE:
break;
+ case MONO_PATCH_INFO_RGCTX_FETCH: {
+ MonoJumpInfoRgctxEntry *entry = patch_info->data.rgctx_entry;
+ guint32 slot = -1;
+
+ switch (entry->data->type) {
+ case MONO_PATCH_INFO_CLASS:
+ slot = mono_method_lookup_or_register_other_info (entry->method, entry->in_mrgctx, &entry->data->data.klass->byval_arg, entry->info_type, mono_method_get_context (entry->method));
+ break;
+ case MONO_PATCH_INFO_METHOD:
+ case MONO_PATCH_INFO_METHODCONST:
+ slot = mono_method_lookup_or_register_other_info (entry->method, entry->in_mrgctx, entry->data->data.method, entry->info_type, mono_method_get_context (entry->method));
+ break;
+ case MONO_PATCH_INFO_FIELD:
+ slot = mono_method_lookup_or_register_other_info (entry->method, entry->in_mrgctx, entry->data->data.field, entry->info_type, mono_method_get_context (entry->method));
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ target = mono_create_rgctx_lazy_fetch_trampoline (slot);
+ break;
+ }
+ case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
+ target = mono_create_generic_class_init_trampoline ();
+ break;
default:
g_assert_not_reached ();
}
}
static void
-nullify_basic_block (MonoBasicBlock *bb)
-{
- bb->in_count = 0;
- bb->out_count = 0;
- bb->in_bb = NULL;
- bb->out_bb = NULL;
- bb->next_bb = NULL;
- bb->code = bb->last_ins = NULL;
- bb->cil_code = NULL;
-}
-
-static void
-replace_out_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
+mono_compile_create_vars (MonoCompile *cfg)
{
+ MonoMethodSignature *sig;
+ MonoMethodHeader *header;
int i;
- for (i = 0; i < bb->out_count; i++) {
- MonoBasicBlock *ob = bb->out_bb [i];
- if (ob == orig) {
- if (!repl) {
- if (bb->out_count > 1) {
- bb->out_bb [i] = bb->out_bb [bb->out_count - 1];
- }
- bb->out_count--;
- } else {
- bb->out_bb [i] = repl;
- }
+ header = mono_method_get_header (cfg->method);
+
+ sig = mono_method_signature (cfg->method);
+
+ if (!MONO_TYPE_IS_VOID (sig->ret)) {
+ if (cfg->new_ir) {
+ cfg->ret = mono_compile_create_var (cfg, sig->ret, OP_ARG);
+ /* Inhibit optimizations */
+ cfg->ret->flags |= MONO_INST_VOLATILE;
+ } else {
+ cfg->ret = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
+ cfg->ret->opcode = OP_RETARG;
+ cfg->ret->inst_vtype = sig->ret;
+ cfg->ret->klass = mono_class_from_mono_type (sig->ret);
}
}
-}
+ if (cfg->verbose_level > 2)
+ g_print ("creating vars\n");
-static void
-replace_in_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
-{
- int i;
+ cfg->args = mono_mempool_alloc0 (cfg->mempool, (sig->param_count + sig->hasthis) * sizeof (MonoInst*));
- 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;
- }
+ if (sig->hasthis)
+ cfg->args [0] = mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
+
+ for (i = 0; i < sig->param_count; ++i) {
+ cfg->args [i + sig->hasthis] = mono_compile_create_var (cfg, sig->params [i], OP_ARG);
+ if (sig->params [i]->byref) {
+ if (!cfg->new_ir) cfg->disable_ssa = TRUE;
}
}
-}
-static void
-replace_out_block_in_code (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl) {
- MonoInst *ins;
-
- for (ins = bb->code; ins != NULL; ins = ins->next) {
- switch (ins->opcode) {
- case OP_BR:
- if (ins->inst_target_bb == orig)
- ins->inst_target_bb = repl;
- break;
- case OP_CALL_HANDLER:
- if (ins->inst_target_bb == orig)
- ins->inst_target_bb = repl;
- break;
- case OP_SWITCH: {
- int i;
- int n = GPOINTER_TO_INT (ins->klass);
- for (i = 0; i < n; i++ ) {
- if (ins->inst_many_bb [i] == orig)
- ins->inst_many_bb [i] = repl;
- }
- break;
+ if (cfg->new_ir && cfg->verbose_level > 2) {
+ if (cfg->ret) {
+ printf ("\treturn : ");
+ mono_print_ins (cfg->ret);
}
- default:
- if (MONO_IS_COND_BRANCH_OP (ins)) {
- if (ins->inst_true_bb == orig)
- ins->inst_true_bb = repl;
- if (ins->inst_false_bb == orig)
- ins->inst_false_bb = repl;
- } else if (MONO_IS_JUMP_TABLE (ins)) {
- int i;
- MonoJumpInfoBBTable *table = MONO_JUMP_TABLE_FROM_INS (ins);
- for (i = 0; i < table->table_size; i++ ) {
- if (table->table [i] == orig)
- table->table [i] = repl;
- }
- }
- break;
+ if (sig->hasthis) {
+ printf ("\tthis: ");
+ mono_print_ins (cfg->args [0]);
}
- }
-}
-
-/**
- * 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) {
- bb->not_useless = TRUE;
- return FALSE;
- }
-
- MONO_BB_FOR_EACH_INS (bb, inst) {
- switch (inst->opcode) {
- case OP_NOP:
- break;
- case OP_BR:
- target_bb = inst->inst_target_bb;
- break;
- default:
- bb->not_useless = TRUE;
- 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;
+ for (i = 0; i < sig->param_count; ++i) {
+ printf ("\targ [%d]: ", i);
+ mono_print_ins (cfg->args [i + sig->hasthis]);
}
}
-
- /* Do not touch BBs following a switch (they are the "default" branch) */
- if ((previous_bb->last_ins != NULL) && (previous_bb->last_ins->opcode == OP_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;
- }
- /*
- * Do not touch BBs following a try block as the code in
- * mini_method_compile needs them to compute the length of the try block.
- */
- if (MONO_BBLOCK_IS_IN_REGION (previous_bb, MONO_REGION_TRY))
- return FALSE;
-
- /* Check that there is a target BB, and that bb is not an empty loop (Bug 75061) */
- if ((target_bb != NULL) && (target_bb != bb)) {
- int i;
-
- if (cfg->verbose_level > 1) {
- printf ("remove_block_if_useless, removed BB%d\n", bb->block_num);
- }
-
- /* unlink_bblock () modifies the bb->in_bb array so can't use a for loop here */
- while (bb->in_count) {
- MonoBasicBlock *in_bb = bb->in_bb [0];
- mono_unlink_bblock (cfg, in_bb, bb);
- link_bblock (cfg, in_bb, target_bb);
- replace_out_block_in_code (in_bb, bb, target_bb);
- }
-
- mono_unlink_bblock (cfg, bb, target_bb);
-
- if ((previous_bb != cfg->bb_entry) &&
- (previous_bb->region == bb->region) &&
- ((previous_bb->last_ins == NULL) ||
- ((previous_bb->last_ins->opcode != OP_BR) &&
- (! (MONO_IS_COND_BRANCH_OP (previous_bb->last_ins))) &&
- (previous_bb->last_ins->opcode != OP_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, OP_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;
- }
-}
-
-void
-mono_merge_basic_blocks (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *bbn)
-{
- MonoInst *inst;
- MonoBasicBlock *prev_bb;
- int i;
-
- bb->has_array_access |= bbn->has_array_access;
- bb->extended |= bbn->extended;
-
- mono_unlink_bblock (cfg, bb, bbn);
- for (i = 0; i < bbn->out_count; ++i)
- mono_link_bblock (cfg, bb, bbn->out_bb [i]);
- while (bbn->out_count)
- mono_unlink_bblock (cfg, bbn, bbn->out_bb [0]);
-
- /* Handle the branch at the end of the bb */
- for (inst = bb->code; inst != NULL; inst = inst->next) {
- if (inst->opcode == OP_CALL_HANDLER) {
- g_assert (inst->inst_target_bb == bbn);
- NULLIFY_INS (inst);
- }
- if (MONO_IS_JUMP_TABLE (inst)) {
- int i;
- MonoJumpInfoBBTable *table = MONO_JUMP_TABLE_FROM_INS (inst);
- for (i = 0; i < table->table_size; i++ ) {
- /* Might be already NULL from a previous merge */
- if (table->table [i])
- g_assert (table->table [i] == bbn);
- table->table [i] = NULL;
- }
- /* Can't nullify this as later instructions depend on it */
- }
- }
- if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins)) {
- g_assert (bb->last_ins->inst_false_bb == bbn);
- bb->last_ins->inst_false_bb = NULL;
- bb->extended = TRUE;
- } else if (bb->last_ins && MONO_IS_BRANCH_OP (bb->last_ins)) {
- NULLIFY_INS (bb->last_ins);
- }
-
- if (bb->last_ins) {
- if (bbn->code) {
- bb->last_ins->next = bbn->code;
- bbn->code->prev = bb->last_ins;
- bb->last_ins = bbn->last_ins;
- }
- } else {
- bb->code = bbn->code;
- bb->last_ins = bbn->last_ins;
- }
- for (prev_bb = cfg->bb_entry; prev_bb && prev_bb->next_bb != bbn; prev_bb = prev_bb->next_bb)
- ;
- if (prev_bb) {
- prev_bb->next_bb = bbn->next_bb;
- } else {
- /* bbn might not be in the bb list yet */
- if (bb->next_bb == bbn)
- bb->next_bb = bbn->next_bb;
- }
- nullify_basic_block (bbn);
-}
-
-static void
-move_basic_block_to_end (MonoCompile *cfg, MonoBasicBlock *bb)
-{
- MonoBasicBlock *bbn, *next;
-
- next = bb->next_bb;
-
- /* 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;
-
- /* Add a branch */
- if (next && (!bb->last_ins || ((bb->last_ins->opcode != OP_NOT_REACHED) && (bb->last_ins->opcode != OP_BR) && (bb->last_ins->opcode != OP_BR_REG) && (!MONO_IS_COND_BRANCH_OP (bb->last_ins))))) {
- MonoInst *ins;
-
- MONO_INST_NEW (cfg, ins, OP_BR);
- MONO_ADD_INS (bb, ins);
- link_bblock (cfg, bb, next);
- ins->inst_target_bb = next;
- }
-}
-
-/*
- * mono_remove_block:
- *
- * Remove BB from the control flow graph
- */
-void
-mono_remove_bblock (MonoCompile *cfg, MonoBasicBlock *bb)
-{
- MonoBasicBlock *tmp_bb;
-
- for (tmp_bb = cfg->bb_entry; tmp_bb && tmp_bb->next_bb != bb; tmp_bb = tmp_bb->next_bb)
- ;
-
- g_assert (tmp_bb);
- tmp_bb->next_bb = bb->next_bb;
-}
-
-/* checks that a and b represent the same instructions, conservatively,
- * it can return FALSE also for two trees that are equal.
- * FIXME: also make sure there are no side effects.
- */
-static int
-same_trees (MonoInst *a, MonoInst *b)
-{
- int arity;
- if (a->opcode != b->opcode)
- return FALSE;
- arity = mono_burg_arity [a->opcode];
- if (arity == 1) {
- if (a->ssa_op == b->ssa_op && a->ssa_op == MONO_SSA_LOAD && a->inst_i0 == b->inst_i0)
- return TRUE;
- return same_trees (a->inst_left, b->inst_left);
- } else if (arity == 2) {
- return same_trees (a->inst_left, b->inst_left) && same_trees (a->inst_right, b->inst_right);
- } else if (arity == 0) {
- switch (a->opcode) {
- case OP_ICONST:
- return a->inst_c0 == b->inst_c0;
- default:
- return FALSE;
- }
- }
- return FALSE;
-}
-
-static int
-get_unsigned_condbranch (int opcode)
-{
- switch (opcode) {
- case CEE_BLE: return CEE_BLE_UN;
- case CEE_BLT: return CEE_BLT_UN;
- case CEE_BGE: return CEE_BGE_UN;
- case CEE_BGT: return CEE_BGT_UN;
- }
- g_assert_not_reached ();
- return 0;
-}
-
-static int
-tree_is_unsigned (MonoInst* ins) {
- switch (ins->opcode) {
- case OP_ICONST:
- return (int)ins->inst_c0 >= 0;
- /* array lengths are positive as are string sizes */
- case CEE_LDLEN:
- case OP_STRLEN:
- return TRUE;
- case CEE_CONV_U1:
- case CEE_CONV_U2:
- case CEE_CONV_U4:
- case CEE_CONV_OVF_U1:
- case CEE_CONV_OVF_U2:
- case CEE_CONV_OVF_U4:
- return TRUE;
- case CEE_LDIND_U1:
- case CEE_LDIND_U2:
- case CEE_LDIND_U4:
- return TRUE;
- default:
- return FALSE;
- }
-}
-
-/* check if an unsigned compare can be used instead of two signed compares
- * for (val < 0 || val > limit) conditionals.
- * Returns TRUE if the optimization has been applied.
- * Note that this can't be applied if the second arg is not positive...
- */
-static int
-try_unsigned_compare (MonoCompile *cfg, MonoBasicBlock *bb)
-{
- MonoBasicBlock *truet, *falset;
- MonoInst *cmp_inst = bb->last_ins->inst_left;
- MonoInst *condb;
- if (!cmp_inst->inst_right->inst_c0 == 0)
- return FALSE;
- truet = bb->last_ins->inst_true_bb;
- falset = bb->last_ins->inst_false_bb;
- if (falset->in_count != 1)
- return FALSE;
- condb = falset->last_ins;
- /* target bb must have one instruction */
- if (!condb || (condb != falset->code))
- return FALSE;
- if ((((condb->opcode == CEE_BLE || condb->opcode == CEE_BLT) && (condb->inst_false_bb == truet))
- || ((condb->opcode == CEE_BGE || condb->opcode == CEE_BGT) && (condb->inst_true_bb == truet)))
- && same_trees (cmp_inst->inst_left, condb->inst_left->inst_left)) {
- if (!tree_is_unsigned (condb->inst_left->inst_right))
- return FALSE;
- condb->opcode = get_unsigned_condbranch (condb->opcode);
- /* change the original condbranch to just point to the new unsigned check */
- bb->last_ins->opcode = OP_BR;
- bb->last_ins->inst_target_bb = falset;
- replace_out_block (bb, truet, NULL);
- replace_in_block (truet, bb, NULL);
- return TRUE;
- }
- return FALSE;
-}
-
-/*
- * Optimizes the branches on the Control Flow Graph
- *
- */
-void
-mono_optimize_branches (MonoCompile *cfg)
-{
- int i, changed = FALSE;
- MonoBasicBlock *bb, *bbn;
- guint32 niterations;
-
- /*
- * Some crazy loops could cause the code below to go into an infinite
- * loop, see bug #53003 for an example. To prevent this, we put an upper
- * bound on the number of iterations.
- */
- if (cfg->num_bblocks > 1000)
- niterations = cfg->num_bblocks * 2;
- else
- niterations = 1000;
-
- do {
- MonoBasicBlock *previous_bb;
- changed = FALSE;
- niterations --;
-
- /* we skip the entry block (exit is handled specially instead ) */
- 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 (!bb->not_useless && 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);
-
- bb->next_bb = bbn->next_bb;
-
- for (i = 0; i < bbn->out_count; i++)
- replace_in_block (bbn->out_bb [i], bbn, NULL);
-
- nullify_basic_block (bbn);
- changed = TRUE;
- }
-
- if (bb->out_count == 1) {
- bbn = bb->out_bb [0];
-
- /* conditional branches where true and false targets are the same can be also replaced with OP_BR */
- if (bb->last_ins && (bb->last_ins->opcode != OP_BR) && MONO_IS_COND_BRANCH_OP (bb->last_ins)) {
- if (!cfg->new_ir) {
- 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 = OP_BR;
- bb->last_ins->inst_target_bb = bb->last_ins->inst_true_bb;
- changed = TRUE;
- if (cfg->verbose_level > 2)
- g_print ("cond branch removal triggered in %d %d\n", bb->block_num, bb->out_count);
- }
-
- if (bb->region == bbn->region && bb->next_bb == bbn) {
- /* the block are in sequence anyway ... */
-
- /* branches to the following block can be removed */
- if (bb->last_ins && bb->last_ins->opcode == OP_BR) {
- bb->last_ins->opcode = OP_NOP;
- changed = TRUE;
- if (cfg->verbose_level > 2)
- g_print ("br removal triggered %d -> %d\n", bb->block_num, bbn->block_num);
- }
-
- if (bbn->in_count == 1 && !bb->extended) {
- if (bbn != cfg->bb_exit) {
- if (cfg->verbose_level > 2)
- g_print ("block merge triggered %d -> %d\n", bb->block_num, bbn->block_num);
- mono_merge_basic_blocks (cfg, bb, bbn);
- changed = TRUE;
- continue;
- }
-
- //mono_print_bb_code (bb);
- }
- }
- }
-
- 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);
- }
- bb->next_bb = bbn->next_bb;
-
- for (i = 0; i < bbn->out_count; i++)
- replace_in_block (bbn->out_bb [i], bbn, NULL);
-
- nullify_basic_block (bbn);
- changed = TRUE;
- continue;
- }
-
- if (bb->out_count == 1) {
- bbn = bb->out_bb [0];
-
- if (bb->last_ins && bb->last_ins->opcode == OP_BR) {
- bbn = bb->last_ins->inst_target_bb;
- if (bb->region == bbn->region && bbn->code && bbn->code->opcode == OP_BR &&
- bbn->code->inst_target_bb->region == bb->region) {
-
- if (cfg->verbose_level > 2)
- g_print ("branch to branch triggered %d -> %d -> %d\n", bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num);
-
- replace_in_block (bbn, bb, NULL);
- replace_out_block (bb, bbn, bbn->code->inst_target_bb);
- link_bblock (cfg, bb, bbn->code->inst_target_bb);
- bb->last_ins->inst_target_bb = bbn->code->inst_target_bb;
- changed = TRUE;
- continue;
- }
- }
- } else if (bb->out_count == 2) {
- if (bb->last_ins && MONO_IS_COND_BRANCH_NOFP (bb->last_ins)) {
- int branch_result;
- MonoBasicBlock *taken_branch_target = NULL, *untaken_branch_target = NULL;
-
- if (cfg->new_ir) {
- if (bb->last_ins->flags & MONO_INST_CFOLD_TAKEN)
- branch_result = BRANCH_TAKEN;
- else if (bb->last_ins->flags & MONO_INST_CFOLD_NOT_TAKEN)
- branch_result = BRANCH_NOT_TAKEN;
- else
- branch_result = BRANCH_UNDEF;
- }
- else
- branch_result = mono_eval_cond_branch (bb->last_ins);
-
- 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 = OP_BR;
- bb->last_ins->inst_target_bb = taken_branch_target;
- if (!bb->extended)
- mono_unlink_bblock (cfg, bb, untaken_branch_target);
- changed = TRUE;
- continue;
- }
- bbn = bb->last_ins->inst_true_bb;
- if (bb->region == bbn->region && bbn->code && bbn->code->opcode == OP_BR &&
- bbn->code->inst_target_bb->region == bb->region) {
- if (cfg->verbose_level > 2)
- g_print ("cbranch1 to branch triggered %d -> (%d) %d (0x%02x)\n",
- bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num,
- bbn->code->opcode);
-
- /*
- * Unlink, then relink bblocks to avoid various
- * tricky situations when the two targets of the branch
- * are equal, or will become equal after the change.
- */
- mono_unlink_bblock (cfg, bb, bb->last_ins->inst_true_bb);
- mono_unlink_bblock (cfg, bb, bb->last_ins->inst_false_bb);
-
- bb->last_ins->inst_true_bb = bbn->code->inst_target_bb;
-
- link_bblock (cfg, bb, bb->last_ins->inst_true_bb);
- link_bblock (cfg, bb, bb->last_ins->inst_false_bb);
-
- changed = TRUE;
- continue;
- }
-
- bbn = bb->last_ins->inst_false_bb;
- if (bbn && bb->region == bbn->region && bbn->code && bbn->code->opcode == OP_BR &&
- bbn->code->inst_target_bb->region == bb->region) {
- if (cfg->verbose_level > 2)
- g_print ("cbranch2 to branch triggered %d -> (%d) %d (0x%02x)\n",
- bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num,
- bbn->code->opcode);
-
- mono_unlink_bblock (cfg, bb, bb->last_ins->inst_true_bb);
- mono_unlink_bblock (cfg, bb, bb->last_ins->inst_false_bb);
-
- bb->last_ins->inst_false_bb = bbn->code->inst_target_bb;
-
- link_bblock (cfg, bb, bb->last_ins->inst_true_bb);
- link_bblock (cfg, bb, bb->last_ins->inst_false_bb);
-
- changed = TRUE;
- continue;
- }
-
- bbn = bb->last_ins->inst_false_bb;
- /*
- * If bb is an extended bb, it could contain an inside branch to bbn.
- * FIXME: Enable the optimization if that is not true.
- * If bblocks_linked () is true, then merging bb and bbn
- * would require addition of an extra branch at the end of bbn
- * slowing down loops.
- */
- if (cfg->new_ir && bbn && bb->region == bbn->region && bbn->in_count == 1 && cfg->enable_extended_bblocks && bbn != cfg->bb_exit && !bb->extended && !bbn->out_of_line && !mono_bblocks_linked (bbn, bb)) {
- g_assert (bbn->in_bb [0] == bb);
- if (cfg->verbose_level > 2)
- g_print ("merge false branch target triggered BB%d -> BB%d\n", bb->block_num, bbn->block_num);
- mono_merge_basic_blocks (cfg, bb, bbn);
- changed = TRUE;
- continue;
- }
- }
-
- /* detect and optimize to unsigned compares checks like: if (v < 0 || v > limit */
- if (bb->last_ins && bb->last_ins->opcode == CEE_BLT && !cfg->new_ir && bb->last_ins->inst_left->inst_right->opcode == OP_ICONST) {
- if (try_unsigned_compare (cfg, bb)) {
- /*g_print ("applied in bb %d (->%d) %s\n", bb->block_num, bb->last_ins->inst_target_bb->block_num, mono_method_full_name (cfg->method, TRUE));*/
- changed = TRUE;
- continue;
- }
- }
-
- if (bb->last_ins && MONO_IS_COND_BRANCH_NOFP (bb->last_ins)) {
- if (bb->last_ins->inst_false_bb && bb->last_ins->inst_false_bb->out_of_line && (bb->region == bb->last_ins->inst_false_bb->region)) {
- /* 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);
- }
- }
- }
- }
- } while (changed && (niterations > 0));
-}
-
-static void
-mono_compile_create_vars (MonoCompile *cfg)
-{
- MonoMethodSignature *sig;
- MonoMethodHeader *header;
- int i;
-
- header = mono_method_get_header (cfg->method);
-
- sig = mono_method_signature (cfg->method);
-
- if (!MONO_TYPE_IS_VOID (sig->ret)) {
- if (cfg->new_ir) {
- cfg->ret = mono_compile_create_var (cfg, sig->ret, OP_ARG);
- /* Inhibit optimizations */
- cfg->ret->flags |= MONO_INST_VOLATILE;
- } else {
- cfg->ret = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
- cfg->ret->opcode = OP_RETARG;
- cfg->ret->inst_vtype = sig->ret;
- cfg->ret->klass = mono_class_from_mono_type (sig->ret);
- }
- }
- if (cfg->verbose_level > 2)
- g_print ("creating vars\n");
-
- cfg->args = mono_mempool_alloc0 (cfg->mempool, (sig->param_count + sig->hasthis) * sizeof (MonoInst*));
-
- if (sig->hasthis)
- cfg->args [0] = mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
-
- for (i = 0; i < sig->param_count; ++i) {
- cfg->args [i + sig->hasthis] = mono_compile_create_var (cfg, sig->params [i], OP_ARG);
- if (sig->params [i]->byref) {
- if (!cfg->new_ir) cfg->disable_ssa = TRUE;
- }
- }
-
- if (cfg->new_ir && cfg->verbose_level > 2) {
- if (cfg->ret) {
- printf ("\treturn : ");
- mono_print_ins (cfg->ret);
- }
-
- if (sig->hasthis) {
- printf ("\tthis: ");
- mono_print_ins (cfg->args [0]);
- }
-
- for (i = 0; i < sig->param_count; ++i) {
- printf ("\targ [%d]: ", i);
- mono_print_ins (cfg->args [i + sig->hasthis]);
- }
- }
-
- cfg->locals_start = cfg->num_varinfo;
- cfg->locals = mono_mempool_alloc0 (cfg->mempool, header->num_locals * sizeof (MonoInst*));
+ cfg->locals_start = cfg->num_varinfo;
+ cfg->locals = mono_mempool_alloc0 (cfg->mempool, header->num_locals * sizeof (MonoInst*));
if (cfg->verbose_level > 2)
g_print ("creating locals\n");
}
}
+#ifndef DISABLE_JIT
+
extern const char * const mono_burg_rule_string [];
static void
bb->last_ins->inst_true_bb = bb->last_ins->inst_false_bb;
bb->last_ins->inst_false_bb = tmp;
- bb->last_ins->opcode = reverse_branch_op (bb->last_ins->opcode);
+ bb->last_ins->opcode = mono_reverse_branch_op (bb->last_ins->opcode);
} else {
MonoInst *ins;
switch (patch_info->type) {
case MONO_PATCH_INFO_ABS: {
MonoJitICallInfo *info = mono_find_jit_icall_by_addr (patch_info->data.target);
+
+ /*
+ * Change patches of type MONO_PATCH_INFO_ABS into patches describing the
+ * absolute address.
+ */
if (info) {
//printf ("TEST %s %p\n", info->name, patch_info->data.target);
// FIXME: CLEAN UP THIS MESS.
}
}
}
- else {
+
+ if (patch_info->type == MONO_PATCH_INFO_ABS && !cfg->new_ir) {
MonoVTable *vtable = mono_find_class_init_trampoline_by_addr (patch_info->data.target);
if (vtable) {
patch_info->type = MONO_PATCH_INFO_CLASS_INIT;
patch_info->data.klass = vtable->klass;
- } else {
- MonoClass *klass = mono_find_delegate_trampoline_by_addr (patch_info->data.target);
- if (klass) {
- patch_info->type = MONO_PATCH_INFO_DELEGATE_TRAMPOLINE;
- patch_info->data.klass = klass;
+ }
+ }
+
+ if (patch_info->type == MONO_PATCH_INFO_ABS) {
+ MonoClass *klass = mono_find_delegate_trampoline_by_addr (patch_info->data.target);
+ if (klass) {
+ patch_info->type = MONO_PATCH_INFO_DELEGATE_TRAMPOLINE;
+ patch_info->data.klass = klass;
+ }
+ }
+
+ if (patch_info->type == MONO_PATCH_INFO_ABS) {
+ if (cfg->abs_patches) {
+ MonoJumpInfo *abs_ji = g_hash_table_lookup (cfg->abs_patches, patch_info->data.target);
+ if (abs_ji) {
+ patch_info->type = abs_ji->type;
+ patch_info->data.target = abs_ji->data.target;
}
}
}
+
break;
}
case MONO_PATCH_INFO_SWITCH: {
unsigned char *ip = cfg->native_code + patch_info->ip.i;
mono_domain_lock (domain);
- if (!domain->jump_target_hash)
- domain->jump_target_hash = g_hash_table_new (NULL, NULL);
- list = g_hash_table_lookup (domain->jump_target_hash, patch_info->data.method);
+ if (!domain_jit_info (domain)->jump_target_hash)
+ domain_jit_info (domain)->jump_target_hash = g_hash_table_new (NULL, NULL);
+ list = g_hash_table_lookup (domain_jit_info (domain)->jump_target_hash, patch_info->data.method);
list = g_slist_prepend (list, ip);
- g_hash_table_insert (domain->jump_target_hash, patch_info->data.method, list);
+ g_hash_table_insert (domain_jit_info (domain)->jump_target_hash, patch_info->data.method, list);
mono_domain_unlock (domain);
break;
}
#endif
}
-void
-mono_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) {
- int i;
- printf ("remove_critical_edges, BEFORE BB%d (in:", bb->block_num);
- for (i = 0; i < bb->in_count; i++) {
- printf (" %d", bb->in_bb [i]->block_num);
- }
- printf (") (out:");
- for (i = 0; i < bb->out_count; i++) {
- printf (" %d", bb->out_bb [i]->block_num);
- }
- printf (")");
- if (bb->last_ins != NULL) {
- printf (" ");
- mono_print_tree (bb->last_ins);
- }
- printf ("\n");
- }
- }
-
- 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->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 OP_BR */
- if ((previous_bb->last_ins == NULL) ||
- ((previous_bb->last_ins->opcode != OP_BR) &&
- (! (MONO_IS_COND_BRANCH_OP (previous_bb->last_ins))) &&
- (previous_bb->last_ins->opcode != OP_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, OP_BR);
- MONO_ADD_INS (previous_bb, jump);
- jump->cil_code = previous_bb->cil_code;
- jump->inst_target_bb = bb;
- break;
- }
- }
- }
- } else {
- /* We cannot add any inst to the entry BB, so we must */
- /* put a new BB in the middle to hold the OP_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, OP_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, added helper BB%d jumping to BB%d\n", new_bb_after_entry->block_num, bb->block_num);
- }
- }
- }
-
- /* 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, removed critical edge from BB%d to BB%d (added BB%d)\n", in_bb->block_num, bb->block_num, new_bb->block_num);
- }
- }
- }
- }
- }
-
- if (cfg->verbose_level > 3) {
- for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
- int i;
- printf ("remove_critical_edges, AFTER BB%d (in:", bb->block_num);
- for (i = 0; i < bb->in_count; i++) {
- printf (" %d", bb->in_bb [i]->block_num);
- }
- printf (") (out:");
- for (i = 0; i < bb->out_count; i++) {
- printf (" %d", bb->out_bb [i]->block_num);
- }
- printf (")");
- if (bb->last_ins != NULL) {
- printf (" ");
- mono_print_tree (bb->last_ins);
- }
- printf ("\n");
- }
- }
-}
-
static MonoGenericInst*
get_object_generic_inst (int type_argc)
{
* for this in the debugger. */
cfg->disable_omit_fp = TRUE;
+ /* The debugger needs all locals to be on the stack or in a global register */
+ cfg->disable_vreg_to_lvreg = TRUE;
+
// cfg->opt |= MONO_OPT_SHARED;
cfg->opt &= ~MONO_OPT_INLINE;
cfg->opt &= ~MONO_OPT_COPYPROP;
* FIXME: Can't use the second case in methods with clauses, since the
* bblocks inside the clauses are not processed during dfn computation.
*/
- if ((header->clauses && (bbn && bbn->region == -1 && bbn->in_count == 0)) ||
- (!header->clauses && (bbn && bbn->region == -1 && !bbn->dfn))) {
+ if (((header->clauses && (bbn && bbn->region == -1 && bbn->in_count == 0)) ||
+ (!header->clauses && (bbn && bbn->region == -1 && !bbn->dfn))) &&
+ bbn != cfg->bb_exit) {
if (cfg->verbose_level > 1)
g_print ("found unreachable code in BB%d\n", bbn->block_num);
/* There may exist unreachable branches to this bb */
bb->next_bb = bbn->next_bb;
- nullify_basic_block (bbn);
+ mono_nullify_basic_block (bbn);
} else {
bb = bb->next_bb;
}
bb->last_ins->inst_true_bb = bb->last_ins->inst_false_bb;
bb->last_ins->inst_false_bb = tmp;
- bb->last_ins->opcode = reverse_branch_op (bb->last_ins->opcode);
+ bb->last_ins->opcode = mono_reverse_branch_op (bb->last_ins->opcode);
} else {
MonoInst *inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
inst->opcode = OP_BR;
} else {
/* we access cfg->domain->mp */
mono_domain_lock (cfg->domain);
- jinfo = mono_mempool_alloc0 (cfg->domain->mp, sizeof (MonoJitInfo) +
+ jinfo = mono_domain_alloc0 (cfg->domain, sizeof (MonoJitInfo) +
(header->num_clauses * sizeof (MonoJitExceptionInfo)) +
generic_info_size);
mono_domain_unlock (cfg->domain);
*/
if (cfg->rgctx_var ||
(!(method_to_compile->flags & METHOD_ATTRIBUTE_STATIC) &&
- !mini_method_get_context (method_to_compile)->method_inst)) {
+ !mini_method_get_context (method_to_compile)->method_inst &&
+ !method_to_compile->klass->valuetype)) {
gi->has_this = 1;
if ((method_to_compile->flags & METHOD_ATTRIBUTE_STATIC) ||
- mini_method_get_context (method_to_compile)->method_inst) {
+ mini_method_get_context (method_to_compile)->method_inst ||
+ method_to_compile->klass->valuetype) {
inst = cfg->rgctx_var;
g_assert (inst->opcode == OP_REGOFFSET);
} else {
return cfg;
}
+#else
+
+MonoCompile*
+mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gboolean run_cctors, gboolean compile_aot, int parts)
+{
+ g_assert_not_reached ();
+ return NULL;
+}
+
+#endif /* DISABLE_JIT */
+
static MonoJitInfo*
lookup_generic_method (MonoDomain *domain, MonoMethod *method)
{
if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("mono_delegate_ctor");
g_assert (mi);
- return mono_get_addr_from_ftnptr ((gpointer)mono_icall_get_wrapper (mi));
+ /*
+ * We need to make sure this wrapper
+ * is compiled because it might end up
+ * in an (M)RGCTX if generic sharing
+ * is enabled, and would be called
+ * indirectly. If it were a
+ * trampoline we'd try to patch that
+ * indirect call, which is not
+ * possible.
+ */
+ return mono_get_addr_from_ftnptr ((gpointer)mono_icall_get_wrapper_full (mi, TRUE));
} else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
#ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
return mono_create_delegate_trampoline (method->klass);
mono_destroy_compile (cfg);
- if (target_domain->jump_target_hash) {
+ if (domain_jit_info (target_domain)->jump_target_hash) {
MonoJumpInfo patch_info;
GSList *list, *tmp;
- list = g_hash_table_lookup (target_domain->jump_target_hash, method);
+ list = g_hash_table_lookup (domain_jit_info (target_domain)->jump_target_hash, method);
if (list) {
patch_info.next = NULL;
patch_info.ip.i = 0;
patch_info.type = MONO_PATCH_INFO_METHOD_JUMP;
patch_info.data.method = method;
- g_hash_table_remove (target_domain->jump_target_hash, method);
+ g_hash_table_remove (domain_jit_info (target_domain)->jump_target_hash, method);
}
for (tmp = list; tmp; tmp = tmp->next)
mono_arch_patch_code (NULL, target_domain, tmp->data, &patch_info, TRUE);
if (!ji)
return;
mono_domain_lock (domain);
- g_hash_table_remove (domain->dynamic_code_hash, method);
+ g_hash_table_remove (domain_jit_info (domain)->dynamic_code_hash, method);
mono_internal_hash_table_remove (&domain->jit_code_hash, method);
- g_hash_table_remove (domain->jump_trampoline_hash, method);
+ g_hash_table_remove (domain_jit_info (domain)->jump_trampoline_hash, method);
mono_domain_unlock (domain);
#ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
return NULL;
}
- if (((method->flags & METHOD_ATTRIBUTE_STATIC) ||
- (method->is_inflated && mono_method_get_context (method)->method_inst)) &&
- mono_class_generic_sharing_enabled (method->klass) &&
- mono_method_is_generic_sharable_impl (method, FALSE)) {
+ if (mono_method_needs_static_rgctx_invoke (method, FALSE))
to_compile = mono_marshal_get_static_rgctx_invoke (method);
- } else {
+ else
to_compile = method;
- }
invoke = mono_marshal_get_runtime_invoke (method);
runtime_invoke = mono_jit_compile_method (invoke);
ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context (ctx));
#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
- /* we got a stack overflow in the soft-guard pages
- * There are two cases:
- * 1) managed code caused the overflow: we unprotect the soft-guard page
- * and let the arch-specific code trigger the exception handling mechanism
- * in the thread stack. The soft-guard pages will be protected again as the stack is unwound.
- * 2) unmanaged code caused the overflow: we unprotect the soft-guard page
- * and hope we can continue with those enabled, at least until the hard-guard page
- * is hit. The alternative to continuing here is to just print a message and abort.
- * We may add in the future the code to protect the pages again in the codepath
- * when we return from unmanaged to managed code.
- */
- if (jit_tls->stack_ovf_guard_size && (guint8*)info->si_addr >= (guint8*)jit_tls->stack_ovf_guard_base &&
- (guint8*)info->si_addr < (guint8*)jit_tls->stack_ovf_guard_base + jit_tls->stack_ovf_guard_size) {
- mono_mprotect (jit_tls->stack_ovf_guard_base, jit_tls->stack_ovf_guard_size, MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_EXEC);
- if (ji) {
- mono_arch_handle_altstack_exception (ctx, info->si_addr, TRUE);
- } else {
- /* We print a message: after this even managed stack overflows
- * may crash the runtime
- */
- fprintf (stderr, "Stack overflow in unmanaged: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx), (gpointer)info->si_addr);
- }
+ if (mono_handle_soft_stack_ovf (jit_tls, ji, ctx, (guint8*)info->si_addr))
return;
- }
+
/* The hard-guard page has been hit: there is not much we can do anymore
* Print a hopefully clear message and abort.
*/
else
method = "Unmanaged";
fprintf (stderr, "At %s\n", method);
- abort ();
+ _exit (1);
} else {
mono_arch_handle_altstack_exception (ctx, info->si_addr, FALSE);
}
static void
SIG_HANDLER_SIGNATURE (sigquit_signal_handler)
{
+ gboolean res;
+
GET_CONTEXT;
+ /* We use this signal to start the attach agent too */
+ res = mono_attach_start ();
+ if (res)
+ return;
+
printf ("Full thread dump:\n");
mono_threads_request_thread_dump ();
#else /* !PLATFORM_WIN32 */
-#ifdef PLATFORM_MACOSX
+#if defined(PLATFORM_MACOSX) && !defined(__arm__)
macosx_register_exception_handler ();
#endif
{
MonoJitDomainInfo *info = g_new0 (MonoJitDomainInfo, 1);
+ info->class_init_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
+ info->jump_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
+ info->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
+ info->delegate_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
+
domain->runtime_info = info;
}
g_slist_free (value);
}
+static void
+dynamic_method_info_free (gpointer key, gpointer value, gpointer user_data)
+{
+ MonoJitDynamicMethodInfo *di = value;
+ mono_code_manager_destroy (di->code_mp);
+ g_free (di);
+}
+
static void
mini_free_jit_domain_info (MonoDomain *domain)
{
- MonoJitDomainInfo *info = jit_domain_info (domain);
+ MonoJitDomainInfo *info = domain_jit_info (domain);
+ if (info->jump_target_hash) {
+ g_hash_table_foreach (info->jump_target_hash, delete_jump_list, NULL);
+ g_hash_table_destroy (info->jump_target_hash);
+ }
if (info->jump_target_got_slot_hash) {
g_hash_table_foreach (info->jump_target_got_slot_hash, delete_jump_list, NULL);
g_hash_table_destroy (info->jump_target_got_slot_hash);
}
+ if (info->dynamic_code_hash) {
+ g_hash_table_foreach (info->dynamic_code_hash, dynamic_method_info_free, NULL);
+ g_hash_table_destroy (info->dynamic_code_hash);
+ }
+ if (info->method_code_hash)
+ g_hash_table_destroy (info->method_code_hash);
+ g_hash_table_destroy (info->class_init_trampoline_hash);
+ g_hash_table_destroy (info->jump_trampoline_hash);
+ g_hash_table_destroy (info->jit_trampoline_hash);
+ g_hash_table_destroy (info->delegate_trampoline_hash);
+
g_free (domain->runtime_info);
+ domain->runtime_info = NULL;
}
MonoDomain *
mono_jit_tls_id = TlsAlloc ();
setup_jit_tls_data ((gpointer)-1, mono_thread_abort);
+#ifndef DISABLE_JIT
mono_burg_init ();
+#endif
if (default_opt & MONO_OPT_AOT)
mono_aot_init ();
register_icall (mono_array_new_specific, "mono_array_new_specific", "object ptr int32", FALSE);
register_icall (mono_runtime_class_init, "mono_runtime_class_init", "void ptr", FALSE);
register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
- register_icall (mono_ldftn_nosync, "mono_ldftn_nosync", "ptr ptr", FALSE);
register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
register_icall (mono_ldvirtfn_gshared, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE);
register_icall (mono_helper_compile_generic_method, "compile_generic_method", "ptr object ptr ptr", FALSE);
register_icall (mono_array_new_2, "mono_array_new_2", "object ptr int int", FALSE);
#endif
+ mono_generic_sharing_init ();
+
+ if (mono_compile_aot)
+ /*
+ * Avoid running managed code when AOT compiling, since the platform
+ * might only support aot-only execution.
+ */
+ mono_runtime_set_no_exec (TRUE);
+
#define JIT_RUNTIME_WORKS
#ifdef JIT_RUNTIME_WORKS
mono_install_runtime_cleanup ((MonoDomainFunc)mini_cleanup);
mono_runtime_init (domain, mono_thread_start_cb, mono_thread_attach_cb);
+ mono_thread_attach (domain);
#endif
- mono_generic_sharing_init ();
-
- mono_thread_attach (domain);
-
mono_profiler_runtime_initialized ();
MONO_PROBE_VES_INIT_END ();
g_print ("Basic blocks: %ld\n", mono_jit_stats.basic_blocks);
g_print ("Max basic blocks: %ld\n", mono_jit_stats.max_basic_blocks);
g_print ("Allocated vars: %ld\n", mono_jit_stats.allocate_var);
- g_print ("Analyze stack repeat: %ld\n", mono_jit_stats.analyze_stack_repeat);
g_print ("Compiled CIL code size: %ld\n", mono_jit_stats.cil_code_size);
g_print ("Native code size: %ld\n", mono_jit_stats.native_code_size);
g_print ("Max code size ratio: %.2f (%s)\n", mono_jit_stats.max_code_size_ratio/100.0,
mono_trampolines_cleanup ();
- mono_code_manager_destroy (global_codeman);
+ if (!mono_dont_free_global_codeman)
+ mono_code_manager_destroy (global_codeman);
g_hash_table_destroy (jit_icall_name_hash);
g_free (emul_opcode_map);