#include <mono/metadata/monitor.h>
#include <mono/metadata/security-manager.h>
#include <mono/utils/mono-math.h>
+#include <mono/utils/mono-compiler.h>
#include <mono/os/gc_wrapper.h>
#include "mini.h"
static MonoMethodSignature *helper_sig_obj_ptr = NULL;
static MonoMethodSignature *helper_sig_obj_ptr_ptr = NULL;
static MonoMethodSignature *helper_sig_obj_obj_ptr_ptr = NULL;
+static MonoMethodSignature *helper_sig_obj_obj_obj_ptr = NULL;
static MonoMethodSignature *helper_sig_obj_void = NULL;
static MonoMethodSignature *helper_sig_ptr_void = NULL;
static MonoMethodSignature *helper_sig_void_void = NULL;
static MonoMethodSignature *helper_sig_ptr_obj = NULL;
static MonoMethodSignature *helper_sig_ptr_obj_int = NULL;
static MonoMethodSignature *helper_sig_ptr_int = NULL;
-static MonoMethodSignature *helper_sig_initobj = NULL;
-static MonoMethodSignature *helper_sig_memcpy = NULL;
-static MonoMethodSignature *helper_sig_memset = NULL;
static MonoMethodSignature *helper_sig_ulong_double = NULL;
static MonoMethodSignature *helper_sig_long_double = NULL;
static MonoMethodSignature *helper_sig_double_long = NULL;
static GHashTable *jit_icall_name_hash = NULL;
+static MonoDebugOptions debug_options;
+
+/*
+ * Address of the trampoline code. This is used by the debugger to check
+ * whether a method is a trampoline.
+ */
+guint8 *mono_generic_trampoline_code = NULL;
+
+static guint8* trampoline_code [MONO_TRAMPOLINE_NUM];
+
gboolean
mono_running_on_valgrind (void)
{
return NULL;
}
method = mono_method_full_name (ji->method, TRUE);
- source = mono_debug_source_location_from_address (ji->method, (int) ip, NULL, domain);
+ source = mono_debug_source_location_from_address (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), 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);
return;
}
method = mono_method_full_name (ji->method, TRUE);
- source = mono_debug_source_location_from_address (ji->method, (int) ip, NULL, domain);
+ source = mono_debug_source_location_from_address (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), NULL, domain);
g_print ("IP %p at offset 0x%x of method %s (%p %p)[domain %p - %s]\n", ip, (int)((char*)ip - (char*)ji->code_start), method, ji->code_start, (char*)ji->code_start + ji->code_size, domain, domain->friendly_name);
(dest)->ssa_op = MONO_SSA_MAYBE_LOAD; \
(dest)->inst_i0 = (cfg)->ret; \
(dest)->inst_i0->flags |= MONO_INST_INDIRECT; \
- (dest)->opcode = CEE_LDIND_I; \
+ (dest)->opcode = cfg->ret_var_is_local ? OP_LDADDR : CEE_LDIND_I; \
(dest)->type = STACK_MP; \
(dest)->klass = (dest)->inst_i0->klass; \
(cfg)->disable_ssa = TRUE; \
case MONO_TYPE_I:
case MONO_TYPE_U:
case MONO_TYPE_PTR:
+ case MONO_TYPE_FNPTR:
return calli? OP_CALL_REG: virt? CEE_CALLVIRT: CEE_CALL;
case MONO_TYPE_CLASS:
case MONO_TYPE_STRING:
case MONO_TYPE_I:
case MONO_TYPE_U:
case MONO_TYPE_PTR:
+ case MONO_TYPE_FNPTR:
if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
return 1;
continue;
}
static MonoCallInst*
-mono_emit_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
- MonoInst **args, const guint8 *ip, MonoInst *this)
+mono_emit_method_call_full (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
+ MonoInst **args, const guint8 *ip, MonoInst *this, gboolean to_end)
{
gboolean virtual = this != NULL;
MonoCallInst *call;
- call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, virtual, ip, FALSE);
+ call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, virtual, ip, to_end);
if (this && sig->hasthis &&
(method->klass->marshalbyref || method->klass == mono_defaults.object_class) &&
return call;
}
+static MonoCallInst*
+mono_emit_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method, MonoMethodSignature *sig,
+ MonoInst **args, const guint8 *ip, MonoInst *this)
+{
+ return mono_emit_method_call_full (cfg, bblock, method, sig, args, ip, this, FALSE);
+}
+
inline static int
mono_emit_method_call_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,
MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this)
return mono_spill_call (cfg, bblock, call, signature, method->string_ctor, ip, FALSE);
}
+inline static int
+mono_emit_method_call_spilled_full (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,
+ MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this,
+ gboolean ret_object, gboolean to_end)
+{
+ MonoCallInst *call = mono_emit_method_call_full (cfg, bblock, method, signature, args, ip, this, to_end);
+
+ return mono_spill_call (cfg, bblock, call, signature, ret_object, ip, to_end);
+}
+
inline static int
mono_emit_native_call (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoMethodSignature *sig,
MonoInst **args, const guint8 *ip, gboolean ret_object, gboolean to_end)
return res;
}
+static MonoMethod*
+get_memcpy_method (void)
+{
+ static MonoMethod *memcpy_method = NULL;
+ if (!memcpy_method) {
+ memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
+ if (!memcpy_method)
+ g_error ("Old corlib found. Install a new one");
+ }
+ return memcpy_method;
+}
+
static void
handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native) {
MonoInst *iargs [3];
int n;
- guint32 align = 0;
+ int align = 0;
+ MonoMethod *memcpy_method;
g_assert (klass);
/*
iargs [1] = src;
NEW_ICONST (cfg, iargs [2], n);
- mono_emit_native_call (cfg, bblock, helper_memcpy, helper_sig_memcpy, iargs, ip, FALSE, to_end);
+ memcpy_method = get_memcpy_method ();
+ mono_emit_method_call_spilled_full (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL, FALSE, to_end);
+}
+
+static MonoMethod*
+get_memset_method (void)
+{
+ static MonoMethod *memset_method = NULL;
+ if (!memset_method) {
+ memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
+ if (!memset_method)
+ g_error ("Old corlib found. Install a new one");
+ }
+ return memset_method;
}
static void
handle_initobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, const guchar *ip, MonoClass *klass, MonoInst **stack_start, MonoInst **sp)
{
- MonoInst *iargs [2];
+ MonoInst *iargs [3];
MonoInst *ins, *zero_int32;
int n;
+ MonoMethod *memset_method;
NEW_ICONST (cfg, zero_int32, 0);
MONO_ADD_INS (bblock, ins);
break;
}
+ memset_method = get_memset_method ();
handle_loaded_temps (cfg, bblock, stack_start, sp);
- NEW_ICONST (cfg, ins, n);
iargs [0] = dest;
- iargs [1] = ins;
- mono_emit_jit_icall (cfg, bblock, helper_initobj, iargs, ip);
+ NEW_ICONST (cfg, iargs [1], 0);
+ NEW_ICONST (cfg, iargs [2], n);
+ mono_emit_method_call_spilled (cfg, bblock, memset_method, memset_method->signature, iargs, ip, NULL);
break;
}
}
static int
-handle_alloc (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, const guchar *ip)
+handle_alloc (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, gboolean for_box, const guchar *ip)
{
MonoInst *iargs [2];
void *alloc_ftn;
MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
gboolean pass_lw;
- alloc_ftn = mono_class_get_allocation_ftn (vtable, &pass_lw);
+ alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
if (pass_lw) {
guint32 lw = vtable->klass->instance_size;
lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
MonoInst *dest, *vtoffset, *add, *vstore;
int temp;
- temp = handle_alloc (cfg, bblock, klass, ip);
+ temp = handle_alloc (cfg, bblock, klass, TRUE, ip);
NEW_TEMPLOAD (cfg, dest, temp);
NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
MONO_INST_NEW (cfg, add, OP_PADD);
return method;
}
+static
+void check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee, MonoBasicBlock *bblock, unsigned char *ip)
+{
+ guint32 result = mono_declsec_linkdemand (cfg->domain, caller, callee);
+ if (result == MONO_JIT_SECURITY_OK)
+ return;
+
+ if (result == MONO_JIT_LINKDEMAND_ECMA) {
+ /* Generate code to throw a SecurityException before the actual call/link */
+ MonoAssembly *assembly = mono_image_get_assembly (caller->klass->image);
+ MonoReflectionAssembly *refass = (MonoReflectionAssembly*) mono_assembly_get_object (cfg->domain, assembly);
+ MonoReflectionMethod *refmet = mono_method_get_object (cfg->domain, caller, NULL);
+ MonoSecurityManager *secman = mono_security_manager_get_methods ();
+ MonoInst *args [3];
+
+ NEW_ICONST (cfg, args [0], 4);
+ NEW_PCONST (cfg, args [1], refass);
+ NEW_PCONST (cfg, args [2], refmet);
+ mono_emit_method_call_spilled (cfg, bblock, secman->linkdemandsecurityexception, mono_method_signature (secman->linkdemandsecurityexception), args, ip, NULL);
+ } else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
+ /* don't hide previous results */
+ cfg->exception_type = MONO_EXCEPTION_SECURITY_LINKDEMAND;
+ cfg->exception_data = result;
+ }
+}
+
+
/*
* mono_method_to_ir: translates IL into basic blocks containing trees
*/
int num_calls = 0, inline_costs = 0;
int breakpoint_id = 0;
guint real_offset, num_args;
- MonoBoolean security;
+ MonoBoolean security, pinvoke;
+ MonoSecurityManager* secman = NULL;
MonoDeclSecurityActions actions;
image = method->klass->image;
}
}
- security = mono_use_security_manager && mono_method_has_declsec (method);
+ if (mono_use_security_manager)
+ secman = mono_security_manager_get_methods ();
+
+ security = (secman && 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.
* have nothing to generate */
security = mono_declsec_get_demands (method, &actions);
}
+
+ /* we must Demand SecurityPermission.Unmanaged before P/Invoking */
+ pinvoke = (secman && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE));
+ if (pinvoke) {
+ MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
+ if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
+ MonoCustomAttrInfo* custom = mono_custom_attrs_from_method (wrapped);
+
+ /* unless the method or it's class has the [SuppressUnmanagedCodeSecurity] attribute */
+ if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
+ pinvoke = FALSE;
+ }
+
+ if (pinvoke) {
+ custom = mono_custom_attrs_from_class (wrapped->klass);
+ if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
+ pinvoke = FALSE;
+ }
+ }
+ } else {
+ /* not a P/Invoke after all */
+ pinvoke = FALSE;
+ }
+ }
- if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || mono_compile_aot || security) {
+ if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || mono_compile_aot || security || pinvoke) {
/* we use a separate basic block for the initialization code */
cfg->bb_init = init_localsbb = NEW_BBLOCK (cfg);
init_localsbb->real_offset = real_offset;
/* 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 ();
+
+ mono_jit_stats.cas_demand_generation++;
if (actions.demand.blob) {
/* Add code for SecurityAction.Demand */
}
}
+ /* we must Demand SecurityPermission.Unmanaged before p/invoking */
+ if (pinvoke) {
+ mono_emit_method_call_spilled (cfg, init_localsbb, secman->demandunmanaged, mono_method_signature (secman->demandunmanaged), NULL, ip, NULL);
+ }
+
if (get_basic_blocks (cfg, bbhash, header, real_offset, ip, end, &err_pos)) {
ip = err_pos;
goto unverified;
*sp++ = ins;
break;
case CEE_LDC_R4: {
- float *f = mono_mempool_alloc (cfg->domain->mp, sizeof (float));
+ 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));
+ mono_domain_unlock (cfg->domain);
CHECK_OPSIZE (5);
CHECK_STACK_OVF (1);
MONO_INST_NEW (cfg, ins, OP_R4CONST);
break;
}
case CEE_LDC_R8: {
- double *d = mono_mempool_alloc (cfg->domain->mp, sizeof (double));
+ double *d;
+ mono_domain_lock (cfg->domain);
+ d = mono_mempool_alloc (cfg->domain->mp, sizeof (double));
+ mono_domain_unlock (cfg->domain);
CHECK_OPSIZE (9);
CHECK_STACK_OVF (1);
MONO_INST_NEW (cfg, ins, OP_R8CONST);
token = read32 (ip + 1);
/* FIXME: check the signature matches */
cmethod = mini_get_method (image, token, NULL, generic_context);
+
+ if (mono_use_security_manager) {
+ check_linkdemand (cfg, method, cmethod, bblock, ip);
+ }
+
ins->inst_p0 = cmethod;
MONO_ADD_INS (bblock, ins);
ip += 5;
g_assert (cmethod);
+ if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
+ goto unverified;
+
if (!cmethod->klass->inited)
mono_class_init (cmethod->klass);
n = fsig->param_count + fsig->hasthis;
+ if (mono_use_security_manager) {
+ check_linkdemand (cfg, method, cmethod, bblock, ip);
+ }
+
if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
cmethod->klass->parent == mono_defaults.array_class) {
array_rank = cmethod->klass->rank;
link_bblock (cfg, bblock, tblock);
ins->inst_target_bb = tblock;
start_new_bblock = 1;
- ip += 5;
-
+
if (!MONO_TYPE_IS_VOID (fsig->ret)) {
/* just create a dummy - the value is never used */
ins = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
sp++;
+ MONO_INST_NEW (cfg, ins, CEE_POP);
+ MONO_ADD_INS (bblock, ins);
+ --sp;
+ ins->inst_i0 = *sp;
}
+ /* skip the CEE_RET, too */
+ if (ip_in_bb (cfg, bblock, ip + 5))
+ ip += 6;
+ else
+ ip += 5;
break;
}
copy->unused = n;
MONO_ADD_INS (bblock, copy);
} else {
+ MonoMethod *memcpy_method = get_memcpy_method ();
MonoInst *iargs [3];
iargs [0] = sp [0];
iargs [1] = sp [1];
NEW_ICONST (cfg, iargs [2], n);
iargs [2]->cil_code = ip;
- mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
+ mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
}
}
ins_flag = 0;
copy->unused = n;
MONO_ADD_INS (bblock, copy);
} else {
+ MonoMethod *memcpy_method = get_memcpy_method ();
iargs [1] = *sp;
NEW_ICONST (cfg, iargs [2], n);
iargs [2]->cil_code = ip;
- mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
+ mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
}
NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
++sp;
MonoInst *iargs [2];
MonoMethodSignature *fsig;
int temp;
-
+
CHECK_OPSIZE (5);
token = read32 (ip + 1);
if (method->wrapper_type != MONO_WRAPPER_NONE) {
mono_class_init (cmethod->klass);
+ if (mono_use_security_manager) {
+ check_linkdemand (cfg, method, cmethod, bblock, ip);
+ }
+
n = fsig->param_count;
CHECK_STACK (n);
}
handle_loaded_temps (cfg, bblock, stack_start, sp);
-
if (cmethod->klass->parent == mono_defaults.array_class) {
NEW_METHODCONST (cfg, *sp, cmethod);
/* now call the string ctor */
temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, NULL);
} else {
+ MonoInst* callvirt_this_arg = NULL;
+
if (cmethod->klass->valuetype) {
iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
temp = iargs [0]->inst_c0;
NEW_TEMPLOADA (cfg, *sp, temp);
+
+ /*
+ * The code generated by mini_emit_virtual_call () expects
+ * iargs [0] to be a boxed instance, but luckily the vcall
+ * will be transformed into a normal call there. The AOT
+ * case needs an already allocate got_var.
+ */
+ mono_get_got_var (cfg);
} else {
- temp = handle_alloc (cfg, bblock, cmethod->klass, ip);
+ temp = handle_alloc (cfg, bblock, cmethod->klass, FALSE, ip);
NEW_TEMPLOAD (cfg, *sp, temp);
}
+ /* Avoid virtual calls to ctors if possible */
+ if (cmethod->klass->marshalbyref)
+ callvirt_this_arg = sp [0];
+
if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
mono_method_check_inlining (cfg, cmethod) &&
!mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
break;
} else {
- mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, sp[0]);
+ mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, callvirt_this_arg);
}
} else {
/* now call the actual ctor */
- mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, sp[0]);
+ mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, callvirt_this_arg);
}
}
copy->unused = n;
MONO_ADD_INS (bblock, copy);
} else {
+ MonoMethod *memcpy_method = get_memcpy_method ();
iargs [1] = *sp;
NEW_ICONST (cfg, iargs [2], n);
iargs [2]->cil_code = ip;
- mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
+ mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
}
NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
++sp;
ins->cil_code = ip++;
bblock->out_of_line = TRUE;
MONO_ADD_INS (bblock, ins);
+ MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
+ ins->cil_code = ip - 1;
+ MONO_ADD_INS (bblock, ins);
sp = stack_start;
link_bblock (cfg, bblock, end_bblock);
start_new_bblock = 1;
+ mono_get_got_var (cfg);
break;
case CEE_LDFLD:
case CEE_LDFLDA:
field = mono_field_from_token (image, token, &klass, generic_context);
mono_class_init (klass);
+ g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
+
if ((*ip) == CEE_STSFLD)
handle_loaded_temps (cfg, bblock, stack_start, sp);
*/
if (!(cfg->opt & MONO_OPT_SHARED))
mono_class_vtable (cfg->domain, klass);
-
+ mono_domain_lock (cfg->domain);
if (cfg->domain->special_static_fields)
addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
+ mono_domain_unlock (cfg->domain);
if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
int temp;
ip += 6;
inline_costs += 10 * num_calls++;
break;
+ case CEE_MONO_NOT_TAKEN:
+ bblock->out_of_line = TRUE;
+ ip += 2;
+ break;
default:
g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
break;
}
mono_class_init (cmethod->klass);
+
+ if (mono_use_security_manager) {
+ check_linkdemand (cfg, method, cmethod, bblock, ip);
+ }
+
handle_loaded_temps (cfg, bblock, stack_start, sp);
NEW_METHODCONST (cfg, argconst, cmethod);
cmethod = mini_get_method (image, n, NULL, generic_context);
mono_class_init (cmethod->klass);
+
+ if (mono_use_security_manager) {
+ check_linkdemand (cfg, method, cmethod, bblock, ip);
+ }
+
handle_loaded_temps (cfg, bblock, stack_start, sp);
--sp;
iargs [2] = sp [2];
handle_loaded_temps (cfg, bblock, stack_start, sp);
if (ip [1] == CEE_CPBLK) {
- mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
+ MonoMethod *memcpy_method = get_memcpy_method ();
+ mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
} else {
- mono_emit_jit_icall (cfg, bblock, helper_memset, iargs, ip);
+ MonoMethod *memset_method = get_memset_method ();
+ mono_emit_method_call_spilled (cfg, bblock, memset_method, memset_method->signature, iargs, ip, NULL);
}
ip += 2;
inline_costs += 1;
link_bblock (cfg, bblock, end_bblock);
start_new_bblock = 1;
ip += 2;
+ mono_get_got_var (cfg);
break;
}
case CEE_SIZEOF:
int t = ptype->type;
if (t == MONO_TYPE_VALUETYPE && ptype->data.klass->enumtype)
t = ptype->data.klass->enum_basetype->type;
- /* FIXME: use initobj for valuetypes, handle pointers, long, float. */
- if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
+ if (ptype->byref) {
+ NEW_PCONST (cfg, ins, NULL);
+ NEW_LOCSTORE (cfg, store, i, ins);
+ MONO_ADD_INS (init_localsbb, store);
+ } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
NEW_ICONST (cfg, ins, 0);
NEW_LOCSTORE (cfg, store, i, ins);
MONO_ADD_INS (init_localsbb, store);
/* int amethod (double) */
helper_sig_int_double = make_icall_sig ("int32 double");
- /* void initobj (intptr, int size) */
- helper_sig_initobj = make_icall_sig ("void ptr int32");
-
- /* void memcpy (intptr, intptr, int size) */
- helper_sig_memcpy = make_icall_sig ("void ptr ptr int32");
-
- /* void memset (intptr, int val, int size) */
- helper_sig_memset = make_icall_sig ("void ptr int32 int32");
-
helper_sig_class_init_trampoline = make_icall_sig ("void");
+
+ helper_sig_obj_obj_obj_ptr = make_icall_sig ("object object object ptr");
}
gconstpointer
return callinfo->wrapper;
}
+static void
+mono_init_trampolines (void)
+{
+ trampoline_code [MONO_TRAMPOLINE_GENERIC] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_GENERIC);
+ trampoline_code [MONO_TRAMPOLINE_JUMP] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_JUMP);
+ trampoline_code [MONO_TRAMPOLINE_CLASS_INIT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT);
+#ifdef MONO_ARCH_HAVE_PIC_AOT
+ trampoline_code [MONO_TRAMPOLINE_AOT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_AOT);
+#endif
+
+ mono_generic_trampoline_code = trampoline_code [MONO_TRAMPOLINE_GENERIC];
+}
+
+guint8 *
+mono_get_trampoline_code (MonoTrampolineType tramp_type)
+{
+ return trampoline_code [tramp_type];
+}
+
gpointer
mono_create_class_init_trampoline (MonoVTable *vtable)
{
MonoDomain *domain = mono_domain_get ();
gpointer tramp;
- /* Trampoline are domain specific, so cache only the one used in the root domain */
- if ((domain == mono_get_root_domain ()) && method->info)
- return method->info;
+ mono_domain_lock (domain);
+ tramp = g_hash_table_lookup (domain->jit_trampoline_hash, method);
+ mono_domain_unlock (domain);
+ if (tramp)
+ return tramp;
if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
return mono_create_jit_trampoline (mono_marshal_get_synchronized_wrapper (method));
tramp = mono_arch_create_jit_trampoline (method);
- if (domain == mono_get_root_domain ())
- method->info = tramp;
+
+ mono_domain_lock (domain);
+ g_hash_table_insert (domain->jit_trampoline_hash, method, tramp);
+ mono_domain_unlock (domain);
mono_jit_stats.method_trampolines++;
return tramp;
}
+#ifdef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN
+gpointer
+mono_create_jit_trampoline_from_token (MonoImage *image, guint32 token)
+{
+ gpointer tramp;
+
+ tramp = mono_arch_create_jit_trampoline_from_token (image, token);
+
+ mono_jit_stats.method_trampolines++;
+
+ return tramp;
+}
+#endif
+
MonoVTable*
mono_find_class_init_trampoline_by_addr (gconstpointer addr)
{
vtype_stack_slots = g_new0 (StackSlotInfo, 256);
nvtypes = 0;
- offsets = g_new (guint32, m->num_varinfo);
+ offsets = g_new (gint32, m->num_varinfo);
for (i = 0; i < m->num_varinfo; ++i)
offsets [i] = -1;
}
#ifdef HAVE_KW_THREAD
-static __thread gpointer mono_lmf_addr;
+static __thread gpointer mono_lmf_addr MONO_TLS_FAST;
#endif
+guint32
+mono_get_jit_tls_key (void)
+{
+ return mono_jit_tls_id;
+}
+
+gint32
+mono_get_lmf_tls_offset (void)
+{
+ int offset;
+ MONO_THREAD_VAR_OFFSET(mono_lmf_addr,offset);
+ return offset;
+}
+
MonoLMF **
mono_get_lmf_addr (void)
{
#endif
}
+/* Called by native->managed wrappers */
+void
+mono_jit_thread_attach (MonoDomain *domain)
+{
+#ifdef HAVE_KW_THREAD
+ if (!mono_lmf_addr) {
+ mono_thread_attach (domain);
+ }
+#else
+ if (!TlsGetValue (mono_jit_tls_id))
+ mono_thread_attach (domain);
+#endif
+}
+
/**
* mono_thread_abort:
* @obj: exception object
if (target_bb != NULL) {
int i;
-
+
if (cfg->verbose_level > 1) {
printf ("remove_block_if_useless %s, removed BB%d\n", mono_method_full_name (cfg->method, TRUE), bb->block_num);
}
static void
move_basic_block_to_end (MonoCompile *cfg, MonoBasicBlock *bb)
{
- MonoBasicBlock *bbn;
+ 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)
;
bbn->next_bb = bb;
bb->next_bb = NULL;
+
+ /* Add a branch */
+ if (next && (!bb->last_ins || (bb->last_ins->opcode != OP_NOT_REACHED))) {
+ MonoInst *ins;
+
+ MONO_INST_NEW (cfg, ins, CEE_BR);
+ MONO_ADD_INS (bb, ins);
+ link_bblock (cfg, bb, next);
+ ins->inst_target_bb = next;
+ }
}
/*
}
}
-#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) {
+ if (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->block_num);
}
}
-#endif
}
}
} while (changed && (niterations > 0));
mono_compile_create_var (cfg, header->locals [i], OP_LOCAL);
if (cfg->verbose_level > 2)
g_print ("locals done\n");
+
+#ifdef MONO_ARCH_HAVE_CREATE_VARS
+ mono_arch_create_vars (cfg);
+#endif
}
void
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;
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);
max_epilog_size = 0;
-#endif
code = cfg->native_code + cfg->code_len;
code = cfg->native_code + cfg->code_len;
/* 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)
- 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
-
for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
switch (patch_info->type) {
case MONO_PATCH_INFO_ABS: {
}
}
- if (cfg->verbose_level > 0)
+ if (cfg->verbose_level > 0) {
+ char* nm = mono_method_full_name (cfg->method, TRUE);
g_print ("Method %s emitted at %p to %p [%s]\n",
- mono_method_full_name (cfg->method, TRUE),
+ nm,
cfg->native_code, cfg->native_code + cfg->code_len, cfg->domain->friendly_name);
-
+ g_free (nm);
+ }
+
mono_arch_patch_code (cfg->method, cfg->domain, cfg->native_code, cfg->patch_info, cfg->run_cctors);
if (cfg->method->dynamic) {
g_free (id);
}
- if (cfg->method->dynamic)
+ if (cfg->method->dynamic) {
jinfo = g_malloc0 (sizeof (MonoJitInfo) + (header->num_clauses * sizeof (MonoJitExceptionInfo)));
- else
+ } else {
+ /* we access cfg->domain->mp */
+ mono_domain_lock (cfg->domain);
jinfo = mono_mempool_alloc0 (cfg->domain->mp, sizeof (MonoJitInfo) + (header->num_clauses * sizeof (MonoJitExceptionInfo)));
+ mono_domain_unlock (cfg->domain);
+ }
jinfo->method = method;
jinfo->code_start = cfg->native_code;
cfg->jit_info = jinfo;
+ mono_domain_lock (cfg->domain);
mono_jit_info_table_add (cfg->domain, jinfo);
if (cfg->method->dynamic)
mono_dynamic_code_hash_lookup (cfg->domain, cfg->method)->ji = jinfo;
+ mono_domain_unlock (cfg->domain);
/* collect statistics */
mono_jit_stats.allocated_code_size += cfg->code_len;
if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
+ /* this can only be set if the security manager is active */
+ if (cfg->exception_type == MONO_EXCEPTION_SECURITY_LINKDEMAND) {
+ MonoAssembly *assembly = mono_image_get_assembly (method->klass->image);
+ MonoReflectionAssembly *refass = (MonoReflectionAssembly*) mono_assembly_get_object (domain, assembly);
+ MonoReflectionMethod *refmet = mono_method_get_object (domain, method, NULL);
+ MonoSecurityManager* secman = mono_security_manager_get_methods ();
+ MonoObject *exc = NULL;
+ gpointer args [3];
+
+ args [0] = &cfg->exception_data;
+ args [1] = refass;
+ args [2] = refmet;
+ mono_runtime_invoke (secman->linkdemandsecurityexception, NULL, args, &exc);
+
+ mono_destroy_compile (cfg);
+ cfg = NULL;
+
+ mono_raise_exception ((MonoException*)exc);
+ }
+
return cfg;
}
MonoMethod *nm;
MonoMethodPInvoke* piinfo = (MonoMethodPInvoke *) method;
+ if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)
+ g_error ("Method '%s' in assembly '%s' contains native code and mono can't run it. The assembly was probably created by Managed C++.\n", mono_method_full_name (method, TRUE), method->klass->image->name);
+
if (!piinfo->addr) {
if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
piinfo->addr = mono_lookup_internal_call (method);
if (method->klass->parent == mono_defaults.multicastdelegate_class) {
if (*name == '.' && (strcmp (name, ".ctor") == 0)) {
- /* FIXME: uhm, we need a wrapper to handle exceptions? */
- return (gpointer)mono_delegate_ctor;
+ MonoJitICallInfo *mi = mono_find_jit_icall_by_name ("mono_delegate_ctor");
+ g_assert (mi);
+ return (gpointer)mono_icall_get_wrapper (mi);
} else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
nm = mono_marshal_get_delegate_invoke (method);
return mono_jit_compile_method (nm);
}
static void
-invalidated_delegate_trampoline (MonoClass *klass)
+invalidated_delegate_trampoline (char *desc)
{
g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n"
"See http://www.go-mono.com/delegate.html for an explanation and ways to fix this.",
- mono_type_full_name (&klass->byval_arg));
+ desc);
}
/*
mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
{
MonoJitDynamicMethodInfo *ji;
+ gboolean destroy = TRUE;
g_assert (method->dynamic);
mono_domain_lock (domain);
ji = mono_dynamic_code_hash_lookup (domain, method);
mono_domain_unlock (domain);
+
+ if (!ji)
+ return;
+ mono_domain_lock (domain);
+ g_hash_table_remove (domain->dynamic_code_hash, method);
+ g_hash_table_remove (domain->jit_code_hash, method);
+ mono_domain_unlock (domain);
+
#ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
- /* FIXME: only enable this with a env var */
- if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
+ if (debug_options.keep_delegates && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
/*
* Instead of freeing the code, change it to call an error routine
* so people can fix their code.
*/
- if (ji){
- char *type = mono_type_full_name (&method->klass->byval_arg);
- char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
+ char *type = mono_type_full_name (&method->klass->byval_arg);
+ char *type_and_method = g_strdup_printf ("%s.%s", type, method->name);
- g_free (type);
- mono_arch_invalidate_method (ji->ji, invalidated_delegate_trampoline, type_and_method);
- }
- return;
+ g_free (type);
+ mono_arch_invalidate_method (ji->ji, invalidated_delegate_trampoline, type_and_method);
+ destroy = FALSE;
}
#endif
- if (!ji)
- return;
- mono_domain_lock (domain);
- g_hash_table_remove (domain->dynamic_code_hash, method);
- mono_domain_unlock (domain);
-
- mono_code_manager_destroy (ji->code_mp);
+ if (destroy)
+ mono_code_manager_destroy (ji->code_mp);
mono_jit_info_table_remove (domain, ji->ji);
g_free (ji->ji);
g_free (ji);
#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
+#ifndef MONO_ARCH_USE_SIGACTION
+#error "Can't use sigaltstack without sigaction"
+#endif
+
+#endif
+
static void
-sigsegv_signal_handler (int _dummy, siginfo_t *info, void *context)
+SIG_HANDLER_SIGNATURE (sigsegv_signal_handler)
{
- MonoException *exc;
+ MonoException *exc = NULL;
+#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
- struct sigcontext *ctx = (struct sigcontext *)&(((ucontext_t*)context)->uc_mcontext);
+#endif
+ GET_CONTEXT
+#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
/* Can't allocate memory using Boehm GC on altstack */
if (jit_tls->stack_size &&
((guint8*)info->si_addr >= (guint8*)jit_tls->end_of_stack - jit_tls->stack_size) &&
exc = mono_domain_get ()->stack_overflow_ex;
else
exc = mono_domain_get ()->null_reference_ex;
+#endif
+
+ if (debug_options.abort_on_sigsegv) {
+ MonoJitInfo *ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
+ if (!ji) {
+ fprintf (stderr, "Got SIGSEGV while in unmanaged code, and the 'abort-on-sigsegv' MONO_DEBUG option is set. Aborting...\n");
+ /* Segfault in unmanaged code */
+ abort ();
+ }
+ }
mono_arch_handle_exception (ctx, exc, FALSE);
}
-#else
-
-static void
-SIG_HANDLER_SIGNATURE (sigsegv_signal_handler)
-{
- GET_CONTEXT;
-
- mono_arch_handle_exception (ctx, NULL, FALSE);
-}
-
-#endif
-
static void
SIG_HANDLER_SIGNATURE (sigusr1_signal_handler)
{
gboolean running_managed;
MonoException *exc;
+ void *ji;
- GET_CONTEXT
+ GET_CONTEXT;
- running_managed = (mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx)) != NULL);
+ /*
+ * FIXME:
+ * This is an async signal, so the code below must not call anything which
+ * is not async safe. That includes the pthread locking functions. If we
+ * know that we interrupted managed code, then locking is safe.
+ */
+ ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
+ running_managed = ji != NULL;
exc = mono_thread_request_interruption (running_managed);
if (!exc) return;
win32_seh_set_handler(SIGFPE, sigfpe_signal_handler);
win32_seh_set_handler(SIGILL, sigill_signal_handler);
win32_seh_set_handler(SIGSEGV, sigsegv_signal_handler);
- if (getenv ("MONO_DEBUG"))
+ if (debug_options.handle_sigint)
win32_seh_set_handler(SIGINT, sigint_signal_handler);
#else /* !PLATFORM_WIN32 */
* handlers. If not we must call syscall directly instead
* of sigaction */
- if (getenv ("MONO_DEBUG")) {
+ if (debug_options.handle_sigint)
add_signal_handler (SIGINT, sigint_signal_handler);
- }
add_signal_handler (SIGFPE, sigfpe_signal_handler);
add_signal_handler (SIGQUIT, sigquit_signal_handler);
return addr;
}
+static void
+mini_parse_debug_options (void)
+{
+ char *options = getenv ("MONO_DEBUG");
+ gchar **args, **ptr;
+
+ if (!options)
+ return;
+
+ args = g_strsplit (options, ",", -1);
+
+ for (ptr = args; ptr && *ptr; ptr++) {
+ const char *arg = *ptr;
+
+ if (!strcmp (arg, "handle-sigint"))
+ debug_options.handle_sigint = TRUE;
+ else if (!strcmp (arg, "keep-delegates"))
+ debug_options.keep_delegates = TRUE;
+ else if (!strcmp (arg, "abort-on-sigsegv"))
+ debug_options.abort_on_sigsegv = TRUE;
+ else {
+ fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
+ fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'abort-on-sigsegv'\n");
+ exit (1);
+ }
+ }
+}
+
MonoDomain *
mini_init (const char *filename)
{
mono_arch_cpu_init ();
+ mono_init_trampolines ();
+
if (!g_thread_supported ())
g_thread_init (NULL);
+
+ if (getenv ("MONO_DEBUG") != NULL)
+ mini_parse_debug_options ();
MONO_GC_PRE_INIT ();
mono_install_handler (mono_arch_get_throw_exception ());
#endif
mono_install_stack_walk (mono_jit_walk_stack);
+ mono_install_init_vtable (mono_aot_init_vtable);
+ mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
domain = mono_init_from_assembly (filename, filename);
mono_icall_init ();
mono_register_jit_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
mono_register_jit_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
mono_register_jit_icall (mono_get_lmf_addr, "mono_get_lmf_addr", helper_sig_ptr_void, TRUE);
+ mono_register_jit_icall (mono_jit_thread_attach, "mono_jit_thread_attach", helper_sig_void_void, TRUE);
mono_register_jit_icall (mono_domain_get, "mono_domain_get", helper_sig_domain_get, TRUE);
mono_register_jit_icall (mono_arch_get_throw_exception (), "mono_arch_throw_exception", helper_sig_void_obj, TRUE);
* when adding emulation for some opcodes, remember to also add a dummy
* rule to the burg files, because we need the arity information to be correct.
*/
+#ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
mono_register_opcode_emulation (OP_LMUL, "__emul_lmul", helper_sig_long_long_long, mono_llmult, TRUE);
- mono_register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", helper_sig_long_long_long, mono_llmult_ovf_un, FALSE);
- mono_register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", helper_sig_long_long_long, mono_llmult_ovf, FALSE);
mono_register_opcode_emulation (OP_LDIV, "__emul_ldiv", helper_sig_long_long_long, mono_lldiv, FALSE);
mono_register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", helper_sig_long_long_long, mono_lldiv_un, FALSE);
mono_register_opcode_emulation (OP_LREM, "__emul_lrem", helper_sig_long_long_long, mono_llrem, FALSE);
mono_register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", helper_sig_long_long_long, mono_llrem_un, FALSE);
+ mono_register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", helper_sig_long_long_long, mono_llmult_ovf_un, FALSE);
+ mono_register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", helper_sig_long_long_long, mono_llmult_ovf, FALSE);
+#endif
#ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
mono_register_opcode_emulation (OP_LSHL, "__emul_lshl", helper_sig_long_long_int, mono_lshl, TRUE);
#endif
/* other jit icalls */
+ mono_register_jit_icall (mono_delegate_ctor, "mono_delegate_ctor", helper_sig_obj_obj_obj_ptr, FALSE);
mono_register_jit_icall (mono_class_static_field_address , "mono_class_static_field_address",
helper_sig_ptr_ptr_ptr, FALSE);
mono_register_jit_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", helper_sig_ptr_ptr_ptr_ptr, FALSE);
mono_register_jit_icall (mono_get_special_static_data, "mono_get_special_static_data", helper_sig_ptr_int, FALSE);
mono_register_jit_icall (mono_ldstr, "mono_ldstr", helper_sig_ldstr, FALSE);
- mono_register_jit_icall (helper_memcpy, "helper_memcpy", helper_sig_memcpy, FALSE);
- mono_register_jit_icall (helper_memset, "helper_memset", helper_sig_memset, FALSE);
- mono_register_jit_icall (helper_initobj, "helper_initobj", helper_sig_initobj, FALSE);
mono_register_jit_icall (helper_stelem_ref, "helper_stelem_ref", helper_sig_stelem_ref, FALSE);
mono_register_jit_icall (helper_stelem_ref_check, "helper_stelem_ref_check", helper_sig_stelem_ref_check, FALSE);
mono_register_jit_icall (mono_object_new, "mono_object_new", helper_sig_object_new, FALSE);
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);
+
+ if (mono_use_security_manager) {
+ g_print ("\nDecl security check : %ld\n", mono_jit_stats.cas_declsec_check);
+ g_print ("LinkDemand (user) : %ld\n", mono_jit_stats.cas_linkdemand);
+ g_print ("LinkDemand (icall) : %ld\n", mono_jit_stats.cas_linkdemand_icall);
+ g_print ("LinkDemand (pinvoke) : %ld\n", mono_jit_stats.cas_linkdemand_pinvoke);
+ g_print ("LinkDemand (aptc) : %ld\n", mono_jit_stats.cas_linkdemand_aptc);
+ g_print ("Demand (code gen) : %ld\n", mono_jit_stats.cas_demand_generation);
+ }
}
}
static void
mono_precompile_assembly (MonoAssembly *ass, void *user_data)
{
+ GHashTable *assemblies = (GHashTable*)user_data;
MonoImage *image = mono_assembly_get_image (ass);
MonoMethod *method, *invoke;
int i, count = 0;
+ if (g_hash_table_lookup (assemblies, ass))
+ return;
+
+ g_hash_table_insert (assemblies, ass, ass);
+
if (mini_verbose > 0)
printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
mono_compile_method (invoke);
}
}
+
+ /* Load and precompile referenced assemblies as well */
+ for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_ASSEMBLYREF); ++i) {
+ mono_assembly_load_reference (image, i);
+ if (image->references [i])
+ mono_precompile_assembly (image->references [i], assemblies);
+ }
}
void mono_precompile_assemblies ()
{
- mono_assembly_foreach ((GFunc)mono_precompile_assembly, NULL);
+ GHashTable *assemblies = g_hash_table_new (NULL, NULL);
+
+ mono_assembly_foreach ((GFunc)mono_precompile_assembly, assemblies);
+
+ g_hash_table_destroy (assemblies);
}