X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Fjit%2Fx86_64%2Femit.c;h=7a4c65a39d20537e2ec1d99604208695a9634156;hb=d1377204f560df4d6656f58914bc4d242193c5e0;hp=d59278a0145440a8173861094ae9f1b21efe9f7d;hpb=77aec8e4b43ed054693fa21b13ea25524a63a349;p=cacao.git diff --git a/src/vm/jit/x86_64/emit.c b/src/vm/jit/x86_64/emit.c index d59278a01..7a4c65a39 100644 --- a/src/vm/jit/x86_64/emit.c +++ b/src/vm/jit/x86_64/emit.c @@ -1,9 +1,7 @@ /* src/vm/jit/x86_64/emit.c - x86_64 code emitter functions - Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien + Copyright (C) 1996-2005, 2006, 2007, 2008, 2009 + CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO This file is part of CACAO. @@ -22,8 +20,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - $Id: emit.c 7723 2007-04-16 18:03:08Z michi $ - */ #include "config.h" @@ -31,30 +27,29 @@ #include #include "vm/types.h" +#include "vm/os.hpp" #include "md-abi.h" #include "vm/jit/x86_64/codegen.h" #include "vm/jit/x86_64/emit.h" -#include "mm/memory.h" +#include "mm/memory.hpp" -#if defined(ENABLE_THREADS) -# include "threads/native/lock.h" -#endif +#include "threads/lock.hpp" -#include "vm/builtin.h" -#include "vm/exceptions.h" +#include "vm/options.h" #include "vm/jit/abi.h" #include "vm/jit/abi-asm.h" #include "vm/jit/asmpart.h" -#include "vm/jit/codegen-common.h" -#include "vm/jit/emit-common.h" -#include "vm/jit/jit.h" -#include "vm/jit/replace.h" - -#include "vmcore/options.h" +#include "vm/jit/codegen-common.hpp" +#include "vm/jit/emit-common.hpp" +#include "vm/jit/jit.hpp" +#include "vm/jit/patcher-common.hpp" +#include "vm/jit/replace.hpp" +#include "vm/jit/trace.hpp" +#include "vm/jit/trap.hpp" /* emit_load ******************************************************************* @@ -76,7 +71,7 @@ s4 emit_load(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg) if (IS_INMEMORY(src->flags)) { COUNT_SPILLS; - disp = src->vv.regoff * 8; + disp = src->vv.regoff; switch (src->type) { case TYPE_INT: @@ -114,46 +109,19 @@ s4 emit_load(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg) *******************************************************************************/ -inline void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d) +void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d) { codegendata *cd; s4 disp; -#if 0 - s4 s; - u2 opcode; -#endif /* get required compiler data */ cd = jd->cd; -#if 0 - /* do we have to generate a conditional move? */ - - if ((iptr != NULL) && (iptr->opc & ICMD_CONDITION_MASK)) { - /* the passed register d is actually the source register */ - - s = d; - - /* Only pass the opcode to codegen_reg_of_var to get the real - destination register. */ - - opcode = iptr->opc & ICMD_OPCODE_MASK; - - /* get the real destination register */ - - d = codegen_reg_of_var(rd, opcode, dst, REG_ITMP1); - - /* and emit the conditional move */ - - emit_cmovxx(cd, iptr, s, d); - } -#endif - if (IS_INMEMORY(dst->flags)) { COUNT_SPILLS; - disp = dst->vv.regoff * 8; + disp = dst->vv.regoff; switch (dst->type) { case TYPE_INT: @@ -180,29 +148,41 @@ inline void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d) *******************************************************************************/ -void emit_copy(jitdata *jd, instruction *iptr, varinfo *src, varinfo *dst) +void emit_copy(jitdata *jd, instruction *iptr) { - codegendata *cd; - s4 s1, d; + codegendata *cd; + varinfo *src; + varinfo *dst; + s4 s1, d; /* get required compiler data */ cd = jd->cd; + /* get source and destination variables */ + + src = VAROP(iptr->s1); + dst = VAROP(iptr->dst); + if ((src->vv.regoff != dst->vv.regoff) || ((src->flags ^ dst->flags) & INMEMORY)) { + if ((src->type == TYPE_RET) || (dst->type == TYPE_RET)) { + /* emit nothing, as the value won't be used anyway */ + return; + } + /* If one of the variables resides in memory, we can eliminate the register move from/to the temporary register with the order of getting the destination register and the load. */ if (IS_INMEMORY(src->flags)) { - d = codegen_reg_of_var(iptr->opc, dst, REG_IFTMP); + d = codegen_reg_of_var(iptr->opc, dst, REG_IFTMP); s1 = emit_load(jd, iptr, src, d); } else { s1 = emit_load(jd, iptr, src, REG_IFTMP); - d = codegen_reg_of_var(iptr->opc, dst, s1); + d = codegen_reg_of_var(iptr->opc, dst, s1); } if (s1 != d) { @@ -253,6 +233,16 @@ void emit_cmovxx(codegendata *cd, instruction *iptr, s4 s, s4 d) } +/** + * Emits code updating the condition register by comparing one integer + * register to an immediate integer value. + */ +void emit_icmp_imm(codegendata* cd, int reg, int32_t value) +{ + M_ICMP_IMM(value, reg); +} + + /* emit_branch ***************************************************************** Emits the code for conditional and unconditional branchs. @@ -329,7 +319,7 @@ void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg) if (INSTRUCTION_MUST_CHECK(iptr)) { M_TEST(reg); M_BNE(8); - M_ALD_MEM(reg, EXCEPTION_HARDWARE_ARITHMETIC); + M_ALD_MEM(reg, TRAP_ArithmeticException); } } @@ -343,10 +333,26 @@ void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg) void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, s4 s2) { if (INSTRUCTION_MUST_CHECK(iptr)) { - M_ILD(REG_ITMP3, s1, OFFSET(java_arrayheader, size)); + M_ILD(REG_ITMP3, s1, OFFSET(java_array_t, size)); M_ICMP(REG_ITMP3, s2); M_BULT(8); - M_ALD_MEM(s2, EXCEPTION_HARDWARE_ARRAYINDEXOUTOFBOUNDS); + M_ALD_MEM(s2, TRAP_ArrayIndexOutOfBoundsException); + } +} + + +/* emit_arraystore_check ******************************************************* + + Emit an ArrayStoreException check. + +*******************************************************************************/ + +void emit_arraystore_check(codegendata *cd, instruction *iptr) +{ + if (INSTRUCTION_MUST_CHECK(iptr)) { + M_TEST(REG_RESULT); + M_BNE(8); + M_ALD_MEM(REG_RESULT, TRAP_ArrayStoreException); } } @@ -364,16 +370,22 @@ void emit_classcast_check(codegendata *cd, instruction *iptr, s4 condition, s4 r case BRANCH_LE: M_BGT(8); break; + case BRANCH_GE: + M_BLT(8); + break; case BRANCH_EQ: M_BNE(8); break; + case BRANCH_NE: + M_BEQ(8); + break; case BRANCH_UGT: M_BULE(8); break; default: vm_abort("emit_classcast_check: unknown condition %d", condition); } - M_ALD_MEM(s1, EXCEPTION_HARDWARE_CLASSCAST); + M_ALD_MEM(s1, TRAP_ClassCastException); } } @@ -389,7 +401,7 @@ void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg) if (INSTRUCTION_MUST_CHECK(iptr)) { M_TEST(reg); M_BNE(8); - M_ALD_MEM(reg, EXCEPTION_HARDWARE_NULLPOINTER); + M_ALD_MEM(reg, TRAP_NullPointerException); } } @@ -405,157 +417,259 @@ void emit_exception_check(codegendata *cd, instruction *iptr) if (INSTRUCTION_MUST_CHECK(iptr)) { M_TEST(REG_RESULT); M_BNE(8); - M_ALD_MEM(REG_RESULT, EXCEPTION_HARDWARE_EXCEPTION); + M_ALD_MEM(REG_RESULT, TRAP_CHECK_EXCEPTION); } } -/* emit_patcher_stubs ********************************************************** +/* emit_trap_compiler ********************************************************** - Generates the code for the patcher stubs. + Emit a trap instruction which calls the JIT compiler. *******************************************************************************/ -void emit_patcher_stubs(jitdata *jd) +void emit_trap_compiler(codegendata *cd) { - codegendata *cd; - patchref *pref; - u8 mcode; - u1 *savedmcodeptr; - u1 *tmpmcodeptr; - s4 targetdisp; - s4 disp; + M_ALD_MEM(REG_METHODPTR, TRAP_COMPILER); +} - /* get required compiler data */ - cd = jd->cd; +/* emit_patcher_alignment ****************************************************** + + Emit NOP to ensure placement at an even address. + +*******************************************************************************/ - /* generate code patching stub call code */ +void emit_patcher_alignment(codegendata *cd) +{ + if ((uintptr_t) cd->mcodeptr & 1) + M_NOP; +} - targetdisp = 0; - for (pref = cd->patchrefs; pref != NULL; pref = pref->next) { - /* check size of code segment */ +/* emit_trap ******************************************************************* - MCODECHECK(512); + Emit a trap instruction and return the original machine code. - /* Get machine code which is patched back in later. A - `call rel32' is 5 bytes long (but read 8 bytes). */ +*******************************************************************************/ - savedmcodeptr = cd->mcodebase + pref->branchpos; - mcode = *((u8 *) savedmcodeptr); +uint32_t emit_trap(codegendata *cd) +{ + uint16_t mcode; + + /* Get machine code which is patched back in later. The trap is 2 + bytes long. */ - /* patch in `call rel32' to call the following code */ + mcode = *((uint16_t *) cd->mcodeptr); - tmpmcodeptr = cd->mcodeptr; /* save current mcodeptr */ - cd->mcodeptr = savedmcodeptr; /* set mcodeptr to patch position */ + /* XXX This needs to be change to INT3 when the debugging problems + with gdb are resolved. */ - M_CALL_IMM(tmpmcodeptr - (savedmcodeptr + PATCHER_CALL_SIZE)); + M_UD2; - cd->mcodeptr = tmpmcodeptr; /* restore the current mcodeptr */ + return mcode; +} - /* move pointer to java_objectheader onto stack */ +/** + * Generates fast-path code for the below builtin. + * Function: LOCK_monitor_enter + * Signature: (Ljava/lang/Object;)V + * Slow-path: bool lock_monitor_enter(java_handle_t*); + */ +void emit_fastpath_monitor_enter(jitdata* jd, instruction* iptr, int d) +{ + // Get required compiler data. + codegendata* cd = jd->cd; + + // XXX Currently the fast-path always fails. Implement me! + M_CLR(d); +} + + +/** + * Generates fast-path code for the below builtin. + * Function: LOCK_monitor_exit + * Signature: (Ljava/lang/Object;)V + * Slow-path: bool lock_monitor_exit(java_handle_t*); + */ +void emit_fastpath_monitor_exit(jitdata* jd, instruction* iptr, int d) +{ + // Get required compiler data. + codegendata* cd = jd->cd; + + // XXX Currently the fast-path always fails. Implement me! + M_CLR(d); +} + + +/** + * Generates synchronization code to enter a monitor. + */ #if defined(ENABLE_THREADS) - /* create a virtual java_objectheader */ +void emit_monitor_enter(jitdata* jd, int32_t syncslot_offset) +{ + int32_t p; - (void) dseg_add_unique_address(cd, NULL); /* flcword */ - (void) dseg_add_unique_address(cd, lock_get_initial_lock_word()); - disp = dseg_add_unique_address(cd, NULL); /* vftbl */ + // Get required compiler data. + methodinfo* m = jd->m; + codegendata* cd = jd->cd; - emit_lea_membase_reg(cd, RIP, -((cd->mcodeptr + 7) - cd->mcodebase) + disp, REG_ITMP3); - M_PUSH(REG_ITMP3); -#else - M_PUSH_IMM(0); -#endif +# if !defined(NDEBUG) + if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) { + M_LSUB_IMM((INT_ARG_CNT + FLT_ARG_CNT) * 8, REG_SP); - /* move machine code bytes and classinfo pointer into registers */ + for (p = 0; p < INT_ARG_CNT; p++) + M_LST(abi_registers_integer_argument[p], REG_SP, p * 8); - M_MOV_IMM(mcode, REG_ITMP3); - M_PUSH(REG_ITMP3); + for (p = 0; p < FLT_ARG_CNT; p++) + M_DST(abi_registers_float_argument[p], REG_SP, (INT_ARG_CNT + p) * 8); - M_MOV_IMM(pref->ref, REG_ITMP3); - M_PUSH(REG_ITMP3); + syncslot_offset += (INT_ARG_CNT + FLT_ARG_CNT) * 8; + } +# endif - M_MOV_IMM(pref->disp, REG_ITMP3); - M_PUSH(REG_ITMP3); + /* decide which monitor enter function to call */ - M_MOV_IMM(pref->patcher, REG_ITMP3); - M_PUSH(REG_ITMP3); + if (m->flags & ACC_STATIC) { + M_MOV_IMM(&m->clazz->object.header, REG_A0); + } + else { + M_TEST(REG_A0); + M_BNE(8); + M_ALD_MEM(REG_A0, TRAP_NullPointerException); + } - if (targetdisp == 0) { - targetdisp = cd->mcodeptr - cd->mcodebase; + M_AST(REG_A0, REG_SP, syncslot_offset); + M_MOV_IMM(LOCK_monitor_enter, REG_ITMP1); + M_CALL(REG_ITMP1); - M_MOV_IMM(asm_patcher_wrapper, REG_ITMP3); - M_JMP(REG_ITMP3); - } - else { - M_JMP_IMM((cd->mcodebase + targetdisp) - - (cd->mcodeptr + PATCHER_CALL_SIZE)); - } +# if !defined(NDEBUG) + if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) { + + for (p = 0; p < INT_ARG_CNT; p++) + M_LLD(abi_registers_integer_argument[p], REG_SP, p * 8); + + for (p = 0; p < FLT_ARG_CNT; p++) + M_DLD(abi_registers_float_argument[p], REG_SP, (INT_ARG_CNT + p) * 8); + + M_LADD_IMM((INT_ARG_CNT + FLT_ARG_CNT) * 8, REG_SP); } +# endif } +#endif -/* emit_replacement_stubs ****************************************************** +/** + * Generates synchronization code to leave a monitor. + */ +#if defined(ENABLE_THREADS) +void emit_monitor_exit(jitdata* jd, int32_t syncslot_offset) +{ + // Get required compiler data. + methodinfo* m = jd->m; + codegendata* cd = jd->cd; - Generates the code for the replacement stubs. + M_ALD(REG_A0, REG_SP, syncslot_offset); -*******************************************************************************/ + /* we need to save the proper return value */ -#if defined(ENABLE_REPLACEMENT) -void emit_replacement_stubs(jitdata *jd) -{ - codegendata *cd; - codeinfo *code; - rplpoint *rplp; - s4 i; -#if !defined(NDEBUG) - u1 *savedmcodeptr; -#endif + methoddesc* md = m->parseddesc; - /* get required compiler data */ + switch (md->returntype.type) { + case TYPE_INT: + case TYPE_ADR: + case TYPE_LNG: + M_LST(REG_RESULT, REG_SP, syncslot_offset); + break; + case TYPE_FLT: + case TYPE_DBL: + M_DST(REG_FRESULT, REG_SP, syncslot_offset); + break; + } - cd = jd->cd; - code = jd->code; + M_MOV_IMM(LOCK_monitor_exit, REG_ITMP1); + M_CALL(REG_ITMP1); - rplp = code->rplpoints; + /* and now restore the proper return value */ + + switch (md->returntype.type) { + case TYPE_INT: + case TYPE_ADR: + case TYPE_LNG: + M_LLD(REG_RESULT, REG_SP, syncslot_offset); + break; + case TYPE_FLT: + case TYPE_DBL: + M_DLD(REG_FRESULT, REG_SP, syncslot_offset); + break; + } +} +#endif - /* store beginning of replacement stubs */ - code->replacementstubs = (u1*) (cd->mcodeptr - cd->mcodebase); +/** + * Emit profiling code for method frequency counting. + */ +#if defined(ENABLE_PROFILING) +void emit_profile_method(codegendata* cd, codeinfo* code) +{ + M_MOV_IMM(code, REG_ITMP3); + M_IINC_MEMBASE(REG_ITMP3, OFFSET(codeinfo, frequency)); +} +#endif - for (i = 0; i < code->rplpointcount; ++i, ++rplp) { - /* do not generate stubs for non-trappable points */ - if (rplp->flags & RPLPOINT_FLAG_NOTRAP) - continue; +/** + * Emit profiling code for basicblock frequency counting. + */ +#if defined(ENABLE_PROFILING) +void emit_profile_basicblock(codegendata* cd, codeinfo* code, basicblock* bptr) +{ + M_MOV_IMM(code->bbfrequency, REG_ITMP3); + M_IINC_MEMBASE(REG_ITMP3, bptr->nr * 4); +} +#endif - /* check code segment size */ - MCODECHECK(512); +/** + * Emit profiling code to start CPU cycle counting. + */ +#if defined(ENABLE_PROFILING) +void emit_profile_cycle_start(codegendata* cd, codeinfo* code) +{ + M_PUSH(RAX); + M_PUSH(RDX); - /* note start of stub code */ + M_MOV_IMM(code, REG_ITMP3); + M_RDTSC; + M_ISUB_MEMBASE(RAX, REG_ITMP3, OFFSET(codeinfo, cycles)); + M_ISBB_MEMBASE(RDX, REG_ITMP3, OFFSET(codeinfo, cycles) + 4); -#if !defined(NDEBUG) - savedmcodeptr = cd->mcodeptr; + M_POP(RDX); + M_POP(RAX); +} #endif - /* push address of `rplpoint` struct */ - - M_MOV_IMM(rplp, REG_ITMP3); - M_PUSH(REG_ITMP3); - /* jump to replacement function */ +/** + * Emit profiling code to stop CPU cycle counting. + */ +#if defined(ENABLE_PROFILING) +void emit_profile_cycle_stop(codegendata* cd, codeinfo* code) +{ + M_PUSH(RAX); + M_PUSH(RDX); - M_MOV_IMM(asm_replacement_out, REG_ITMP3); - M_PUSH(REG_ITMP3); - M_RET; + M_MOV_IMM(code, REG_ITMP3); + M_RDTSC; + M_IADD_MEMBASE(RAX, REG_ITMP3, OFFSET(codeinfo, cycles)); + M_IADC_MEMBASE(RDX, REG_ITMP3, OFFSET(codeinfo, cycles) + 4); - assert((cd->mcodeptr - savedmcodeptr) == REPLACEMENT_STUB_SIZE); - } + M_POP(RDX); + M_POP(RAX); } -#endif /* defined(ENABLE_REPLACEMENT) */ +#endif /* emit_verbosecall_enter ****************************************************** @@ -568,16 +682,19 @@ void emit_replacement_stubs(jitdata *jd) void emit_verbosecall_enter(jitdata *jd) { methodinfo *m; + codeinfo *code; codegendata *cd; registerdata *rd; methoddesc *md; - s4 i, j, k; + s4 stackframesize; + s4 i, s; /* get required compiler data */ - m = jd->m; - cd = jd->cd; - rd = jd->rd; + m = jd->m; + code = jd->code; + cd = jd->cd; + rd = jd->rd; md = m->parseddesc; @@ -585,69 +702,94 @@ void emit_verbosecall_enter(jitdata *jd) M_NOP; - /* additional +1 is for 16-byte stack alignment */ + /* keep 16-byte stack alignment */ + + stackframesize = md->paramcount + ARG_CNT + TMP_CNT; + ALIGN_2(stackframesize); - M_LSUB_IMM((ARG_CNT + TMP_CNT + 1 + 1) * 8, REG_SP); + M_LSUB_IMM(stackframesize * 8, REG_SP); /* save argument registers */ - for (i = 0; i < INT_ARG_CNT; i++) - M_LST(abi_registers_integer_argument[i], REG_SP, (1 + i) * 8); + for (i = 0; i < md->paramcount; i++) { + if (!md->params[i].inmemory) { + s = md->params[i].regoff; - for (i = 0; i < FLT_ARG_CNT; i++) - M_DST(abi_registers_float_argument[i], REG_SP, (1 + INT_ARG_CNT + i) * 8); + switch (md->paramtypes[i].type) { + case TYPE_ADR: + case TYPE_INT: + case TYPE_LNG: + M_LST(s, REG_SP, i * 8); + break; + case TYPE_FLT: + case TYPE_DBL: + M_DST(s, REG_SP, i * 8); + break; + } + } + } + + /* save all argument and temporary registers for leaf methods */ + + if (code_is_leafmethod(code)) { + for (i = 0; i < INT_ARG_CNT; i++) + M_LST(abi_registers_integer_argument[i], REG_SP, (md->paramcount + i) * 8); - /* save temporary registers for leaf methods */ + for (i = 0; i < FLT_ARG_CNT; i++) + M_DST(abi_registers_float_argument[i], REG_SP, (md->paramcount + INT_ARG_CNT + i) * 8); - if (jd->isleafmethod) { for (i = 0; i < INT_TMP_CNT; i++) - M_LST(rd->tmpintregs[i], REG_SP, (1 + ARG_CNT + i) * 8); + M_LST(rd->tmpintregs[i], REG_SP, (md->paramcount + ARG_CNT + i) * 8); for (i = 0; i < FLT_TMP_CNT; i++) - M_DST(rd->tmpfltregs[i], REG_SP, (1 + ARG_CNT + INT_TMP_CNT + i) * 8); + M_DST(rd->tmpfltregs[i], REG_SP, (md->paramcount + ARG_CNT + INT_TMP_CNT + i) * 8); } - /* show integer hex code for float arguments */ + M_MOV_IMM(m, REG_A0); + M_MOV(REG_SP, REG_A1); + M_MOV(REG_SP, REG_A2); + M_AADD_IMM((stackframesize + cd->stackframesize + 1) * 8, REG_A2); + M_MOV_IMM(trace_java_call_enter, REG_ITMP1); + M_CALL(REG_ITMP1); - for (i = 0, j = 0; i < md->paramcount && i < INT_ARG_CNT; i++) { - /* If the paramtype is a float, we have to right shift all - following integer registers. */ - - if (IS_FLT_DBL_TYPE(md->paramtypes[i].type)) { - for (k = INT_ARG_CNT - 2; k >= i; k--) - M_MOV(abi_registers_integer_argument[k], - abi_registers_integer_argument[k + 1]); - - emit_movd_freg_reg(cd, abi_registers_float_argument[j], - abi_registers_integer_argument[i]); - j++; + /* restore argument registers */ + + for (i = 0; i < md->paramcount; i++) { + if (!md->params[i].inmemory) { + s = md->params[i].regoff; + + switch (md->paramtypes[i].type) { + case TYPE_ADR: + case TYPE_INT: + case TYPE_LNG: + M_LLD(s, REG_SP, i * 8); + break; + case TYPE_FLT: + case TYPE_DBL: + M_DLD(s, REG_SP, i * 8); + break; + } } } - M_MOV_IMM(m, REG_ITMP2); - M_AST(REG_ITMP2, REG_SP, 0 * 8); - M_MOV_IMM(builtin_verbosecall_enter, REG_ITMP1); - M_CALL(REG_ITMP1); - /* restore argument registers */ + /* restore all argument and temporary registers for leaf methods */ - for (i = 0; i < INT_ARG_CNT; i++) - M_LLD(abi_registers_integer_argument[i], REG_SP, (1 + i) * 8); + if (code_is_leafmethod(code)) { + for (i = 0; i < INT_ARG_CNT; i++) + M_LLD(abi_registers_integer_argument[i], REG_SP, (md->paramcount + i) * 8); - for (i = 0; i < FLT_ARG_CNT; i++) - M_DLD(abi_registers_float_argument[i], REG_SP, (1 + INT_ARG_CNT + i) * 8); + for (i = 0; i < FLT_ARG_CNT; i++) + M_DLD(abi_registers_float_argument[i], REG_SP, (md->paramcount + INT_ARG_CNT + i) * 8); - /* restore temporary registers for leaf methods */ - - if (jd->isleafmethod) { for (i = 0; i < INT_TMP_CNT; i++) - M_LLD(rd->tmpintregs[i], REG_SP, (1 + ARG_CNT + i) * 8); + M_LLD(rd->tmpintregs[i], REG_SP, (md->paramcount + ARG_CNT + i) * 8); for (i = 0; i < FLT_TMP_CNT; i++) - M_DLD(rd->tmpfltregs[i], REG_SP, (1 + ARG_CNT + INT_TMP_CNT + i) * 8); + M_DLD(rd->tmpfltregs[i], REG_SP, (md->paramcount + ARG_CNT + INT_TMP_CNT + i) * 8); } - M_LADD_IMM((ARG_CNT + TMP_CNT + 1 + 1) * 8, REG_SP); + M_LADD_IMM(stackframesize * 8, REG_SP); /* mark trace code */ @@ -668,6 +810,7 @@ void emit_verbosecall_exit(jitdata *jd) methodinfo *m; codegendata *cd; registerdata *rd; + methoddesc *md; /* get required compiler data */ @@ -675,25 +818,49 @@ void emit_verbosecall_exit(jitdata *jd) cd = jd->cd; rd = jd->rd; + md = m->parseddesc; + /* mark trace code */ M_NOP; + /* keep 16-byte stack alignment */ + M_ASUB_IMM(2 * 8, REG_SP); - M_LST(REG_RESULT, REG_SP, 0 * 8); - M_DST(REG_FRESULT, REG_SP, 1 * 8); + /* save return value */ - M_INTMOVE(REG_RESULT, REG_A0); - M_FLTMOVE(REG_FRESULT, REG_FA0); - M_FLTMOVE(REG_FRESULT, REG_FA1); - M_MOV_IMM(m, REG_A1); + switch (md->returntype.type) { + case TYPE_ADR: + case TYPE_INT: + case TYPE_LNG: + M_LST(REG_RESULT, REG_SP, 0 * 8); + break; + case TYPE_FLT: + case TYPE_DBL: + M_DST(REG_FRESULT, REG_SP, 0 * 8); + break; + } + + M_MOV_IMM(m, REG_A0); + M_MOV(REG_SP, REG_A1); - M_MOV_IMM(builtin_verbosecall_exit, REG_ITMP1); + M_MOV_IMM(trace_java_call_exit, REG_ITMP1); M_CALL(REG_ITMP1); - M_LLD(REG_RESULT, REG_SP, 0 * 8); - M_DLD(REG_FRESULT, REG_SP, 1 * 8); + /* restore return value */ + + switch (md->returntype.type) { + case TYPE_ADR: + case TYPE_INT: + case TYPE_LNG: + M_LLD(REG_RESULT, REG_SP, 0 * 8); + break; + case TYPE_FLT: + case TYPE_DBL: + M_DLD(REG_FRESULT, REG_SP, 0 * 8); + break; + } M_AADD_IMM(2 * 8, REG_SP); @@ -805,53 +972,53 @@ void emit_ishift(jitdata *jd, s4 shift_op, instruction *iptr) if (IS_INMEMORY(v_dst->flags)) { if (IS_INMEMORY(v_s2->flags) && IS_INMEMORY(v_s1->flags)) { if (s1 == d) { - M_ILD(RCX, REG_SP, s2 * 8); - emit_shiftl_membase(cd, shift_op, REG_SP, d * 8); + M_ILD(RCX, REG_SP, s2); + emit_shiftl_membase(cd, shift_op, REG_SP, d); } else { - M_ILD(RCX, REG_SP, s2 * 8); - M_ILD(REG_ITMP2, REG_SP, s1 * 8); + M_ILD(RCX, REG_SP, s2); + M_ILD(REG_ITMP2, REG_SP, s1); emit_shiftl_reg(cd, shift_op, REG_ITMP2); - M_IST(REG_ITMP2, REG_SP, d * 8); + M_IST(REG_ITMP2, REG_SP, d); } } else if (IS_INMEMORY(v_s2->flags) && !IS_INMEMORY(v_s1->flags)) { /* s1 may be equal to RCX */ if (s1 == RCX) { if (s2 == d) { - M_ILD(REG_ITMP1, REG_SP, s2 * 8); - M_IST(s1, REG_SP, d * 8); + M_ILD(REG_ITMP1, REG_SP, s2); + M_IST(s1, REG_SP, d); M_INTMOVE(REG_ITMP1, RCX); } else { - M_IST(s1, REG_SP, d * 8); - M_ILD(RCX, REG_SP, s2 * 8); + M_IST(s1, REG_SP, d); + M_ILD(RCX, REG_SP, s2); } } else { - M_ILD(RCX, REG_SP, s2 * 8); - M_IST(s1, REG_SP, d * 8); + M_ILD(RCX, REG_SP, s2); + M_IST(s1, REG_SP, d); } - emit_shiftl_membase(cd, shift_op, REG_SP, d * 8); + emit_shiftl_membase(cd, shift_op, REG_SP, d); } else if (!IS_INMEMORY(v_s2->flags) && IS_INMEMORY(v_s1->flags)) { if (s1 == d) { M_INTMOVE(s2, RCX); - emit_shiftl_membase(cd, shift_op, REG_SP, d * 8); + emit_shiftl_membase(cd, shift_op, REG_SP, d); } else { M_INTMOVE(s2, RCX); - M_ILD(REG_ITMP2, REG_SP, s1 * 8); + M_ILD(REG_ITMP2, REG_SP, s1); emit_shiftl_reg(cd, shift_op, REG_ITMP2); - M_IST(REG_ITMP2, REG_SP, d * 8); + M_IST(REG_ITMP2, REG_SP, d); } } else { /* s1 may be equal to RCX */ - M_IST(s1, REG_SP, d * 8); + M_IST(s1, REG_SP, d); M_INTMOVE(s2, RCX); - emit_shiftl_membase(cd, shift_op, REG_SP, d * 8); + emit_shiftl_membase(cd, shift_op, REG_SP, d); } M_INTMOVE(REG_ITMP1, RCX); /* restore RCX */ @@ -863,19 +1030,19 @@ void emit_ishift(jitdata *jd, s4 shift_op, instruction *iptr) } if (IS_INMEMORY(v_s2->flags) && IS_INMEMORY(v_s1->flags)) { - M_ILD(RCX, REG_SP, s2 * 8); - M_ILD(d, REG_SP, s1 * 8); + M_ILD(RCX, REG_SP, s2); + M_ILD(d, REG_SP, s1); emit_shiftl_reg(cd, shift_op, d); } else if (IS_INMEMORY(v_s2->flags) && !IS_INMEMORY(v_s1->flags)) { /* s1 may be equal to RCX */ M_INTMOVE(s1, d); - M_ILD(RCX, REG_SP, s2 * 8); + M_ILD(RCX, REG_SP, s2); emit_shiftl_reg(cd, shift_op, d); } else if (!IS_INMEMORY(v_s2->flags) && IS_INMEMORY(v_s1->flags)) { M_INTMOVE(s2, RCX); - M_ILD(d, REG_SP, s1 * 8); + M_ILD(d, REG_SP, s1); emit_shiftl_reg(cd, shift_op, d); } else { @@ -932,53 +1099,53 @@ void emit_lshift(jitdata *jd, s4 shift_op, instruction *iptr) if (IS_INMEMORY(v_dst->flags)) { if (IS_INMEMORY(v_s2->flags) && IS_INMEMORY(v_s1->flags)) { if (s1 == d) { - M_ILD(RCX, REG_SP, s2 * 8); - emit_shift_membase(cd, shift_op, REG_SP, d * 8); + M_ILD(RCX, REG_SP, s2); + emit_shift_membase(cd, shift_op, REG_SP, d); } else { - M_ILD(RCX, REG_SP, s2 * 8); - M_LLD(REG_ITMP2, REG_SP, s1 * 8); + M_ILD(RCX, REG_SP, s2); + M_LLD(REG_ITMP2, REG_SP, s1); emit_shift_reg(cd, shift_op, REG_ITMP2); - M_LST(REG_ITMP2, REG_SP, d * 8); + M_LST(REG_ITMP2, REG_SP, d); } } else if (IS_INMEMORY(v_s2->flags) && !IS_INMEMORY(v_s1->flags)) { /* s1 may be equal to RCX */ if (s1 == RCX) { if (s2 == d) { - M_ILD(REG_ITMP1, REG_SP, s2 * 8); - M_LST(s1, REG_SP, d * 8); + M_ILD(REG_ITMP1, REG_SP, s2); + M_LST(s1, REG_SP, d); M_INTMOVE(REG_ITMP1, RCX); } else { - M_LST(s1, REG_SP, d * 8); - M_ILD(RCX, REG_SP, s2 * 8); + M_LST(s1, REG_SP, d); + M_ILD(RCX, REG_SP, s2); } } else { - M_ILD(RCX, REG_SP, s2 * 8); - M_LST(s1, REG_SP, d * 8); + M_ILD(RCX, REG_SP, s2); + M_LST(s1, REG_SP, d); } - emit_shift_membase(cd, shift_op, REG_SP, d * 8); + emit_shift_membase(cd, shift_op, REG_SP, d); } else if (!IS_INMEMORY(v_s2->flags) && IS_INMEMORY(v_s1->flags)) { if (s1 == d) { M_INTMOVE(s2, RCX); - emit_shift_membase(cd, shift_op, REG_SP, d * 8); + emit_shift_membase(cd, shift_op, REG_SP, d); } else { M_INTMOVE(s2, RCX); - M_LLD(REG_ITMP2, REG_SP, s1 * 8); + M_LLD(REG_ITMP2, REG_SP, s1); emit_shift_reg(cd, shift_op, REG_ITMP2); - M_LST(REG_ITMP2, REG_SP, d * 8); + M_LST(REG_ITMP2, REG_SP, d); } } else { /* s1 may be equal to RCX */ - M_LST(s1, REG_SP, d * 8); + M_LST(s1, REG_SP, d); M_INTMOVE(s2, RCX); - emit_shift_membase(cd, shift_op, REG_SP, d * 8); + emit_shift_membase(cd, shift_op, REG_SP, d); } M_INTMOVE(REG_ITMP1, RCX); /* restore RCX */ @@ -990,19 +1157,19 @@ void emit_lshift(jitdata *jd, s4 shift_op, instruction *iptr) } if (IS_INMEMORY(v_s2->flags) && IS_INMEMORY(v_s1->flags)) { - M_ILD(RCX, REG_SP, s2 * 8); - M_LLD(d, REG_SP, s1 * 8); + M_ILD(RCX, REG_SP, s2); + M_LLD(d, REG_SP, s1); emit_shift_reg(cd, shift_op, d); } else if (IS_INMEMORY(v_s2->flags) && !IS_INMEMORY(v_s1->flags)) { /* s1 may be equal to RCX */ M_INTMOVE(s1, d); - M_ILD(RCX, REG_SP, s2 * 8); + M_ILD(RCX, REG_SP, s2); emit_shift_reg(cd, shift_op, d); } else if (!IS_INMEMORY(v_s2->flags) && IS_INMEMORY(v_s1->flags)) { M_INTMOVE(s2, RCX); - M_LLD(d, REG_SP, s1 * 8); + M_LLD(d, REG_SP, s1); emit_shift_reg(cd, shift_op, d); } else { @@ -1038,6 +1205,76 @@ void emit_lshift(jitdata *jd, s4 shift_op, instruction *iptr) /* low-level code emitter functions *******************************************/ +void emit_nop(codegendata *cd, int length) +{ + assert(length >= 1 && length <= 9); + switch (length) { + case 1: + *(cd->mcodeptr++) = 0x90; + break; + case 2: + *(cd->mcodeptr++) = 0x66; + *(cd->mcodeptr++) = 0x90; + break; + case 3: + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x1f; + *(cd->mcodeptr++) = 0x00; + break; + case 4: + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x1f; + *(cd->mcodeptr++) = 0x40; + *(cd->mcodeptr++) = 0x00; + break; + case 5: + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x1f; + *(cd->mcodeptr++) = 0x44; + *(cd->mcodeptr++) = 0x00; + *(cd->mcodeptr++) = 0x00; + break; + case 6: + *(cd->mcodeptr++) = 0x66; + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x1f; + *(cd->mcodeptr++) = 0x44; + *(cd->mcodeptr++) = 0x00; + *(cd->mcodeptr++) = 0x00; + break; + case 7: + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x1f; + *(cd->mcodeptr++) = 0x80; + *(cd->mcodeptr++) = 0x00; + *(cd->mcodeptr++) = 0x00; + *(cd->mcodeptr++) = 0x00; + *(cd->mcodeptr++) = 0x00; + break; + case 8: + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x1f; + *(cd->mcodeptr++) = 0x84; + *(cd->mcodeptr++) = 0x00; + *(cd->mcodeptr++) = 0x00; + *(cd->mcodeptr++) = 0x00; + *(cd->mcodeptr++) = 0x00; + *(cd->mcodeptr++) = 0x00; + break; + case 9: + *(cd->mcodeptr++) = 0x66; + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0x1f; + *(cd->mcodeptr++) = 0x84; + *(cd->mcodeptr++) = 0x00; + *(cd->mcodeptr++) = 0x00; + *(cd->mcodeptr++) = 0x00; + *(cd->mcodeptr++) = 0x00; + *(cd->mcodeptr++) = 0x00; + break; + } +} + void emit_mov_reg_reg(codegendata *cd, s8 reg, s8 dreg) { emit_rex(1,(reg),0,(dreg)); @@ -1241,6 +1478,16 @@ void emit_movslq_reg_reg(codegendata *cd, s8 reg, s8 dreg) } +void emit_movzbq_reg_reg(codegendata *cd, s8 reg, s8 dreg) +{ + emit_rex(1,(dreg),0,(reg)); + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0xb6; + /* XXX: why do reg and dreg have to be exchanged */ + emit_reg((dreg),(reg)); +} + + void emit_movzwq_reg_reg(codegendata *cd, s8 reg, s8 dreg) { emit_rex(1,(dreg),0,(reg)); @@ -1422,12 +1669,12 @@ void emit_alul_imm_reg(codegendata *cd, s8 opc, s8 imm, s8 dreg) { void emit_alu_imm_membase(codegendata *cd, s8 opc, s8 imm, s8 basereg, s8 disp) { if (IS_IMM8(imm)) { - emit_rex(1,(basereg),0,0); + emit_rex(1,0,0,(basereg)); *(cd->mcodeptr++) = 0x83; emit_membase(cd, (basereg),(disp),(opc)); emit_imm8((imm)); } else { - emit_rex(1,(basereg),0,0); + emit_rex(1,0,0,(basereg)); *(cd->mcodeptr++) = 0x81; emit_membase(cd, (basereg),(disp),(opc)); emit_imm32((imm)); @@ -1437,18 +1684,31 @@ void emit_alu_imm_membase(codegendata *cd, s8 opc, s8 imm, s8 basereg, s8 disp) void emit_alul_imm_membase(codegendata *cd, s8 opc, s8 imm, s8 basereg, s8 disp) { if (IS_IMM8(imm)) { - emit_rex(0,(basereg),0,0); + emit_rex(0,0,0,(basereg)); *(cd->mcodeptr++) = 0x83; emit_membase(cd, (basereg),(disp),(opc)); emit_imm8((imm)); } else { - emit_rex(0,(basereg),0,0); + emit_rex(0,0,0,(basereg)); *(cd->mcodeptr++) = 0x81; emit_membase(cd, (basereg),(disp),(opc)); emit_imm32((imm)); } } +void emit_alu_memindex_reg(codegendata *cd, s8 opc, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 reg) +{ + emit_rex(1,(reg),(indexreg),(basereg)); + *(cd->mcodeptr++) = (((opc)) << 3) + 3; + emit_memindex(cd, (reg),(disp),(basereg),(indexreg),(scale)); +} + +void emit_alul_memindex_reg(codegendata *cd, s8 opc, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 reg) +{ + emit_rex(0,(reg),(indexreg),(basereg)); + *(cd->mcodeptr++) = (((opc)) << 3) + 3; + emit_memindex(cd, (reg),(disp),(basereg),(indexreg),(scale)); +} void emit_test_reg_reg(codegendata *cd, s8 reg, s8 dreg) { emit_rex(1,(reg),0,(dreg)); @@ -1500,6 +1760,18 @@ void emit_leal_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 reg) { } +void emit_incl_reg(codegendata *cd, s8 reg) +{ + *(cd->mcodeptr++) = 0xff; + emit_reg(0,(reg)); +} + +void emit_incq_reg(codegendata *cd, s8 reg) +{ + emit_rex(1,0,0,(reg)); + *(cd->mcodeptr++) = 0xff; + emit_reg(0,(reg)); +} void emit_incl_membase(codegendata *cd, s8 basereg, s8 disp) { @@ -1508,6 +1780,13 @@ void emit_incl_membase(codegendata *cd, s8 basereg, s8 disp) emit_membase(cd, (basereg),(disp),0); } +void emit_incq_membase(codegendata *cd, s8 basereg, s8 disp) +{ + emit_rex(1,0,0,(basereg)); + *(cd->mcodeptr++) = 0xff; + emit_membase(cd, (basereg),(disp),0); +} + void emit_cltd(codegendata *cd) { @@ -1644,12 +1923,6 @@ void emit_idivl_reg(codegendata *cd, s8 reg) { -void emit_ret(codegendata *cd) { - *(cd->mcodeptr++) = 0xc3; -} - - - /* * shift ops */ @@ -1746,6 +2019,18 @@ void emit_jmp_imm(codegendata *cd, s8 imm) { emit_imm32((imm)); } +/* like emit_jmp_imm but allows 8 bit optimization */ +void emit_jmp_imm2(codegendata *cd, s8 imm) { + if (IS_IMM8(imm)) { + *(cd->mcodeptr++) = 0xeb; + emit_imm8((imm)); + } + else { + *(cd->mcodeptr++) = 0xe9; + emit_imm32((imm)); + } +} + void emit_jmp_reg(codegendata *cd, s8 reg) { emit_rex(0,0,0,(reg)); @@ -1845,11 +2130,6 @@ void emit_xchg_reg_reg(codegendata *cd, s8 reg, s8 dreg) { } -void emit_nop(codegendata *cd) { - *(cd->mcodeptr++) = 0x90; -} - - /* * call instructions @@ -2363,6 +2643,13 @@ void emit_rdtsc(codegendata *cd) *(cd->mcodeptr++) = 0x31; } +void emit_mfence(codegendata *cd) +{ + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0xae; + *(cd->mcodeptr++) = 0xf0; +} + /* * These are local overrides for various environment variables in Emacs. @@ -2375,4 +2662,5 @@ void emit_rdtsc(codegendata *cd) * c-basic-offset: 4 * tab-width: 4 * End: + * vim:noexpandtab:sw=4:ts=4: */