X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fmini.c;h=716feaa2acd486330ba028823f8b40b4e847f7d0;hb=49065425ce3128e78cc6191c940320af20b584dc;hp=1497fae204de020ad92349f1cd76c1ef94074008;hpb=496dfbf9ec0fd3143e5dd560a863d916e56a52b8;p=mono.git diff --git a/mono/mini/mini.c b/mono/mini/mini.c index 1497fae204d..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) { @@ -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 */ @@ -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; @@ -2636,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) { @@ -2949,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 } /* @@ -3079,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 @@ -3395,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 @@ -4099,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; @@ -4110,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; @@ -4126,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); @@ -4139,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; @@ -4174,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; @@ -4197,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); @@ -4544,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) { @@ -4852,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; @@ -4913,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; @@ -4978,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: @@ -4988,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 */ @@ -5138,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; @@ -5189,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; @@ -5457,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; @@ -5514,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 */ @@ -5616,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); @@ -5654,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; @@ -5804,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; @@ -5884,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; } } @@ -6092,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); @@ -6119,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; @@ -6191,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; @@ -6235,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 @@ -6267,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; @@ -6304,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; @@ -6333,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; @@ -6357,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 (); @@ -6453,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; @@ -6472,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; @@ -6904,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 @@ -6989,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; @@ -7027,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; @@ -7052,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); @@ -7140,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); @@ -7165,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: @@ -7247,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); } @@ -7330,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); @@ -8122,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; @@ -8254,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 @@ -8264,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) { @@ -8337,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); @@ -9433,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 @@ -10218,17 +10546,15 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in #ifdef MONO_USE_AOT_COMPILER if ((opt & MONO_OPT_AOT) && !(mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)) { - MonoJitInfo *info; 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); @@ -10288,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 (); } } @@ -10556,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 @@ -10749,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) @@ -10797,6 +11257,11 @@ mono_runtime_install_handlers (void) #else /* !PLATFORM_WIN32 */ + +#ifdef PLATFORM_MACOSX + macosx_register_exception_handler (); +#endif + if (debug_options.handle_sigint) add_signal_handler (SIGINT, sigint_signal_handler); @@ -11182,6 +11647,8 @@ mini_init (const char *filename) 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); +#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 @@ -11209,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