X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fmini-amd64.c;h=43d0e17babbd6c4d5fa6509eac2eb389aade1999;hb=919a03d17d36604f05e1d99c3f9f26a1509e9655;hp=949f8946ddd1c73cf2a3d56a303448eff7115656;hpb=098f6e8aa8ead1a80b751fa34e5e049439c2f0c3;p=mono.git diff --git a/mono/mini/mini-amd64.c b/mono/mini/mini-amd64.c index 949f8946ddd..43d0e17babb 100644 --- a/mono/mini/mini-amd64.c +++ b/mono/mini/mini-amd64.c @@ -2374,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 @@ -2400,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; @@ -2426,6 +2424,7 @@ mono_arch_dyn_call_prepare (MonoMethodSignature *sig) { ArchDynCallInfo *info; CallInfo *cinfo; + int i; cinfo = get_call_info (NULL, sig); @@ -2438,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; } @@ -2456,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) @@ -2474,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; @@ -2491,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; @@ -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);