X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Fjit%2Fx86_64%2Femit.c;h=12aaf1e1e5d754962ebfc05c355727d6ff80c4f6;hb=c414f560a7e0b7636a780e6b933e91e441f80503;hp=9c777fb54a558b0545c5177ea11a2fdea6107ae3;hpb=0809f4a711ccc2537204c735daa18017680ced86;p=cacao.git diff --git a/src/vm/jit/x86_64/emit.c b/src/vm/jit/x86_64/emit.c index 9c777fb54..12aaf1e1e 100644 --- a/src/vm/jit/x86_64/emit.c +++ b/src/vm/jit/x86_64/emit.c @@ -1,6 +1,6 @@ /* src/vm/jit/x86_64/emit.c - x86_64 code emitter functions - Copyright (C) 1996-2005, 2006, 2007, 2008 + Copyright (C) 1996-2011 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO This file is part of CACAO. @@ -27,13 +27,14 @@ #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.hpp" @@ -48,7 +49,7 @@ #include "vm/jit/patcher-common.hpp" #include "vm/jit/replace.hpp" #include "vm/jit/trace.hpp" -#include "vm/jit/trap.h" +#include "vm/jit/trap.hpp" /* emit_load ******************************************************************* @@ -232,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. @@ -423,6 +434,19 @@ void emit_trap_compiler(codegendata *cd) } +/* 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; +} + + /* emit_trap ******************************************************************* Emit a trap instruction and return the original machine code. @@ -447,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. @@ -980,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)); @@ -2348,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. @@ -2360,4 +2671,5 @@ void emit_rdtsc(codegendata *cd) * c-basic-offset: 4 * tab-width: 4 * End: + * vim:noexpandtab:sw=4:ts=4: */