X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Fjit%2Farm%2Fcodegen.c;h=b82661a1d997e17bfb0d2ea77f5961f1c8d4f72a;hb=278063eaf49b3b3fc68b40cc7fc4172a065f4e99;hp=09f3d0b5f2cb5c0d260d06faa7a807b5963748db;hpb=35f32713571d45a9b6ebfc1c4c8ffbbab46937a0;p=cacao.git diff --git a/src/vm/jit/arm/codegen.c b/src/vm/jit/arm/codegen.c index 09f3d0b5f..b82661a1d 100644 --- a/src/vm/jit/arm/codegen.c +++ b/src/vm/jit/arm/codegen.c @@ -1,6 +1,6 @@ /* src/vm/jit/arm/codegen.c - machine code generator for Arm - 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. @@ -35,7 +35,7 @@ #include "vm/jit/arm/arch.h" #include "vm/jit/arm/codegen.h" -#include "mm/memory.h" +#include "mm/memory.hpp" #include "native/localref.hpp" #include "native/native.hpp" @@ -57,128 +57,59 @@ #include "vm/jit/jit.hpp" #include "vm/jit/linenumbertable.hpp" #include "vm/jit/methodheader.h" -#include "vm/jit/parse.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 - - -/* 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; - - 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 = code_is_leafmethod(code) ? 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 && code_is_synchronized(code)) - 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 */ - - code->synchronizedoffset = rd->memuse * 8; - - /* REMOVEME: We still need it for exception handling in assembler. */ - - if (code_is_leafmethod(code)) - (void) dseg_add_unique_s4(cd, 1); - else - (void) dseg_add_unique_s4(cd, 0); - - (void) dseg_add_unique_s4(cd, INT_SAV_CNT - rd->savintreguse); /* IntSave */ - (void) dseg_add_unique_s4(cd, FLT_SAV_CNT - rd->savfltreguse); /* FltSave */ - - /* save return address and used callee saved registers */ - - savedregs_bitmask = 0; - - if (!code_is_leafmethod(code)) + 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 */ @@ -217,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) @@ -246,157 +177,94 @@ 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 && code_is_synchronized(code)) { - /* 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->clazz->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); + for (i = INT_SAV_CNT - 1; i >= rd->savintreguse; i--) { + savedregs_num++; + savedregs_bitmask |= (1<<(rd->savintregs[i])); + } - /* handle replacement points */ - REPLACEMENT_POINT_BLOCK_START(cd, bptr); + /* deallocate stackframe for spilled variables */ - /* copy interface registers to their destination */ + int32_t additional_bytes = (cd->stackframesize * 8 - savedregs_num * 4); - len = bptr->indepth; + if (additional_bytes > 0) + M_ADD_IMM_EXT_MUL4(REG_SP, REG_SP, additional_bytes / 4); - MCODECHECK(64+len); + /* restore callee saved registers + do return */ -#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); - } + if (savedregs_bitmask) { + if (!code_is_leafmethod(code)) { + savedregs_bitmask &= ~(1<invars[len]); - - 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 defined(ENABLE_LSRA) - } -#endif - - /* for all instructions */ - len = bptr->icount; - currentline = 0; - for (iptr = bptr->iinstr; len > 0; len--, iptr++) { + M_LDMFD(savedregs_bitmask, REG_SP); + } - /* add line number */ - if (iptr->line != currentline) { - linenumbertable_list_entry_add(cd, iptr->line); - currentline = iptr->line; - } + /* if LR was not on stack, we need to return manually */ - MCODECHECK(64); /* an instruction usually needs < 64 words */ + if (code_is_leafmethod(code)) + M_MOV(REG_PC, REG_LR); +} - /* the big switch */ - switch (iptr->opc) { - case ICMD_NOP: /* ... ==> ... */ - case ICMD_POP: /* ..., value ==> ... */ - case ICMD_POP2: /* ..., value, value ==> ... */ - 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; + + // Get required compiler data. + codegendata* cd = jd->cd; + + /* the big switch */ + switch (iptr->opc) { /* constant operations ************************************************/ - case ICMD_ICONST: /* ... ==> ..., constant */ - - d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); - ICONST(d, iptr->sx.val.i); - emit_store_dst(jd, iptr, d); - break; - case ICMD_ACONST: /* ... ==> ..., constant */ d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); @@ -414,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) @@ -448,30 +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; - - /* integer operations *************************************************/ case ICMD_INT2BYTE: /* ..., value ==> ..., value */ @@ -681,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); @@ -710,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); @@ -1150,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); @@ -1370,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); @@ -1384,111 +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); - } - 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->clazz)) { - patcher_add_patch_ref(jd, PATCHER_initialize_class, - fi->clazz, 0); - } - } - - 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); - } - 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->clazz)) { - patcher_add_patch_ref(jd, PATCHER_initialize_class, - fi->clazz, 0); - } - } - - 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); @@ -1636,12 +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); - } disp = dseg_add_functionptr(cd, asm_handle_exception); M_DSEG_LOAD(REG_ITMP3, disp); M_MOV(REG_ITMP2_XPC, REG_PC); @@ -1650,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); @@ -1689,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); @@ -1709,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); @@ -1717,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); @@ -1743,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); @@ -1751,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); @@ -1773,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); @@ -1781,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); @@ -1813,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); @@ -1821,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); @@ -1842,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); @@ -1851,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 */ @@ -2012,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 */ @@ -2031,373 +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_F2I(s1, REG_RESULT); - goto ICMD_RETURN_do; -#endif - - case ICMD_IRETURN: /* ..., retvalue ==> ... */ - REPLACEMENT_POINT_RETURN(cd, iptr); - s1 = emit_load_s1(jd, iptr, REG_RESULT); - M_INTMOVE(s1, REG_RESULT); - goto ICMD_RETURN_do; + M_DSEG_LOAD(REG_PV, disp); /* pointer to built-in-function */ - case ICMD_DRETURN: /* ..., retvalue ==> ... */ - -#if !defined(ENABLE_SOFTFLOAT) - REPLACEMENT_POINT_RETURN(cd, iptr); - s1 = emit_load_s1(jd, iptr, REG_FTMP1); - M_CAST_D2L(s1, REG_RESULT_PACKED); - goto ICMD_RETURN_do; -#endif + /* generate the actual call */ - case ICMD_LRETURN: /* ..., retvalue ==> ... */ + M_MOV(REG_LR, REG_PC); + M_MOV(REG_PC, REG_PV); - 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); - } - 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 && code_is_synchronized(code)) { - /* 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); + um = iptr->sx.s23.s3.um; + disp = dseg_add_unique_address(cd, NULL); - /* 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; - } + patcher_add_patch_ref(jd, PATCHER_invokestatic_special, + um, disp); } -#endif - - /* deallocate stackframe for spilled variables */ - - if ((cd->stackframesize / 4 - savedregs_num) > 0) - M_ADD_IMM_EXT_MUL4(REG_SP, REG_SP, cd->stackframesize / 4 - savedregs_num); - - /* restore callee saved registers + do return */ - - if (savedregs_bitmask) { - if (!code_is_leafmethod(code)) { - savedregs_bitmask &= ~(1<sx.s23.s3.fmiref->p.method; + disp = dseg_add_address(cd, lm->stubroutine); } - /* if LR was not on stack, we need to return manually */ + M_DSEG_LOAD(REG_PV, disp); /* Pointer to method */ + + /* generate the actual call */ - if (code_is_leafmethod(code)) - 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; + s1 = OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * lm->vftblindex; - MCODECHECK((s3 << 1) + 64); - - for (s3 = s3 - 1; s3 >= 0; s3--) { - var = VAR(iptr->sx.s23.s2.args[s3]); - d = md->params[s3].regoff; - - 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); - if (IS_2_WORD_TYPE(var->type)) - M_CAST_D2L(s1, d); - else - M_CAST_F2I(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); - 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); - } - 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); - - 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)); - s1 = 0; - s2 = 0; - } - else { - s1 = OFFSET(vftbl_t, interfacetable[0]) - - sizeof(methodptr*) * lm->clazz->index; - s2 = sizeof(methodptr) * (lm - lm->clazz->methods); - } + // Sanity check. + assert(REG_ITMP1 != REG_METHODPTR); + assert(REG_ITMP2 == REG_METHODPTR); + assert(REG_ITMP3 != REG_METHODPTR); - /* 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->clazz->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); - if (IS_2_WORD_TYPE(d)) - M_CAST_L2D(REG_RESULT_PACKED, s1); - else - M_CAST_I2F(REG_RESULT, 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 */ @@ -2517,17 +1932,67 @@ bool codegen_emit(jitdata *jd) emit_label_beq(cd, BRANCH_LABEL_5); } + // 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; + M_LDR_INTERN(REG_ITMP2, s1, OFFSET(java_object_t, vftbl)); M_DSEG_LOAD(REG_ITMP3, disp); - 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_DSEG_LOAD(REG_ITMP3, disp); - M_LDR_INTERN(REG_ITMP3, REG_ITMP3, OFFSET(vftbl_t, diffval)); + 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); @@ -2560,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); @@ -2709,19 +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); + // 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); - 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); + 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 */ + } + + // 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); @@ -2786,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 */ @@ -2800,29 +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 */ - - /* generate traps */ - - emit_patcher_traps(jd); - - /* everything's ok */ - - return true; + vm_abort("Unknown ICMD %d during code generation", iptr->opc); + } /* the big switch */ } @@ -2856,14 +2353,14 @@ void codegen_emit_stub_native(jitdata *jd, methoddesc *nmd, functionptr f, int s /* calculate stackframe size */ cd->stackframesize = - 4 + /* return address */ - sizeof(stackframeinfo_t) + /* 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 */ @@ -2876,12 +2373,7 @@ void codegen_emit_stub_native(jitdata *jd, methoddesc *nmd, functionptr f, int s /* generate stub code */ M_STMFD(1<stackframesize / 4 - 1); - -#if !defined(NDEBUG) - if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) - emit_verbosecall_enter(jd); -#endif + 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 @@ -2909,8 +2401,7 @@ void codegen_emit_stub_native(jitdata *jd, methoddesc *nmd, functionptr f, int s /* recompute pv */ - s1 = (s4) (cd->mcodeptr - cd->mcodebase); - M_RECOMPUTE_PV(s1); + emit_recompute_pv(cd); /* remember class argument */ @@ -2955,7 +2446,7 @@ void codegen_emit_stub_native(jitdata *jd, methoddesc *nmd, functionptr f, int s } } 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)) { @@ -2992,32 +2483,7 @@ void codegen_emit_stub_native(jitdata *jd, methoddesc *nmd, functionptr f, int s /* 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->clazz->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 */ @@ -3028,8 +2494,7 @@ void codegen_emit_stub_native(jitdata *jd, methoddesc *nmd, functionptr f, int s 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); @@ -3047,7 +2512,7 @@ void codegen_emit_stub_native(jitdata *jd, methoddesc *nmd, functionptr f, int s /* 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<