X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Fjit%2Farm%2Fcodegen.c;h=b82661a1d997e17bfb0d2ea77f5961f1c8d4f72a;hb=278063eaf49b3b3fc68b40cc7fc4172a065f4e99;hp=d2c42dd0a281c44341c0de573f939eb6b967e753;hpb=d969014454626b778b743698246fb5cf695d9fc7;p=cacao.git diff --git a/src/vm/jit/arm/codegen.c b/src/vm/jit/arm/codegen.c index d2c42dd0a..b82661a1d 100644 --- a/src/vm/jit/arm/codegen.c +++ b/src/vm/jit/arm/codegen.c @@ -1,9 +1,7 @@ /* src/vm/jit/arm/codegen.c - machine code generator for Arm - 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. @@ -37,167 +35,81 @@ #include "vm/jit/arm/arch.h" #include "vm/jit/arm/codegen.h" -#include "mm/memory.h" +#include "mm/memory.hpp" -#include "native/localref.h" -#include "native/native.h" +#include "native/localref.hpp" +#include "native/native.hpp" -#include "threads/lock-common.h" +#include "threads/lock.hpp" -#include "vm/builtin.h" -#include "vm/exceptions.h" +#include "vm/jit/builtin.hpp" +#include "vm/exceptions.hpp" #include "vm/global.h" -#include "vm/vm.h" +#include "vm/loader.hpp" +#include "vm/options.h" +#include "vm/vm.hpp" #include "vm/jit/abi.h" #include "vm/jit/asmpart.h" -#include "vm/jit/codegen-common.h" +#include "vm/jit/codegen-common.hpp" #include "vm/jit/dseg.h" -#include "vm/jit/emit-common.h" -#include "vm/jit/jit.h" -#include "vm/jit/md.h" +#include "vm/jit/emit-common.hpp" +#include "vm/jit/jit.hpp" +#include "vm/jit/linenumbertable.hpp" #include "vm/jit/methodheader.h" -#include "vm/jit/parse.h" -#include "vm/jit/patcher-common.h" +#include "vm/jit/parse.hpp" +#include "vm/jit/patcher-common.hpp" #include "vm/jit/reg.h" -#if defined(ENABLE_LSRA) -#include "vm/jit/allocator/lsra.h" -#endif - -#include "vmcore/loader.h" -#include "vmcore/options.h" - - -/* codegen_emit **************************************************************** - Generates machine code. - -*******************************************************************************/ - -bool codegen_emit(jitdata *jd) +/** + * Generates machine code for the method prolog. + */ +void codegen_emit_prolog(jitdata* jd) { - methodinfo *m; - codeinfo *code; - codegendata *cd; - registerdata *rd; - s4 i, t, len; - s4 s1, s2, s3, d; - s4 disp; - varinfo *var; - basicblock *bptr; - instruction *iptr; - exception_entry *ex; - - s4 spilledregs_num; - s4 savedregs_num; - u2 savedregs_bitmask; - u2 currentline; - - methodinfo *lm; /* local methodinfo for ICMD_INVOKE* */ - unresolved_method *um; - builtintable_entry *bte; - methoddesc *md; - fieldinfo *fi; - unresolved_field *uf; - int fieldtype; - int varindex; - - /* get required compiler data */ - - m = jd->m; - code = jd->code; - cd = jd->cd; - rd = jd->rd; - - /* prevent compiler warnings */ - - lm = NULL; - um = NULL; - bte = NULL; - - fieldtype = -1; - - /* space to save used callee saved registers */ - - savedregs_num = (jd->isleafmethod) ? 0 : 1; /* space to save the LR */ - savedregs_num += (INT_SAV_CNT - rd->savintreguse); - /*savedregs_num += (FLT_SAV_CNT - rd->savfltreguse);*/ - assert((FLT_SAV_CNT - rd->savfltreguse) == 0); - - spilledregs_num = rd->memuse; - -#if defined(ENABLE_THREADS) /* space to save argument of monitor_enter */ - if (checksync && (m->flags & ACC_SYNCHRONIZED)) - spilledregs_num++; -#endif - - cd->stackframesize = spilledregs_num * 8 + savedregs_num * 4; - - /* XXX QUICK FIX: We shouldn't align the stack in Java code, but - only in native stubs. */ - /* align stack to 8-byte */ - - cd->stackframesize = (cd->stackframesize + 4) & ~4; - - /* SECTION: Method Header */ - /* create method header */ - - (void) dseg_add_unique_address(cd, code); /* CodeinfoPointer */ - (void) dseg_add_unique_s4(cd, cd->stackframesize); /* FrameSize */ - -#if defined(ENABLE_THREADS) - /* IsSync contains the offset relative to the stack pointer for the - argument of monitor_exit used in the exception handler. Since the - offset could be zero and give a wrong meaning of the flag it is - offset by one. - */ - - if (checksync && (m->flags & ACC_SYNCHRONIZED)) - (void) dseg_add_unique_s4(cd, rd->memuse * 8 + 4);/* IsSync */ - else -#endif - (void) dseg_add_unique_s4(cd, 0); /* IsSync */ - - (void) dseg_add_unique_s4(cd, jd->isleafmethod); /* IsLeaf */ - (void) dseg_add_unique_s4(cd, INT_SAV_CNT - rd->savintreguse); /* IntSave */ - (void) dseg_add_unique_s4(cd, FLT_SAV_CNT - rd->savfltreguse); /* FltSave */ - (void) dseg_addlinenumbertablesize(cd); - (void) dseg_add_unique_s4(cd, jd->exceptiontablelength); /* ExTableSize */ - - /* create exception table */ - - for (ex = jd->exceptiontable; ex != NULL; ex = ex->down) { - dseg_add_target(cd, ex->start); - dseg_add_target(cd, ex->end); - dseg_add_target(cd, ex->handler); - (void) dseg_add_unique_address(cd, ex->catchtype.any); - } - - /* save return address and used callee saved registers */ - - savedregs_bitmask = 0; - - if (!jd->isleafmethod) + varinfo* var; + methoddesc* md; + int32_t s1; + int32_t t, len; + int32_t varindex; + int i; + + // Get required compiler data. + methodinfo* m = jd->m; + codeinfo* code = jd->code; + codegendata* cd = jd->cd; + registerdata* rd = jd->rd; + + int32_t savedregs_num = 0; + uint32_t savedregs_bitmask = 0; + + if (!code_is_leafmethod(code)) { + savedregs_num++; savedregs_bitmask = (1<= rd->savintreguse; i--) + for (i = INT_SAV_CNT - 1; i >= rd->savintreguse; i--) { + savedregs_num++; savedregs_bitmask |= (1<<(rd->savintregs[i])); + } #if !defined(NDEBUG) for (i = FLT_SAV_CNT - 1; i >= rd->savfltreguse; i--) { - log_text("!!! CODEGEN: floating-point callee saved registers are not saved to stack (SEVERE! STACK IS MESSED UP!)"); - /* TODO: floating-point */ + vm_abort("codegen_emit_prolog: Floating-point callee saved registers are not saved to stack"); } #endif - if (savedregs_bitmask) + /* save return address and used callee saved registers */ + + if (savedregs_bitmask != 0) M_STMFD(savedregs_bitmask, REG_SP); /* create additional stack frame for spilled variables (if necessary) */ - if ((cd->stackframesize / 4 - savedregs_num) > 0) - M_SUB_IMM_EXT_MUL4(REG_SP, REG_SP, cd->stackframesize / 4 - savedregs_num); + int32_t additional_bytes = (cd->stackframesize * 8 - savedregs_num * 4); + + if (additional_bytes > 0) + M_SUB_IMM_EXT_MUL4(REG_SP, REG_SP, additional_bytes / 4); /* take arguments out of register or stack frame */ @@ -236,13 +148,13 @@ bool codegen_emit(jitdata *jd) else { /* stack arguments */ if (!(var->flags & INMEMORY)) { /* stack arg -> register */ if (IS_2_WORD_TYPE(t)) - M_LLD(var->vv.regoff, REG_SP, cd->stackframesize + s1); + M_LLD(var->vv.regoff, REG_SP, cd->stackframesize * 8 + s1); else - M_ILD(var->vv.regoff, REG_SP, cd->stackframesize + s1); + M_ILD(var->vv.regoff, REG_SP, cd->stackframesize * 8 + s1); } else { /* stack arg -> spilled */ /* Reuse Memory Position on Caller Stack */ - var->vv.regoff = cd->stackframesize + s1; + var->vv.regoff = cd->stackframesize * 8 + s1; } } #if !defined(ENABLE_SOFTFLOAT) @@ -250,7 +162,10 @@ bool codegen_emit(jitdata *jd) else { if (!md->params[i].inmemory) { if (!(var->flags & INMEMORY)) { - M_CAST_INT_TO_FLT_TYPED(t, s1, var->vv.regoff); + if (IS_2_WORD_TYPE(t)) + M_CAST_L2D(s1, var->vv.regoff); + else + M_CAST_I2F(s1, var->vv.regoff); } else { if (IS_2_WORD_TYPE(t)) @@ -262,153 +177,93 @@ bool codegen_emit(jitdata *jd) else { if (!(var->flags & INMEMORY)) { if (IS_2_WORD_TYPE(t)) - M_DLD(var->vv.regoff, REG_SP, cd->stackframesize + s1); + M_DLD(var->vv.regoff, REG_SP, cd->stackframesize * 8 + s1); else - M_FLD(var->vv.regoff, REG_SP, cd->stackframesize + s1); + M_FLD(var->vv.regoff, REG_SP, cd->stackframesize * 8 + s1); } else { /* Reuse Memory Position on Caller Stack */ - var->vv.regoff = cd->stackframesize + s1; + var->vv.regoff = cd->stackframesize * 8 + s1; } } } #endif /* !defined(ENABLE_SOFTFLOAT) */ } +} -#if defined(ENABLE_THREADS) - /* call monitorenter function */ - - if (checksync && (m->flags & ACC_SYNCHRONIZED)) { - /* stack offset for monitor argument */ - - s1 = rd->memuse * 8; - -# if !defined(NDEBUG) - if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) { - M_STMFD(BITMASK_ARGS, REG_SP); - s1 += 4 * 4; - } -# endif - /* get the correct lock object */ +/** + * Generates machine code for the method epilog. + */ +void codegen_emit_epilog(jitdata* jd) +{ + int i; - if (m->flags & ACC_STATIC) { - disp = dseg_add_address(cd, &m->class->object.header); - M_DSEG_LOAD(REG_A0, disp); - } - else { - emit_nullpointer_check_force(cd, iptr, REG_A0); - } + // Get required compiler data. + codeinfo* code = jd->code; + codegendata* cd = jd->cd; + registerdata* rd = jd->rd; - M_STR(REG_A0, REG_SP, s1); - disp = dseg_add_functionptr(cd, LOCK_monitor_enter); - M_DSEG_BRANCH(disp); - s1 = (s4) (cd->mcodeptr - cd->mcodebase); - M_RECOMPUTE_PV(s1); + int32_t savedregs_num = 0; + uint32_t savedregs_bitmask = 0; -# if !defined(NDEBUG) - if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) - M_LDMFD(BITMASK_ARGS, REG_SP); -# endif + if (!code_is_leafmethod(code)) { + savedregs_num++; + savedregs_bitmask = (1<basicblocks; bptr != NULL; bptr = bptr->next) { - - bptr->mpc = (s4) (cd->mcodeptr - cd->mcodebase); - - /* is this basic block reached? */ - - if (bptr->flags < BBREACHED) - continue; - /* branch resolving */ - - codegen_resolve_branchrefs(cd, bptr); - - /* handle replacement points */ - REPLACEMENT_POINT_BLOCK_START(cd, bptr); + for (i = INT_SAV_CNT - 1; i >= rd->savintreguse; i--) { + savedregs_num++; + savedregs_bitmask |= (1<<(rd->savintregs[i])); + } - /* copy interface registers to their destination */ + /* deallocate stackframe for spilled variables */ - len = bptr->indepth; + int32_t additional_bytes = (cd->stackframesize * 8 - savedregs_num * 4); - MCODECHECK(64+len); + if (additional_bytes > 0) + M_ADD_IMM_EXT_MUL4(REG_SP, REG_SP, additional_bytes / 4); -#if defined(ENABLE_LSRA) - if (opt_lsra) { - while (len) { - len--; - var = VAR(bptr->invars[len]); - if ((len == bptr->indepth-1) && (bptr->type == BBTYPE_EXH)) { - if (!(var->flags & INMEMORY)) - d= var->vv.regoff; - else - d=REG_ITMP1; - M_INTMOVE(REG_ITMP1, d); - emit_store(jd, NULL, var, d); - } - } - } else { -#endif - while (len) { - len--; - var = VAR(bptr->invars[len]); + /* restore callee saved registers + do return */ - if ((len == bptr->indepth-1) && (bptr->type == BBTYPE_EXH)) { - d = codegen_reg_of_var(0, var, REG_ITMP1); - M_INTMOVE(REG_ITMP1, d); - emit_store(jd, NULL, var, d); - } - else { - assert((var->flags & INOUT)); - } + if (savedregs_bitmask) { + if (!code_is_leafmethod(code)) { + savedregs_bitmask &= ~(1<icount; - currentline = 0; - for (iptr = bptr->iinstr; len > 0; len--, iptr++) { + /* if LR was not on stack, we need to return manually */ - /* add line number */ - if (iptr->line != currentline) { - dseg_addlinenumber(cd, iptr->line); - currentline = iptr->line; - } + if (code_is_leafmethod(code)) + M_MOV(REG_PC, REG_LR); +} - MCODECHECK(64); /* an instruction usually needs < 64 words */ - /* the big switch */ - switch (iptr->opc) { - case ICMD_NOP: /* ... ==> ... */ - break; +/** + * Generates machine code for one ICMD. + */ +void codegen_emit_instruction(jitdata* jd, instruction* iptr) +{ + varinfo* var; + builtintable_entry* bte; + methoddesc* md; + methodinfo* lm; // Local methodinfo for ICMD_INVOKE*. + unresolved_method* um; + fieldinfo* fi; + unresolved_field* uf; + int32_t fieldtype; + int32_t s1, s2, s3, d; + int32_t disp; - /* constant operations ************************************************/ + // Get required compiler data. + codegendata* cd = jd->cd; - case ICMD_ICONST: /* ... ==> ..., constant */ + /* the big switch */ + switch (iptr->opc) { - d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); - ICONST(d, iptr->sx.val.i); - emit_store_dst(jd, iptr, d); - break; + /* constant operations ************************************************/ case ICMD_ACONST: /* ... ==> ..., constant */ @@ -419,9 +274,6 @@ bool codegen_emit(jitdata *jd) patcher_add_patch_ref(jd, PATCHER_resolve_classref_to_classinfo, iptr->sx.val.c.ref, disp); - if (opt_showdisassemble) - M_NOP; - M_DSEG_LOAD(d, disp); } else { @@ -430,13 +282,6 @@ bool codegen_emit(jitdata *jd) emit_store_dst(jd, iptr, d); break; - case ICMD_LCONST: /* ... ==> ..., constant */ - - d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED); - LCONST(d, iptr->sx.val.l); - emit_store_dst(jd, iptr, d); - break; - case ICMD_FCONST: /* ... ==> ..., constant */ #if defined(ENABLE_SOFTFLOAT) @@ -464,38 +309,6 @@ bool codegen_emit(jitdata *jd) break; - /* load/store/copy/move operations ************************************/ - - case ICMD_ILOAD: /* ... ==> ..., content of local variable */ - case ICMD_ALOAD: /* op1 = local variable */ - case ICMD_FLOAD: - case ICMD_LLOAD: - case ICMD_DLOAD: - case ICMD_ISTORE: /* ..., value ==> ... */ - case ICMD_FSTORE: - case ICMD_LSTORE: - case ICMD_DSTORE: - case ICMD_COPY: - case ICMD_MOVE: - - emit_copy(jd, iptr); - break; - - case ICMD_ASTORE: - if (!(iptr->flags.bits & INS_FLAG_RETADDR)) - emit_copy(jd, iptr); - break; - - /* pop operations *****************************************************/ - - /* attention: double and longs are only one entry in CACAO ICMDs */ - - case ICMD_POP: /* ..., value ==> ... */ - case ICMD_POP2: /* ..., value, value ==> ... */ - - break; - - /* integer operations *************************************************/ case ICMD_INT2BYTE: /* ..., value ==> ..., value */ @@ -705,8 +518,7 @@ bool codegen_emit(jitdata *jd) M_DSEG_BRANCH(disp); /* recompute pv */ - s1 = (s4) (cd->mcodeptr - cd->mcodebase); - M_RECOMPUTE_PV(s1); + emit_recompute_pv(cd); /* move result into destination register */ d = codegen_reg_of_dst(jd, iptr, REG_RESULT); @@ -734,8 +546,7 @@ bool codegen_emit(jitdata *jd) M_DSEG_BRANCH(disp); /* recompute pv */ - s1 = (s4) (cd->mcodeptr - cd->mcodebase); - M_RECOMPUTE_PV(s1); + emit_recompute_pv(cd); /* move result into destination register */ d = codegen_reg_of_dst(jd, iptr, REG_RESULT_PACKED); @@ -922,7 +733,7 @@ bool codegen_emit(jitdata *jd) s1 = emit_load_s1(jd, iptr, REG_FTMP1); d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); - M_MNFS(d, s1); + M_FNEG(s1, d); emit_store_dst(jd, iptr, d); break; @@ -931,7 +742,7 @@ bool codegen_emit(jitdata *jd) s1 = emit_load_s1(jd, iptr, REG_FTMP1); s2 = emit_load_s2(jd, iptr, REG_FTMP2); d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); - M_ADFS(d, s1, s2); + M_FADD(s1, s2, d); emit_store_dst(jd, iptr, d); break; @@ -940,7 +751,7 @@ bool codegen_emit(jitdata *jd) s1 = emit_load_s1(jd, iptr, REG_FTMP1); s2 = emit_load_s2(jd, iptr, REG_FTMP2); d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); - M_SUFS(d, s1, s2); + M_FSUB(s1, s2, d); emit_store_dst(jd, iptr, d); break; @@ -949,7 +760,7 @@ bool codegen_emit(jitdata *jd) s1 = emit_load_s1(jd, iptr, REG_FTMP1); s2 = emit_load_s2(jd, iptr, REG_FTMP2); d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); - M_MUFS(d, s1, s2); + M_FMUL(s1, s2, d); emit_store_dst(jd, iptr, d); break; @@ -957,13 +768,14 @@ bool codegen_emit(jitdata *jd) s1 = emit_load_s1(jd, iptr, REG_FTMP1); s2 = emit_load_s2(jd, iptr, REG_FTMP2); d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); - M_DVFS(d, s1, s2); + M_FDIV(s1, s2, d); emit_store_dst(jd, iptr, d); break; /* ATTENTION: Jave does not want IEEE behaviour in FREM, do not use this */ +#if 0 case ICMD_FREM: /* ..., val1, val2 ==> ..., val1 % val2 */ s1 = emit_load_s1(jd, iptr, REG_FTMP1); @@ -972,12 +784,13 @@ bool codegen_emit(jitdata *jd) M_RMFS(d, s1, s2); emit_store_dst(jd, iptr, d); break; +#endif case ICMD_DNEG: /* ..., value ==> ..., - value */ s1 = emit_load_s1(jd, iptr, REG_FTMP1); d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); - M_MNFD(d, s1); + M_DNEG(s1, d); emit_store_dst(jd, iptr, d); break; @@ -986,7 +799,7 @@ bool codegen_emit(jitdata *jd) s1 = emit_load_s1(jd, iptr, REG_FTMP1); s2 = emit_load_s2(jd, iptr, REG_FTMP2); d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); - M_ADFD(d, s1, s2); + M_DADD(s1, s2, d); emit_store_dst(jd, iptr, d); break; @@ -995,7 +808,7 @@ bool codegen_emit(jitdata *jd) s1 = emit_load_s1(jd, iptr, REG_FTMP1); s2 = emit_load_s2(jd, iptr, REG_FTMP2); d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); - M_SUFD(d, s1, s2); + M_DSUB(s1, s2, d); emit_store_dst(jd, iptr, d); break; @@ -1004,7 +817,7 @@ bool codegen_emit(jitdata *jd) s1 = emit_load_s1(jd, iptr, REG_FTMP1); s2 = emit_load_s2(jd, iptr, REG_FTMP2); d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); - M_MUFD(d, s1, s2); + M_DMUL(s1, s2, d); emit_store_dst(jd, iptr, d); break; @@ -1013,13 +826,14 @@ bool codegen_emit(jitdata *jd) s1 = emit_load_s1(jd, iptr, REG_FTMP1); s2 = emit_load_s2(jd, iptr, REG_FTMP2); d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); - M_DVFD(d, s1, s2); + M_DDIV(s1, s2, d); emit_store_dst(jd, iptr, d); break; /* ATTENTION: Jave does not want IEEE behaviour in DREM, do not use this */ +#if 0 case ICMD_DREM: /* ..., val1, val2 ==> ..., val1 % val2 */ s1 = emit_load_s1(jd, iptr, REG_FTMP1); @@ -1028,12 +842,18 @@ bool codegen_emit(jitdata *jd) M_RMFD(d, s1, s2); emit_store_dst(jd, iptr, d); break; +#endif case ICMD_I2F: /* ..., value ==> ..., (float) value */ s1 = emit_load_s1(jd, iptr, REG_ITMP1); d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); - M_FLTS(d, s1); +#if defined(__VFP_FP__) + M_FMSR(s1, d); + M_CVTIF(d, d); +#else + M_CVTIF(s1, d); +#endif emit_store_dst(jd, iptr, d); break; @@ -1041,7 +861,12 @@ bool codegen_emit(jitdata *jd) s1 = emit_load_s1(jd, iptr, REG_ITMP1); d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); - M_FLTD(d, s1); +#if defined(__VFP_FP__) + M_FMSR(s1, d); + M_CVTID(d, d); +#else + M_CVTID(s1, d); +#endif emit_store_dst(jd, iptr, d); break; @@ -1049,11 +874,16 @@ bool codegen_emit(jitdata *jd) s1 = emit_load_s1(jd, iptr, REG_FTMP1); d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); +#if defined(__VFP_FP__) + M_CVTFI(s1, REG_FTMP2); + M_FMRS(REG_FTMP2, d); +#else /* this uses round towards zero, as Java likes it */ - M_FIX(d, s1); + M_CVTFI(s1, d); /* this checks for NaN; to return zero as Java likes it */ - M_CMF(s1, 0x8); + M_FCMP(s1, 0x8); M_MOVVS_IMM(0, d); +#endif emit_store_dst(jd, iptr, d); break; @@ -1061,11 +891,16 @@ bool codegen_emit(jitdata *jd) s1 = emit_load_s1(jd, iptr, REG_FTMP1); d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); +#if defined(__VFP_FP__) + M_CVTDI(s1, REG_FTMP2); + M_FMRS(REG_FTMP2, d); +#else /* this uses round towards zero, as Java likes it */ - M_FIX(d, s1); + M_CVTDI(s1, d); /* this checks for NaN; to return zero as Java likes it */ - M_CMF(s1, 0x8); + M_DCMP(s1, 0x8); M_MOVVS_IMM(0, d); +#endif emit_store_dst(jd, iptr, d); break; @@ -1073,7 +908,7 @@ bool codegen_emit(jitdata *jd) s1 = emit_load_s1(jd, iptr, REG_FTMP1); d = codegen_reg_of_dst(jd, iptr, REG_FTMP2); - M_MVFS(d,s1); + M_CVTDF(s1, d); emit_store_dst(jd, iptr, d); break; @@ -1081,7 +916,7 @@ bool codegen_emit(jitdata *jd) s1 = emit_load_s1(jd, iptr, REG_FTMP1); d = codegen_reg_of_dst(jd, iptr, REG_FTMP2); - M_MVFD(d,s1); + M_CVTFD(s1, d); emit_store_dst(jd, iptr, d); break; @@ -1090,8 +925,11 @@ bool codegen_emit(jitdata *jd) s1 = emit_load_s1(jd, iptr, REG_FTMP1); s2 = emit_load_s2(jd, iptr, REG_FTMP2); d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); - M_CMF(s2, s1); + M_FCMP(s2, s1); M_MOV_IMM(d, 0); +#if defined(__VFP_FP__) + M_FMSTAT; /* on VFP we need to transfer the flags */ +#endif M_SUBGT_IMM(d, d, 1); M_ADDLT_IMM(d, d, 1); emit_store_dst(jd, iptr, d); @@ -1102,8 +940,11 @@ bool codegen_emit(jitdata *jd) s1 = emit_load_s1(jd, iptr, REG_FTMP1); s2 = emit_load_s2(jd, iptr, REG_FTMP2); d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); - M_CMF(s2, s1); + M_DCMP(s2, s1); M_MOV_IMM(d, 0); +#if defined(__VFP_FP__) + M_FMSTAT; /* on VFP we need to transfer the flags */ +#endif M_SUBGT_IMM(d, d, 1); M_ADDLT_IMM(d, d, 1); emit_store_dst(jd, iptr, d); @@ -1114,8 +955,11 @@ bool codegen_emit(jitdata *jd) s1 = emit_load_s1(jd, iptr, REG_FTMP1); s2 = emit_load_s2(jd, iptr, REG_FTMP2); d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); - M_CMF(s1, s2); + M_FCMP(s1, s2); M_MOV_IMM(d, 0); +#if defined(__VFP_FP__) + M_FMSTAT; /* on VFP we need to transfer the flags */ +#endif M_SUBLT_IMM(d, d, 1); M_ADDGT_IMM(d, d, 1); emit_store_dst(jd, iptr, d); @@ -1126,8 +970,11 @@ bool codegen_emit(jitdata *jd) s1 = emit_load_s1(jd, iptr, REG_FTMP1); s2 = emit_load_s2(jd, iptr, REG_FTMP2); d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); - M_CMF(s1, s2); + M_DCMP(s1, s2); M_MOV_IMM(d, 0); +#if defined(__VFP_FP__) + M_FMSTAT; /* on VFP we need to transfer the flags */ +#endif M_SUBLT_IMM(d, d, 1); M_ADDGT_IMM(d, d, 1); emit_store_dst(jd, iptr, d); @@ -1138,15 +985,6 @@ bool codegen_emit(jitdata *jd) /* memory operations **************************************************/ - case ICMD_ARRAYLENGTH: /* ..., arrayref ==> ..., length */ - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); - /* implicit null-pointer check */ - M_ILD_INTERN(d, s1, OFFSET(java_array_t, size)); - emit_store_dst(jd, iptr, d); - break; - case ICMD_BALOAD: /* ..., arrayref, index ==> ..., value */ s1 = emit_load_s1(jd, iptr, REG_ITMP1); @@ -1358,8 +1196,7 @@ bool codegen_emit(jitdata *jd) M_DSEG_BRANCH(disp); /* recompute pv */ - s1 = (s4) (cd->mcodeptr - cd->mcodebase); - M_RECOMPUTE_PV(s1); + emit_recompute_pv(cd); /* check resturn value of builtin */ emit_arraystore_check(cd, iptr); @@ -1372,123 +1209,6 @@ bool codegen_emit(jitdata *jd) M_STR_INTERN(s3, REG_ITMP1, OFFSET(java_objectarray_t, data[0])); break; - case ICMD_GETSTATIC: /* ... ==> ..., value */ - - if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - uf = iptr->sx.s23.s3.uf; - fieldtype = uf->fieldref->parseddesc.fd->type; - disp = dseg_add_unique_address(cd, NULL); - - patcher_add_patch_ref(jd, PATCHER_get_putstatic, uf, disp); - - if (opt_showdisassemble) - M_NOP; - } - else { - fi = iptr->sx.s23.s3.fmiref->p.field; - fieldtype = fi->type; - disp = dseg_add_address(cd, fi->value); - - if (!CLASS_IS_OR_ALMOST_INITIALIZED(fi->class)) { - patcher_add_patch_ref(jd, PATCHER_initialize_class, - fi->class, 0); - - if (opt_showdisassemble) - M_NOP; - } - } - - M_DSEG_LOAD(REG_ITMP3, disp); - switch (fieldtype) { - case TYPE_INT: -#if defined(ENABLE_SOFTFLOAT) - case TYPE_FLT: -#endif - case TYPE_ADR: - d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); - M_ILD_INTERN(d, REG_ITMP3, 0); - break; - case TYPE_LNG: -#if defined(ENABLE_SOFTFLOAT) - case TYPE_DBL: -#endif - d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED); - M_LLD_INTERN(d, REG_ITMP3, 0); - break; -#if !defined(ENABLE_SOFTFLOAT) - case TYPE_FLT: - d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); - M_FLD_INTERN(d, REG_ITMP3, 0); - break; - case TYPE_DBL: - d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); - M_DLD_INTERN(d, REG_ITMP3, 0); - break; -#endif - default: - assert(0); - } - emit_store_dst(jd, iptr, d); - break; - - case ICMD_PUTSTATIC: /* ..., value ==> ... */ - - if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - uf = iptr->sx.s23.s3.uf; - fieldtype = uf->fieldref->parseddesc.fd->type; - disp = dseg_add_unique_address(cd, NULL); - - patcher_add_patch_ref(jd, PATCHER_get_putstatic, uf, disp); - - if (opt_showdisassemble) - M_NOP; - } - else { - fi = iptr->sx.s23.s3.fmiref->p.field; - fieldtype = fi->type; - disp = dseg_add_address(cd, fi->value); - - if (!CLASS_IS_OR_ALMOST_INITIALIZED(fi->class)) { - patcher_add_patch_ref(jd, PATCHER_initialize_class, - fi->class, 0); - - if (opt_showdisassemble) - M_NOP; - } - } - - M_DSEG_LOAD(REG_ITMP3, disp); - switch (fieldtype) { - case TYPE_INT: -#if defined(ENABLE_SOFTFLOAT) - case TYPE_FLT: -#endif - case TYPE_ADR: - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - M_IST_INTERN(s1, REG_ITMP3, 0); - break; - case TYPE_LNG: -#if defined(ENABLE_SOFTFLOAT) - case TYPE_DBL: -#endif - s1 = emit_load_s1(jd, iptr, REG_ITMP12_PACKED); - M_LST_INTERN(s1, REG_ITMP3, 0); - break; -#if !defined(ENABLE_SOFTFLOAT) - case TYPE_FLT: - s1 = emit_load_s1(jd, iptr, REG_FTMP1); - M_FST_INTERN(s1, REG_ITMP3, 0); - break; - case TYPE_DBL: - s1 = emit_load_s1(jd, iptr, REG_FTMP1); - M_DST_INTERN(s1, REG_ITMP3, 0); - break; -#endif - default: - assert(0); - } - break; - case ICMD_GETFIELD: /* ..., objectref, value ==> ... */ s1 = emit_load_s1(jd, iptr, REG_ITMP3); @@ -1517,9 +1237,6 @@ bool codegen_emit(jitdata *jd) uf = iptr->sx.s23.s3.uf; patcher_add_patch_ref(jd, PATCHER_get_putfield, uf, 0); - - if (opt_showdisassemble) - M_NOP; } switch (fieldtype) { @@ -1605,9 +1322,6 @@ bool codegen_emit(jitdata *jd) uf = iptr->sx.s23.s3.uf; patcher_add_patch_ref(jd, PATCHER_get_putfield, uf, 0); - - if (opt_showdisassemble) - M_NOP; } switch (fieldtype) { @@ -1642,15 +1356,6 @@ bool codegen_emit(jitdata *jd) case ICMD_ATHROW: /* ..., objectref ==> ... (, objectref) */ - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - M_INTMOVE(s1, REG_ITMP1_XPTR); - if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - patcher_add_patch_ref(jd, PATCHER_resolve_class, - iptr->sx.s23.s2.uc, 0); - - if (opt_showdisassemble) - M_NOP; - } disp = dseg_add_functionptr(cd, asm_handle_exception); M_DSEG_LOAD(REG_ITMP3, disp); M_MOV(REG_ITMP2_XPC, REG_PC); @@ -1659,37 +1364,6 @@ bool codegen_emit(jitdata *jd) /* of basic block */ break; - case ICMD_GOTO: /* ... ==> ... */ - case ICMD_RET: - - emit_br(cd, iptr->dst.block); - break; - - case ICMD_JSR: /* ... ==> ... */ - - emit_br(cd, iptr->sx.s23.s3.jsrtarget.block); - break; - - case ICMD_IFNULL: /* ..., value ==> ... */ - case ICMD_IFNONNULL: - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - M_TEQ_IMM(s1, 0); - emit_bcc(cd, iptr->dst.block, iptr->opc - ICMD_IFNULL, BRANCH_OPT_NONE); - break; - - case ICMD_IFLT: /* ..., value ==> ... */ - case ICMD_IFLE: /* op1 = target JavaVM pc, val.i = constant */ - case ICMD_IFGT: - case ICMD_IFGE: - case ICMD_IFEQ: - case ICMD_IFNE: - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - M_COMPARE(s1, iptr->sx.val.i); - emit_bcc(cd, iptr->dst.block, iptr->opc - ICMD_IFEQ, BRANCH_OPT_NONE); - break; - case ICMD_IF_LEQ: /* ..., value ==> ... */ s1 = emit_load_s1_high(jd, iptr, REG_ITMP1); @@ -1698,7 +1372,7 @@ bool codegen_emit(jitdata *jd) M_ORR_S(s1, s2, REG_ITMP3); } else { - M_COMPARE(s1, (iptr->sx.val.l >> 32)); + emit_icmp_imm(cd, s1, (iptr->sx.val.l >> 32)); /*ICONST(REG_ITMP3, iptr->sx.val.l >> 32); M_CMP(s1, REG_ITMP3);*/ ICONST(REG_ITMP3, iptr->sx.val.l & 0xffffffff); @@ -1718,7 +1392,7 @@ bool codegen_emit(jitdata *jd) } else { /* high compare: x=0(ifLT) ; x=1(ifEQ) ; x=2(ifGT) */ - M_COMPARE(s1, (iptr->sx.val.l >> 32)); + emit_icmp_imm(cd, s1, (iptr->sx.val.l >> 32)); /*ICONST(REG_ITMP3, iptr->sx.val.l >> 32); M_CMP(s1, REG_ITMP3);*/ M_EOR(REG_ITMP1, REG_ITMP1, REG_ITMP1); @@ -1726,7 +1400,7 @@ bool codegen_emit(jitdata *jd) M_MOVEQ_IMM(1, REG_ITMP1); /* low compare: x=x-1(ifLO) */ - M_COMPARE(s2, (iptr->sx.val.l & 0xffffffff)); + emit_icmp_imm(cd, s2, (iptr->sx.val.l & 0xffffffff)); /*ICONST(REG_ITMP3, iptr->sx.val.l & 0xffffffff); M_CMP(s2, REG_ITMP3);*/ M_SUBLO_IMM(REG_ITMP1, REG_ITMP1, 1); @@ -1752,7 +1426,7 @@ bool codegen_emit(jitdata *jd) } else { /* high compare: x=0(ifLT) ; x=1(ifEQ) ; x=2(ifGT) */ - M_COMPARE(s1, (iptr->sx.val.l >> 32)); + emit_icmp_imm(cd, s1, (iptr->sx.val.l >> 32)); /*ICONST(REG_ITMP3, iptr->sx.val.l >> 32); M_CMP(s1, REG_ITMP3);*/ M_EOR(REG_ITMP1, REG_ITMP1, REG_ITMP1); @@ -1760,7 +1434,7 @@ bool codegen_emit(jitdata *jd) M_MOVEQ_IMM(1, REG_ITMP1); /* low compare: x=x+1(ifHI) */ - M_COMPARE(s2, (iptr->sx.val.l & 0xffffffff)); + emit_icmp_imm(cd, s2, (iptr->sx.val.l & 0xffffffff)); /*ICONST(REG_ITMP3, iptr->sx.val.l & 0xffffffff); M_CMP(s2, REG_ITMP3);*/ M_ADDHI_IMM(REG_ITMP1, REG_ITMP1, 1); @@ -1782,7 +1456,7 @@ bool codegen_emit(jitdata *jd) } else { /* high compare: x=0(ifLT) ; x=1(ifEQ) ; x=2(ifGT) */ - M_COMPARE(s1, (iptr->sx.val.l >> 32)); + emit_icmp_imm(cd, s1, (iptr->sx.val.l >> 32)); /*ICONST(REG_ITMP3, iptr->sx.val.l >> 32); M_CMP(s1, REG_ITMP3);*/ M_EOR(REG_ITMP1, REG_ITMP1, REG_ITMP1); @@ -1790,7 +1464,7 @@ bool codegen_emit(jitdata *jd) M_MOVEQ_IMM(1, REG_ITMP1); /* low compare: x=x-1(ifLO) */ - M_COMPARE(s2, (iptr->sx.val.l & 0xffffffff)); + emit_icmp_imm(cd, s2, (iptr->sx.val.l & 0xffffffff)); /*ICONST(REG_ITMP3, iptr->sx.val.l & 0xffffffff); M_CMP(s2, REG_ITMP3);*/ M_SUBLO_IMM(REG_ITMP1, REG_ITMP1, 1); @@ -1822,7 +1496,7 @@ bool codegen_emit(jitdata *jd) else { #endif /* high compare: x=0(ifLT) ; x=1(ifEQ) ; x=2(ifGT) */ - M_COMPARE(s1, (iptr->sx.val.l >> 32)); + emit_icmp_imm(cd, s1, (iptr->sx.val.l >> 32)); /*ICONST(REG_ITMP3, iptr->sx.val.l >> 32); M_CMP(s1, REG_ITMP3);*/ M_EOR(REG_ITMP1, REG_ITMP1, REG_ITMP1); @@ -1830,7 +1504,7 @@ bool codegen_emit(jitdata *jd) M_MOVEQ_IMM(1, REG_ITMP1); /* low compare: x=x+1(ifHI) */ - M_COMPARE(s2, (iptr->sx.val.l & 0xffffffff)); + emit_icmp_imm(cd, s2, (iptr->sx.val.l & 0xffffffff)); /*ICONST(REG_ITMP3, iptr->sx.val.l & 0xffffffff); M_CMP(s2, REG_ITMP3);*/ M_ADDHI_IMM(REG_ITMP1, REG_ITMP1, 1); @@ -1851,7 +1525,7 @@ bool codegen_emit(jitdata *jd) M_ORR_S(s1, s2, REG_ITMP3); } else { - M_COMPARE(s1, (iptr->sx.val.l >> 32)); + emit_icmp_imm(cd, s1, (iptr->sx.val.l >> 32)); /*ICONST(REG_ITMP3, iptr->sx.val.l >> 32); M_CMP(s1, REG_ITMP3);*/ ICONST(REG_ITMP3, iptr->sx.val.l & 0xffffffff); @@ -1860,28 +1534,6 @@ bool codegen_emit(jitdata *jd) emit_bne(cd, iptr->dst.block); break; - case ICMD_IF_ICMPEQ: /* ..., value, value ==> ... */ - case ICMD_IF_ICMPNE: - case ICMD_IF_ICMPLT: - case ICMD_IF_ICMPLE: - case ICMD_IF_ICMPGT: - case ICMD_IF_ICMPGE: - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - s2 = emit_load_s2(jd, iptr, REG_ITMP2); - M_CMP(s1, s2); - emit_bcc(cd, iptr->dst.block, iptr->opc - ICMD_IF_ICMPEQ, BRANCH_OPT_NONE); - break; - - case ICMD_IF_ACMPEQ: /* ..., value, value ==> ... */ - case ICMD_IF_ACMPNE: - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - s2 = emit_load_s2(jd, iptr, REG_ITMP2); - M_CMP(s1, s2); - emit_bcc(cd, iptr->dst.block, iptr->opc - ICMD_IF_ACMPEQ, BRANCH_OPT_NONE); - break; - case ICMD_IF_LCMPEQ: /* ..., value, value ==> ... */ /* op1 = target JavaVM pc */ @@ -2021,7 +1673,7 @@ bool codegen_emit(jitdata *jd) /* range check (index <= high-low) */ i = i - l + 1; - M_COMPARE(REG_ITMP1, i-1); + emit_icmp_imm(cd, REG_ITMP1, i-1); emit_bugt(cd, table[0].block); /* build jump table top down and use address of lowest entry */ @@ -2040,381 +1692,127 @@ bool codegen_emit(jitdata *jd) M_LDR(REG_PC, REG_ITMP2, -(cd->dseglen)); break; - case ICMD_LOOKUPSWITCH: /* ..., key ==> ... */ - { - s4 i; - lookup_target_t *lookup; - - lookup = iptr->dst.lookup; - - i = iptr->sx.s23.s2.lookupcount; - - /* compare keys */ - MCODECHECK((i<<2)+8); - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - - while (--i >= 0) { - M_COMPARE(s1, lookup->value); - emit_beq(cd, lookup->target.block); - lookup++; - } - - /* default branch */ - emit_br(cd, iptr->sx.s23.s3.lookupdefault.block); + case ICMD_BUILTIN: + bte = iptr->sx.s23.s3.bte; + md = bte->md; + if (bte->stub == NULL) { + disp = dseg_add_functionptr(cd, bte->fp); + } else { + disp = dseg_add_functionptr(cd, bte->stub); } - break; - case ICMD_FRETURN: /* ..., retvalue ==> ... */ - -#if !defined(ENABLE_SOFTFLOAT) - REPLACEMENT_POINT_RETURN(cd, iptr); - s1 = emit_load_s1(jd, iptr, REG_FTMP1); - M_CAST_FLT_TO_INT_TYPED(VAROP(iptr->s1)->type, s1, REG_RESULT); - goto ICMD_RETURN_do; -#endif + M_DSEG_LOAD(REG_PV, disp); /* pointer to built-in-function */ - case ICMD_IRETURN: /* ..., retvalue ==> ... */ + /* generate the actual call */ - REPLACEMENT_POINT_RETURN(cd, iptr); - s1 = emit_load_s1(jd, iptr, REG_RESULT); - M_INTMOVE(s1, REG_RESULT); - goto ICMD_RETURN_do; + M_MOV(REG_LR, REG_PC); + M_MOV(REG_PC, REG_PV); - case ICMD_DRETURN: /* ..., retvalue ==> ... */ - -#if !defined(ENABLE_SOFTFLOAT) - REPLACEMENT_POINT_RETURN(cd, iptr); - s1 = emit_load_s1(jd, iptr, REG_FTMP1); - M_CAST_FLT_TO_INT_TYPED(VAROP(iptr->s1)->type, s1, REG_RESULT_PACKED); - goto ICMD_RETURN_do; -#endif - - case ICMD_LRETURN: /* ..., retvalue ==> ... */ - - REPLACEMENT_POINT_RETURN(cd, iptr); - s1 = emit_load_s1(jd, iptr, REG_RESULT_PACKED); - M_LNGMOVE(s1, REG_RESULT_PACKED); - goto ICMD_RETURN_do; + break; - case ICMD_ARETURN: /* ..., retvalue ==> ... */ + case ICMD_INVOKESPECIAL: + emit_nullpointer_check(cd, iptr, REG_A0); + /* fall through */ - REPLACEMENT_POINT_RETURN(cd, iptr); - s1 = emit_load_s1(jd, iptr, REG_RESULT); - M_INTMOVE(s1, REG_RESULT); + case ICMD_INVOKESTATIC: if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - patcher_add_patch_ref(jd, PATCHER_resolve_class, - iptr->sx.s23.s2.uc, 0); + um = iptr->sx.s23.s3.um; + disp = dseg_add_unique_address(cd, NULL); - if (opt_showdisassemble) - M_NOP; + patcher_add_patch_ref(jd, PATCHER_invokestatic_special, + um, disp); } - goto ICMD_RETURN_do; - - case ICMD_RETURN: /* ... ==> ... */ - - REPLACEMENT_POINT_RETURN(cd, iptr); - ICMD_RETURN_do: - -#if !defined(NDEBUG) - if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) - emit_verbosecall_exit(jd); -#endif - -#if defined(ENABLE_THREADS) - /* call monitorexit function */ - - if (checksync && (m->flags & ACC_SYNCHRONIZED)) { - /* stack offset for monitor argument */ - - s1 = rd->memuse * 8; - - /* we need to save the proper return value */ - - switch (iptr->opc) { - case ICMD_IRETURN: - case ICMD_ARETURN: - case ICMD_LRETURN: - case ICMD_FRETURN: /* XXX TWISTI: is that correct? */ - case ICMD_DRETURN: - M_STMFD(BITMASK_RESULT, REG_SP); - s1 += 2 * 4; - break; - } - - M_LDR(REG_A0, REG_SP, s1); - disp = dseg_add_functionptr(cd, LOCK_monitor_exit); - M_DSEG_BRANCH(disp); - - /* we no longer need PV here, no more loading */ - /*s1 = (s4) (cd->mcodeptr - cd->mcodebase); - M_RECOMPUTE_PV(s1);*/ - - switch (iptr->opc) { - case ICMD_IRETURN: - case ICMD_ARETURN: - case ICMD_LRETURN: - case ICMD_FRETURN: /* XXX TWISTI: is that correct? */ - case ICMD_DRETURN: - M_LDMFD(BITMASK_RESULT, REG_SP); - break; - } + else { + lm = iptr->sx.s23.s3.fmiref->p.method; + disp = dseg_add_address(cd, lm->stubroutine); } -#endif - /* deallocate stackframe for spilled variables */ + M_DSEG_LOAD(REG_PV, disp); /* Pointer to method */ - if ((cd->stackframesize / 4 - savedregs_num) > 0) - M_ADD_IMM_EXT_MUL4(REG_SP, REG_SP, cd->stackframesize / 4 - savedregs_num); + /* generate the actual call */ - /* restore callee saved registers + do return */ - - if (savedregs_bitmask) { - if (!jd->isleafmethod) { - savedregs_bitmask &= ~(1<isleafmethod) - M_MOV(REG_PC, REG_LR); + M_MOV(REG_LR, REG_PC); + M_MOV(REG_PC, REG_PV); break; - case ICMD_BUILTIN: /* ..., arg1, arg2, arg3 ==> ... */ + case ICMD_INVOKEVIRTUAL: + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + um = iptr->sx.s23.s3.um; + int32_t disp = dseg_add_unique_s4(cd, 0); + patcher_add_patch_ref(jd, PATCHER_invokevirtual, um, disp); - bte = iptr->sx.s23.s3.bte; - md = bte->md; - goto ICMD_INVOKE_do; + // The following instruction MUST NOT change a0 because of the implicit NPE check. + M_LDR_INTERN(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl)); - case ICMD_INVOKESTATIC: /* ..., [arg1, [arg2 ...]] ==> ... */ - case ICMD_INVOKESPECIAL:/* ..., objectref, [arg1, [arg2 ...]] ==> ... */ - case ICMD_INVOKEVIRTUAL:/* op1 = arg count, val.a = method pointer */ - case ICMD_INVOKEINTERFACE: + // Sanity check. + assert(REG_ITMP1 != REG_METHODPTR); + assert(REG_ITMP2 == REG_METHODPTR); - REPLACEMENT_POINT_INVOKE(cd, iptr); + M_DSEG_LOAD(REG_ITMP1, disp); + M_ADD(REG_METHODPTR, REG_METHODPTR, REG_ITMP1); - if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - lm = NULL; - um = iptr->sx.s23.s3.um; - md = um->methodref->parseddesc.md; + // This must be a load with displacement, + // otherwise the JIT method address patching does + // not work anymore (see md_jit_method_patch_address). + M_LDR_INTERN(REG_PV, REG_METHODPTR, 0); } else { lm = iptr->sx.s23.s3.fmiref->p.method; - um = NULL; - md = lm->parseddesc; - } - - ICMD_INVOKE_do: - /* copy arguments to registers or stack location */ - - s3 = md->paramcount; - - MCODECHECK((s3 << 1) + 64); - - for (s3 = s3 - 1; s3 >= 0; s3--) { - var = VAR(iptr->sx.s23.s2.args[s3]); - d = md->params[s3].regoff; + s1 = OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * lm->vftblindex; - if (var->flags & PREALLOC) /* argument was precolored? */ - continue; - - /* TODO: document me */ -#if !defined(ENABLE_SOFTFLOAT) - if (IS_INT_LNG_TYPE(var->type)) { -#endif /* !defined(ENABLE_SOFTFLOAT) */ - if (!md->params[s3].inmemory) { - s1 = emit_load(jd, iptr, var, d); - - if (IS_2_WORD_TYPE(var->type)) - M_LNGMOVE(s1, d); - else - M_INTMOVE(s1, d); - } - else { - if (IS_2_WORD_TYPE(var->type)) { - s1 = emit_load(jd, iptr, var, REG_ITMP12_PACKED); - M_LST(s1, REG_SP, d); - } - else { - s1 = emit_load(jd, iptr, var, REG_ITMP1); - M_IST(s1, REG_SP, d); - } - } -#if !defined(ENABLE_SOFTFLOAT) - } - else { - if (!md->params[s3].inmemory) { - s1 = emit_load(jd, iptr, var, REG_FTMP1); - M_CAST_FLT_TO_INT_TYPED(var->type, s1, d); - } - else { - s1 = emit_load(jd, iptr, var, REG_FTMP1); - if (IS_2_WORD_TYPE(var->type)) - M_DST(s1, REG_SP, d); - else - M_FST(s1, REG_SP, d); - } - } -#endif /* !defined(ENABLE_SOFTFLOAT) */ + // The following instruction MUST NOT change a0 because of the implicit NPE check. + M_LDR_INTERN(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl)); + M_LDR(REG_PV, REG_METHODPTR, s1); } - switch (iptr->opc) { - case ICMD_BUILTIN: - - if (bte->stub == NULL) { - disp = dseg_add_functionptr(cd, bte->fp); - } else { - disp = dseg_add_functionptr(cd, bte->stub); - } - - M_DSEG_LOAD(REG_PV, disp); /* pointer to built-in-function */ - - /* generate the actual call */ - - M_MOV(REG_LR, REG_PC); - M_MOV(REG_PC, REG_PV); - s1 = (s4) (cd->mcodeptr - cd->mcodebase); - M_RECOMPUTE_PV(s1); - - emit_exception_check(cd, iptr); - break; - - case ICMD_INVOKESPECIAL: - emit_nullpointer_check(cd, iptr, REG_A0); - /* fall through */ - - case ICMD_INVOKESTATIC: - if (lm == NULL) { - disp = dseg_add_unique_address(cd, NULL); - - patcher_add_patch_ref(jd, PATCHER_invokestatic_special, - um, disp); - - if (opt_showdisassemble) - M_NOP; - } - else - disp = dseg_add_address(cd, lm->stubroutine); - - M_DSEG_LOAD(REG_PV, disp); /* Pointer to method */ - - /* generate the actual call */ - - M_MOV(REG_LR, REG_PC); - M_MOV(REG_PC, REG_PV); - s1 = (s4) (cd->mcodeptr - cd->mcodebase); - M_RECOMPUTE_PV(s1); - break; - - case ICMD_INVOKEVIRTUAL: - if (lm == NULL) { - patcher_add_patch_ref(jd, PATCHER_invokevirtual, um, 0); - - if (opt_showdisassemble) - M_NOP; - - s1 = 0; - } - else - s1 = OFFSET(vftbl_t, table[0]) + - sizeof(methodptr) * lm->vftblindex; - - /* implicit null-pointer check */ - M_LDR_INTERN(REG_METHODPTR, REG_A0, - OFFSET(java_object_t, vftbl)); - M_LDR_INTERN(REG_PV, REG_METHODPTR, s1); + // Generate the actual call. + M_MOV(REG_LR, REG_PC); + M_MOV(REG_PC, REG_PV); + break; - /* generate the actual call */ + case ICMD_INVOKEINTERFACE: + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + um = iptr->sx.s23.s3.um; + int32_t disp = dseg_add_unique_s4(cd, 0); + int32_t disp2 = dseg_add_unique_s4(cd, 0); - M_MOV(REG_LR, REG_PC); - M_MOV(REG_PC, REG_PV); - s1 = (s4) (cd->mcodeptr - cd->mcodebase); - M_RECOMPUTE_PV(s1); - break; + // XXX We need two displacements. + assert(disp2 == disp - 4); + patcher_add_patch_ref(jd, PATCHER_invokeinterface, um, disp); - case ICMD_INVOKEINTERFACE: - if (lm == NULL) { - patcher_add_patch_ref(jd, PATCHER_invokeinterface, um, 0); + // The following instruction MUST NOT change a0 because of the implicit NPE check. + M_LDR_INTERN(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl)); - if (opt_showdisassemble) - M_NOP; + // Sanity check. + assert(REG_ITMP1 != REG_METHODPTR); + assert(REG_ITMP2 == REG_METHODPTR); + assert(REG_ITMP3 != REG_METHODPTR); - s1 = 0; - s2 = 0; - } - else { - s1 = OFFSET(vftbl_t, interfacetable[0]) - - sizeof(methodptr*) * lm->class->index; - s2 = sizeof(methodptr) * (lm - lm->class->methods); - } - - /* implicit null-pointer check */ - M_LDR_INTERN(REG_METHODPTR, REG_A0, - OFFSET(java_object_t, vftbl)); - M_LDR_INTERN(REG_METHODPTR, REG_METHODPTR, s1); - M_LDR_INTERN(REG_PV, REG_METHODPTR, s2); + M_DSEG_LOAD(REG_ITMP1, disp); + M_LDR_REG(REG_METHODPTR, REG_METHODPTR, REG_ITMP1); - /* generate the actual call */ + M_DSEG_LOAD(REG_ITMP3, disp2); + M_ADD(REG_METHODPTR, REG_METHODPTR, REG_ITMP3); - M_MOV(REG_LR, REG_PC); - M_MOV(REG_PC, REG_PV); - s1 = (s4) (cd->mcodeptr - cd->mcodebase); - M_RECOMPUTE_PV(s1); - break; + // This must be a load with displacement, + // otherwise the JIT method address patching does + // not work anymore (see md_jit_method_patch_address). + M_LDR_INTERN(REG_PV, REG_METHODPTR, 0); } + else { + lm = iptr->sx.s23.s3.fmiref->p.method; + s1 = OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr*) * lm->clazz->index; + s2 = sizeof(methodptr) * (lm - lm->clazz->methods); - /* store size of call code in replacement point */ - REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr); - - /* store return value */ - - d = md->returntype.type; - -#if !defined(__SOFTFP__) - /* TODO: this is only a hack, since we use R0/R1 for float - return! this depends on gcc; it is independent from - our ENABLE_SOFTFLOAT define */ - if (iptr->opc == ICMD_BUILTIN && d != TYPE_VOID && IS_FLT_DBL_TYPE(d)) { -#if 0 && !defined(NDEBUG) - dolog("BUILTIN that returns float or double (%s.%s)", m->class->name->text, m->name->text); -#endif - /* we cannot use this macro, since it is not defined - in ENABLE_SOFTFLOAT M_CAST_FLT_TO_INT_TYPED(d, - REG_FRESULT, REG_RESULT_TYPED(d)); */ - if (IS_2_WORD_TYPE(d)) { - DCD(0xed2d8102); /* stfd f0, [sp, #-8]! */ - M_LDRD_UPDATE(REG_RESULT_PACKED, REG_SP, 8); - } else { - DCD(0xed2d0101); /* stfs f0, [sp, #-4]!*/ - M_LDR_UPDATE(REG_RESULT, REG_SP, 4); - } + // The following instruction MUST NOT change a0 because of the implicit NPE check. + M_LDR_INTERN(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl)); + M_LDR(REG_METHODPTR, REG_METHODPTR, s1); + M_LDR(REG_PV, REG_METHODPTR, s2); } -#endif - - if (d != TYPE_VOID) { -#if !defined(ENABLE_SOFTFLOAT) - if (IS_INT_LNG_TYPE(d)) { -#endif /* !defined(ENABLE_SOFTFLOAT) */ - if (IS_2_WORD_TYPE(d)) { - s1 = codegen_reg_of_dst(jd, iptr, REG_RESULT_PACKED); - M_LNGMOVE(REG_RESULT_PACKED, s1); - } - else { - s1 = codegen_reg_of_dst(jd, iptr, REG_RESULT); - M_INTMOVE(REG_RESULT, s1); - } - -#if !defined(ENABLE_SOFTFLOAT) - } else { - s1 = codegen_reg_of_dst(jd, iptr, REG_FTMP1); - M_CAST_INT_TO_FLT_TYPED(VAROP(iptr->dst)->type, REG_RESULT_TYPED(VAROP(iptr->dst)->type), s1); - } -#endif /* !defined(ENABLE_SOFTFLOAT) */ - emit_store_dst(jd, iptr, s1); - } + // Generate the actual call. + M_MOV(REG_LR, REG_PC); + M_MOV(REG_PC, REG_PV); break; case ICMD_CHECKCAST: /* ..., objectref ==> ..., objectref */ @@ -2434,9 +1832,6 @@ bool codegen_emit(jitdata *jd) superindex = super->index; } - if ((super == NULL) || !(super->flags & ACC_INTERFACE)) - CODEGEN_CRITICAL_SECTION_NEW; - s1 = emit_load_s1(jd, iptr, REG_ITMP1); /* if class is not resolved, check which code to call */ @@ -2449,9 +1844,6 @@ bool codegen_emit(jitdata *jd) patcher_add_patch_ref(jd, PATCHER_resolve_classref_to_flags, iptr->sx.s23.s3.c.ref, disp); - if (opt_showdisassemble) - M_NOP; - M_DSEG_LOAD(REG_ITMP2, disp); disp = dseg_add_s4(cd, ACC_INTERFACE); M_DSEG_LOAD(REG_ITMP3, disp); @@ -2468,9 +1860,6 @@ bool codegen_emit(jitdata *jd) if (super == NULL) { patcher_add_patch_ref(jd, PATCHER_resolve_classref_to_index, iptr->sx.s23.s3.c.ref, disp); - - if (opt_showdisassemble) - M_NOP; } else { M_TST(s1, s1); @@ -2535,9 +1924,6 @@ bool codegen_emit(jitdata *jd) patcher_add_patch_ref(jd, PATCHER_resolve_classref_to_vftbl, iptr->sx.s23.s3.c.ref, disp); - - if (opt_showdisassemble) - M_NOP; } else { disp = dseg_add_address(cd, super->vftbl); @@ -2546,21 +1932,67 @@ bool codegen_emit(jitdata *jd) emit_label_beq(cd, BRANCH_LABEL_5); } - M_LDR_INTERN(REG_ITMP2, s1, OFFSET(java_object_t, vftbl)); - M_DSEG_LOAD(REG_ITMP3, disp); + // The following code checks whether object s is a subtype of class t. + // Represents the following semantic: + // if (!fast_subtype_check(s->vftbl, t->vftbl)) throw; - CODEGEN_CRITICAL_SECTION_START; - - M_LDR_INTERN(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, baseval)); - M_LDR_INTERN(REG_ITMP3, REG_ITMP3, OFFSET(vftbl_t, baseval)); - M_SUB(REG_ITMP2, REG_ITMP2, REG_ITMP3); + M_LDR_INTERN(REG_ITMP2, s1, OFFSET(java_object_t, vftbl)); M_DSEG_LOAD(REG_ITMP3, disp); - M_LDR_INTERN(REG_ITMP3, REG_ITMP3, OFFSET(vftbl_t, diffval)); - CODEGEN_CRITICAL_SECTION_END; + if (super == NULL || super->vftbl->subtype_depth >= DISPLAY_SIZE) { + // Represents the following semantic: + // if (*(s->vftbl + t->vftbl->subtype_offset) == t->vftbl) good; + // Preconditions: + // REG_ITMP2==s->vftbl; REG_ITMP3==t->vftbl; + M_LDR_INTERN(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_offset)); + M_LDR_REG(REG_ITMP1, REG_ITMP2, REG_ITMP1); + M_CMP(REG_ITMP1, REG_ITMP3); + emit_load_s1(jd, iptr, REG_ITMP1); /* reload s1, might have been destroyed */ + emit_label_beq(cd, BRANCH_LABEL_6); /* good */ + + // Represents the following semantic: + // if (t->vftbl->subtype_offset != OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE])) throw; + // Preconditions: + // REG_ITMP3==t->vftbl; + if (super == NULL) { + M_LDR_INTERN(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_offset)); + M_CMP_IMM(REG_ITMP1, OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE])); + emit_load_s1(jd, iptr, REG_ITMP1); /* reload s1, might have been destroyed */ + emit_classcast_check(cd, iptr, BRANCH_NE, 0, s1); /* throw */ + } - M_CMP(REG_ITMP2, REG_ITMP3); - emit_classcast_check(cd, iptr, BRANCH_UGT, 0, s1); + // Represents the following semantic: + // if (s->vftbl->subtype_depth < t->vftbl->subtype_depth) throw; + // Preconditions: + // REG_ITMP2==s->vftbl; REG_ITMP3==t->vftbl; + M_LDR_INTERN(REG_ITMP1, REG_ITMP2, OFFSET(vftbl_t, subtype_depth)); + M_LDR_INTERN(REG_ITMP3, REG_ITMP3, OFFSET(vftbl_t, subtype_depth)); + M_CMP(REG_ITMP1, REG_ITMP3); + emit_load_s1(jd, iptr, REG_ITMP1); /* reload s1, might have been destroyed */ + emit_classcast_check(cd, iptr, BRANCH_LT, 0, s1); /* throw */ + + // Represents the following semantic: + // if (s->vftbl->subtype_overflow[t->vftbl->subtype_depth - DISPLAY_SIZE] != t->vftbl) throw; + // Preconditions: + // REG_ITMP2==s->vftbl; REG_ITMP3==t->vftbl->subtype_depth; + M_LDR_INTERN(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, subtype_overflow)); + M_ADD(REG_ITMP2, REG_ITMP2, REG_LSL(REG_ITMP3, 2)); /* REG_ITMP2 = REG_ITMP2 + 4 * REG_ITMP3 */ + M_LDR_INTERN(REG_ITMP2, REG_ITMP2, -DISPLAY_SIZE * SIZEOF_VOID_P); + M_DSEG_LOAD(REG_ITMP3, disp); /* reload REG_ITMP3, was destroyed */ + M_CMP(REG_ITMP2, REG_ITMP3); + emit_classcast_check(cd, iptr, BRANCH_NE, 0, s1); /* throw */ + + emit_label(cd, BRANCH_LABEL_6); + } + else { + // Represents the following semantic: + // if (*(s->vftbl + t->vftbl->subtype_offset) != t->vftbl) throw; + // Preconditions: + // REG_ITMP2==s->vftbl; REG_ITMP3==t->vftbl; + M_ALD(REG_ITMP2, REG_ITMP2, super->vftbl->subtype_offset); + M_CMP(REG_ITMP2, REG_ITMP3); + emit_classcast_check(cd, iptr, BRANCH_NE, 0, s1); + } if (super != NULL) emit_label(cd, BRANCH_LABEL_5); @@ -2585,9 +2017,6 @@ bool codegen_emit(jitdata *jd) patcher_add_patch_ref(jd, PATCHER_resolve_classref_to_classinfo, iptr->sx.s23.s3.c.ref, disp); - - if (opt_showdisassemble) - M_NOP; } else disp = dseg_add_address(cd, iptr->sx.s23.s3.c.cls); @@ -2596,9 +2025,7 @@ bool codegen_emit(jitdata *jd) disp = dseg_add_functionptr(cd, BUILTIN_arraycheckcast); M_DSEG_BRANCH(disp); - /* recompute pv */ - disp = (s4) (cd->mcodeptr - cd->mcodebase); - M_RECOMPUTE_PV(disp); + emit_recompute_pv(cd); s1 = emit_load_s1(jd, iptr, REG_ITMP1); M_TST(REG_RESULT, REG_RESULT); @@ -2626,9 +2053,6 @@ bool codegen_emit(jitdata *jd) superindex = super->index; } - if ((super == NULL) || !(super->flags & ACC_INTERFACE)) - CODEGEN_CRITICAL_SECTION_NEW; - s1 = emit_load_s1(jd, iptr, REG_ITMP1); d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); @@ -2649,9 +2073,6 @@ bool codegen_emit(jitdata *jd) patcher_add_patch_ref(jd, PATCHER_resolve_classref_to_flags, iptr->sx.s23.s3.c.ref, disp); - if (opt_showdisassemble) - M_NOP; - M_DSEG_LOAD(REG_ITMP2, disp); disp = dseg_add_s4(cd, ACC_INTERFACE); M_DSEG_LOAD(REG_ITMP3, disp); @@ -2673,9 +2094,6 @@ bool codegen_emit(jitdata *jd) patcher_add_patch_ref(jd, PATCHER_resolve_classref_to_index, iptr->sx.s23.s3.c.ref, disp); - - if (opt_showdisassemble) - M_NOP; } else { M_EOR(d, d, d); @@ -2745,9 +2163,6 @@ bool codegen_emit(jitdata *jd) patcher_add_patch_ref(jd, PATCHER_resolve_classref_to_vftbl, iptr->sx.s23.s3.c.ref, disp); - - if (opt_showdisassemble) - M_NOP; } else { disp = dseg_add_address(cd, super->vftbl); @@ -2757,23 +2172,74 @@ bool codegen_emit(jitdata *jd) emit_label_beq(cd, BRANCH_LABEL_5); } - M_LDR_INTERN(REG_ITMP1, s1, OFFSET(java_object_t, vftbl)); - M_DSEG_LOAD(REG_ITMP2, disp); - - CODEGEN_CRITICAL_SECTION_START; + // The following code checks whether object s is a subtype of class t. + // Represents the following semantic: + // fast_subtype_check(s->vftbl, t->vftbl)); - M_LDR_INTERN(REG_ITMP1, REG_ITMP1, OFFSET(vftbl_t, baseval)); - M_LDR_INTERN(REG_ITMP3, REG_ITMP2, OFFSET(vftbl_t, baseval)); - M_LDR_INTERN(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, diffval)); + M_LDR_INTERN(REG_ITMP2, s1, OFFSET(java_object_t, vftbl)); + M_DSEG_LOAD(REG_ITMP3, disp); - CODEGEN_CRITICAL_SECTION_END; + if (super == NULL || super->vftbl->subtype_depth >= DISPLAY_SIZE) { + // Represents the following semantic: + // if (*(s->vftbl + t->vftbl->subtype_offset) == t->vftbl) true; + // Preconditions: + // REG_ITMP2==s->vftbl; REG_ITMP3==t->vftbl; + M_LDR_INTERN(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_offset)); + M_LDR_REG(REG_ITMP1, REG_ITMP2, REG_ITMP1); + M_CMP(REG_ITMP1, REG_ITMP3); + emit_label_beq(cd, BRANCH_LABEL_6); /* true */ + + // Represents the following semantic: + // if (t->vftbl->subtype_offset != OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE])) false; + // Preconditions: + // REG_ITMP3==t->vftbl; + if (super == NULL) { + M_LDR_INTERN(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_offset)); + M_CMP_IMM(REG_ITMP1, OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE])); + emit_label_bne(cd, BRANCH_LABEL_7); /* false */ + } - M_SUB(REG_ITMP1, REG_ITMP1, REG_ITMP3); - M_CMP(REG_ITMP1, REG_ITMP2); - /* If d == REG_ITMP2, then it's destroyed */ - if (d == REG_ITMP2) - M_EOR(d, d, d); - M_MOVLS_IMM(1, d); + // Represents the following semantic: + // if (s->vftbl->subtype_depth < t->vftbl->subtype_depth) false; + // Preconditions: + // REG_ITMP2==s->vftbl; REG_ITMP3==t->vftbl; + M_LDR_INTERN(REG_ITMP1, REG_ITMP2, OFFSET(vftbl_t, subtype_depth)); + M_LDR_INTERN(REG_ITMP3, REG_ITMP3, OFFSET(vftbl_t, subtype_depth)); + M_CMP(REG_ITMP1, REG_ITMP3); + emit_label_blt(cd, BRANCH_LABEL_8); /* false */ + + // Represents the following semantic: + // if (s->vftbl->subtype_overflow[t->vftbl->subtype_depth - DISPLAY_SIZE] != t->vftbl) false; + // Preconditions: + // REG_ITMP2==s->vftbl; REG_ITMP3==t->vftbl->subtype_depth; + M_LDR_INTERN(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, subtype_overflow)); + M_ADD(REG_ITMP2, REG_ITMP2, REG_LSL(REG_ITMP3, 2)); /* REG_ITMP2 = REG_ITMP2 + 4 * REG_ITMP3 */ + M_LDR_INTERN(REG_ITMP2, REG_ITMP2, -DISPLAY_SIZE * SIZEOF_VOID_P); + M_DSEG_LOAD(REG_ITMP3, disp); /* reload REG_ITMP3, was destroyed */ + M_CMP(REG_ITMP2, REG_ITMP3); + + emit_label(cd, BRANCH_LABEL_6); + if (super == NULL) + emit_label(cd, BRANCH_LABEL_7); + emit_label(cd, BRANCH_LABEL_8); + + /* If d == REG_ITMP2, then it's destroyed */ + if (d == REG_ITMP2) + M_EOR(d, d, d); + M_MOVEQ_IMM(1, d); + } + else { + // Represents the following semantic: + // *(s->vftbl + t->vftbl->subtype_offset) == t->vftbl; + // Preconditions: + // REG_ITMP2==s->vftbl; REG_ITMP3==t->vftbl; + M_ALD(REG_ITMP2, REG_ITMP2, super->vftbl->subtype_offset); + M_CMP(REG_ITMP2, REG_ITMP3); + /* If d == REG_ITMP2, then it's destroyed */ + if (d == REG_ITMP2) + M_EOR(d, d, d); + M_MOVEQ_IMM(1, d); + } if (super != NULL) emit_label(cd, BRANCH_LABEL_5); @@ -2819,9 +2285,6 @@ bool codegen_emit(jitdata *jd) patcher_add_patch_ref(jd, PATCHER_resolve_classref_to_classinfo, iptr->sx.s23.s3.c.ref, disp); - - if (opt_showdisassemble) - M_NOP; } else disp = dseg_add_address(cd, iptr->sx.s23.s3.c.cls); @@ -2841,8 +2304,7 @@ bool codegen_emit(jitdata *jd) /* recompute pv */ - s1 = (s4) (cd->mcodeptr - cd->mcodebase); - M_RECOMPUTE_PV(s1); + emit_recompute_pv(cd); /* check for exception before result assignment */ @@ -2855,55 +2317,9 @@ bool codegen_emit(jitdata *jd) emit_store_dst(jd, iptr, d); break; - case ICMD_CHECKNULL: /* ..., objectref ==> ..., objectref */ - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - emit_nullpointer_check(cd, iptr, s1); - break; - default: - exceptions_throw_internalerror("Unknown ICMD %d during code generation", - iptr->opc); - return false; - } /* the big switch */ - - } /* for all instructions */ - - } /* for all basic blocks */ - - dseg_createlinenumbertable(cd); - - - /* generate traps */ - - emit_patcher_traps(jd); - - /* everything's ok */ - - return true; -} - - -/* codegen_emit_stub_compiler ************************************************** - - Emits a stub routine which calls the compiler. - -*******************************************************************************/ - -void codegen_emit_stub_compiler(jitdata *jd) -{ - methodinfo *m; - codegendata *cd; - - /* get required compiler data */ - - m = jd->m; - cd = jd->cd; - - /* code for the stub */ - - M_LDR_INTERN(REG_ITMP1, REG_PC, -(2 * 4 + 2 * SIZEOF_VOID_P)); - M_LDR_INTERN(REG_PC, REG_PC, -(3 * 4 + 3 * SIZEOF_VOID_P)); + vm_abort("Unknown ICMD %d during code generation", iptr->opc); + } /* the big switch */ } @@ -2913,16 +2329,16 @@ void codegen_emit_stub_compiler(jitdata *jd) *******************************************************************************/ -void codegen_emit_stub_native(jitdata *jd, methoddesc *nmd, functionptr f) +void codegen_emit_stub_native(jitdata *jd, methoddesc *nmd, functionptr f, int skipparams) { methodinfo *m; codeinfo *code; codegendata *cd; - s4 nativeparams; methoddesc *md; s4 i, j; s4 t; - s4 disp, funcdisp, s1, s2; + int s1, s2; + int disp; /* get required compiler data */ @@ -2933,59 +2349,38 @@ void codegen_emit_stub_native(jitdata *jd, methoddesc *nmd, functionptr f) /* initialize variables */ md = m->parseddesc; - nativeparams = (m->flags & ACC_NATIVE) ? 1 : 0; - nativeparams += (m->flags & ACC_STATIC) ? 1 : 0; /* calculate stackframe size */ cd->stackframesize = - 4 + /* return address */ - sizeof(stackframeinfo) + /* stackframeinfo */ - sizeof(localref_table) + /* localref_table */ - nmd->memuse * 4; /* stack arguments */ + 1 + /* return address */ + sizeof(stackframeinfo_t) / SIZEOF_VOID_P + /* stackframeinfo */ + sizeof(localref_table) / SIZEOF_VOID_P + /* localref_table */ + nmd->memuse; /* stack arguments */ /* align stack to 8-byte */ - cd->stackframesize = (cd->stackframesize + 4) & ~4; + cd->stackframesize = (cd->stackframesize + 1) & ~1; /* create method header */ (void) dseg_add_unique_address(cd, code); /* CodeinfoPointer */ (void) dseg_add_unique_s4(cd, cd->stackframesize); /* FrameSize */ - (void) dseg_add_unique_s4(cd, 0); /* IsSync */ (void) dseg_add_unique_s4(cd, 0); /* IsLeaf */ (void) dseg_add_unique_s4(cd, 0); /* IntSave */ (void) dseg_add_unique_s4(cd, 0); /* FltSave */ - (void) dseg_addlinenumbertablesize(cd); - (void) dseg_add_unique_s4(cd, 0); /* ExTableSize */ /* generate stub code */ M_STMFD(1<stackframesize / 4 - 1); - -#if !defined(NDEBUG) - if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) - emit_verbosecall_enter(jd); -#endif - - /* get function address (this must happen before the stackframeinfo) */ - - funcdisp = dseg_add_functionptr(cd, f); - - if (f == NULL) { - patcher_add_patch_ref(jd, PATCHER_resolve_native_function, m, funcdisp); - - if (opt_showdisassemble) - M_NOP; - } + M_SUB_IMM_EXT_MUL4(REG_SP, REG_SP, cd->stackframesize * 2 - 1); #if defined(ENABLE_GC_CACAO) /* Save callee saved integer registers in stackframeinfo (GC may need to recover them during a collection). */ - disp = cd->stackframesize - SIZEOF_VOID_P - sizeof(stackframeinfo) + - OFFSET(stackframeinfo, intregs); + disp = cd->stackframesize - SIZEOF_VOID_P - sizeof(stackframeinfo_t) + + OFFSET(stackframeinfo_t, intregs); for (i = 0; i < INT_SAV_CNT; i++) M_STR_INTERN(abi_registers_integer_saved[i], REG_SP, disp + i * 4); @@ -3006,8 +2401,7 @@ void codegen_emit_stub_native(jitdata *jd, methoddesc *nmd, functionptr f) /* recompute pv */ - s1 = (s4) (cd->mcodeptr - cd->mcodebase); - M_RECOMPUTE_PV(s1); + emit_recompute_pv(cd); /* remember class argument */ @@ -3023,7 +2417,7 @@ void codegen_emit_stub_native(jitdata *jd, methoddesc *nmd, functionptr f) /* copy or spill arguments to new locations */ /* ATTENTION: the ARM has only integer argument registers! */ - for (i = md->paramcount - 1, j = i + nativeparams; i >= 0; i--, j--) { + for (i = md->paramcount - 1, j = i + skipparams; i >= 0; i--, j--) { t = md->paramtypes[i].type; if (!md->params[i].inmemory) { @@ -3052,7 +2446,7 @@ void codegen_emit_stub_native(jitdata *jd, methoddesc *nmd, functionptr f) } } else { - s1 = md->params[i].regoff + cd->stackframesize; + s1 = md->params[i].regoff + cd->stackframesize * 8; s2 = nmd->params[j].regoff; if (IS_2_WORD_TYPE(t)) { @@ -3066,52 +2460,30 @@ void codegen_emit_stub_native(jitdata *jd, methoddesc *nmd, functionptr f) } } - /* put class into second argument register */ + /* Handle native Java methods. */ - if (m->flags & ACC_STATIC) - M_MOV(REG_A1, REG_ITMP3); + if (m->flags & ACC_NATIVE) { + /* put class into second argument register */ - /* put env into first argument register */ + if (m->flags & ACC_STATIC) + M_MOV(REG_A1, REG_ITMP3); - if (m->flags & ACC_NATIVE) { - disp = dseg_add_address(cd, _Jv_env); + /* put env into first argument register */ + + disp = dseg_add_address(cd, VM_get_jnienv()); M_DSEG_LOAD(REG_A0, disp); } - /* do the native function call */ + /* Call the native function. */ - M_DSEG_BRANCH(funcdisp); + disp = dseg_add_functionptr(cd, f); + M_DSEG_BRANCH(disp); /* recompute pv */ /* TODO: this is only needed because of the tracer ... do we really need it? */ - s1 = (s4) (cd->mcodeptr - cd->mcodebase); - M_RECOMPUTE_PV(s1); - -#if !defined(__SOFTFP__) - /* TODO: this is only a hack, since we use R0/R1 for float return! */ - /* this depends on gcc; it is independent from our ENABLE_SOFTFLOAT define */ - if (md->returntype.type != TYPE_VOID && IS_FLT_DBL_TYPE(md->returntype.type)) { -#if 0 && !defined(NDEBUG) - dolog("NATIVESTUB that returns float or double (%s.%s)", m->class->name->text, m->name->text); -#endif - /* we cannot use this macro, since it is not defined in ENABLE_SOFTFLOAT */ - /* M_CAST_FLT_TO_INT_TYPED(md->returntype.type, REG_FRESULT, REG_RESULT_TYPED(md->returntype.type)); */ - if (IS_2_WORD_TYPE(md->returntype.type)) { - DCD(0xed2d8102); /* stfd f0, [sp, #-8]! */ - M_LDRD_UPDATE(REG_RESULT_PACKED, REG_SP, 8); - } else { - DCD(0xed2d0101); /* stfs f0, [sp, #-4]!*/ - M_LDR_UPDATE(REG_RESULT, REG_SP, 4); - } - } -#endif - -#if !defined(NDEBUG) - if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) - emit_verbosecall_exit(jd); -#endif + emit_recompute_pv(cd); /* remove native stackframe info */ /* TODO: improve this store/load */ @@ -3122,8 +2494,7 @@ void codegen_emit_stub_native(jitdata *jd, methoddesc *nmd, functionptr f) M_MOV(REG_A1, REG_PV); disp = dseg_add_functionptr(cd, codegen_finish_native_call); M_DSEG_BRANCH(disp); - s1 = (s4) (cd->mcodeptr - cd->mcodebase); - M_RECOMPUTE_PV(s1); + emit_recompute_pv(cd); M_MOV(REG_ITMP1_XPTR, REG_RESULT); M_LDMFD(BITMASK_RESULT, REG_SP); @@ -3132,8 +2503,8 @@ void codegen_emit_stub_native(jitdata *jd, methoddesc *nmd, functionptr f) /* restore callee saved int registers from stackframeinfo (GC might have */ /* modified them during a collection). */ - disp = cd->stackframesize - SIZEOF_VOID_P - sizeof(stackframeinfo) + - OFFSET(stackframeinfo, intregs); + disp = cd->stackframesize - SIZEOF_VOID_P - sizeof(stackframeinfo_t) + + OFFSET(stackframeinfo_t, intregs); for (i = 0; i < INT_SAV_CNT; i++) M_LDR_INTERN(abi_registers_integer_saved[i], REG_SP, disp + i * 4); @@ -3141,7 +2512,7 @@ void codegen_emit_stub_native(jitdata *jd, methoddesc *nmd, functionptr f) /* finish stub code, but do not yet return to caller */ - M_ADD_IMM_EXT_MUL4(REG_SP, REG_SP, cd->stackframesize / 4 - 1); + M_ADD_IMM_EXT_MUL4(REG_SP, REG_SP, cd->stackframesize * 2 - 1); M_LDMFD(1<