X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Fjit%2Fi386%2Femit.c;h=7c61037afcaf40aa14b4b3befe25e6f81290c25b;hb=7659949229c634784f7d27aa8b679fdd4c8351ab;hp=12fa5660f4b9ca2f48959c3027999756a5d814c7;hpb=d618789d14ccf54bd2f7343f67763983158d1b3b;p=cacao.git diff --git a/src/vm/jit/i386/emit.c b/src/vm/jit/i386/emit.c index 12fa5660f..7c61037af 100644 --- a/src/vm/jit/i386/emit.c +++ b/src/vm/jit/i386/emit.c @@ -1,9 +1,7 @@ /* src/vm/jit/i386/emit.c - i386 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 + 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 7579 2007-03-25 22:42:13Z twisti $ - */ @@ -39,18 +35,19 @@ #include "mm/memory.h" -#if defined(ENABLE_THREADS) -# include "threads/native/lock.h" -#endif +#include "threads/lock-common.h" -#include "vm/builtin.h" #include "vm/exceptions.h" +#include "vm/jit/abi.h" #include "vm/jit/asmpart.h" #include "vm/jit/dseg.h" #include "vm/jit/emit-common.h" #include "vm/jit/jit.h" +#include "vm/jit/patcher-common.h" #include "vm/jit/replace.h" +#include "vm/jit/trace.h" +#include "vm/jit/trap.h" #include "vmcore/options.h" #include "vmcore/statistics.h" @@ -75,7 +72,7 @@ inline s4 emit_load(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg) if (IS_INMEMORY(src->flags)) { COUNT_SPILLS; - disp = src->vv.regoff * 4; + disp = src->vv.regoff; switch (src->type) { case TYPE_INT: @@ -126,7 +123,7 @@ inline s4 emit_load_low(jitdata *jd, instruction *iptr, varinfo *src,s4 tempreg) if (IS_INMEMORY(src->flags)) { COUNT_SPILLS; - disp = src->vv.regoff * 4; + disp = src->vv.regoff; M_ILD(tempreg, REG_SP, disp); @@ -160,7 +157,7 @@ inline s4 emit_load_high(jitdata *jd, instruction *iptr,varinfo *src,s4 tempreg) if (IS_INMEMORY(src->flags)) { COUNT_SPILLS; - disp = src->vv.regoff * 4; + disp = src->vv.regoff; M_ILD(tempreg, REG_SP, disp + 4); @@ -191,7 +188,7 @@ inline void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d) if (IS_INMEMORY(dst->flags)) { COUNT_SPILLS; - disp = dst->vv.regoff * 4; + disp = dst->vv.regoff; switch (dst->type) { case TYPE_INT: @@ -233,7 +230,7 @@ inline void emit_store_low(jitdata *jd, instruction *iptr, varinfo *dst, s4 d) if (IS_INMEMORY(dst->flags)) { COUNT_SPILLS; - M_IST(GET_LOW_REG(d), REG_SP, dst->vv.regoff * 4); + M_IST(GET_LOW_REG(d), REG_SP, dst->vv.regoff); } } @@ -257,7 +254,7 @@ inline void emit_store_high(jitdata *jd, instruction *iptr, varinfo *dst, s4 d) if (IS_INMEMORY(dst->flags)) { COUNT_SPILLS; - M_IST(GET_HIGH_REG(d), REG_SP, dst->vv.regoff * 4 + 4); + M_IST(GET_HIGH_REG(d), REG_SP, dst->vv.regoff + 4); } } @@ -268,18 +265,30 @@ inline void emit_store_high(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. */ @@ -400,7 +409,7 @@ void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg) if (INSTRUCTION_MUST_CHECK(iptr)) { M_TEST(reg); M_BNE(6); - M_ALD_MEM(reg, EXCEPTION_HARDWARE_ARITHMETIC); + M_ALD_MEM(reg, TRAP_ArithmeticException); } } @@ -414,10 +423,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_CMP(REG_ITMP3, s2); M_BB(6); - 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(6); + M_ALD_MEM(REG_RESULT, TRAP_ArrayStoreException); } } @@ -444,7 +469,7 @@ void emit_classcast_check(codegendata *cd, instruction *iptr, s4 condition, s4 r default: vm_abort("emit_classcast_check: unknown condition %d", condition); } - M_ALD_MEM(s1, EXCEPTION_HARDWARE_CLASSCAST); + M_ALD_MEM(s1, TRAP_ClassCastException); } } @@ -460,7 +485,7 @@ void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg) if (INSTRUCTION_MUST_CHECK(iptr)) { M_TEST(reg); M_BNE(6); - M_ALD_MEM(reg, EXCEPTION_HARDWARE_NULLPOINTER); + M_ALD_MEM(reg, TRAP_NullPointerException); } } @@ -476,160 +501,63 @@ void emit_exception_check(codegendata *cd, instruction *iptr) if (INSTRUCTION_MUST_CHECK(iptr)) { M_TEST(REG_RESULT); M_BNE(6); - 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; - - /* get required compiler data */ - - cd = jd->cd; - - /* generate code patching stub call code */ - - targetdisp = 0; - - for (pref = cd->patchrefs; pref != NULL; pref = pref->next) { - /* check code segment size */ - - MCODECHECK(512); - - /* Get machine code which is patched back in later. A - `call rel32' is 5 bytes long. */ - - savedmcodeptr = cd->mcodebase + pref->branchpos; - mcode = *((u8 *) savedmcodeptr); - - /* patch in `call rel32' to call the following code */ - - tmpmcodeptr = cd->mcodeptr; /* save current mcodeptr */ - cd->mcodeptr = savedmcodeptr; /* set mcodeptr to patch position */ - - M_CALL_IMM(tmpmcodeptr - (savedmcodeptr + PATCHER_CALL_SIZE)); - - cd->mcodeptr = tmpmcodeptr; /* restore the current mcodeptr */ - - /* save REG_ITMP3 */ - - M_PUSH(REG_ITMP3); - - /* move pointer to java_objectheader onto stack */ - -#if defined(ENABLE_THREADS) - (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 */ - - M_MOV_IMM(0, REG_ITMP3); - dseg_adddata(cd); - M_AADD_IMM(disp, REG_ITMP3); - M_PUSH(REG_ITMP3); -#else - M_PUSH_IMM(0); -#endif - - /* move machine code bytes and classinfo pointer into registers */ - - M_PUSH_IMM(mcode >> 32); - M_PUSH_IMM(mcode); - M_PUSH_IMM(pref->ref); - M_PUSH_IMM(pref->patcher); - - if (targetdisp == 0) { - targetdisp = cd->mcodeptr - cd->mcodebase; - - M_MOV_IMM(asm_patcher_wrapper, REG_ITMP3); - M_JMP(REG_ITMP3); - } - else { - M_JMP_IMM((cd->mcodebase + targetdisp) - - (cd->mcodeptr + PATCHER_CALL_SIZE)); - } - } + M_ALD_MEM(REG_METHODPTR, TRAP_COMPILER); } +/* emit_trap_countdown ********************************************************* -/* emit_replacement_stubs ****************************************************** + Emit a countdown trap. - Generates the code for the replacement stubs. + counter....absolute address of the counter variable *******************************************************************************/ -#if defined(ENABLE_REPLACEMENT) -void emit_replacement_stubs(jitdata *jd) +void emit_trap_countdown(codegendata *cd, s4 *counter) { - codegendata *cd; - codeinfo *code; - rplpoint *rplp; - s4 disp; - s4 i; - s4 branchmpc; - s4 outcode; - - /* get required compiler data */ - - cd = jd->cd; - code = jd->code; - - rplp = code->rplpoints; - - /* store beginning of replacement stubs */ - - code->replacementstubs = (u1*) (cd->mcodeptr - cd->mcodebase); - - for (i = 0; i < code->rplpointcount; ++i, ++rplp) { - /* do not generate stubs for non-trappable points */ - - if (rplp->flags & RPLPOINT_FLAG_NOTRAP) - continue; - - /* check code segment size */ - - MCODECHECK(512); - - /* note start of stub code */ - - outcode = (s4) (cd->mcodeptr - cd->mcodebase); + M_ISUB_IMM_MEMABS(1, (s4) counter); + M_BNS(6); + M_ALD_MEM(REG_METHODPTR, TRAP_COUNTDOWN); +} - /* push address of `rplpoint` struct */ - - M_PUSH_IMM(rplp); +/* emit_trap ******************************************************************* - /* jump to replacement function */ + Emit a trap instruction and return the original machine code. - M_PUSH_IMM(asm_replacement_out); - M_RET; +*******************************************************************************/ - /* add jump reference for COUNTDOWN points */ +uint32_t emit_trap(codegendata *cd) +{ + uint16_t mcode; - if (rplp->flags & RPLPOINT_FLAG_COUNTDOWN) { + /* Get machine code which is patched back in later. The + trap is 2 bytes long. */ - branchmpc = (s4)rplp->pc + (7 + 6); + mcode = *((uint16_t *) cd->mcodeptr); - md_codegen_patch_branch(cd, branchmpc, (s4) outcode); - } +#if 0 + /* XXX this breaks GDB, so we disable it for now */ + *(cd->mcodeptr++) = 0xcc; + M_INT3; +#else + M_UD2; +#endif - assert(((cd->mcodeptr - cd->mcodebase) - outcode) == REPLACEMENT_STUB_SIZE); - } + return (uint32_t) mcode; } -#endif /* defined(ENABLE_REPLACEMENT) */ - + /* emit_verbosecall_enter ****************************************************** @@ -641,20 +569,23 @@ void emit_replacement_stubs(jitdata *jd) void emit_verbosecall_enter(jitdata *jd) { methodinfo *m; + codeinfo *code; codegendata *cd; registerdata *rd; methoddesc *md; - s4 disp; - s4 i, t; + int32_t stackframesize; + int i; + int align_off; /* offset for alignment compensation */ if (!JITDATA_HAS_FLAG_VERBOSECALL(jd)) return; /* 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; @@ -662,63 +593,40 @@ void emit_verbosecall_enter(jitdata *jd) M_NOP; - /* methodinfo* + arguments + return address */ + /* keep stack 16-byte aligned */ - disp = TRACE_ARGS_NUM * 8 + 4 + INT_TMP_CNT * 4 + - cd->stackframesize * 4 + 4; + stackframesize = 2 + TMP_CNT; + ALIGN_2(stackframesize); - M_ASUB_IMM(TRACE_ARGS_NUM * 8 + 4 + INT_TMP_CNT * 4, REG_SP); + M_ASUB_IMM(stackframesize * 8, REG_SP); /* save temporary registers for leaf methods */ - for (i = 0; i < INT_TMP_CNT; i++) - M_IST(rd->tmpintregs[i], REG_SP, TRACE_ARGS_NUM * 8 + 4 + i * 4); - - for (i = 0; i < md->paramcount && i < TRACE_ARGS_NUM; i++) { - t = md->paramtypes[i].type; - - if (IS_INT_LNG_TYPE(t)) { - if (IS_2_WORD_TYPE(t)) { - M_LLD(REG_ITMP12_PACKED, REG_SP, disp); - M_LST(REG_ITMP12_PACKED, REG_SP, i * 8); - } - else if (IS_ADR_TYPE(t)) { - M_ALD(REG_ITMP1, REG_SP, disp); - M_AST(REG_ITMP1, REG_SP, i * 8); - M_IST_IMM(0, REG_SP, i * 8 + 4); - } - else { - M_ILD(EAX, REG_SP, disp); - emit_cltd(cd); - M_LST(EAX_EDX_PACKED, REG_SP, i * 8); - } - } - else { - if (IS_2_WORD_TYPE(t)) { - M_DLD(REG_NULL, REG_SP, disp); - M_DST(REG_NULL, REG_SP, i * 8); - } - else { - M_FLD(REG_NULL, REG_SP, disp); - M_FST(REG_NULL, REG_SP, i * 8); - M_IST_IMM(0, REG_SP, i * 8 + 4); - } - } - - disp += (IS_2_WORD_TYPE(t)) ? 8 : 4; + if (code_is_leafmethod(code)) { + for (i = 0; i < INT_TMP_CNT; i++) + M_IST(rd->tmpintregs[i], REG_SP, (2 + i) * 8); } - - M_AST_IMM(m, REG_SP, TRACE_ARGS_NUM * 8); - M_MOV_IMM(builtin_verbosecall_enter, REG_ITMP1); + /* no argument registers to save */ + + align_off = cd->stackframesize ? 4 : 0; + M_AST_IMM(m, REG_SP, 0 * 4); + M_AST_IMM(0, REG_SP, 1 * 4); + M_AST(REG_SP, REG_SP, 2 * 4); + M_IADD_IMM_MEMBASE(stackframesize * 8 + cd->stackframesize * 8 + 4 + align_off, REG_SP, 2 * 4); + M_MOV_IMM(trace_java_call_enter, REG_ITMP1); M_CALL(REG_ITMP1); + /* no argument registers to restore */ + /* restore temporary registers for leaf methods */ - for (i = 0; i < INT_TMP_CNT; i++) - M_ILD(rd->tmpintregs[i], REG_SP, TRACE_ARGS_NUM * 8 + 4 + i * 4); + if (code_is_leafmethod(code)) { + for (i = 0; i < INT_TMP_CNT; i++) + M_ILD(rd->tmpintregs[i], REG_SP, (2 + i) * 8); + } - M_AADD_IMM(TRACE_ARGS_NUM * 8 + 4 + INT_TMP_CNT * 4, REG_SP); + M_AADD_IMM(stackframesize * 8, REG_SP); /* mark trace code */ @@ -731,8 +639,6 @@ void emit_verbosecall_enter(jitdata *jd) Generates the code for the call trace. - void builtin_verbosecall_exit(s8 l, double d, float f, methodinfo *m); - *******************************************************************************/ #if !defined(NDEBUG) @@ -741,6 +647,7 @@ void emit_verbosecall_exit(jitdata *jd) methodinfo *m; codegendata *cd; registerdata *rd; + methoddesc *md; if (!JITDATA_HAS_FLAG_VERBOSECALL(jd)) return; @@ -751,25 +658,53 @@ void emit_verbosecall_exit(jitdata *jd) cd = jd->cd; rd = jd->rd; + md = m->parseddesc; + /* mark trace code */ M_NOP; - M_ASUB_IMM(8 + 8 + 4 + 4 + 8, REG_SP); /* +8: keep stack 16-byte aligned */ - - M_LST(REG_RESULT_PACKED, REG_SP, 0 * 8); - - M_DSTNP(REG_NULL, REG_SP, 1 * 8); - M_FSTNP(REG_NULL, REG_SP, 2 * 8); - - M_AST_IMM(m, REG_SP, 2 * 8 + 1 * 4); + /* keep stack 16-byte aligned */ + + M_ASUB_IMM(4 + 4 + 8, REG_SP); + + /* save return value */ + + switch (md->returntype.type) { + case TYPE_ADR: + case TYPE_INT: + M_IST(REG_RESULT, REG_SP, 2 * 4); + break; + case TYPE_LNG: + M_LST(REG_RESULT_PACKED, REG_SP, 2 * 4); + break; + case TYPE_FLT: + M_FSTNP(REG_NULL, REG_SP, 2 * 4); + break; + case TYPE_DBL: + M_DSTNP(REG_NULL, REG_SP, 2 * 4); + break; + } - M_MOV_IMM(builtin_verbosecall_exit, REG_ITMP1); + M_AST_IMM(m, REG_SP, 0 * 4); + M_AST(REG_SP, REG_SP, 1 * 4); + M_IADD_IMM_MEMBASE(2 * 4, REG_SP, 1 * 4); + M_MOV_IMM(trace_java_call_exit, REG_ITMP1); M_CALL(REG_ITMP1); - M_LLD(REG_RESULT_PACKED, REG_SP, 0 * 4); + /* restore return value */ + + switch (md->returntype.type) { + case TYPE_ADR: + case TYPE_INT: + M_ILD(REG_RESULT, REG_SP, 2 * 4); + break; + case TYPE_LNG: + M_LLD(REG_RESULT_PACKED, REG_SP, 2 * 4); + break; + } - M_AADD_IMM(8 + 8 + 4 + 4 + 8, REG_SP); + M_AADD_IMM(4 + 4 + 8, REG_SP); /* mark trace code */ @@ -992,6 +927,15 @@ void emit_movb_imm_membase(codegendata *cd, s4 imm, s4 basereg, s4 disp) } +void emit_movsbl_reg_reg(codegendata *cd, s4 a, s4 b) +{ + assert(a < 4); /* Can only operate on al, bl, cl, dl. */ + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0xbe; + emit_reg((b),(a)); +} + + void emit_movsbl_memindex_reg(codegendata *cd, s4 disp, s4 basereg, s4 indexreg, s4 scale, s4 reg) { COUNT(count_mov_mem_reg); @@ -1018,6 +962,15 @@ void emit_movswl_memindex_reg(codegendata *cd, s4 disp, s4 basereg, s4 indexreg, } +void emit_movzbl_reg_reg(codegendata *cd, s4 a, s4 b) +{ + assert(a < 4); /* Can only operate on al, bl, cl, dl. */ + *(cd->mcodeptr++) = 0x0f; + *(cd->mcodeptr++) = 0xb6; + emit_reg((b),(a)); +} + + void emit_movzwl_reg_reg(codegendata *cd, s4 a, s4 b) { *(cd->mcodeptr++) = 0x0f; @@ -1160,12 +1113,6 @@ void emit_dec_mem(codegendata *cd, s4 mem) } -void emit_cltd(codegendata *cd) -{ - *(cd->mcodeptr++) = 0x99; -} - - void emit_imul_reg_reg(codegendata *cd, s4 reg, s4 dreg) { *(cd->mcodeptr++) = 0x0f; @@ -1245,12 +1192,6 @@ void emit_idiv_reg(codegendata *cd, s4 reg) } -void emit_ret(codegendata *cd) -{ - *(cd->mcodeptr++) = 0xc3; -} - - /* * shift ops @@ -1406,12 +1347,6 @@ void emit_push_reg(codegendata *cd, s4 reg) } -void emit_nop(codegendata *cd) -{ - *(cd->mcodeptr++) = 0x90; -} - - void emit_lock(codegendata *cd) { *(cd->mcodeptr++) = 0xf0; @@ -1941,6 +1876,14 @@ void emit_fincstp(codegendata *cd) *(cd->mcodeptr++) = 0xf7; } +#if defined(ENABLE_ESCAPE_CHECK) +void emit_escape_check(codegendata *cd, s4 reg) { + M_PUSH(reg); + M_MOV_IMM(asm_escape_check, REG_ITMP3); + M_CALL(REG_ITMP3); + M_IADD_IMM(4, REG_SP); +} +#endif /* * These are local overrides for various environment variables in Emacs.