#include <math.h>
#include <sys/time.h>
-#ifdef sun // Solaris x86
-#include <sys/types.h>
-#include <sys/ucontext.h>
+#ifdef PLATFORM_MACOSX
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <mach/exception.h>
+#include <mach/task.h>
+#include <pthread.h>
#endif
#ifdef HAVE_VALGRIND_MEMCHECK_H
#define MONO_IS_COND_BRANCH_OP(ins) (((ins)->opcode >= CEE_BEQ && (ins)->opcode <= CEE_BLT_UN) || ((ins)->opcode >= OP_LBEQ && (ins)->opcode <= OP_LBLT_UN) || ((ins)->opcode >= OP_FBEQ && (ins)->opcode <= OP_FBLT_UN) || ((ins)->opcode >= OP_IBEQ && (ins)->opcode <= OP_IBLT_UN))
#define MONO_IS_COND_BRANCH_NOFP(ins) (MONO_IS_COND_BRANCH_OP(ins) && (ins)->inst_left->inst_left->type != STACK_R8)
+#define MONO_IS_BRANCH_OP(ins) (MONO_IS_COND_BRANCH_OP(ins) || ((ins)->opcode == CEE_BR) || ((ins)->opcode == OP_BR_REG) || ((ins)->opcode == CEE_SWITCH))
+
#define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && (ins)->ssa_op == MONO_SSA_LOAD && (ins)->inst_left->inst_c0 == 0)
static void setup_stat_profiler (void);
return res;
}
+/**
+ * mono_pmip:
+ * @ip: an instruction pointer address
+ *
+ * This method is used from a debugger to get the name of the
+ * method at address @ip. This routine is typically invoked from
+ * a debugger like this:
+ *
+ * (gdb) print mono_pmip ($pc)
+ *
+ * Returns: the name of the method at address @ip.
+ */
G_GNUC_UNUSED char *
mono_pmip (void *ip)
{
return get_method_from_ip (ip);
}
-/* debug function */
+/**
+ * mono_print_method_from_ip
+ * @ip: an instruction pointer address
+ *
+ * This method is used from a debugger to get the name of the
+ * method at address @ip.
+ *
+ * This prints the name of the method at address @ip in the standard
+ * output. Unlike mono_pmip which returns a string, this routine
+ * prints the value on the standard output.
+ */
void
mono_print_method_from_ip (void *ip)
{
} while (0)
//#define UNVERIFIED do { G_BREAKPOINT (); goto unverified; } while (0)
-#define UNVERIFIED do { goto unverified; } while (0)
+#define UNVERIFIED do { if (debug_options.break_on_unverified) G_BREAKPOINT (); else goto unverified; } while (0)
/*
* Basic blocks have two numeric identifiers:
(dest)->type = STACK_PTR; \
} while (0)
-#define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type) do { \
+#define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type,stack_class) do { \
(dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
(dest)->opcode = OP_AOTCONST; \
(dest)->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token)); \
(dest)->inst_p1 = (gpointer)(patch_type); \
(dest)->type = (stack_type); \
+ (dest)->klass = (stack_class); \
} while (0)
#endif
return opcode;
}
+#ifdef MONO_ARCH_SOFT_FLOAT
+static int
+condbr_to_fp_br (int opcode)
+{
+ switch (opcode) {
+ case CEE_BEQ: return OP_FBEQ;
+ case CEE_BGE: return OP_FBGE;
+ case CEE_BGT: return OP_FBGT;
+ case CEE_BLE: return OP_FBLE;
+ case CEE_BLT: return OP_FBLT;
+ case CEE_BNE_UN: return OP_FBNE_UN;
+ case CEE_BGE_UN: return OP_FBGE_UN;
+ case CEE_BGT_UN: return OP_FBGT_UN;
+ case CEE_BLE_UN: return OP_FBLE_UN;
+ case CEE_BLT_UN: return OP_FBLT_UN;
+ }
+ g_assert_not_reached ();
+ return 0;
+}
+#endif
+
/*
* Returns the type used in the eval stack when @type is loaded.
* FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
/* handles from CEE_CEQ to CEE_CLT_UN */
static const guint16
ceqops_op_map [STACK_MAX] = {
- 0, 0, OP_LCEQ-CEE_CEQ, OP_PCEQ-CEE_CEQ, OP_FCEQ-CEE_CEQ, OP_LCEQ-CEE_CEQ
+ 0, 0, OP_LCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, OP_FCEQ-OP_CEQ, OP_LCEQ-OP_CEQ
};
/*
ins->opcode = OP_LCOMPARE;
return;
case OP_CEQ:
+ ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
+ ins->opcode += ceqops_op_map [ins->inst_i0->type];
+ return;
+
case OP_CGT:
case OP_CGT_UN:
case OP_CLT:
case OP_CLT_UN:
- ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
+ ins->type = (bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] & 1) ? STACK_I4: STACK_INV;
ins->opcode += ceqops_op_map [ins->inst_i0->type];
return;
/* unops */
inst->inst_vtype = type;
inst->klass = mono_class_from_mono_type (type);
/* if set to 1 the variable is native */
- inst->unused = 0;
+ inst->backend.is_pinvoke = 0;
cfg->varinfo [num] = inst;
MONO_ADD_INS (bblock, dummy_store);
/* we use this to allocate native sized structs */
- temp->unused = sig->pinvoke;
+ temp->backend.is_pinvoke = sig->pinvoke;
NEW_TEMPLOADA (cfg, loada, temp->inst_c0);
if (call->inst.opcode == OP_VCALL)
MonoInst *arg;
MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual));
-
+
+#ifdef MONO_ARCH_SOFT_FLOAT
+ /* we need to convert the r4 value to an int value */
+ {
+ int i;
+ for (i = 0; i < sig->param_count; ++i) {
+ if (sig->params [i]->type == MONO_TYPE_R4) {
+ MonoInst *iargs [1];
+ int temp;
+ iargs [0] = args [i + sig->hasthis];
+
+ temp = mono_emit_jit_icall (cfg, bblock, mono_fload_r4_arg, iargs, ip);
+ NEW_TEMPLOAD (cfg, arg, temp);
+ args [i + sig->hasthis] = arg;
+ }
+ }
+ }
+#endif
+
call->inst.cil_code = ip;
call->args = args;
call->signature = sig;
call = mono_arch_call_opcode (cfg, bblock, call, virtual);
type_to_eval_stack_type (sig->ret, &call->inst);
-
+
for (arg = call->out_args; arg;) {
MonoInst *narg = arg->next;
arg->next = NULL;
res->call_convention = MONO_CALL_VARARG;
#endif
res->params [0] = &mono_defaults.array_class->byval_arg;
-
+
+#ifdef PLATFORM_WIN32
+ /*
+ * The default pinvoke calling convention is STDCALL but we need CDECL.
+ */
+ res->call_convention = MONO_CALL_C;
+#endif
+
for (i = 1; i <= arity; i++)
res->params [i] = &mono_defaults.int_class->byval_arg;
res->call_convention = MONO_CALL_VARARG;
#endif
+#ifdef PLATFORM_WIN32
+ res->call_convention = MONO_CALL_C;
+#endif
+
res->params [0] = &mono_defaults.int_class->byval_arg;
for (i = 0; i < arity; i++)
res->params [i + 1] = &mono_defaults.int_class->byval_arg;
return res;
}
+#ifdef MONO_ARCH_SOFT_FLOAT
+static void
+handle_store_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, MonoInst *val, const unsigned char *ip)
+{
+ MonoInst *iargs [2];
+ iargs [0] = val;
+ iargs [1] = ptr;
+
+ mono_emit_jit_icall (cfg, bblock, mono_fstore_r4, iargs, ip);
+}
+
+static int
+handle_load_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, const unsigned char *ip)
+{
+ MonoInst *iargs [1];
+ iargs [0] = ptr;
+
+ return mono_emit_jit_icall (cfg, bblock, mono_fload_r4, iargs, ip);
+}
+
+#define LDLOC_SOFT_FLOAT(cfg,ins,idx,ip) do {\
+ if (header->locals [(idx)]->type == MONO_TYPE_R4 && !header->locals [(idx)]->byref) { \
+ int temp; \
+ NEW_LOCLOADA (cfg, (ins), (idx)); \
+ temp = handle_load_float (cfg, bblock, (ins), (ip)); \
+ NEW_TEMPLOAD (cfg, (ins), temp); \
+ } \
+ } while (0)
+#define STLOC_SOFT_FLOAT(cfg,ins,idx,ip) do {\
+ if (header->locals [(idx)]->type == MONO_TYPE_R4 && !header->locals [(idx)]->byref) { \
+ int temp; \
+ NEW_LOCLOADA (cfg, (ins), (idx)); \
+ handle_store_float (cfg, bblock, (ins), *sp, (ip)); \
+ MONO_INST_NEW (cfg, (ins), CEE_NOP); \
+ } \
+ } while (0)
+#define LDARG_SOFT_FLOAT(cfg,ins,idx,ip) do {\
+ if (param_types [(idx)]->type == MONO_TYPE_R4 && !param_types [(idx)]->byref) { \
+ int temp; \
+ NEW_ARGLOADA (cfg, (ins), (idx)); \
+ temp = handle_load_float (cfg, bblock, (ins), (ip)); \
+ NEW_TEMPLOAD (cfg, (ins), temp); \
+ } \
+ } while (0)
+#else
+#define LDLOC_SOFT_FLOAT(cfg,ins,idx,ip)
+#define STLOC_SOFT_FLOAT(cfg,ins,idx,ip)
+#define LDARG_SOFT_FLOAT(cfg,ins,idx,ip)
+#endif
+
static MonoMethod*
get_memcpy_method (void)
{
inst->inst_left = dest;
inst->inst_right = src;
inst->cil_code = ip;
- inst->unused = n;
+ inst->backend.size = n;
MONO_ADD_INS (bblock, inst);
return;
}
if (n <= sizeof (gpointer) * 5) {
ins->opcode = OP_MEMSET;
ins->inst_imm = 0;
- ins->unused = n;
+ ins->backend.size = n;
MONO_ADD_INS (bblock, ins);
break;
}
/* Need to register the icall so it gets an icall wrapper */
sprintf (icall_name, "ves_array_new_va_%d", rank);
+ mono_jit_lock ();
info = mono_find_jit_icall_by_name (icall_name);
if (info == NULL) {
esig = mono_get_array_new_va_signature (rank);
name = g_strdup (icall_name);
info = mono_register_jit_icall (mono_array_new_va, name, esig, FALSE);
- mono_jit_lock ();
g_hash_table_insert (jit_icall_name_hash, name, name);
- mono_jit_unlock ();
}
+ mono_jit_unlock ();
cfg->flags |= MONO_CFG_HAS_VARARGS;
+ /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
return mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, sp, ip, TRUE, FALSE);
}
{
if (klass->parent == mono_defaults.array_class)
return TRUE;
- else if (mono_defaults.generic_array_class && klass->parent && klass->parent->generic_class)
- return klass->parent->generic_class->container_class == mono_defaults.generic_array_class;
else
return FALSE;
}
if (MONO_TYPE_ISSTRUCT (signature->params [i])) {
return FALSE;
}
+#ifdef MONO_ARCH_SOFT_FLOAT
+ /* this complicates things, fix later */
+ if (signature->params [i]->type == MONO_TYPE_R4)
+ return FALSE;
+#endif
}
/*
if (!(cfg->opt & MONO_OPT_SHARED)) {
vtable = mono_class_vtable (cfg->domain, method->klass);
if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
- if (cfg->run_cctors)
+ if (cfg->run_cctors) {
+ /* This makes so that inline cannot trigger */
+ /* .cctors: too many apps depend on them */
+ /* running with a specific order... */
+ if (! vtable->initialized)
+ return FALSE;
mono_runtime_class_init (vtable);
+ }
}
else if (!vtable->initialized && mono_class_needs_cctor_run (method->klass, NULL))
return FALSE;
}
if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
-#ifdef MONO_ARCH_EMULATE_MUL_DIV
+#if defined(MONO_ARCH_EMULATE_MUL_DIV) && !defined(MONO_ARCH_NO_EMULATE_MUL)
/* OP_LDELEMA2D depends on OP_LMUL */
#else
MonoInst *indexes;
addr->inst_right = indexes;
addr->cil_code = ip;
addr->type = STACK_MP;
- addr->klass = cmethod->klass;
+ addr->klass = cmethod->klass->element_class;
return addr;
#endif
}
/* Need to register the icall so it gets an icall wrapper */
sprintf (icall_name, "ves_array_element_address_%d", rank);
+ mono_jit_lock ();
info = mono_find_jit_icall_by_name (icall_name);
if (info == NULL) {
esig = mono_get_element_address_signature (rank);
name = g_strdup (icall_name);
info = mono_register_jit_icall (ves_array_element_address, name, esig, FALSE);
- mono_jit_lock ();
g_hash_table_insert (jit_icall_name_hash, name, name);
- mono_jit_unlock ();
}
+ mono_jit_unlock ();
+ /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
temp = mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, sp, ip, FALSE, FALSE);
cfg->flags |= MONO_CFG_HAS_VARARGS;
return addr;
}
-MonoJitICallInfo **emul_opcode_map = NULL;
+static MonoJitICallInfo **emul_opcode_map = NULL;
MonoJitICallInfo *
mono_find_jit_opcode_emulation (int opcode)
{
+ g_assert (opcode >= 0 && opcode <= OP_LAST);
if (emul_opcode_map)
return emul_opcode_map [opcode];
else
sp++;
}
}
-#define MONO_INLINE_CALLED_LIMITED_METHODS 1
-#define MONO_INLINE_CALLER_LIMITED_METHODS 1
+#define MONO_INLINE_CALLED_LIMITED_METHODS 0
+#define MONO_INLINE_CALLER_LIMITED_METHODS 0
#if (MONO_INLINE_CALLED_LIMITED_METHODS)
static char*
return 0;
#endif
+ if (bblock->out_of_line && !inline_allways)
+ return 0;
+
if (cfg->verbose_level > 2)
g_print ("INLINE START %p %s -> %s\n", cmethod, mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
#define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
#define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
#define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
+#define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) {cfg->exception_ptr = klass; goto load_error;}
/* offset from br.s -> br like opcodes */
#define BIG_BRANCH_OFFSET 13
return klass;
}
+/*
+ * Returns TRUE if the JIT should abort inlining because "callee"
+ * is influenced by security attributes.
+ */
static
-void check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee, MonoBasicBlock *bblock, unsigned char *ip)
+gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee, MonoBasicBlock *bblock, unsigned char *ip)
{
- guint32 result = mono_declsec_linkdemand (cfg->domain, caller, callee);
+ guint32 result;
+
+ if ((cfg->method != caller) && mono_method_has_declsec (callee)) {
+ return TRUE;
+ }
+
+ result = mono_declsec_linkdemand (cfg->domain, caller, callee);
if (result == MONO_JIT_SECURITY_OK)
- return;
+ return FALSE;
if (result == MONO_JIT_LINKDEMAND_ECMA) {
/* Generate code to throw a SecurityException before the actual call/link */
cfg->exception_type = MONO_EXCEPTION_SECURITY_LINKDEMAND;
cfg->exception_data = result;
}
+
+ return FALSE;
}
static gboolean
dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
+ dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
+ dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
- /* still some type unsefety issues in marshal wrappers... (unknown is PtrToStructure) */
+ /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
}
}
- if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || mono_compile_aot || security || pinvoke) {
+ if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || cfg->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;
n = (*ip)-CEE_LDARG_0;
CHECK_ARG (n);
NEW_ARGLOAD (cfg, ins, n);
+ LDARG_SOFT_FLOAT (cfg, ins, n, ip);
ins->cil_code = ip++;
*sp++ = ins;
break;
n = (*ip)-CEE_LDLOC_0;
CHECK_LOCAL (n);
NEW_LOCLOAD (cfg, ins, n);
+ LDLOC_SOFT_FLOAT (cfg, ins, n, ip);
ins->cil_code = ip++;
*sp++ = ins;
break;
ins->cil_code = ip;
if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
UNVERIFIED;
+ STLOC_SOFT_FLOAT (cfg, ins, n, ip);
if (ins->opcode == CEE_STOBJ) {
NEW_LOCLOADA (cfg, ins, n);
handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
CHECK_STACK_OVF (1);
CHECK_ARG (ip [1]);
NEW_ARGLOAD (cfg, ins, ip [1]);
+ LDARG_SOFT_FLOAT (cfg, ins, ip [1], ip);
ins->cil_code = ip;
*sp++ = ins;
ip += 2;
CHECK_STACK_OVF (1);
CHECK_LOCAL (ip [1]);
NEW_LOCLOAD (cfg, ins, ip [1]);
+ LDLOC_SOFT_FLOAT (cfg, ins, ip [1], ip);
ins->cil_code = ip;
*sp++ = ins;
ip += 2;
ins->cil_code = ip;
if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
UNVERIFIED;
+ STLOC_SOFT_FLOAT (cfg, ins, ip [1], ip);
if (ins->opcode == CEE_STOBJ) {
NEW_LOCLOADA (cfg, ins, ip [1]);
handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
goto load_error;
if (mono_use_security_manager) {
- check_linkdemand (cfg, method, cmethod, bblock, ip);
+ if (check_linkdemand (cfg, method, cmethod, bblock, ip))
+ INLINE_FAILURE;
}
ins->inst_p0 = cmethod;
n = fsig->param_count + fsig->hasthis;
} else {
+ MonoMethod *cil_method;
+
if (method->wrapper_type != MONO_WRAPPER_NONE) {
cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
+ cil_method = cmethod;
} else if (constrained_call) {
- cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context);
+ cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
cmethod = mono_get_inflated_method (cmethod);
} else {
cmethod = mini_get_method (method, token, NULL, generic_context);
+ cil_method = cmethod;
}
if (!cmethod)
goto load_error;
- if (!dont_verify && !can_access_method (method, cmethod))
+ if (!dont_verify && !cfg->skip_visibility && !can_access_method (method, cil_method))
UNVERIFIED;
if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
n = fsig->param_count + fsig->hasthis;
if (mono_use_security_manager) {
- check_linkdemand (cfg, method, cmethod, bblock, ip);
+ if (check_linkdemand (cfg, method, cmethod, bblock, ip))
+ INLINE_FAILURE;
}
if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
!((cmethod->flags & METHOD_ATTRIBUTE_FINAL) &&
cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
mono_method_signature (cmethod)->generic_param_count) {
- MonoInst *this_temp, *store;
- MonoInst *iargs [3];
+ MonoInst *this_temp, *this_arg_temp, *store;
+ MonoInst *iargs [4];
g_assert (mono_method_signature (cmethod)->is_inflated);
/* Prevent inlining of methods that contain indirect calls */
store->cil_code = ip;
MONO_ADD_INS (bblock, store);
+ /* FIXME: This should be a managed pointer */
+ this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
+ this_arg_temp->cil_code = ip;
+
NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
NEW_PCONST (cfg, iargs [1], cmethod);
NEW_PCONST (cfg, iargs [2], ((MonoMethodInflated *) cmethod)->context);
+ NEW_TEMPLOADA (cfg, iargs [3], this_arg_temp->inst_c0);
temp = mono_emit_jit_icall (cfg, bblock, mono_helper_compile_generic_method, iargs, ip);
NEW_TEMPLOAD (cfg, addr, temp);
- NEW_TEMPLOAD (cfg, sp [0], this_temp->inst_c0);
+ NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
if ((temp = mono_emit_calli (cfg, bblock, fsig, sp, addr, ip)) != -1) {
NEW_TEMPLOAD (cfg, *sp, temp);
}
ip += 5;
+ ins_flag = 0;
break;
}
if ((ins_flag & MONO_INST_TAILCALL) && cmethod && (*ip == CEE_CALL) &&
(mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)))) {
int i;
+
/* Prevent inlining of methods with tail calls (the call stack would be altered) */
INLINE_FAILURE;
/* FIXME: This assumes the two methods has the same number and type of arguments */
+ /*
+ * We implement tail calls by storing the actual arguments into the
+ * argument variables, then emitting a CEE_JMP. Since the actual arguments
+ * can refer to the arg variables, we have to spill them.
+ */
+ handle_loaded_temps (cfg, bblock, sp, sp + n);
for (i = 0; i < n; ++i) {
+ /* Prevent argument from being register allocated */
+ arg_array [i]->flags |= MONO_INST_VOLATILE;
+
/* Check if argument is the same */
+ /*
+ * FIXME: This loses liveness info, so it can only be done if the
+ * argument is not register allocated.
+ */
NEW_ARGLOAD (cfg, ins, i);
if ((ins->opcode == sp [i]->opcode) && (ins->inst_i0 == sp [i]->inst_i0))
continue;
- /* Prevent argument from being register allocated */
- arg_array [i]->flags |= MONO_INST_VOLATILE;
NEW_ARGSTORE (cfg, ins, i, sp [i]);
ins->cil_code = ip;
if (ins->opcode == CEE_STOBJ) {
}
ip += 5;
+ ins_flag = 0;
break;
}
bblock = ebblock;
inline_costs += costs;
+ ins_flag = 0;
break;
}
}
ip += 6;
else
ip += 5;
-
+ ins_flag = 0;
break;
}
}
}
ip += 5;
+ ins_flag = 0;
break;
}
case CEE_RET:
ins->cil_code = ip++;
target = ip + 1 + *(signed char*)ip;
ip++;
+#ifdef MONO_ARCH_SOFT_FLOAT
+ if (sp [-1]->type == STACK_R8 || sp [-2]->type == STACK_R8) {
+ ins->opcode = condbr_to_fp_br (ins->opcode);
+ sp -= 2;
+ ins->inst_left = sp [0];
+ ins->inst_right = sp [1];
+ ins->type = STACK_I4;
+ *sp++ = emit_tree (cfg, bblock, ins, ins->cil_code);
+ MONO_INST_NEW (cfg, ins, CEE_BRTRUE);
+ ADD_UNCOND (TRUE);
+ } else {
+ ADD_BINCOND (NULL);
+ }
+#else
ADD_BINCOND (NULL);
+#endif
if (sp != stack_start) {
handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
sp = stack_start;
ins->cil_code = ip++;
target = ip + 4 + (gint32)read32(ip);
ip += 4;
- ADD_BINCOND(NULL);
+#ifdef MONO_ARCH_SOFT_FLOAT
+ if (sp [-1]->type == STACK_R8 || sp [-2]->type == STACK_R8) {
+ ins->opcode = condbr_to_fp_br (ins->opcode);
+ sp -= 2;
+ ins->inst_left = sp [0];
+ ins->inst_right = sp [1];
+ ins->type = STACK_I4;
+ *sp++ = emit_tree (cfg, bblock, ins, ins->cil_code);
+ MONO_INST_NEW (cfg, ins, CEE_BRTRUE);
+ ADD_UNCOND (TRUE);
+ } else {
+ ADD_BINCOND (NULL);
+ }
+#else
+ ADD_BINCOND (NULL);
+#endif
if (sp != stack_start) {
handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
sp = stack_start;
ins_flag = 0;
if (ins->type == STACK_OBJ)
ins->klass = mono_defaults.object_class;
+#ifdef MONO_ARCH_SOFT_FLOAT
+ if (*ip == CEE_LDIND_R4) {
+ int temp;
+ ++sp;
+ temp = handle_load_float (cfg, bblock, ins->inst_i0, ip);
+ NEW_TEMPLOAD (cfg, *sp, temp);
+ sp++;
+ }
+#endif
++ip;
break;
case CEE_STIND_REF:
case CEE_STIND_R4:
case CEE_STIND_R8:
CHECK_STACK (2);
+#ifdef MONO_ARCH_SOFT_FLOAT
+ if (*ip == CEE_STIND_R4) {
+ sp -= 2;
+ handle_store_float (cfg, bblock, sp [0], sp [1], ip);
+ ip++;
+ break;
+ }
+#endif
#if HAVE_WRITE_BARRIERS
if (*ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER) {
/* insert call to write barrier */
CHECK_STACK (2);
token = read32 (ip + 1);
klass = mini_get_class (method, token, generic_context);
- if (!klass)
- goto load_error;
+ CHECK_TYPELOAD (klass);
sp -= 2;
if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
MonoInst *store, *load;
copy->inst_left = sp [0];
copy->inst_right = sp [1];
copy->cil_code = ip;
- copy->unused = n;
+ copy->backend.size = n;
MONO_ADD_INS (bblock, copy);
} else {
MonoMethod *memcpy_method = get_memcpy_method ();
--sp;
token = read32 (ip + 1);
klass = mini_get_class (method, token, generic_context);
- if (!klass)
- goto load_error;
+ CHECK_TYPELOAD (klass);
if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
ins->cil_code = ip;
copy->inst_left = iargs [0];
copy->inst_right = *sp;
copy->cil_code = ip;
- copy->unused = n;
+ copy->backend.size = n;
MONO_ADD_INS (bblock, copy);
} else {
MonoMethod *memcpy_method = get_memcpy_method ();
goto load_error;
if (mono_use_security_manager) {
- check_linkdemand (cfg, method, cmethod, bblock, ip);
+ if (check_linkdemand (cfg, method, cmethod, bblock, ip))
+ INLINE_FAILURE;
}
n = fsig->param_count;
CHECK_OPSIZE (5);
token = read32 (ip + 1);
klass = mini_get_class (method, token, generic_context);
- if (!klass)
- goto load_error;
+ CHECK_TYPELOAD (klass);
if (sp [0]->type != STACK_OBJ)
UNVERIFIED;
CHECK_OPSIZE (5);
token = read32 (ip + 1);
klass = mini_get_class (method, token, generic_context);
- if (!klass)
- goto load_error;
+ CHECK_TYPELOAD (klass);
if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
/* CASTCLASS */
copy->inst_left = iargs [0];
copy->inst_right = *sp;
copy->cil_code = ip;
- copy->unused = n;
+ copy->backend.size = n;
MONO_ADD_INS (bblock, copy);
} else {
MonoMethod *memcpy_method = get_memcpy_method ();
CHECK_OPSIZE (5);
token = read32 (ip + 1);
klass = mini_get_class (method, token, generic_context);
- if (!klass)
- goto load_error;
+ CHECK_TYPELOAD (klass);
if (mono_class_is_nullable (klass)) {
int v = handle_unbox_nullable (cfg, bblock, *sp, ip, klass);
CHECK_OPSIZE (5);
token = read32 (ip + 1);
klass = mini_get_class (method, token, generic_context);
- if (!klass)
- goto load_error;
+ CHECK_TYPELOAD (klass);
if (sp [0]->type != STACK_OBJ)
UNVERIFIED;
if (!field)
goto load_error;
mono_class_init (klass);
- if (!dont_verify && !can_access_field (method, field))
+ if (!dont_verify && !cfg->skip_visibility && !can_access_field (method, field))
UNVERIFIED;
foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
iargs [0] = ins;
iargs [1] = sp [1];
mono_emit_method_call_spilled (cfg, bblock, write_barrier, mono_method_signature (write_barrier), iargs, ip, NULL);
+#endif
+#ifdef MONO_ARCH_SOFT_FLOAT
+ } else if (mono_type_to_stind (field->type) == CEE_STIND_R4) {
+ NEW_ICONST (cfg, offset_ins, foffset);
+ MONO_INST_NEW (cfg, ins, OP_PADD);
+ ins->cil_code = ip;
+ ins->inst_left = *sp;
+ ins->inst_right = offset_ins;
+ ins->type = STACK_MP;
+ ins->klass = mono_defaults.object_class;
+ handle_store_float (cfg, bblock, ins, sp [1], ip);
#endif
} else {
MonoInst *store;
load->inst_left = ins;
load->flags |= ins_flag;
ins_flag = 0;
+#ifdef MONO_ARCH_SOFT_FLOAT
+ if (mono_type_to_ldind (field->type) == CEE_LDIND_R4) {
+ int temp;
+ temp = handle_load_float (cfg, bblock, ins, ip);
+ NEW_TEMPLOAD (cfg, *sp, temp);
+ sp++;
+ } else
+#endif
*sp++ = load;
}
}
g_print ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, field->name);
class_inits = g_slist_prepend (class_inits, vtable);
} else {
- if (cfg->run_cctors)
+ if (cfg->run_cctors) {
+ /* This makes so that inline cannot trigger */
+ /* .cctors: too many apps depend on them */
+ /* running with a specific order... */
+ if (! vtable->initialized)
+ INLINE_FAILURE;
mono_runtime_class_init (vtable);
+ }
}
addr = (char*)vtable->data + field->offset;
CHECK_OPSIZE (5);
token = read32 (ip + 1);
klass = mini_get_class (method, token, generic_context);
- if (!klass)
- goto load_error;
+ CHECK_TYPELOAD (klass);
n = mono_type_to_stind (&klass->byval_arg);
if (n == CEE_STOBJ) {
handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE, TRUE);
CHECK_OPSIZE (5);
token = read32 (ip + 1);
klass = mini_get_class (method, token, generic_context);
- if (!klass)
- goto load_error;
+ CHECK_TYPELOAD (klass);
if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
*sp++ = val;
mono_get_got_var (cfg);
klass = mini_get_class (method, token, generic_context);
- if (!klass)
- goto load_error;
+ CHECK_TYPELOAD (klass);
ins->inst_newa_class = klass;
ins->inst_newa_len = *sp;
ins->type = STACK_OBJ;
UNVERIFIED;
klass = mini_get_class (method, read32 (ip + 1), generic_context);
- if (!klass)
- goto load_error;
+ CHECK_TYPELOAD (klass);
/* we need to make sure that this array is exactly the type it needs
* to be for correctness. the wrappers are lax with their usage
* so we need to ignore them here
CHECK_OPSIZE (5);
token = read32 (ip + 1);
klass = mono_class_get_full (image, token, generic_context);
- if (!klass)
- goto load_error;
+ CHECK_TYPELOAD (klass);
mono_class_init (klass);
NEW_LDELEMA (cfg, load, sp, klass);
load->cil_code = ip;
klass = array_access_to_klass (*ip);
NEW_LDELEMA (cfg, load, sp, klass);
load->cil_code = ip;
+#ifdef MONO_ARCH_SOFT_FLOAT
+ if (*ip == CEE_LDELEM_R4) {
+ int temp;
+ temp = handle_load_float (cfg, bblock, load, ip);
+ NEW_TEMPLOAD (cfg, *sp, temp);
+ sp++;
+ ++ip;
+ break;
+ }
+#endif
MONO_INST_NEW (cfg, ins, ldelem_to_ldind [*ip - CEE_LDELEM_I1]);
ins->cil_code = ip;
ins->inst_left = load;
klass = array_access_to_klass (*ip);
NEW_LDELEMA (cfg, load, sp, klass);
load->cil_code = ip;
+#ifdef MONO_ARCH_SOFT_FLOAT
+ if (*ip == CEE_STELEM_R4) {
+ handle_store_float (cfg, bblock, load, sp [2], ip);
+ ip++;
+ break;
+ }
+#endif
MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
ins->cil_code = ip;
ins->inst_left = load;
CHECK_OPSIZE (5);
token = read32 (ip + 1);
klass = mono_class_get_full (image, token, generic_context);
- if (!klass)
- goto load_error;
+ CHECK_TYPELOAD (klass);
mono_class_init (klass);
if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
MonoMethod* helper = mono_marshal_get_stelemref ();
--sp;
CHECK_OPSIZE (5);
klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
- if (!klass)
- goto load_error;
+ CHECK_TYPELOAD (klass);
mono_class_init (klass);
ins->type = STACK_MP;
ins->inst_left = *sp;
--sp;
CHECK_OPSIZE (5);
klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
- if (!klass)
- goto load_error;
+ CHECK_TYPELOAD (klass);
mono_class_init (klass);
ins->cil_code = ip;
cmp->cil_code = ip;
type_from_op (cmp);
CHECK_TYPE (cmp);
+ ins->cil_code = ip;
+ ins->type = STACK_I4;
+ ins->inst_i0 = cmp;
+#if MONO_ARCH_SOFT_FLOAT
+ if (sp [0]->type == STACK_R8) {
+ cmp->type = STACK_I4;
+ *sp++ = emit_tree (cfg, bblock, cmp, ip + 2);
+ ip += 2;
+ break;
+ }
+#endif
if ((sp [0]->type == STACK_I8) || ((sizeof (gpointer) == 8) && ((sp [0]->type == STACK_PTR) || (sp [0]->type == STACK_OBJ) || (sp [0]->type == STACK_MP))))
cmp->opcode = OP_LCOMPARE;
else
cmp->opcode = OP_COMPARE;
- ins->cil_code = ip;
- ins->type = STACK_I4;
- ins->inst_i0 = cmp;
*sp++ = ins;
/* spill it to reduce the expression complexity
* and workaround bug 54209
mono_class_init (cmethod->klass);
if (mono_use_security_manager) {
- check_linkdemand (cfg, method, cmethod, bblock, ip);
+ if (check_linkdemand (cfg, method, cmethod, bblock, ip))
+ INLINE_FAILURE;
}
handle_loaded_temps (cfg, bblock, stack_start, sp);
mono_class_init (cmethod->klass);
if (mono_use_security_manager) {
- check_linkdemand (cfg, method, cmethod, bblock, ip);
+ if (check_linkdemand (cfg, method, cmethod, bblock, ip))
+ INLINE_FAILURE;
}
handle_loaded_temps (cfg, bblock, stack_start, sp);
n = read16 (ip + 2);
CHECK_ARG (n);
NEW_ARGLOAD (cfg, ins, n);
+ LDARG_SOFT_FLOAT (cfg, ins, n, ip);
ins->cil_code = ip;
*sp++ = ins;
ip += 4;
n = read16 (ip + 2);
CHECK_LOCAL (n);
NEW_LOCLOAD (cfg, ins, n);
+ LDLOC_SOFT_FLOAT (cfg, ins, n, ip);
ins->cil_code = ip;
*sp++ = ins;
ip += 4;
if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
UNVERIFIED;
ins->cil_code = ip;
+ STLOC_SOFT_FLOAT (cfg, ins, n, ip);
if (ins->opcode == CEE_STOBJ) {
NEW_LOCLOADA (cfg, ins, n);
handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
CHECK_OPSIZE (6);
token = read32 (ip + 2);
klass = mini_get_class (method, token, generic_context);
- if (!klass)
- goto load_error;
+ CHECK_TYPELOAD (klass);
if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
MonoInst *store, *load;
NEW_PCONST (cfg, load, NULL);
CHECK_OPSIZE (6);
token = read32 (ip + 2);
constrained_call = mono_class_get_full (image, token, generic_context);
- if (!constrained_call)
- goto load_error;
+ CHECK_TYPELOAD (constrained_call);
ip += 6;
break;
case CEE_CPBLK:
copy->inst_left = sp [0];
copy->inst_right = sp [1];
copy->cil_code = ip;
- copy->unused = n;
+ copy->backend.size = n;
MONO_ADD_INS (bblock, copy);
ip += 2;
break;
token = mono_type_size (type, &ialign);
} else {
MonoClass *klass = mono_class_get_full (image, token, generic_context);
- if (!klass)
- goto load_error;
+ CHECK_TYPELOAD (klass);
mono_class_init (klass);
token = mono_class_value_size (klass, &align);
}
NEW_LOCSTORE (cfg, store, i, ins);
MONO_ADD_INS (init_localsbb, store);
} else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
+#ifdef MONO_ARCH_SOFT_FLOAT
+ /* FIXME: handle init of R4 */
+#else
MONO_INST_NEW (cfg, ins, OP_R8CONST);
ins->type = STACK_R8;
ins->inst_p0 = (void*)&r8_0;
NEW_LOCSTORE (cfg, store, i, ins);
MONO_ADD_INS (init_localsbb, store);
+#endif
} else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (ptype))) {
NEW_LOCLOADA (cfg, ins, i);
{
char *name;
MonoMethod *wrapper;
+ gconstpointer trampoline;
+ MonoDomain *domain = mono_get_root_domain ();
if (callinfo->wrapper) {
return callinfo->wrapper;
if (callinfo->trampoline)
return callinfo->trampoline;
+ /*
+ * We use the lock on the root domain instead of the JIT lock to protect
+ * callinfo->trampoline, since we do a lot of stuff inside the critical section.
+ */
+ mono_domain_lock (domain);
+
+ if (callinfo->trampoline) {
+ mono_domain_unlock (domain);
+ return callinfo->trampoline;
+ }
+
name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func);
g_free (name);
- callinfo->trampoline = mono_create_ftnptr (mono_get_root_domain (), mono_create_jit_trampoline_in_domain (mono_get_root_domain (), wrapper));
- mono_register_jit_icall_wrapper (callinfo, callinfo->trampoline);
+ trampoline = mono_create_ftnptr (domain, mono_create_jit_trampoline_in_domain (domain, wrapper));
+ mono_register_jit_icall_wrapper (callinfo, trampoline);
+
+ callinfo->trampoline = trampoline;
+ mono_domain_unlock (domain);
+
return callinfo->trampoline;
}
} StackSlotInfo;
/*
- * mono_allocate_stack_slots_full:
+ * mono_allocate_stack_slots_full:
*
* Allocate stack slots for all non register allocated variables using a
* linear scan algorithm.
vmv = l->data;
inst = m->varinfo [vmv->idx];
- /* inst->unused indicates native sized value types, this is used by the
+ /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
* pinvoke wrappers when they call functions returning structures */
- if (inst->unused && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
+ if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
size = mono_class_native_size (inst->inst_vtype->data.klass, &align);
else {
int ialign;
}
t = mono_type_get_underlying_type (inst->inst_vtype);
- switch (t->type) {
- case MONO_TYPE_GENERICINST:
- if (!mono_type_generic_inst_is_valuetype (t)) {
- slot_info = &scalar_stack_slots [t->type];
- break;
- }
- /* Fall through */
- case MONO_TYPE_VALUETYPE:
- for (i = 0; i < nvtypes; ++i)
- if (t->data.klass == vtype_stack_slots [i].vtype)
+ if (t->byref) {
+ slot_info = &scalar_stack_slots [MONO_TYPE_I];
+ } else {
+ switch (t->type) {
+ case MONO_TYPE_GENERICINST:
+ if (!mono_type_generic_inst_is_valuetype (t)) {
+ slot_info = &scalar_stack_slots [t->type];
break;
- if (i < nvtypes)
- slot_info = &vtype_stack_slots [i];
- else {
- g_assert (nvtypes < 256);
- vtype_stack_slots [nvtypes].vtype = t->data.klass;
- slot_info = &vtype_stack_slots [nvtypes];
- nvtypes ++;
+ }
+ /* Fall through */
+ case MONO_TYPE_VALUETYPE:
+ for (i = 0; i < nvtypes; ++i)
+ if (t->data.klass == vtype_stack_slots [i].vtype)
+ break;
+ if (i < nvtypes)
+ slot_info = &vtype_stack_slots [i];
+ else {
+ g_assert (nvtypes < 256);
+ vtype_stack_slots [nvtypes].vtype = t->data.klass;
+ slot_info = &vtype_stack_slots [nvtypes];
+ nvtypes ++;
+ }
+ break;
+ default:
+ slot_info = &scalar_stack_slots [t->type];
}
- break;
- default:
- slot_info = &scalar_stack_slots [t->type];
}
slot = 0xffffff;
dec_foreach (iargs [i], cfg);
break;
}
+#ifdef MONO_ARCH_SOFT_FLOAT
+ case OP_FBEQ:
+ case OP_FBGE:
+ case OP_FBGT:
+ case OP_FBLE:
+ case OP_FBLT:
+ case OP_FBNE_UN:
+ case OP_FBGE_UN:
+ case OP_FBGT_UN:
+ case OP_FBLE_UN:
+ case OP_FBLT_UN: {
+ if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
+ MonoCompile *cfg = data;
+ MonoInst *iargs [2];
+
+ iargs [0] = tree->inst_i0;
+ iargs [1] = tree->inst_i1;
+
+ mono_emulate_opcode (cfg, tree, iargs, info);
+
+ dec_foreach (iargs [0], cfg);
+ dec_foreach (iargs [1], cfg);
+ break;
+ } else {
+ g_assert_not_reached ();
+ }
+ break;
+ }
+ case OP_FCEQ:
+ case OP_FCGT:
+ case OP_FCGT_UN:
+ case OP_FCLT:
+ case OP_FCLT_UN: {
+ if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
+ MonoCompile *cfg = data;
+ MonoInst *iargs [2];
+
+ /* the args are in the compare opcode ... */
+ iargs [0] = tree->inst_i0;
+ iargs [1] = tree->inst_i1;
+
+ mono_emulate_opcode (cfg, tree, iargs, info);
+
+ dec_foreach (iargs [0], cfg);
+ dec_foreach (iargs [1], cfg);
+ break;
+ } else {
+ g_assert_not_reached ();
+ }
+ break;
+ }
+#endif
default:
break;
#ifdef HAVE_KW_THREAD
static __thread gpointer mono_lmf_addr MONO_TLS_FAST;
+#ifdef MONO_ARCH_ENABLE_MONO_LMF_VAR
+/*
+ * When this is defined, the current lmf is stored in this tls variable instead of in
+ * jit_tls->lmf.
+ */
+static __thread gpointer mono_lmf MONO_TLS_FAST;
+#endif
#endif
guint32
gint32
mono_get_lmf_tls_offset (void)
+{
+#if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
+ int offset;
+ MONO_THREAD_VAR_OFFSET(mono_lmf,offset);
+ return offset;
+#else
+ return -1;
+#endif
+}
+
+gint32
+mono_get_lmf_addr_tls_offset (void)
{
int offset;
MONO_THREAD_VAR_OFFSET(mono_lmf_addr,offset);
return offset;
}
+MonoLMF *
+mono_get_lmf (void)
+{
+#if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
+ return mono_lmf;
+#else
+ MonoJitTlsData *jit_tls;
+
+ if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
+ return jit_tls->lmf;
+
+ g_assert_not_reached ();
+ return NULL;
+#endif
+}
+
MonoLMF **
mono_get_lmf_addr (void)
{
lmf = g_new0 (MonoLMF, 1);
lmf->ebp = -1;
- jit_tls->lmf = jit_tls->first_lmf = lmf;
+ jit_tls->first_lmf = lmf;
-#ifdef HAVE_KW_THREAD
- mono_lmf_addr = &jit_tls->lmf;
+#if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
+ /* jit_tls->lmf is unused */
+ mono_lmf = lmf;
+ mono_lmf_addr = &mono_lmf;
+#else
+#if defined(HAVE_KW_THREAD)
+ mono_lmf_addr = &jit_tls->lmf;
+#endif
+
+ jit_tls->lmf = lmf;
#endif
mono_arch_setup_jit_tls_data (jit_tls);
}
}
+/**
+ * mono_patch_info_dup_mp:
+ *
+ * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
+ */
+MonoJumpInfo*
+mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
+{
+ MonoJumpInfo *res = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
+ memcpy (res, patch_info, sizeof (MonoJumpInfo));
+
+ switch (patch_info->type) {
+ case MONO_PATCH_INFO_LDSTR:
+ case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
+ case MONO_PATCH_INFO_LDTOKEN:
+ case MONO_PATCH_INFO_DECLSEC:
+ res->data.token = mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
+ memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
+ break;
+ case MONO_PATCH_INFO_SWITCH:
+ res->data.table = mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
+ memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
+ break;
+ default:
+ break;
+ }
+
+ return res;
+}
+
+guint
+mono_patch_info_hash (gconstpointer data)
+{
+ const MonoJumpInfo *ji = (MonoJumpInfo*)data;
+
+ switch (ji->type) {
+ case MONO_PATCH_INFO_LDSTR:
+ case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
+ case MONO_PATCH_INFO_LDTOKEN:
+ case MONO_PATCH_INFO_DECLSEC:
+ return (ji->type << 8) | ji->data.token->token;
+ default:
+ return (ji->type << 8);
+ }
+}
+
+/*
+ * mono_patch_info_equal:
+ *
+ * This might fail to recognize equivalent patches, i.e. floats, so its only
+ * usable in those cases where this is not a problem, i.e. sharing GOT slots
+ * in AOT.
+ */
+gint
+mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
+{
+ const MonoJumpInfo *ji1 = (MonoJumpInfo*)ka;
+ const MonoJumpInfo *ji2 = (MonoJumpInfo*)kb;
+
+ if (ji1->type != ji2->type)
+ return 0;
+
+ switch (ji1->type) {
+ case MONO_PATCH_INFO_LDSTR:
+ case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
+ case MONO_PATCH_INFO_LDTOKEN:
+ case MONO_PATCH_INFO_DECLSEC:
+ if ((ji1->data.token->image != ji2->data.token->image) ||
+ (ji1->data.token->token != ji2->data.token->token))
+ return 0;
+ break;
+ default:
+ if (ji1->data.name != ji2->data.name)
+ return 0;
+ break;
+ }
+
+ return 1;
+}
+
gpointer
mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors)
{
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)) {
replace_basic_block (bb, bbn, bb);
+ /* Nullify branch at the end of bb */
+ if (bb->last_ins && MONO_IS_BRANCH_OP (bb->last_ins)) {
+ bb->last_ins->opcode = CEE_NOP;
+ }
+
if (bb->last_ins) {
if (bbn->code) {
bb->last_ins->next = bbn->code;
MBState *kids [10];
int ern = mono_burg_rule (state, goal);
const guint16 *nts = mono_burg_nts_data + mono_burg_nts [ern];
- MBEmitFunc emit;
//g_print ("rule: %s\n", mono_burg_rule_string [ern]);
switch (goal) {
state->reg2 = mono_regstate_next_int (cfg->rs);
break;
case MB_NTERM_freg:
+#ifdef MONO_ARCH_SOFT_FLOAT
+ state->reg1 = mono_regstate_next_int (cfg->rs);
+ state->reg2 = mono_regstate_next_int (cfg->rs);
+#else
state->reg1 = mono_regstate_next_float (cfg->rs);
+#endif
break;
default:
#ifdef MONO_ARCH_ENABLE_EMIT_STATE_OPT
}
// g_print ("emit: %s (%p)\n", mono_burg_rule_string [ern], state);
- if ((emit = mono_burg_func [ern]))
- emit (state, state->tree, cfg);
+ mono_burg_emit (ern, state, state->tree, cfg);
}
#define DEBUG_SELECTION
cfg->domain = domain;
cfg->verbose_level = mini_verbose;
cfg->compile_aot = compile_aot;
+ cfg->skip_visibility = method->skip_visibility;
if (!header) {
cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
mono_jit_stats.basic_blocks += cfg->num_bblocks;
mono_jit_stats.max_basic_blocks = MAX (cfg->num_bblocks, mono_jit_stats.max_basic_blocks);
- if ((cfg->num_varinfo > 2000) && !mono_compile_aot) {
+ if ((cfg->num_varinfo > 2000) && !cfg->compile_aot) {
/*
* we disable some optimizations if there are too many variables
* because JIT time may become too expensive. The actual number needs
if (parts == 3)
return cfg;
+ if (cfg->verbose_level > 4) {
+ printf ("BEFORE DECOMPSE START\n");
+ mono_print_code (cfg);
+ printf ("BEFORE DECOMPSE END\n");
+ }
+
decompose_pass (cfg);
if (cfg->got_var) {
method = mono_get_inflated_method (method);
#ifdef MONO_USE_AOT_COMPILER
- if (!mono_compile_aot && (opt & MONO_OPT_AOT) && !(mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)) {
- MonoJitInfo *info;
+ if ((opt & MONO_OPT_AOT) && !(mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)) {
MonoDomain *domain = mono_domain_get ();
- mono_domain_lock (domain);
-
mono_class_init (method->klass);
- if ((info = mono_aot_get_method (domain, method))) {
- g_hash_table_insert (domain->jit_code_hash, method, info);
+
+ mono_domain_lock (domain);
+ if ((code = mono_aot_get_method (domain, method))) {
mono_domain_unlock (domain);
mono_runtime_class_init (mono_class_vtable (domain, method->klass));
- return info->code_start;
+ return code;
}
mono_domain_unlock (domain);
MonoMethod *nm;
MonoMethodPInvoke* piinfo = (MonoMethodPInvoke *) method;
- if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)
+ if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE && !MONO_CLASS_IS_IMPORT(method->klass))
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) {
/* Throw a type load exception if needed */
MonoLoaderError *error = mono_loader_get_last_error ();
- mono_destroy_compile (cfg);
if (error) {
MonoException *ex = mono_loader_error_prepare_exception (error);
+ mono_destroy_compile (cfg);
mono_raise_exception (ex);
} else {
+ if (cfg->exception_ptr) {
+ MonoException *ex = mono_class_get_exception_for_failure (cfg->exception_ptr);
+ mono_destroy_compile (cfg);
+ mono_raise_exception (ex);
+ }
g_assert_not_reached ();
}
}
return runtime_invoke (obj, params, exc, compiled_method);
}
+#ifdef MONO_GET_CONTEXT
+#define GET_CONTEXT MONO_GET_CONTEXT
+#endif
+
+#ifndef GET_CONTEXT
#ifdef PLATFORM_WIN32
#define GET_CONTEXT \
struct sigcontext *ctx = (struct sigcontext*)_dummy;
#else
-#ifdef __sparc
+#ifdef MONO_ARCH_USE_SIGACTION
#define GET_CONTEXT \
void *ctx = context;
-#elif defined(sun) // Solaris x86
-#define GET_CONTEXT \
- ucontext_t *uctx = context; \
- struct sigcontext *ctx = (struct sigcontext *)&(uctx->uc_mcontext);
-#elif defined (MONO_ARCH_USE_SIGACTION)
+#elif defined(__sparc__)
#define GET_CONTEXT \
- void *ctx = context;
+ void *ctx = sigctx;
#else
#define GET_CONTEXT \
void **_p = (void **)&_dummy; \
struct sigcontext *ctx = (struct sigcontext *)++_p;
#endif
#endif
+#endif
#ifdef MONO_ARCH_USE_SIGACTION
#define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, siginfo_t *info, void *context)
+#elif defined(__sparc__)
+#define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, void *sigctx)
#else
#define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy)
#endif
mono_trace_enable (!enabled);
}
+#ifdef PLATFORM_MACOSX
+
+/*
+ * This code disables the CrashReporter of MacOS X by installing
+ * a dummy Mach exception handler.
+ */
+
+/*
+ * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/exc_server.html
+ */
+extern
+boolean_t
+exc_server (mach_msg_header_t *request_msg,
+ mach_msg_header_t *reply_msg);
+
+/*
+ * The exception message
+ */
+typedef struct {
+ mach_msg_base_t msg; /* common mach message header */
+ char payload [1024]; /* opaque */
+} mach_exception_msg_t;
+
+/* The exception port */
+static mach_port_t mach_exception_port = VM_MAP_NULL;
+
+/*
+ * Implicitly called by exc_server. Must be public.
+ *
+ * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/catch_exception_raise.html
+ */
+kern_return_t
+catch_exception_raise (
+ mach_port_t exception_port,
+ mach_port_t thread,
+ mach_port_t task,
+ exception_type_t exception,
+ exception_data_t code,
+ mach_msg_type_number_t code_count)
+{
+ /* consume the exception */
+ return KERN_FAILURE;
+}
+
+/*
+ * Exception thread handler.
+ */
+static
+void *
+mach_exception_thread (void *arg)
+{
+ for (;;) {
+ mach_exception_msg_t request;
+ mach_exception_msg_t reply;
+ mach_msg_return_t result;
+
+ /* receive from "mach_exception_port" */
+ result = mach_msg (&request.msg.header,
+ MACH_RCV_MSG | MACH_RCV_LARGE,
+ 0,
+ sizeof (request),
+ mach_exception_port,
+ MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+
+ g_assert (result == MACH_MSG_SUCCESS);
+
+ /* dispatch to catch_exception_raise () */
+ exc_server (&request.msg.header, &reply.msg.header);
+
+ /* send back to sender */
+ result = mach_msg (&reply.msg.header,
+ MACH_SEND_MSG,
+ reply.msg.header.msgh_size,
+ 0,
+ MACH_PORT_NULL,
+ MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+
+ g_assert (result == MACH_MSG_SUCCESS);
+ }
+ return NULL;
+}
+
+static void
+macosx_register_exception_handler ()
+{
+ mach_port_t task;
+ pthread_attr_t attr;
+ pthread_t thread;
+
+ if (mach_exception_port != VM_MAP_NULL)
+ return;
+
+ task = mach_task_self ();
+
+ /* create the "mach_exception_port" with send & receive rights */
+ g_assert (mach_port_allocate (task, MACH_PORT_RIGHT_RECEIVE,
+ &mach_exception_port) == KERN_SUCCESS);
+ g_assert (mach_port_insert_right (task, mach_exception_port, mach_exception_port,
+ MACH_MSG_TYPE_MAKE_SEND) == KERN_SUCCESS);
+
+ /* create the exception handler thread */
+ g_assert (!pthread_attr_init (&attr));
+ g_assert (!pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED));
+ g_assert (!pthread_create (&thread, &attr, mach_exception_thread, NULL));
+ pthread_attr_destroy (&attr);
+
+ /*
+ * register "mach_exception_port" as a receiver for the
+ * EXC_BAD_ACCESS exception
+ *
+ * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/task_set_exception_ports.html
+ */
+ g_assert (task_set_exception_ports (task, EXC_MASK_BAD_ACCESS,
+ mach_exception_port,
+ EXCEPTION_DEFAULT,
+ MACHINE_THREAD_STATE) == KERN_SUCCESS);
+}
+#endif
+
#ifndef PLATFORM_WIN32
static void
add_signal_handler (int signo, gpointer handler)
#endif
g_assert (sigaction (signo, &sa, NULL) != -1);
}
+
+static void
+remove_signal_handler (int signo)
+{
+ struct sigaction sa;
+
+ sa.sa_handler = SIG_DFL;
+ sigemptyset (&sa.sa_mask);
+ sa.sa_flags = 0;
+
+ g_assert (sigaction (signo, &sa, NULL) != -1);
+}
#endif
static void
#else /* !PLATFORM_WIN32 */
- /* libpthreads has its own implementation of sigaction(),
- * but it seems to work well with our current exception
- * handlers. If not we must call syscall directly instead
- * of sigaction */
+
+#ifdef PLATFORM_MACOSX
+ macosx_register_exception_handler ();
+#endif
if (debug_options.handle_sigint)
add_signal_handler (SIGINT, sigint_signal_handler);
#endif /* PLATFORM_WIN32 */
}
+static void
+mono_runtime_cleanup_handlers (void)
+{
+#ifdef PLATFORM_WIN32
+ win32_seh_cleanup();
+#else
+ if (debug_options.handle_sigint)
+ remove_signal_handler (SIGINT);
+
+ remove_signal_handler (SIGFPE);
+ remove_signal_handler (SIGQUIT);
+ remove_signal_handler (SIGILL);
+ remove_signal_handler (SIGBUS);
+ if (mono_jit_trace_calls != NULL)
+ remove_signal_handler (SIGUSR2);
+
+ remove_signal_handler (mono_thread_get_abort_signal ());
+
+ remove_signal_handler (SIGABRT);
+
+ remove_signal_handler (SIGSEGV);
+#endif /* PLATFORM_WIN32 */
+}
+
#ifdef HAVE_LINUX_RTC_H
#include <linux/rtc.h>
debug_options.keep_delegates = TRUE;
else if (!strcmp (arg, "collect-pagefault-stats"))
debug_options.collect_pagefault_stats = TRUE;
+ else if (!strcmp (arg, "break-on-unverified"))
+ debug_options.break_on_unverified = TRUE;
else {
fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
- fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'collect-pagefault-stats'\n");
+ fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'collect-pagefault-stats', 'break-on-unverified'\n");
exit (1);
}
}
{
MonoDomain *domain;
+#ifdef __linux__
+ if (access ("/proc/self/maps", F_OK) != 0) {
+ g_print ("Mono requires /proc to be mounted.\n");
+ exit (1);
+ }
+#endif
+
/* Happens when using the embedding interface */
if (!default_opt_set)
default_opt = mono_parse_default_optimizations (NULL);
* GC_register_stackbottom as well, but don't know how.
*/
#else
- GC_stackbottom = (char*)sstart + size;
+ /* apparently with some linuxthreads implementations sstart can be NULL,
+ * fallback to the more imprecise method (bug# 78096).
+ */
+ if (sstart) {
+ GC_stackbottom = (char*)sstart + size;
+ } else {
+ gsize stack_bottom = (gsize)&domain;
+ stack_bottom += 4095;
+ stack_bottom &= ~4095;
+ GC_stackbottom = (char*)stack_bottom;
+ }
#endif
}
#elif defined(HAVE_PTHREAD_GET_STACKSIZE_NP) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
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);
+ mono_install_get_class_from_name (mono_aot_get_class_from_name);
mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
if (debug_options.collect_pagefault_stats) {
#endif
#if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
- mono_register_opcode_emulation (CEE_DIV, "__emul_idiv", "int32 int32 int32", mono_idiv, TRUE);
- mono_register_opcode_emulation (CEE_DIV_UN, "__emul_idiv_un", "int32 int32 int32", mono_idiv_un, TRUE);
- mono_register_opcode_emulation (CEE_REM, "__emul_irem", "int32 int32 int32", mono_irem, TRUE);
- mono_register_opcode_emulation (CEE_REM_UN, "__emul_irem_un", "int32 int32 int32", mono_irem_un, TRUE);
+ mono_register_opcode_emulation (CEE_DIV, "__emul_idiv", "int32 int32 int32", mono_idiv, FALSE);
+ mono_register_opcode_emulation (CEE_DIV_UN, "__emul_idiv_un", "int32 int32 int32", mono_idiv_un, FALSE);
+ mono_register_opcode_emulation (CEE_REM, "__emul_irem", "int32 int32 int32", mono_irem, FALSE);
+ mono_register_opcode_emulation (CEE_REM_UN, "__emul_irem_un", "int32 int32 int32", mono_irem_un, FALSE);
#endif
#ifdef MONO_ARCH_EMULATE_MUL_DIV
- mono_register_opcode_emulation (CEE_MUL_OVF, "__emul_imul_ovf", "int32 int32 int32", mono_imul_ovf, TRUE);
- mono_register_opcode_emulation (CEE_MUL_OVF_UN, "__emul_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, TRUE);
+ mono_register_opcode_emulation (CEE_MUL_OVF, "__emul_imul_ovf", "int32 int32 int32", mono_imul_ovf, FALSE);
+ mono_register_opcode_emulation (CEE_MUL_OVF_UN, "__emul_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, FALSE);
mono_register_opcode_emulation (CEE_MUL, "__emul_imul", "int32 int32 int32", mono_imul, TRUE);
- mono_register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, TRUE);
+#endif
+#if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT)
+ mono_register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, FALSE);
#endif
mono_register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, FALSE);
mono_register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, FALSE);
#endif
+#ifdef MONO_ARCH_SOFT_FLOAT
+ mono_register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, FALSE);
+ mono_register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, FALSE);
+ mono_register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, FALSE);
+ mono_register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, FALSE);
+ mono_register_opcode_emulation (CEE_CONV_R8, "__emul_conv_r8", "double int32", mono_conv_to_r8, FALSE);
+ mono_register_opcode_emulation (CEE_CONV_R4, "__emul_conv_r4", "double int32", mono_conv_to_r4, FALSE);
+ mono_register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, FALSE);
+ mono_register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, FALSE);
+ mono_register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, FALSE);
+ mono_register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, FALSE);
+ mono_register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, FALSE);
+ mono_register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, FALSE);
+
+ mono_register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, FALSE);
+ mono_register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, FALSE);
+ mono_register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, FALSE);
+ mono_register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, FALSE);
+ mono_register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, FALSE);
+ mono_register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, FALSE);
+ mono_register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, FALSE);
+ mono_register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, FALSE);
+ mono_register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, FALSE);
+ mono_register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, FALSE);
+
+ mono_register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, FALSE);
+ mono_register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, FALSE);
+ mono_register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, FALSE);
+ mono_register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, FALSE);
+ mono_register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, FALSE);
+
+ register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
+ register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
+ register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
+#endif
+
#if SIZEOF_VOID_P == 4
mono_register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, TRUE);
#endif
register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
register_icall (mono_ldstr, "mono_ldstr", "object ptr ptr int32", FALSE);
- register_icall (mono_helper_stelem_ref, "helper_stelem_ref", "void ptr int32 object", FALSE);
register_icall (mono_helper_stelem_ref_check, "helper_stelem_ref_check", "void object object", FALSE);
register_icall (mono_object_new, "mono_object_new", "object ptr ptr", FALSE);
register_icall (mono_object_new_specific, "mono_object_new_specific", "object ptr", FALSE);
register_icall (mono_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_helper_compile_generic_method, "compile_generic_method", "ptr object ptr ptr", FALSE);
+ register_icall (mono_helper_compile_generic_method, "compile_generic_method", "ptr object ptr ptr ptr", FALSE);
register_icall (mono_helper_ldstr, "helper_ldstr", "object ptr int", FALSE);
register_icall (mono_helper_ldstr_mscorlib, "helper_ldstr_mscorlib", "object int", FALSE);
register_icall (mono_helper_newobj_mscorlib, "helper_newobj_mscorlib", "object int", FALSE);
g_print ("\nCreated object count: %ld\n", mono_stats.new_object_count);
g_print ("Initialized classes: %ld\n", mono_stats.initialized_class_count);
g_print ("Used classes: %ld\n", mono_stats.used_class_count);
+ g_print ("Generic vtables: %ld\n", mono_stats.generic_vtable_count);
+ g_print ("Methods: %ld\n", mono_stats.method_count);
g_print ("Static data size: %ld\n", mono_stats.class_static_data_size);
g_print ("VTable data size: %ld\n", mono_stats.class_vtable_size);
+ g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
g_print ("\nGeneric instances: %ld\n", mono_stats.generic_instance_count);
g_print ("Initialized classes: %ld\n", mono_stats.generic_class_count);
mono_icall_cleanup ();
-#ifdef PLATFORM_WIN32
- win32_seh_cleanup();
-#endif
+ mono_runtime_cleanup_handlers ();
mono_domain_free (domain, TRUE);
mono_trace_cleanup ();
mono_counters_dump (-1, stdout);
+
+ TlsFree(mono_jit_tls_id);
+
+ DeleteCriticalSection (&jit_mutex);
+
+ DeleteCriticalSection (&mono_delegate_section);
}
void