X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fmini.c;h=716feaa2acd486330ba028823f8b40b4e847f7d0;hb=49065425ce3128e78cc6191c940320af20b584dc;hp=0d6349ccc188596143960df456442dde585146cf;hpb=c44342c05dbbb79fbee3b0b3dda1d6d15cebfa54;p=mono.git diff --git a/mono/mini/mini.c b/mono/mini/mini.c index 0d6349ccc18..716feaa2acd 100644 --- a/mono/mini/mini.c +++ b/mono/mini/mini.c @@ -14,6 +14,14 @@ #include #include +#ifdef PLATFORM_MACOSX +#include +#include +#include +#include +#include +#endif + #ifdef HAVE_VALGRIND_MEMCHECK_H #include #endif @@ -220,13 +228,35 @@ get_method_from_ip (void *ip) 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) { @@ -330,7 +360,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token) } 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: @@ -1075,6 +1105,27 @@ reverse_branch_op (guint32 opcode) 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. @@ -1243,7 +1294,7 @@ ovf3ops_op_map [STACK_MAX] = { /* 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 }; /* @@ -1289,11 +1340,15 @@ type_from_op (MonoInst *ins) { 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 */ @@ -1562,7 +1617,7 @@ mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode) 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; @@ -2343,7 +2398,7 @@ mono_spill_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoCallInst *call, M 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) @@ -2381,13 +2436,31 @@ mono_emit_call_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignatu 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; @@ -2577,7 +2650,14 @@ mono_get_element_address_signature (int arity) 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; @@ -2613,6 +2693,10 @@ mono_get_array_new_va_signature (int arity) 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; @@ -2625,6 +2709,56 @@ mono_get_array_new_va_signature (int arity) 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) { @@ -2679,7 +2813,7 @@ handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst 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; } @@ -2736,7 +2870,7 @@ handle_initobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, const 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; } @@ -2846,19 +2980,20 @@ handle_array_new (MonoCompile *cfg, MonoBasicBlock *bblock, int rank, MonoInst * /* 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); } @@ -2902,8 +3037,6 @@ mini_class_is_system_array (MonoClass *klass) { 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; } @@ -2939,6 +3072,11 @@ mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method) 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 } /* @@ -3032,7 +3170,7 @@ mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmet } 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; @@ -3042,7 +3180,7 @@ mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmet 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 } @@ -3050,17 +3188,18 @@ mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmet /* 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; @@ -3068,11 +3207,12 @@ mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmet 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 @@ -3384,6 +3524,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, #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 @@ -3720,6 +3861,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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 unsafety issues in marshal wrappers... (unknown is PtrToStructure) */ dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; @@ -3908,7 +4050,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b } } - 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; @@ -4087,6 +4229,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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; @@ -4098,6 +4241,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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; @@ -4114,6 +4258,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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); @@ -4127,6 +4272,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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; @@ -4162,6 +4308,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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; @@ -4185,6 +4332,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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); @@ -4395,7 +4543,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b if (!cmethod) goto load_error; - if (!dont_verify && !can_access_method (method, cil_method)) + if (!dont_verify && !cfg->skip_visibility && !can_access_method (method, cil_method)) UNVERIFIED; if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT)) @@ -4488,8 +4636,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b !((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 */ @@ -4502,13 +4650,18 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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); @@ -4527,14 +4680,25 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b /* 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) { @@ -4835,7 +4999,22 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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; @@ -4896,7 +5075,22 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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; @@ -4961,6 +5155,15 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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: @@ -4971,6 +5174,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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 */ @@ -5121,8 +5332,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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; @@ -5147,7 +5357,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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 (); @@ -5172,8 +5382,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b --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; @@ -5229,7 +5438,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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 (); @@ -5440,8 +5649,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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; @@ -5497,8 +5705,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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 */ @@ -5576,7 +5783,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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 (); @@ -5599,8 +5806,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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); @@ -5637,8 +5843,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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; @@ -5732,7 +5937,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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; @@ -5787,6 +5992,17 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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; @@ -5867,6 +6083,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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; } } @@ -6075,8 +6299,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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); @@ -6102,8 +6325,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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; @@ -6174,8 +6396,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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; @@ -6218,8 +6439,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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 @@ -6250,8 +6470,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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; @@ -6287,6 +6506,16 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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; @@ -6316,6 +6545,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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; @@ -6340,8 +6576,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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 (); @@ -6436,8 +6671,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b --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; @@ -6455,8 +6689,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b --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; @@ -6887,13 +7120,21 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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 @@ -6972,6 +7213,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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; @@ -7010,6 +7252,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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; @@ -7035,6 +7278,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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); @@ -7123,8 +7367,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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); @@ -7148,8 +7391,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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: @@ -7163,7 +7405,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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; @@ -7230,8 +7472,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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); } @@ -7313,11 +7554,15 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b 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); @@ -7550,6 +7795,8 @@ mono_icall_get_wrapper (MonoJitICallInfo* callinfo) { char *name; MonoMethod *wrapper; + gconstpointer trampoline; + MonoDomain *domain = mono_get_root_domain (); if (callinfo->wrapper) { return callinfo->wrapper; @@ -7558,13 +7805,28 @@ mono_icall_get_wrapper (MonoJitICallInfo* callinfo) 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; } @@ -7829,7 +8091,7 @@ typedef struct { } 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. @@ -7875,9 +8137,9 @@ mono_allocate_stack_slots_full (MonoCompile *m, gboolean backward, guint32 *stac 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; @@ -7887,28 +8149,32 @@ mono_allocate_stack_slots_full (MonoCompile *m, gboolean backward, guint32 *stac } 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; @@ -8084,6 +8350,58 @@ decompose_foreach (MonoInst *tree, gpointer data) 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; @@ -8216,6 +8534,13 @@ mono_destroy_compile (MonoCompile *cfg) #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 @@ -8226,12 +8551,40 @@ mono_get_jit_tls_key (void) 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) { @@ -8299,10 +8652,18 @@ setup_jit_tls_data (gpointer stack_start, gpointer abort_func) 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); @@ -8421,6 +8782,56 @@ mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info) 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) { @@ -9327,7 +9738,6 @@ emit_state (MonoCompile *cfg, MBState *state, int goal) 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) { @@ -9346,7 +9756,12 @@ emit_state (MonoCompile *cfg, MBState *state, int 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 @@ -9379,8 +9794,7 @@ emit_state (MonoCompile *cfg, MBState *state, int goal) } // 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 @@ -9803,6 +10217,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool 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); @@ -9834,7 +10249,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool 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 @@ -10130,18 +10545,16 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in 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); @@ -10201,11 +10614,16 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in /* 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 (); } } @@ -10469,25 +10887,33 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec 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 (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 @@ -10662,6 +11088,127 @@ SIG_HANDLER_SIGNATURE (sigusr2_signal_handler) 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) @@ -10679,6 +11226,18 @@ 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 @@ -10698,10 +11257,10 @@ mono_runtime_install_handlers (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); @@ -10730,6 +11289,30 @@ mono_runtime_install_handlers (void) #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 @@ -10857,9 +11440,11 @@ mini_parse_debug_options (void) 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); } } @@ -10870,6 +11455,13 @@ mini_init (const char *filename) { 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); @@ -10915,7 +11507,17 @@ mini_init (const char *filename) * 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) @@ -10959,6 +11561,7 @@ mini_init (const char *filename) 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) { @@ -11034,17 +11637,19 @@ mini_init (const char *filename) #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); @@ -11071,6 +11676,42 @@ mini_init (const char *filename) 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 @@ -11082,7 +11723,6 @@ mini_init (const char *filename) 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); @@ -11092,7 +11732,7 @@ mini_init (const char *filename) 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); @@ -11138,8 +11778,11 @@ print_jit_stats (void) 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); @@ -11190,9 +11833,7 @@ mini_cleanup (MonoDomain *domain) mono_icall_cleanup (); -#ifdef PLATFORM_WIN32 - win32_seh_cleanup(); -#endif + mono_runtime_cleanup_handlers (); mono_domain_free (domain, TRUE);