X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Fjit%2Fx86_64%2Femit.c;h=12aaf1e1e5d754962ebfc05c355727d6ff80c4f6;hb=c414f560a7e0b7636a780e6b933e91e441f80503;hp=1c81412ee6ded1ad19728cb1fa266a295beca9a0;hpb=802ce8af05f0d14f8555e266031e574695721dc1;p=cacao.git diff --git a/src/vm/jit/x86_64/emit.c b/src/vm/jit/x86_64/emit.c index 1c81412ee..12aaf1e1e 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-2011 + CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO This file is part of CACAO. @@ -29,29 +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" -#include "threads/lock-common.h" +#include "threads/lock.hpp" -#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/patcher-common.h" -#include "vm/jit/replace.h" -#include "vm/jit/trace.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 ******************************************************************* @@ -111,7 +109,7 @@ 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; @@ -235,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. @@ -311,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); } } @@ -328,7 +336,7 @@ void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, 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); } } @@ -344,7 +352,7 @@ 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, EXCEPTION_HARDWARE_ARRAYSTORE); + M_ALD_MEM(REG_RESULT, TRAP_ArrayStoreException); } } @@ -362,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); } } @@ -387,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); } } @@ -403,7 +417,7 @@ 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); } } @@ -416,7 +430,20 @@ void emit_exception_check(codegendata *cd, instruction *iptr) void emit_trap_compiler(codegendata *cd) { - M_ALD_MEM(REG_METHODPTR, EXCEPTION_HARDWARE_COMPILER); + M_ALD_MEM(REG_METHODPTR, TRAP_COMPILER); +} + + +/* emit_patcher_alignment ****************************************************** + + Emit NOP to ensure placement at an even address. + +*******************************************************************************/ + +void emit_patcher_alignment(codegendata *cd) +{ + if ((uintptr_t) cd->mcodeptr & 1) + M_NOP; } @@ -444,6 +471,207 @@ uint32_t emit_trap(codegendata *cd) } +/** + * 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) +void emit_monitor_enter(jitdata* jd, int32_t syncslot_offset) +{ + int32_t p; + + // Get required compiler data. + methodinfo* m = jd->m; + codegendata* cd = jd->cd; + +# if !defined(NDEBUG) + if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) { + M_LSUB_IMM((INT_ARG_CNT + FLT_ARG_CNT) * 8, REG_SP); + + for (p = 0; p < INT_ARG_CNT; p++) + M_LST(abi_registers_integer_argument[p], REG_SP, p * 8); + + for (p = 0; p < FLT_ARG_CNT; p++) + M_DST(abi_registers_float_argument[p], REG_SP, (INT_ARG_CNT + p) * 8); + + syncslot_offset += (INT_ARG_CNT + FLT_ARG_CNT) * 8; + } +# endif + + /* decide which monitor enter function to call */ + + 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); + } + + M_AST(REG_A0, REG_SP, syncslot_offset); + M_MOV_IMM(LOCK_monitor_enter, REG_ITMP1); + M_CALL(REG_ITMP1); + +# 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 + + +/** + * 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; + + M_ALD(REG_A0, REG_SP, syncslot_offset); + + /* we need to save the proper return value */ + + methoddesc* md = m->parseddesc; + + 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; + } + + M_MOV_IMM(LOCK_monitor_exit, REG_ITMP1); + M_CALL(REG_ITMP1); + + /* 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 + + +/** + * 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 + + +/** + * 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 + + +/** + * 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); + + 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); + + M_POP(RDX); + M_POP(RAX); +} +#endif + + +/** + * 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(code, REG_ITMP3); + M_RDTSC; + M_IADD_MEMBASE(RAX, REG_ITMP3, OFFSET(codeinfo, cycles)); + M_IADC_MEMBASE(RDX, REG_ITMP3, OFFSET(codeinfo, cycles) + 4); + + M_POP(RDX); + M_POP(RAX); +} +#endif + + /* emit_verbosecall_enter ****************************************************** Generates the code for the call trace. @@ -977,6 +1205,85 @@ 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_arbitrary_nop(codegendata *cd, int disp) +{ + while (disp) { + int x = disp < 9 ? disp : 9; + emit_nop(cd, x); + disp -= x; + } +} + void emit_mov_reg_reg(codegendata *cd, s8 reg, s8 dreg) { emit_rex(1,(reg),0,(dreg)); @@ -1180,6 +1487,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)); @@ -1361,12 +1678,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)); @@ -1376,18 +1693,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)); @@ -1439,6 +1769,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) { @@ -1447,6 +1789,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) { @@ -1679,6 +2028,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)); @@ -2291,6 +2652,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. @@ -2303,4 +2671,5 @@ void emit_rdtsc(codegendata *cd) * c-basic-offset: 4 * tab-width: 4 * End: + * vim:noexpandtab:sw=4:ts=4: */