X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fmini-amd64.c;h=43d0e17babbd6c4d5fa6509eac2eb389aade1999;hb=3d47b20c62870f60d6944078b2a9cff7565c3205;hp=93ef14d2158894e72f0f032dab9bbd1d5617dd08;hpb=006de2be02dde32787cc3eba22b384c086d0bc13;p=mono.git diff --git a/mono/mini/mini-amd64.c b/mono/mini/mini-amd64.c index 93ef14d2158..43d0e17babb 100644 --- a/mono/mini/mini-amd64.c +++ b/mono/mini/mini-amd64.c @@ -37,6 +37,7 @@ #include #include #include +#include #include "trace.h" #include "ir-emit.h" @@ -1001,14 +1002,17 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) case MONO_TYPE_I1: case MONO_TYPE_U1: add_general (&gr, &stack_size, ainfo); + ainfo->byte_arg_size = 1; break; case MONO_TYPE_I2: case MONO_TYPE_U2: add_general (&gr, &stack_size, ainfo); + ainfo->byte_arg_size = 2; break; case MONO_TYPE_I4: case MONO_TYPE_U4: add_general (&gr, &stack_size, ainfo); + ainfo->byte_arg_size = 4; break; case MONO_TYPE_I: case MONO_TYPE_U: @@ -1165,7 +1169,6 @@ mono_arch_init (void) mono_aot_register_jit_icall ("mono_amd64_throw_corlib_exception", mono_amd64_throw_corlib_exception); mono_aot_register_jit_icall ("mono_amd64_resume_unwind", mono_amd64_resume_unwind); mono_aot_register_jit_icall ("mono_amd64_get_original_ip", mono_amd64_get_original_ip); - mono_aot_register_jit_icall ("mono_amd64_handler_block_trampoline_helper", mono_amd64_handler_block_trampoline_helper); #if defined(MONO_ARCH_GSHAREDVT_SUPPORTED) mono_aot_register_jit_icall ("mono_amd64_start_gsharedvt_call", mono_amd64_start_gsharedvt_call); @@ -1330,8 +1333,7 @@ mono_arch_compute_omit_fp (MonoCompile *cfg) cfg->arch.omit_fp = FALSE; if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG)) cfg->arch.omit_fp = FALSE; - if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) || - (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)) + if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))) cfg->arch.omit_fp = FALSE; for (i = 0; i < sig->param_count + sig->hasthis; ++i) { ArgInfo *ainfo = &cinfo->args [i]; @@ -1637,13 +1639,6 @@ mono_arch_allocate_vars (MonoCompile *cfg) /* Allocate locals */ offsets = mono_allocate_stack_slots (cfg, cfg->arch.omit_fp ? FALSE: TRUE, &locals_stack_size, &locals_stack_align); - if (locals_stack_size > MONO_ARCH_MAX_FRAME_SIZE) { - char *mname = mono_method_full_name (cfg->method, TRUE); - mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("Method %s stack is too big.", mname)); - g_free (mname); - return; - } - if (locals_stack_align) { offset += (locals_stack_align - 1); offset &= ~(locals_stack_align - 1); @@ -2379,6 +2374,7 @@ mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val) typedef struct { MonoMethodSignature *sig; CallInfo *cinfo; + int nstack_args; } ArchDynCallInfo; static gboolean @@ -2405,10 +2401,7 @@ dyn_call_supported (MonoMethodSignature *sig, CallInfo *cinfo) case ArgInFloatSSEReg: case ArgInDoubleSSEReg: case ArgValuetypeInReg: - break; case ArgOnStack: - if (!(ainfo->offset + (ainfo->arg_size / 8) <= DYN_CALL_STACK_ARGS)) - return FALSE; break; default: return FALSE; @@ -2431,6 +2424,7 @@ mono_arch_dyn_call_prepare (MonoMethodSignature *sig) { ArchDynCallInfo *info; CallInfo *cinfo; + int i; cinfo = get_call_info (NULL, sig); @@ -2443,6 +2437,21 @@ mono_arch_dyn_call_prepare (MonoMethodSignature *sig) // FIXME: Preprocess the info to speed up get_dyn_call_args (). info->sig = sig; info->cinfo = cinfo; + info->nstack_args = 0; + + for (i = 0; i < cinfo->nargs; ++i) { + ArgInfo *ainfo = &cinfo->args [i]; + switch (ainfo->storage) { + case ArgOnStack: + info->nstack_args = MAX (info->nstack_args, ainfo->offset + (ainfo->arg_size / 8)); + break; + default: + break; + } + } + /* Align to 16 bytes */ + if (info->nstack_args & 1) + info->nstack_args ++; return (MonoDynCallInfo*)info; } @@ -2461,6 +2470,15 @@ mono_arch_dyn_call_free (MonoDynCallInfo *info) g_free (ainfo); } +int +mono_arch_dyn_call_get_buf_size (MonoDynCallInfo *info) +{ + ArchDynCallInfo *ainfo = (ArchDynCallInfo*)info; + + /* Extend the 'regs' field dynamically */ + return sizeof (DynCallArgs) + (ainfo->nstack_args * sizeof (mgreg_t)); +} + #define PTR_TO_GREG(ptr) (mgreg_t)(ptr) #define GREG_TO_PTR(greg) (gpointer)(greg) @@ -2479,7 +2497,7 @@ mono_arch_dyn_call_free (MonoDynCallInfo *info) * libffi. */ void -mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, guint8 *buf, int buf_len) +mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, guint8 *buf) { ArchDynCallInfo *dinfo = (ArchDynCallInfo*)info; DynCallArgs *p = (DynCallArgs*)buf; @@ -2496,10 +2514,9 @@ mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, g param_reg_to_index_inited = 1; } - g_assert (buf_len >= sizeof (DynCallArgs)); - p->res = 0; p->ret = ret; + p->nstack_args = dinfo->nstack_args; arg_index = 0; greg = 0; @@ -2875,6 +2892,11 @@ emit_call_body (MonoCompile *cfg, guint8 *code, MonoJumpInfoType patch_type, gco amd64_call_code (code, 0); } else { + if (!no_patch && ((guint32)(code + 2 - cfg->native_code) % 8) != 0) { + guint32 pad_size = 8 - ((guint32)(code + 2 - cfg->native_code) % 8); + amd64_padding (code, pad_size); + g_assert ((guint64)(code + 2 - cfg->native_code) % 8 == 0); + } mono_add_patch_info (cfg, code - cfg->native_code, patch_type, data); amd64_set_reg_template (code, GP_SCRATCH_REG); amd64_call_reg (code, GP_SCRATCH_REG); @@ -3233,7 +3255,7 @@ mono_emit_stack_alloc (MonoCompile *cfg, guchar *code, MonoInst* tree) #if defined(TARGET_WIN32) need_touch = TRUE; #elif defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK) - if (!tree->flags & MONO_INST_INIT) + if (!(tree->flags & MONO_INST_INIT)) need_touch = TRUE; #endif @@ -3636,16 +3658,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) if (cfg->verbose_level > 2) g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset); - if ((cfg->prof_options & MONO_PROFILE_COVERAGE) && cfg->coverage_info) { - MonoProfileCoverageInfo *cov = cfg->coverage_info; - g_assert (!cfg->compile_aot); - - cov->data [bb->dfn].cil_code = bb->cil_code; - amd64_mov_reg_imm (code, AMD64_R11, (guint64)&cov->data [bb->dfn].count); - /* this is not thread save, but good enough */ - amd64_inc_membase (code, AMD64_R11, 0); - } - offset = code - cfg->native_code; mono_debug_open_block (cfg, bb, offset); @@ -3660,7 +3672,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) #define EXTRA_CODE_SPACE (16) - if (G_UNLIKELY (offset > (cfg->code_size - max_len - EXTRA_CODE_SPACE))) { + if (G_UNLIKELY ((offset + max_len + EXTRA_CODE_SPACE) > cfg->code_size)) { cfg->code_size *= 2; cfg->native_code = (unsigned char *)mono_realloc_native_code(cfg); code = cfg->native_code + offset; @@ -4497,6 +4509,17 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) g_assert (!cfg->method->save_lmf); + /* the size of the tailcall op depends on signature, let's check for enough + * space in the code buffer here again */ + max_len += AMD64_NREG * 4 + call->stack_usage * 15 + EXTRA_CODE_SPACE; + + if (G_UNLIKELY (offset + max_len > cfg->code_size)) { + cfg->code_size *= 2; + cfg->native_code = (unsigned char *) mono_realloc_native_code(cfg); + code = cfg->native_code + offset; + cfg->stat_code_reallocs++; + } + /* Restore callee saved registers */ save_area_offset = cfg->arch.reg_save_area_offset; for (i = 0; i < AMD64_NREG; ++i) @@ -4527,7 +4550,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) #endif } - offset = code - cfg->native_code; mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, call->method); if (cfg->compile_aot) amd64_mov_reg_membase (code, AMD64_R11, AMD64_RIP, 0, 8); @@ -4649,9 +4671,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) code = emit_move_return_value (cfg, ins, code); break; case OP_DYN_CALL: { - int i; + int i, limit_reg, index_reg, src_reg, dst_reg; MonoInst *var = cfg->dyn_call_var; guint8 *label; + guint8 *buf [16]; g_assert (var->opcode == OP_REGOFFSET); @@ -4672,15 +4695,38 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) amd64_sse_movsd_reg_membase (code, i, AMD64_R11, MONO_STRUCT_OFFSET (DynCallArgs, fregs) + (i * sizeof (double))); amd64_patch (label, code); + /* Allocate param area */ + /* This doesn't need to be freed since OP_DYN_CALL is never called in a loop */ + amd64_mov_reg_membase (code, AMD64_RAX, AMD64_R11, MONO_STRUCT_OFFSET (DynCallArgs, nstack_args), 8); + amd64_shift_reg_imm (code, X86_SHL, AMD64_RAX, 3); + amd64_alu_reg_reg (code, X86_SUB, AMD64_RSP, AMD64_RAX); /* Set stack args */ - for (i = 0; i < DYN_CALL_STACK_ARGS; ++i) { - amd64_mov_reg_membase (code, AMD64_RAX, AMD64_R11, MONO_STRUCT_OFFSET (DynCallArgs, regs) + ((PARAM_REGS + i) * sizeof(mgreg_t)), sizeof(mgreg_t)); - amd64_mov_membase_reg (code, AMD64_RSP, i * sizeof (mgreg_t), AMD64_RAX, sizeof (mgreg_t)); - } + /* rax/rcx/rdx/r8/r9 is scratch */ + limit_reg = AMD64_RAX; + index_reg = AMD64_RCX; + src_reg = AMD64_R8; + dst_reg = AMD64_R9; + amd64_mov_reg_membase (code, limit_reg, AMD64_R11, MONO_STRUCT_OFFSET (DynCallArgs, nstack_args), 8); + amd64_mov_reg_imm (code, index_reg, 0); + amd64_lea_membase (code, src_reg, AMD64_R11, MONO_STRUCT_OFFSET (DynCallArgs, regs) + ((PARAM_REGS) * sizeof(mgreg_t))); + amd64_mov_reg_reg (code, dst_reg, AMD64_RSP, 8); + buf [0] = code; + x86_jump8 (code, 0); + buf [1] = code; + amd64_mov_reg_membase (code, AMD64_RDX, src_reg, 0, 8); + amd64_mov_membase_reg (code, dst_reg, 0, AMD64_RDX, 8); + amd64_alu_reg_imm (code, X86_ADD, index_reg, 1); + amd64_alu_reg_imm (code, X86_ADD, src_reg, 8); + amd64_alu_reg_imm (code, X86_ADD, dst_reg, 8); + amd64_patch (buf [0], code); + amd64_alu_reg_reg (code, X86_CMP, index_reg, limit_reg); + buf [2] = code; + x86_branch8 (code, X86_CC_LT, 0, FALSE); + amd64_patch (buf [2], buf [1]); /* Set argument registers */ for (i = 0; i < PARAM_REGS; ++i) - amd64_mov_reg_membase (code, param_regs [i], AMD64_R11, i * sizeof(mgreg_t), sizeof(mgreg_t)); + amd64_mov_reg_membase (code, param_regs [i], AMD64_R11, MONO_STRUCT_OFFSET (DynCallArgs, regs) + (i * sizeof(mgreg_t)), sizeof(mgreg_t)); /* Make the call */ amd64_call_reg (code, AMD64_R10); @@ -4833,7 +4879,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) amd64_mov_membase_reg (code, spvar->inst_basereg, spvar->inst_offset, AMD64_RSP, sizeof(gpointer)); if ((MONO_BBLOCK_IS_IN_REGION (bb, MONO_REGION_FINALLY) || - MONO_BBLOCK_IS_IN_REGION (bb, MONO_REGION_FINALLY)) && + MONO_BBLOCK_IS_IN_REGION (bb, MONO_REGION_FILTER)) && cfg->param_area) { amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, ALIGN_TO (cfg->param_area, MONO_ARCH_FRAME_ALIGNMENT)); } @@ -6435,6 +6481,11 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_GET_LAST_ERROR: emit_get_last_error(code, ins->dreg); break; + case OP_FILL_PROF_CALL_CTX: + for (int i = 0; i < AMD64_NREG; i++) + if (AMD64_IS_CALLEE_SAVED_REG (i) || i == AMD64_RSP) + amd64_mov_membase_reg (code, ins->sreg1, MONO_STRUCT_OFFSET (MonoContext, gregs) + i * sizeof (mgreg_t), i, sizeof (mgreg_t)); + break; default: g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__); g_assert_not_reached (); @@ -6513,9 +6564,6 @@ get_max_epilog_size (MonoCompile *cfg) if (mono_jit_trace_calls != NULL) max_epilog_size += 50; - if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) - max_epilog_size += 50; - max_epilog_size += (AMD64_NREG * 2); return max_epilog_size; @@ -6676,7 +6724,26 @@ mono_arch_emit_prolog (MonoCompile *cfg) /* See mono_emit_stack_alloc */ #if defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK) guint32 remaining_size = alloc_size; - /*FIXME handle unbounded code expansion, we should use a loop in case of more than X interactions*/ + + /* Use a loop for large sizes */ + if (remaining_size > 10 * 0x1000) { + amd64_mov_reg_imm (code, X86_EAX, remaining_size / 0x1000); + guint8 *label = code; + amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, 0x1000); + amd64_test_membase_reg (code, AMD64_RSP, 0, AMD64_RSP); + amd64_alu_reg_imm (code, X86_SUB, AMD64_RAX, 1); + amd64_alu_reg_imm (code, X86_CMP, AMD64_RAX, 0); + guint8 *label2 = code; + x86_branch8 (code, X86_CC_NE, 0, FALSE); + amd64_patch (label2, label); + if (cfg->arch.omit_fp) { + cfa_offset += (remaining_size / 0x1000) * 0x1000; + mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset); + } + + remaining_size = remaining_size % 0x1000; + } + guint32 required_code_size = ((remaining_size / 0x1000) + 1) * 11; /*11 is the max size of amd64_alu_reg_imm + amd64_test_membase_reg*/ guint32 offset = code - cfg->native_code; if (G_UNLIKELY (required_code_size >= (cfg->code_size - offset))) { @@ -6802,8 +6869,6 @@ mono_arch_emit_prolog (MonoCompile *cfg) MonoInst *ins; int max_length = 0; - if (cfg->prof_options & MONO_PROFILE_COVERAGE) - max_length += 6; /* max alignment for loops */ if ((cfg->opt & MONO_OPT_LOOP) && bb_is_loop_start (bb)) max_length += LOOP_ALIGNMENT; @@ -6936,9 +7001,6 @@ mono_arch_emit_prolog (MonoCompile *cfg) code = (guint8 *)mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE); } - if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) - args_clobbered = TRUE; - /* * Optimize the common case of the first bblock making a call with the same * arguments as the method. This works because the arguments are still in their @@ -7103,9 +7165,14 @@ mono_arch_emit_epilog (MonoCompile *cfg) } else { /* FIXME: maybe save the jit tls in the prolog */ } - if (cfg->used_int_regs & (1 << AMD64_RBP)) { + if (cfg->used_int_regs & (1 << AMD64_RBP)) amd64_mov_reg_membase (code, AMD64_RBP, cfg->frame_reg, lmf_offset + MONO_STRUCT_OFFSET (MonoLMF, rbp), 8); - } + if (cfg->arch.omit_fp) + /* + * emit_setup_lmf () marks RBP as saved, we have to mark it as same value here before clearing up the stack + * since its stack slot will become invalid. + */ + mono_emit_unwind_op_same_value (cfg, code, AMD64_RBP); } /* Restore callee saved regs */ @@ -7113,9 +7180,9 @@ mono_arch_emit_epilog (MonoCompile *cfg) if (AMD64_IS_CALLEE_SAVED_REG (i) && (cfg->arch.saved_iregs & (1 << i))) { /* Restore only used_int_regs, not arch.saved_iregs */ #if defined(MONO_SUPPORT_TASKLETS) - int restore_reg=1; + int restore_reg = 1; #else - int restore_reg=(cfg->used_int_regs & (1 << i)); + int restore_reg = (cfg->used_int_regs & (1 << i)); #endif if (restore_reg) { amd64_mov_reg_membase (code, i, cfg->frame_reg, save_area_offset, 8); @@ -7676,7 +7743,7 @@ get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, guint32 par if (!has_target) g_free (buff); } - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL)); return start; } @@ -7710,7 +7777,7 @@ get_delegate_virtual_invoke_impl (MonoTrampInfo **info, gboolean load_imt_reg, i /* Load the vtable */ amd64_mov_reg_membase (code, AMD64_RAX, AMD64_ARG_REG1, MONO_STRUCT_OFFSET (MonoObject, vtable), 8); amd64_jump_membase (code, AMD64_RAX, offset); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL)); tramp_name = mono_get_delegate_virtual_invoke_impl_name (load_imt_reg, offset); *info = mono_tramp_info_create (tramp_name, start, code - start, NULL, unwind_ops); @@ -8006,11 +8073,11 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTC } if (!fail_tramp) - mono_stats.imt_trampolines_size += code - start; + UnlockedAdd (&mono_stats.imt_trampolines_size, code - start); g_assert (code - start <= size); g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_TRAMPOLINE_UNWINDINFO_SIZE(0))); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE, NULL)); mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), domain); @@ -8113,12 +8180,6 @@ mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMetho } #endif -gboolean -mono_arch_print_tree (MonoInst *tree, int arity) -{ - return 0; -} - mgreg_t mono_arch_context_get_int_reg (MonoContext *ctx, int reg) { @@ -8131,25 +8192,6 @@ mono_arch_context_set_int_reg (MonoContext *ctx, int reg, mgreg_t val) ctx->gregs [reg] = val; } -gpointer -mono_arch_install_handler_block_guard (MonoJitInfo *ji, MonoJitExceptionInfo *clause, MonoContext *ctx, gpointer new_value) -{ - gpointer *sp, old_value; - char *bp; - - /*Load the spvar*/ - bp = (char *)MONO_CONTEXT_GET_BP (ctx); - sp = (gpointer *)*(gpointer*)(bp + clause->exvar_offset); - - old_value = *sp; - if (old_value < ji->code_start || (char*)old_value > ((char*)ji->code_start + ji->code_size)) - return old_value; - - *sp = new_value; - - return old_value; -} - /* * mono_arch_emit_load_aotconst: *