X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Fjit%2Farm%2Femit.c;h=f5617cd85cbc926b79e2e4d6c300c7eee1f81a93;hb=f703b1265fbfb70a3de51067803b6b211d5c5d4d;hp=26393f68ab8f16ba55431f5d6a83978229f13a29;hpb=219e4a46e3d127d3c0883ee2e8635b4fe3c94d60;p=cacao.git diff --git a/src/vm/jit/arm/emit.c b/src/vm/jit/arm/emit.c index 26393f68a..f5617cd85 100644 --- a/src/vm/jit/arm/emit.c +++ b/src/vm/jit/arm/emit.c @@ -34,9 +34,9 @@ #include "vm/jit/arm/codegen.h" -#include "mm/memory.h" +#include "mm/memory.hpp" -#include "threads/lock-common.h" +#include "threads/lock.hpp" #include "vm/global.h" @@ -47,9 +47,9 @@ #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" -#include "toolbox/logging.h" /* XXX for debugging only */ +#include "toolbox/logging.hpp" /* XXX for debugging only */ /* emit_load ******************************************************************* @@ -383,6 +383,27 @@ void emit_iconst(codegendata *cd, s4 d, s4 value) } +/** + * 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) +{ + int32_t disp; + + if (IS_IMM(value)) { + M_CMP_IMM(reg, value); + } else if (IS_IMM(-value)) { + M_CMN_IMM(reg, -value); + } else { + assert(reg != REG_ITMP3); + disp = dseg_add_s4(cd, value); + M_DSEG_LOAD(REG_ITMP3, disp); + M_CMP(reg, REG_ITMP3); + } +} + + /* emit_branch ***************************************************************** Emits the code for conditional and unconditional branchs. @@ -544,6 +565,14 @@ void emit_classcast_check(codegendata *cd, instruction *iptr, s4 condition, s4 r M_TRAPEQ(s1, TRAP_ClassCastException); break; + case BRANCH_NE: + M_TRAPNE(s1, TRAP_ClassCastException); + break; + + case BRANCH_LT: + M_TRAPLT(s1, TRAP_ClassCastException); + break; + case BRANCH_LE: M_TRAPLE(s1, TRAP_ClassCastException); break; @@ -573,6 +602,18 @@ void emit_exception_check(codegendata *cd, instruction *iptr) } +/* emit_trap_compiler ********************************************************** + + Emit a trap instruction which calls the JIT compiler. + +*******************************************************************************/ + +void emit_trap_compiler(codegendata *cd) +{ + M_TRAP(REG_METHODPTR, TRAP_COMPILER); +} + + /* emit_trap ******************************************************************* Emit a trap instruction and return the original machine code. @@ -594,6 +635,126 @@ uint32_t emit_trap(codegendata *cd) } +/** + * Emit code to recompute the procedure vector. + */ +void emit_recompute_pv(codegendata *cd) +{ + // This is used to recompute our PV (we use the IP for this) out + // of the current PC. + int32_t disp = (int32_t) (cd->mcodeptr - cd->mcodebase); + + // We use PC relative addressing. + disp += 8; + + // Sanity checks. + assert((disp & 0x03) == 0); + assert(disp >= 0 && disp <= 0x03ffffff); + + // ATTENTION: If you change this, you have to look at other functions + // as well! Following things depend on it: md_codegen_get_pv_from_pc(); + if (disp > 0x0003ffff) { + M_SUB_IMM(REG_PV, REG_PC, IMM_ROTL(disp >> 18, 9)); + M_SUB_IMM(REG_PV, REG_PV, IMM_ROTL(disp >> 10, 5)); + M_SUB_IMM(REG_PV, REG_PV, IMM_ROTL(disp >> 2, 1)); + } else if (disp > 0x000003ff) { + M_SUB_IMM(REG_PV, REG_PC, IMM_ROTL(disp >> 10, 5)); + M_SUB_IMM(REG_PV, REG_PV, IMM_ROTL(disp >> 2, 1)); + } else { + M_SUB_IMM(REG_PV, REG_PC, IMM_ROTL(disp >> 2, 1)); + } +} + + +/** + * Generates synchronization code to enter a monitor. + */ +#if defined(ENABLE_THREADS) +void emit_monitor_enter(jitdata* jd, int32_t syncslot_offset) +{ + int32_t disp; + + // Get required compiler data. + methodinfo* m = jd->m; + codegendata* cd = jd->cd; + +# if !defined(NDEBUG) + if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) { + M_STMFD(BITMASK_ARGS, REG_SP); + syncslot_offset += 4 * 4; + } +# endif + + /* get the correct lock object */ + + if (m->flags & ACC_STATIC) { + disp = dseg_add_address(cd, &m->clazz->object.header); + M_DSEG_LOAD(REG_A0, disp); + } + else { + emit_nullpointer_check_force(cd, NULL, REG_A0); + } + + M_STR(REG_A0, REG_SP, syncslot_offset); + disp = dseg_add_functionptr(cd, LOCK_monitor_enter); + M_DSEG_BRANCH(disp); + emit_recompute_pv(cd); + +# if !defined(NDEBUG) + if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) + M_LDMFD(BITMASK_ARGS, 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) +{ + int32_t disp; + + // Get required compiler data. + methodinfo* m = jd->m; + codegendata* cd = jd->cd; + + /* 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: + case TYPE_FLT: /* XXX TWISTI: is that correct? */ + case TYPE_DBL: + M_STMFD(BITMASK_RESULT, REG_SP); + syncslot_offset += 2 * 4; + break; + } + + M_LDR(REG_A0, REG_SP, syncslot_offset); + disp = dseg_add_functionptr(cd, LOCK_monitor_exit); + M_DSEG_BRANCH(disp); + + /* we no longer need PV here, no more loading */ + /*emit_recompute_pv(cd);*/ + + switch (md->returntype.type) { + case TYPE_INT: + case TYPE_ADR: + case TYPE_LNG: + case TYPE_FLT: /* XXX TWISTI: is that correct? */ + case TYPE_DBL: + M_LDMFD(BITMASK_RESULT, REG_SP); + break; + } +} +#endif + + /* emit_verbosecall_enter ****************************************************** Generates the code for the call trace. @@ -633,7 +794,6 @@ void emit_verbosecall_enter(jitdata *jd) if (!md->params[i].inmemory) { s = md->params[i].regoff; -#if defined(ENABLE_SOFTFLOAT) switch (md->paramtypes[i].type) { case TYPE_INT: case TYPE_FLT: @@ -645,30 +805,13 @@ void emit_verbosecall_enter(jitdata *jd) M_LST(s, REG_SP, i * 8); break; } -#else - switch (md->paramtypes[i].type) { - case TYPE_ADR: - case TYPE_INT: - M_IST(s, REG_SP, i * 8); - break; - case TYPE_LNG: - M_LST(s, REG_SP, i * 8); - break; - case TYPE_FLT: - M_FST(s, REG_SP, i * 8); - break; - case TYPE_DBL: - M_DST(s, REG_SP, i * 8); - break; - } -#endif } } disp = dseg_add_address(cd, m); M_DSEG_LOAD(REG_A0, disp); M_MOV(REG_A1, REG_SP); - M_ADD_IMM(REG_A2, REG_SP, md->paramcount * 8 + 2 * 4 + cd->stackframesize); + M_ADD_IMM(REG_A2, REG_SP, md->paramcount * 8 + 2 * 4 + cd->stackframesize * 8); M_LONGBRANCH(trace_java_call_enter); /* restore argument registers */ @@ -677,7 +820,6 @@ void emit_verbosecall_enter(jitdata *jd) if (!md->params[i].inmemory) { s = md->params[i].regoff; -#if defined(ENABLE_SOFTFLOAT) switch (md->paramtypes[i].type) { case TYPE_INT: case TYPE_FLT: @@ -689,23 +831,6 @@ void emit_verbosecall_enter(jitdata *jd) M_LLD(s, REG_SP, i * 8); break; } -#else - switch (md->paramtypes[i].type) { - case TYPE_ADR: - case TYPE_INT: - M_ILD(s, REG_SP, i * 8); - break; - case TYPE_LNG: - M_LLD(s, REG_SP, i * 8); - break; - case TYPE_FLT: - M_FLD(s, REG_SP, i * 8); - break; - case TYPE_DBL: - M_DLD(s, REG_SP, i * 8); - break; - } -#endif } } @@ -798,6 +923,58 @@ void emit_verbosecall_exit(jitdata *jd) #endif /* !defined(NDEBUG) */ +/** + * Emit profiling code for method frequency counting. + * Its slow but working, so be carefull, if you want to use it... + */ +#if defined(ENABLE_PROFILING) +void emit_profile_method(codegendata* cd, codeinfo* code) +{ + ICONST(REG_ITMP3,code); + M_LDR(REG_ITMP2,REG_ITMP3,OFFSET(codeinfo, frequency)); + M_ADD_IMM(REG_ITMP2, REG_ITMP2, 1); + M_STR(REG_ITMP2,REG_ITMP3,OFFSET(codeinfo, frequency)); +// M_TRAP(0, TRAP_DEBUG); +} + +#endif + +/** + * Emit profiling code for basicblock frequency counting. + * Its slow but working, so be carefull, if you want to use it... + */ +#if defined(ENABLE_PROFILING) +void emit_profile_basicblock(codegendata* cd, codeinfo* code, basicblock* bptr) +{ + ICONST(REG_ITMP3,code); + M_LDR(REG_ITMP2,REG_ITMP3,OFFSET(codeinfo, bbfrequency)); + M_ADD_IMM(REG_ITMP2, REG_ITMP2, 1); + M_STR(REG_ITMP2,REG_ITMP3,OFFSET(codeinfo, bbfrequency)); +} +#endif + + +/** + * Emit profiling code to start CPU cycle counting. + */ +#if defined(ENABLE_PROFILING) +void emit_profile_cycle_start(codegendata* cd, codeinfo* code) +{ + // XXX Not implemented yet! +} +#endif + + +/** + * Emit profiling code to stop CPU cycle counting. + */ +#if defined(ENABLE_PROFILING) +void emit_profile_cycle_stop(codegendata* cd, codeinfo* code) +{ + // XXX Not implemented yet! +} +#endif + /* * These are local overrides for various environment variables in Emacs. * Please do not remove this and leave it at the end of the file, where