From: Michael Starzinger Date: Mon, 31 Aug 2009 22:59:30 +0000 (+0200) Subject: * src/vm/jit/codegen-common.cpp (codegen_emit): New generic version of the X-Git-Url: http://wien.tomnetworks.com/gitweb/?p=cacao.git;a=commitdiff_plain;h=2ab77f5d50859fe9849586d1be0382fb61856b8f * src/vm/jit/codegen-common.cpp (codegen_emit): New generic version of the code generating loop. This is the main point of this huge commit. There are some other changes which might be interesting about this commit, which are described in detail: * src/vm/jit/code.hpp (codeinfo): Added runtime information to replace most parts of the method header. * src/vm/jit/codegen-common.cpp (codegen_finish): Sets runtime information. (codegen_start_native_call): Use MD function to determine size of stackframe. (codegen_finish_native_call): Likewise. * src/vm/jit/codegen-common.hpp: Added prototypes of new MD functions. * src/vm/jit/emit-common.hpp: Added prototypes of new MD functions. (emit_xmove): Added generic inline functions for register moves. * src/vm/jit/optimizing/profile.c: Disabled some broken profiling code. * src/vm/jit/optimizing/profile.h: Moved definitions CPU cycle counting macros to where they belong. * src/vm/jit/replace.cpp: Uses new architecture description macros. * src/vm/jit/stacktrace.cpp: Use MD function to determine size of stackframe. The rest of the files were machine dependent adaptions of the different ports with too many changes to describe here, so I just list the files: * src/vm/jit/alpha/arch.h * src/vm/jit/alpha/codegen.c * src/vm/jit/alpha/codegen.h * src/vm/jit/alpha/emit.c * src/vm/jit/alpha/md.h * src/vm/jit/arm/arch.h * src/vm/jit/arm/codegen.c * src/vm/jit/arm/codegen.h * src/vm/jit/arm/emit.c * src/vm/jit/arm/md.h * src/vm/jit/i386/arch.h * src/vm/jit/i386/codegen.c * src/vm/jit/i386/codegen.h * src/vm/jit/i386/emit.c * src/vm/jit/i386/emit.h * src/vm/jit/i386/md.h * src/vm/jit/m68k/arch.h * src/vm/jit/m68k/codegen.c * src/vm/jit/m68k/codegen.h * src/vm/jit/m68k/emit.c * src/vm/jit/m68k/md.h * src/vm/jit/mips/arch.h * src/vm/jit/mips/codegen.c * src/vm/jit/mips/codegen.h * src/vm/jit/mips/emit.c * src/vm/jit/mips/md.h * src/vm/jit/powerpc/arch.h * src/vm/jit/powerpc/codegen.c * src/vm/jit/powerpc/codegen.h * src/vm/jit/powerpc/emit.c * src/vm/jit/powerpc/md.h * src/vm/jit/powerpc64/arch.h * src/vm/jit/powerpc64/codegen.c * src/vm/jit/powerpc64/codegen.h * src/vm/jit/powerpc64/emit.c * src/vm/jit/powerpc64/md.h * src/vm/jit/s390/arch.h * src/vm/jit/s390/codegen.c * src/vm/jit/s390/codegen.h * src/vm/jit/s390/emit.c * src/vm/jit/s390/md.h * src/vm/jit/sparc64/arch.h * src/vm/jit/sparc64/codegen.c * src/vm/jit/sparc64/codegen.h * src/vm/jit/sparc64/emit.c * src/vm/jit/sparc64/md.h * src/vm/jit/x86_64/arch.h * src/vm/jit/x86_64/codegen.c * src/vm/jit/x86_64/codegen.h * src/vm/jit/x86_64/emit.c * src/vm/jit/x86_64/emit.h * src/vm/jit/x86_64/md.h --- diff --git a/src/vm/jit/alpha/arch.h b/src/vm/jit/alpha/arch.h index 186f1d1b9..e3f96f6a2 100644 --- a/src/vm/jit/alpha/arch.h +++ b/src/vm/jit/alpha/arch.h @@ -101,6 +101,14 @@ #define SUPPORT_HARDWARE_DIVIDE_BY_ZERO 0 +/* stackframe *****************************************************************/ + +#define STACKFRMAE_RA_BETWEEN_FRAMES 0 +#define STACKFRAME_RA_TOP_OF_FRAME 1 +#define STACKFRAME_LEAFMETHODS_RA_REGISTER 1 +#define STACKFRAME_SYNC_NEEDS_TWO_SLOTS 0 + + /* replacement ****************************************************************/ #define REPLACEMENT_PATCH_SIZE 4 /* bytes */ diff --git a/src/vm/jit/alpha/codegen.c b/src/vm/jit/alpha/codegen.c index 918a94e90..209548180 100644 --- a/src/vm/jit/alpha/codegen.c +++ b/src/vm/jit/alpha/codegen.c @@ -1,6 +1,6 @@ /* src/vm/jit/alpha/codegen.c - machine code generator for Alpha - Copyright (C) 1996-2005, 2006, 2007, 2008 + Copyright (C) 1996-2005, 2006, 2007, 2008, 2009 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO This file is part of CACAO. @@ -60,98 +60,27 @@ #include "vm/jit/parse.hpp" #include "vm/jit/patcher-common.hpp" #include "vm/jit/reg.h" -#include "vm/jit/replace.hpp" #include "vm/jit/stacktrace.hpp" #include "vm/jit/trap.hpp" -#if defined(ENABLE_SSA) -# include "vm/jit/optimizing/lsra.h" -# include "vm/jit/optimizing/ssa.h" -#elif 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 len, s1, s2, s3, d, disp; - varinfo *var; - basicblock *bptr; - instruction *iptr; - u2 currentline; - methodinfo *lm; /* local methodinfo for ICMD_INVOKE* */ - unresolved_method *um; - builtintable_entry *bte; - methoddesc *md; - fieldinfo *fi; - unresolved_field *uf; - s4 fieldtype; - s4 varindex; - - /* get required compiler data */ - - m = jd->m; - code = jd->code; - cd = jd->cd; - rd = jd->rd; - - /* prevent compiler warnings */ - - d = 0; - fieldtype = 0; - lm = NULL; - um = NULL; - bte = NULL; - currentline = 0; - - { - s4 i, p, t, l; - s4 savedregs_num; - - savedregs_num = code_is_leafmethod(code) ? 0 : 1; /* space to save the RA */ - - /* space to save used callee saved registers */ - - savedregs_num += (INT_SAV_CNT - rd->savintreguse); - savedregs_num += (FLT_SAV_CNT - rd->savfltreguse); - - cd->stackframesize = rd->memuse + savedregs_num; - -#if defined(ENABLE_THREADS) /* space to save argument of monitor_enter */ - if (checksync && code_is_synchronized(code)) - cd->stackframesize++; -#endif - - /* create method header */ - -#if 0 - cd->stackframesize = (cd->stackframesize + 1) & ~1; /* align stack to 16-bytes */ -#endif - - (void) dseg_add_unique_address(cd, code); /* CodeinfoPointer */ - (void) dseg_add_unique_s4(cd, cd->stackframesize * 8); /* 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 */ + varinfo* var; + methoddesc* md; + int32_t s1; + int32_t p, t, l; + 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; /* create stack frame (if necessary) */ @@ -208,7 +137,7 @@ bool codegen_emit(jitdata *jd) else { /* floating args */ if (!md->params[p].inmemory) { /* register arguments */ if (!IS_INMEMORY(var->flags)) - M_FLTMOVE(s1, var->vv.regoff); + emit_fmove(cd, s1, var->vv.regoff); else M_DST(s1, REG_SP, var->vv.regoff); } @@ -220,187 +149,70 @@ bool codegen_emit(jitdata *jd) } } } +} - /* call monitorenter function */ - -#if defined(ENABLE_THREADS) - if (checksync && code_is_synchronized(code)) { - /* stack offset for monitor argument */ - - s1 = rd->memuse; - -#if !defined(NDEBUG) - if (opt_verbosecall) { - M_LDA(REG_SP, REG_SP, -(INT_ARG_CNT + FLT_ARG_CNT) * 8); - - for (p = 0; p < INT_ARG_CNT; p++) - M_LST(abi_registers_integer_argument[p], REG_SP, p * 8); - - for (p = 0; p < FLT_ARG_CNT; p++) - M_DST(abi_registers_float_argument[p], REG_SP, (INT_ARG_CNT + p) * 8); - - s1 += INT_ARG_CNT + FLT_ARG_CNT; - } -#endif /* !defined(NDEBUG) */ - - /* decide which monitor enter function to call */ - - if (m->flags & ACC_STATIC) { - disp = dseg_add_address(cd, &m->clazz->object.header); - M_ALD(REG_A0, REG_PV, disp); - } - else { - M_BNEZ(REG_A0, 1); - M_ALD_INTERN(REG_ZERO, REG_ZERO, TRAP_NullPointerException); - } - - M_AST(REG_A0, REG_SP, s1 * 8); - disp = dseg_add_functionptr(cd, LOCK_monitor_enter); - M_ALD(REG_PV, REG_PV, disp); - M_JSR(REG_RA, REG_PV); - disp = (s4) (cd->mcodeptr - cd->mcodebase); - M_LDA(REG_PV, REG_RA, -disp); -#if !defined(NDEBUG) - if (opt_verbosecall) { - for (p = 0; p < INT_ARG_CNT; p++) - M_LLD(abi_registers_integer_argument[p], REG_SP, p * 8); +/** + * Generates machine code for the method epilog. + */ +void codegen_emit_epilog(jitdata* jd) +{ + int32_t p; + int i; - for (p = 0; p < FLT_ARG_CNT; p++) - M_DLD(abi_registers_float_argument[p], REG_SP, (INT_ARG_CNT + p) * 8); + // Get required compiler data. + codeinfo* code = jd->code; + codegendata* cd = jd->cd; + registerdata* rd = jd->rd; - M_LDA(REG_SP, REG_SP, (INT_ARG_CNT + FLT_ARG_CNT) * 8); - } -#endif /* !defined(NDEBUG) */ - } -#endif - - /* call trace function */ + p = cd->stackframesize; -#if !defined(NDEBUG) - if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) - emit_verbosecall_enter(jd); -#endif + /* restore return address */ + if (!code_is_leafmethod(code)) { + p--; M_LLD(REG_RA, REG_SP, p * 8); } - /* end of header generation */ - - /* create replacement points */ - - REPLACEMENT_POINTS_INIT(cd, jd); - - /* walk through all basic blocks */ - - for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) { - - bptr->mpc = (s4) (cd->mcodeptr - cd->mcodebase); - - if (bptr->flags >= BBREACHED) { - - /* branch resolving */ - - codegen_resolve_branchrefs(cd, bptr); - - /* handle replacement points */ - - REPLACEMENT_POINT_BLOCK_START(cd, bptr); - - /* copy interface registers to their destination */ - - len = bptr->indepth; - MCODECHECK(64+len); -#if defined(ENABLE_LSRA) - if (opt_lsra) { - while (len) { - len--; - src = bptr->invars[len]; - if ((len == bptr->indepth-1) && (bptr->type == BBTYPE_EXH)) { - /* d = reg_of_var(m, src, REG_ITMP1); */ - if (!(src->flags & INMEMORY)) - d = src->vv.regoff; - else - d = REG_ITMP1; - M_INTMOVE(REG_ITMP1, d); - emit_store(jd, NULL, src, d); - } - } - } else { -#endif - while (len) { - len--; - var = VAR(bptr->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 - - /* walk through all instructions */ - - len = bptr->icount; + /* restore saved registers */ - for (iptr = bptr->iinstr; len > 0; len--, iptr++) { - if (iptr->line != currentline) { - linenumbertable_list_entry_add(cd, iptr->line); - currentline = iptr->line; - } - - MCODECHECK(64); /* an instruction usually needs < 64 words */ - switch (iptr->opc) { - - case ICMD_NOP: /* ... ==> ... */ - case ICMD_POP: /* ..., value ==> ... */ - case ICMD_POP2: /* ..., value, value ==> ... */ - break; - - case ICMD_INLINE_START: + for (i = INT_SAV_CNT - 1; i >= rd->savintreguse; i--) { + p--; M_LLD(rd->savintregs[i], REG_SP, p * 8); + } + for (i = FLT_SAV_CNT - 1; i >= rd->savfltreguse; i--) { + p--; M_DLD(rd->savfltregs[i], REG_SP, p * 8); + } - REPLACEMENT_POINT_INLINE_START(cd, iptr); - break; + /* deallocate stack */ - case ICMD_INLINE_BODY: + if (cd->stackframesize) + M_LDA(REG_SP, REG_SP, cd->stackframesize * 8); - REPLACEMENT_POINT_INLINE_BODY(cd, iptr); - linenumbertable_list_entry_add_inline_start(cd, iptr); - linenumbertable_list_entry_add(cd, iptr->line); - break; + M_RET(REG_ZERO, REG_RA); +} - case ICMD_INLINE_END: - linenumbertable_list_entry_add_inline_end(cd, iptr); - linenumbertable_list_entry_add(cd, iptr->line); - break; +/** + * Generates machine code for one ICMD. + */ +void codegen_emit_instruction(jitdata* jd, instruction* iptr) +{ + varinfo* var; + builtintable_entry* bte; + 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; - case ICMD_CHECKNULL: /* ..., objectref ==> ..., objectref */ + // Get required compiler data. + codegendata* cd = jd->cd; - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - emit_nullpointer_check(cd, iptr, s1); - break; + 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_LCONST: /* ... ==> ..., constant */ - - d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); - LCONST(d, iptr->sx.val.l); - emit_store_dst(jd, iptr, d); - break; - case ICMD_FCONST: /* ... ==> ..., constant */ d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); @@ -448,30 +260,6 @@ bool codegen_emit(jitdata *jd) break; - /* load/store/move/copy operations ************************************/ - - case ICMD_ILOAD: /* ... ==> ..., content of local variable */ - case ICMD_ALOAD: /* s1 = local variable */ - case ICMD_LLOAD: - case ICMD_FLOAD: - case ICMD_DLOAD: - case ICMD_ISTORE: /* ..., value ==> ... */ - case ICMD_LSTORE: - case ICMD_FSTORE: - 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_INEG: /* ..., value ==> ..., - value */ @@ -1338,15 +1126,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(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); @@ -1712,96 +1491,6 @@ bool codegen_emit(jitdata *jd) M_AST(REG_ZERO, 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, uf); - - 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_ALD(REG_ITMP1, REG_PV, disp); - switch (fieldtype) { - case TYPE_INT: - d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); - M_ILD(d, REG_ITMP1, 0); - break; - case TYPE_LNG: - d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); - M_LLD(d, REG_ITMP1, 0); - break; - case TYPE_ADR: - d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); - M_ALD(d, REG_ITMP1, 0); - break; - case TYPE_FLT: - d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); - M_FLD(d, REG_ITMP1, 0); - break; - case TYPE_DBL: - d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); - M_DLD(d, REG_ITMP1, 0); - break; - } - 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, uf); - - 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_ALD(REG_ITMP1, REG_PV, disp); - switch (fieldtype) { - case TYPE_INT: - s1 = emit_load_s1(jd, iptr, REG_ITMP2); - M_IST(s1, REG_ITMP1, 0); - break; - case TYPE_LNG: - s1 = emit_load_s1(jd, iptr, REG_ITMP2); - M_LST(s1, REG_ITMP1, 0); - break; - case TYPE_ADR: - s1 = emit_load_s1(jd, iptr, REG_ITMP2); - M_AST(s1, REG_ITMP1, 0); - break; - case TYPE_FLT: - s1 = emit_load_s1(jd, iptr, REG_FTMP2); - M_FST(s1, REG_ITMP1, 0); - break; - case TYPE_DBL: - s1 = emit_load_s1(jd, iptr, REG_FTMP2); - M_DST(s1, REG_ITMP1, 0); - break; - } - break; - case ICMD_PUTSTATICCONST: /* ... ==> ... */ /* val = value (in current instruction) */ /* following NOP) */ @@ -1975,139 +1664,83 @@ bool codegen_emit(jitdata *jd) case ICMD_ATHROW: /* ..., objectref ==> ... (, objectref) */ - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - M_INTMOVE(s1, REG_ITMP1_XPTR); - -#ifdef ENABLE_VERIFIER - if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - unresolved_class *uc = iptr->sx.s23.s2.uc; - - patcher_add_patch_ref(jd, PATCHER_resolve_class, uc, 0); - } -#endif /* ENABLE_VERIFIER */ - disp = dseg_add_functionptr(cd, asm_handle_exception); M_ALD(REG_ITMP2, REG_PV, disp); M_JMP(REG_ITMP2_XPC, REG_ITMP2); M_NOP; /* nop ensures that XPC is less than the end */ /* of basic block */ - ALIGNCODENOP; - break; - - case ICMD_GOTO: /* ... ==> ... */ - case ICMD_RET: /* ... ==> ... */ - - emit_br(cd, iptr->dst.block); - ALIGNCODENOP; - break; - - case ICMD_JSR: /* ... ==> ... */ - - emit_br(cd, iptr->sx.s23.s3.jsrtarget.block); - ALIGNCODENOP; - break; - - case ICMD_IFNULL: /* ..., value ==> ... */ - case ICMD_IFNONNULL: - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - emit_bccz(cd, iptr->dst.block, iptr->opc - ICMD_IFNULL, s1, BRANCH_OPT_NONE); break; case ICMD_IFEQ: /* ..., value ==> ... */ s1 = emit_load_s1(jd, iptr, REG_ITMP1); - if (iptr->sx.val.i == 0) - emit_beqz(cd, iptr->dst.block, s1); + if ((iptr->sx.val.i > 0) && (iptr->sx.val.i <= 255)) + M_CMPEQ_IMM(s1, iptr->sx.val.i, REG_ITMP1); else { - if ((iptr->sx.val.i > 0) && (iptr->sx.val.i <= 255)) - M_CMPEQ_IMM(s1, iptr->sx.val.i, REG_ITMP1); - else { - ICONST(REG_ITMP2, iptr->sx.val.i); - M_CMPEQ(s1, REG_ITMP2, REG_ITMP1); - } - emit_bnez(cd, iptr->dst.block, REG_ITMP1); + ICONST(REG_ITMP2, iptr->sx.val.i); + M_CMPEQ(s1, REG_ITMP2, REG_ITMP1); } + emit_bnez(cd, iptr->dst.block, REG_ITMP1); break; case ICMD_IFLT: /* ..., value ==> ... */ s1 = emit_load_s1(jd, iptr, REG_ITMP1); - if (iptr->sx.val.i == 0) - emit_bltz(cd, iptr->dst.block, s1); + if ((iptr->sx.val.i > 0) && (iptr->sx.val.i <= 255)) + M_CMPLT_IMM(s1, iptr->sx.val.i, REG_ITMP1); else { - if ((iptr->sx.val.i > 0) && (iptr->sx.val.i <= 255)) - M_CMPLT_IMM(s1, iptr->sx.val.i, REG_ITMP1); - else { - ICONST(REG_ITMP2, iptr->sx.val.i); - M_CMPLT(s1, REG_ITMP2, REG_ITMP1); - } - emit_bnez(cd, iptr->dst.block, REG_ITMP1); + ICONST(REG_ITMP2, iptr->sx.val.i); + M_CMPLT(s1, REG_ITMP2, REG_ITMP1); } + emit_bnez(cd, iptr->dst.block, REG_ITMP1); break; case ICMD_IFLE: /* ..., value ==> ... */ s1 = emit_load_s1(jd, iptr, REG_ITMP1); - if (iptr->sx.val.i == 0) - emit_blez(cd, iptr->dst.block, s1); + if ((iptr->sx.val.i > 0) && (iptr->sx.val.i <= 255)) + M_CMPLE_IMM(s1, iptr->sx.val.i, REG_ITMP1); else { - if ((iptr->sx.val.i > 0) && (iptr->sx.val.i <= 255)) - M_CMPLE_IMM(s1, iptr->sx.val.i, REG_ITMP1); - else { - ICONST(REG_ITMP2, iptr->sx.val.i); - M_CMPLE(s1, REG_ITMP2, REG_ITMP1); - } - emit_bnez(cd, iptr->dst.block, REG_ITMP1); + ICONST(REG_ITMP2, iptr->sx.val.i); + M_CMPLE(s1, REG_ITMP2, REG_ITMP1); } + emit_bnez(cd, iptr->dst.block, REG_ITMP1); break; case ICMD_IFNE: /* ..., value ==> ... */ s1 = emit_load_s1(jd, iptr, REG_ITMP1); - if (iptr->sx.val.i == 0) - emit_bnez(cd, iptr->dst.block, s1); + if ((iptr->sx.val.i > 0) && (iptr->sx.val.i <= 255)) + M_CMPEQ_IMM(s1, iptr->sx.val.i, REG_ITMP1); else { - if ((iptr->sx.val.i > 0) && (iptr->sx.val.i <= 255)) - M_CMPEQ_IMM(s1, iptr->sx.val.i, REG_ITMP1); - else { - ICONST(REG_ITMP2, iptr->sx.val.i); - M_CMPEQ(s1, REG_ITMP2, REG_ITMP1); - } - emit_beqz(cd, iptr->dst.block, REG_ITMP1); + ICONST(REG_ITMP2, iptr->sx.val.i); + M_CMPEQ(s1, REG_ITMP2, REG_ITMP1); } + emit_beqz(cd, iptr->dst.block, REG_ITMP1); break; case ICMD_IFGT: /* ..., value ==> ... */ s1 = emit_load_s1(jd, iptr, REG_ITMP1); - if (iptr->sx.val.i == 0) - emit_bgtz(cd, iptr->dst.block, s1); + if ((iptr->sx.val.i > 0) && (iptr->sx.val.i <= 255)) + M_CMPLE_IMM(s1, iptr->sx.val.i, REG_ITMP1); else { - if ((iptr->sx.val.i > 0) && (iptr->sx.val.i <= 255)) - M_CMPLE_IMM(s1, iptr->sx.val.i, REG_ITMP1); - else { - ICONST(REG_ITMP2, iptr->sx.val.i); - M_CMPLE(s1, REG_ITMP2, REG_ITMP1); - } - emit_beqz(cd, iptr->dst.block, REG_ITMP1); + ICONST(REG_ITMP2, iptr->sx.val.i); + M_CMPLE(s1, REG_ITMP2, REG_ITMP1); } + emit_beqz(cd, iptr->dst.block, REG_ITMP1); break; case ICMD_IFGE: /* ..., value ==> ... */ s1 = emit_load_s1(jd, iptr, REG_ITMP1); - if (iptr->sx.val.i == 0) - emit_bgez(cd, iptr->dst.block, s1); + if ((iptr->sx.val.i > 0) && (iptr->sx.val.i <= 255)) + M_CMPLT_IMM(s1, iptr->sx.val.i, REG_ITMP1); else { - if ((iptr->sx.val.i > 0) && (iptr->sx.val.i <= 255)) - M_CMPLT_IMM(s1, iptr->sx.val.i, REG_ITMP1); - else { - ICONST(REG_ITMP2, iptr->sx.val.i); - M_CMPLT(s1, REG_ITMP2, REG_ITMP1); - } - emit_beqz(cd, iptr->dst.block, REG_ITMP1); + ICONST(REG_ITMP2, iptr->sx.val.i); + M_CMPLT(s1, REG_ITMP2, REG_ITMP1); } + emit_beqz(cd, iptr->dst.block, REG_ITMP1); break; case ICMD_IF_LEQ: /* ..., value ==> ... */ @@ -2208,7 +1841,6 @@ bool codegen_emit(jitdata *jd) case ICMD_IF_ICMPEQ: /* ..., value, value ==> ... */ case ICMD_IF_LCMPEQ: /* op1 = target JavaVM pc */ - case ICMD_IF_ACMPEQ: s1 = emit_load_s1(jd, iptr, REG_ITMP1); s2 = emit_load_s2(jd, iptr, REG_ITMP2); @@ -2218,7 +1850,6 @@ bool codegen_emit(jitdata *jd) case ICMD_IF_ICMPNE: /* ..., value, value ==> ... */ case ICMD_IF_LCMPNE: /* op1 = target JavaVM pc */ - case ICMD_IF_ACMPNE: s1 = emit_load_s1(jd, iptr, REG_ITMP1); s2 = emit_load_s2(jd, iptr, REG_ITMP2); @@ -2262,117 +1893,6 @@ bool codegen_emit(jitdata *jd) emit_beqz(cd, iptr->dst.block, REG_ITMP1); break; - - case ICMD_IRETURN: /* ..., retvalue ==> ... */ - case ICMD_LRETURN: - - REPLACEMENT_POINT_RETURN(cd, iptr); - s1 = emit_load_s1(jd, iptr, REG_RESULT); - M_INTMOVE(s1, REG_RESULT); - goto nowperformreturn; - - case ICMD_ARETURN: /* ..., retvalue ==> ... */ - - REPLACEMENT_POINT_RETURN(cd, iptr); - s1 = emit_load_s1(jd, iptr, REG_RESULT); - M_INTMOVE(s1, REG_RESULT); - -#ifdef ENABLE_VERIFIER - if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - unresolved_class *uc = iptr->sx.s23.s2.uc; - - patcher_add_patch_ref(jd, PATCHER_resolve_class, uc, 0); - } -#endif /* ENABLE_VERIFIER */ - goto nowperformreturn; - - case ICMD_FRETURN: /* ..., retvalue ==> ... */ - case ICMD_DRETURN: - - REPLACEMENT_POINT_RETURN(cd, iptr); - s1 = emit_load_s1(jd, iptr, REG_FRESULT); - M_FLTMOVE(s1, REG_FRESULT); - goto nowperformreturn; - - case ICMD_RETURN: /* ... ==> ... */ - - REPLACEMENT_POINT_RETURN(cd, iptr); - -nowperformreturn: - { - s4 i, p; - - p = cd->stackframesize; - - /* call trace function */ - -#if !defined(NDEBUG) - if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) - emit_verbosecall_exit(jd); -#endif - -#if defined(ENABLE_THREADS) - if (checksync && code_is_synchronized(code)) { - M_ALD(REG_A0, REG_SP, rd->memuse * 8); - - switch (iptr->opc) { - case ICMD_IRETURN: - case ICMD_LRETURN: - case ICMD_ARETURN: - M_LST(REG_RESULT, REG_SP, rd->memuse * 8); - break; - case ICMD_FRETURN: - case ICMD_DRETURN: - M_DST(REG_FRESULT, REG_SP, rd->memuse * 8); - break; - } - - disp = dseg_add_functionptr(cd, LOCK_monitor_exit); - M_ALD(REG_PV, REG_PV, disp); - M_JSR(REG_RA, REG_PV); - disp = -(s4) (cd->mcodeptr - cd->mcodebase); - M_LDA(REG_PV, REG_RA, disp); - - switch (iptr->opc) { - case ICMD_IRETURN: - case ICMD_LRETURN: - case ICMD_ARETURN: - M_LLD(REG_RESULT, REG_SP, rd->memuse * 8); - break; - case ICMD_FRETURN: - case ICMD_DRETURN: - M_DLD(REG_FRESULT, REG_SP, rd->memuse * 8); - break; - } - } -#endif - - /* restore return address */ - - if (!code_is_leafmethod(code)) { - p--; M_LLD(REG_RA, REG_SP, p * 8); - } - - /* restore saved registers */ - - for (i = INT_SAV_CNT - 1; i >= rd->savintreguse; i--) { - p--; M_LLD(rd->savintregs[i], REG_SP, p * 8); - } - for (i = FLT_SAV_CNT - 1; i >= rd->savfltreguse; i--) { - p--; M_DLD(rd->savfltregs[i], REG_SP, p * 8); - } - - /* deallocate stack */ - - if (cd->stackframesize) - M_LDA(REG_SP, REG_SP, cd->stackframesize * 8); - - M_RET(REG_ZERO, REG_RA); - ALIGNCODENOP; - } - break; - - case ICMD_TABLESWITCH: /* ..., index ==> ... */ { s4 i, l; @@ -2424,216 +1944,92 @@ nowperformreturn: ALIGNCODENOP; break; + case ICMD_BUILTIN: /* ..., arg1, arg2, arg3 ==> ... */ + bte = iptr->sx.s23.s3.bte; + if (bte->stub == NULL) + disp = dseg_add_functionptr(cd, bte->fp); + else + disp = dseg_add_functionptr(cd, bte->stub); - case ICMD_LOOKUPSWITCH: /* ..., key ==> ... */ - { - s4 i, val; - lookup_target_t *lookup; - - lookup = iptr->dst.lookup; - - i = iptr->sx.s23.s2.lookupcount; - - MCODECHECK((i<<2)+8); - s1 = emit_load_s1(jd, iptr, REG_ITMP1); + M_ALD(REG_PV, REG_PV, disp); /* Pointer to built-in-function */ - while (--i >= 0) { - val = lookup->value; - if ((val >= 0) && (val <= 255)) { - M_CMPEQ_IMM(s1, val, REG_ITMP2); - } else { - if ((val >= -32768) && (val <= 32767)) { - M_LDA(REG_ITMP2, REG_ZERO, val); - } else { - disp = dseg_add_s4(cd, val); - M_ILD(REG_ITMP2, REG_PV, disp); - } - M_CMPEQ(s1, REG_ITMP2, REG_ITMP2); - } - emit_bnez(cd, lookup->target.block, REG_ITMP2); - lookup++; - } + /* generate the actual call */ - emit_br(cd, iptr->sx.s23.s3.lookupdefault.block); - ALIGNCODENOP; + M_JSR(REG_RA, REG_PV); break; - } - - - case ICMD_BUILTIN: /* ..., arg1, arg2, arg3 ==> ... */ - - REPLACEMENT_POINT_FORGC_BUILTIN(cd, iptr); - bte = iptr->sx.s23.s3.bte; - md = bte->md; - goto gen_method; + case ICMD_INVOKESPECIAL: + emit_nullpointer_check(cd, iptr, REG_A0); + /* fall-through */ case ICMD_INVOKESTATIC: /* ..., [arg1, [arg2 ...]] ==> ... */ - - case ICMD_INVOKESPECIAL:/* ..., objectref, [arg1, [arg2 ...]] ==> ... */ - case ICMD_INVOKEVIRTUAL:/* op1 = arg count, val.a = method pointer */ - case ICMD_INVOKEINTERFACE: - - REPLACEMENT_POINT_INVOKE(cd, iptr); - if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - lm = NULL; um = iptr->sx.s23.s3.um; - md = um->methodref->parseddesc.md; + disp = dseg_add_unique_address(cd, um); + + patcher_add_patch_ref(jd, PATCHER_invokestatic_special, + um, disp); } else { lm = iptr->sx.s23.s3.fmiref->p.method; - um = NULL; - md = lm->parseddesc; + disp = dseg_add_address(cd, lm->stubroutine); } -gen_method: - s3 = md->paramcount; + M_ALD(REG_PV, REG_PV, disp); /* method pointer in r27 */ - MCODECHECK((s3 << 1) + 64); + /* generate the actual call */ - /* copy arguments to registers or stack location */ - - for (s3 = s3 - 1; s3 >= 0; s3--) { - var = VAR(iptr->sx.s23.s2.args[s3]); - d = md->params[s3].regoff; - - /* already preallocated (ARGVAR)? */ + M_JSR(REG_RA, REG_PV); + break; - if (var->flags & PREALLOC) - continue; + case ICMD_INVOKEVIRTUAL:/* op1 = arg count, val.a = method pointer */ + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + um = iptr->sx.s23.s3.um; + patcher_add_patch_ref(jd, PATCHER_invokevirtual, um, 0); - if (IS_INT_LNG_TYPE(var->type)) { - if (!md->params[s3].inmemory) { - s1 = emit_load(jd, iptr, var, d); - M_INTMOVE(s1, d); - } - else { - s1 = emit_load(jd, iptr, var, REG_ITMP1); - M_LST(s1, REG_SP, d); - } - } - else { - if (!md->params[s3].inmemory) { - s1 = emit_load(jd, iptr, var, d); - M_FLTMOVE(s1, d); - } - else { - s1 = emit_load(jd, iptr, var, REG_FTMP1); - M_DST(s1, REG_SP, d); - } - } + s1 = 0; + } + else { + lm = iptr->sx.s23.s3.fmiref->p.method; + s1 = OFFSET(vftbl_t, table[0]) + + sizeof(methodptr) * lm->vftblindex; } - 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_ALD(REG_PV, REG_PV, disp); /* Pointer to built-in-function */ - - /* generate the actual call */ - - M_JSR(REG_RA, REG_PV); - REPLACEMENT_POINT_FORGC_BUILTIN_RETURN(cd, iptr); - disp = (s4) (cd->mcodeptr - cd->mcodebase); - M_LDA(REG_PV, REG_RA, -disp); - 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, um); - - patcher_add_patch_ref(jd, PATCHER_invokestatic_special, - um, disp); - } - else - disp = dseg_add_address(cd, lm->stubroutine); - - M_ALD(REG_PV, REG_PV, disp); /* method pointer in r27 */ - - /* generate the actual call */ - - M_JSR(REG_RA, REG_PV); - REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr); - disp = (s4) (cd->mcodeptr - cd->mcodebase); - M_LDA(REG_PV, REG_RA, -disp); - 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_ALD(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl)); - M_ALD(REG_PV, REG_METHODPTR, s1); - - /* generate the actual call */ - - M_JSR(REG_RA, REG_PV); - REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr); - disp = (s4) (cd->mcodeptr - cd->mcodebase); - M_LDA(REG_PV, REG_RA, -disp); - break; - - case ICMD_INVOKEINTERFACE: - if (lm == NULL) { - patcher_add_patch_ref(jd, PATCHER_invokeinterface, um, 0); + /* implicit null-pointer check */ + M_ALD(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl)); + M_ALD(REG_PV, REG_METHODPTR, s1); - s1 = 0; - s2 = 0; - } - else { - s1 = OFFSET(vftbl_t, interfacetable[0]) - - sizeof(methodptr*) * lm->clazz->index; + /* generate the actual call */ - s2 = sizeof(methodptr) * (lm - lm->clazz->methods); - } - - /* implicit null-pointer check */ - M_ALD(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl)); - M_ALD(REG_METHODPTR, REG_METHODPTR, s1); - M_ALD(REG_PV, REG_METHODPTR, s2); + M_JSR(REG_RA, REG_PV); + break; - /* generate the actual call */ + case ICMD_INVOKEINTERFACE: + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + um = iptr->sx.s23.s3.um; + patcher_add_patch_ref(jd, PATCHER_invokeinterface, um, 0); - M_JSR(REG_RA, REG_PV); - REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr); - disp = (s4) (cd->mcodeptr - cd->mcodebase); - M_LDA(REG_PV, REG_RA, -disp); - break; + s1 = 0; + s2 = 0; } + else { + lm = iptr->sx.s23.s3.fmiref->p.method; + s1 = OFFSET(vftbl_t, interfacetable[0]) - + sizeof(methodptr*) * lm->clazz->index; - /* store the return value */ + s2 = sizeof(methodptr) * (lm - lm->clazz->methods); + } + + /* implicit null-pointer check */ + M_ALD(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl)); + M_ALD(REG_METHODPTR, REG_METHODPTR, s1); + M_ALD(REG_PV, REG_METHODPTR, s2); - d = md->returntype.type; + /* generate the actual call */ - if (d != TYPE_VOID) { - if (IS_INT_LNG_TYPE(d)) { - s1 = codegen_reg_of_dst(jd, iptr, REG_RESULT); - M_INTMOVE(REG_RESULT, s1); - } - else { - s1 = codegen_reg_of_dst(jd, iptr, REG_FRESULT); - M_FLTMOVE(REG_FRESULT, s1); - } - emit_store_dst(jd, iptr, s1); - } + M_JSR(REG_RA, REG_PV); break; - case ICMD_CHECKCAST: /* ..., objectref ==> ..., objectref */ if (!(iptr->flags.bits & INS_FLAG_ARRAY)) { @@ -3029,23 +2425,8 @@ gen_method: break; default: - exceptions_throw_internalerror("Unknown ICMD %d during code generation", - iptr->opc); - return false; + vm_abort("Unknown ICMD %d during code generation", iptr->opc); } /* switch */ - - } /* for instruction */ - - } /* if (bptr -> flags >= BBREACHED) */ - } /* for basic block */ - - /* generate traps */ - - emit_patcher_traps(jd); - - /* everything's ok */ - - return true; } @@ -3197,7 +2578,7 @@ void codegen_emit_stub_native(jitdata *jd, methoddesc *nmd, functionptr f, int s s2 = nmd->params[j].regoff; if (!nmd->params[j].inmemory) - M_FLTMOVE(s1, s2); + emit_fmove(cd, s1, s2); else { if (IS_2_WORD_TYPE(t)) M_DST(s1, REG_SP, s2); diff --git a/src/vm/jit/alpha/codegen.h b/src/vm/jit/alpha/codegen.h index 17953240b..2d4db729e 100644 --- a/src/vm/jit/alpha/codegen.h +++ b/src/vm/jit/alpha/codegen.h @@ -59,30 +59,6 @@ } -/* M_INTMOVE: - generates an integer-move from register a to b. - if a and b are the same int-register, no code will be generated. -*/ - -#define M_INTMOVE(a,b) \ - do { \ - if ((a) != (b)) \ - M_MOV(a, b); \ - } while (0) - - -/* M_FLTMOVE: - generates a floating-point-move from register a to b. - if a and b are the same float-register, no code will be generated -*/ - -#define M_FLTMOVE(a,b) \ - do { \ - if ((a) != (b)) \ - M_FMOV(a, b); \ - } while (0) - - #define ICONST(d,c) emit_iconst(cd, (d), (c)) #define LCONST(d,c) emit_lconst(cd, (d), (c)) @@ -230,6 +206,7 @@ #define M_ALD_INTERN(a,b,disp) M_LLD_INTERN(a,b,disp) #define M_ALD(a,b,disp) M_LLD(a,b,disp) /* addr load */ +#define M_ALD_DSEG(a,disp) M_LLD(a,REG_PV,disp) #define M_BST(a,b,disp) M_MEM(0x0e,a,b,disp) /* 8 store */ #define M_SST(a,b,disp) M_MEM(0x0d,a,b,disp) /* 16 store */ @@ -431,6 +408,7 @@ #define M_FCMPLTS(a,b,c) M_FOP3 (0x16, 0x5a6, a,b,c) /* c = a= 0) && (value <= 255)) { + M_CMPEQ_IMM(reg, value, d); + } else { + assert(reg != REG_ITMP2); + if ((value >= -32768) && (value <= 32767)) { + M_LDA(REG_ITMP2, REG_ZERO, value); + } else { + disp = dseg_add_s4(cd, value); + M_ILD(REG_ITMP2, REG_PV, disp); + } + M_CMPEQ(reg, REG_ITMP2, d); + } +} + + /* emit_branch ***************************************************************** Emits the code for conditional and unconditional branchs. @@ -455,6 +477,124 @@ uint32_t emit_trap(codegendata *cd) } +/** + * Emit code to recompute the procedure vector. + */ +void emit_recompute_pv(codegendata *cd) +{ + int32_t disp = (int32_t) (cd->mcodeptr - cd->mcodebase); + + M_LDA(REG_PV, REG_RA, -disp); +} + + +/** + * Generates synchronization code to enter a monitor. + */ +#if defined(ENABLE_THREADS) +void emit_monitor_enter(jitdata* jd, int32_t syncslot_offset) +{ + int32_t p; + int32_t disp; + + // Get required compiler data. + methodinfo* m = jd->m; + codegendata* cd = jd->cd; + +#if !defined(NDEBUG) + if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) { + M_LDA(REG_SP, REG_SP, -(INT_ARG_CNT + FLT_ARG_CNT) * 8); + + for (p = 0; p < INT_ARG_CNT; p++) + M_LST(abi_registers_integer_argument[p], REG_SP, p * 8); + + for (p = 0; p < FLT_ARG_CNT; p++) + M_DST(abi_registers_float_argument[p], REG_SP, (INT_ARG_CNT + p) * 8); + + syncslot_offset += (INT_ARG_CNT + FLT_ARG_CNT) * 8; + } +#endif /* !defined(NDEBUG) */ + + /* decide which monitor enter function to call */ + + if (m->flags & ACC_STATIC) { + disp = dseg_add_address(cd, &m->clazz->object.header); + M_ALD(REG_A0, REG_PV, disp); + } + else { + M_BNEZ(REG_A0, 1); + M_ALD_INTERN(REG_ZERO, REG_ZERO, TRAP_NullPointerException); + } + + M_AST(REG_A0, REG_SP, syncslot_offset); + disp = dseg_add_functionptr(cd, LOCK_monitor_enter); + M_ALD(REG_PV, REG_PV, disp); + M_JSR(REG_RA, REG_PV); + emit_recompute_pv(cd); + +#if !defined(NDEBUG) + if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) { + for (p = 0; p < INT_ARG_CNT; p++) + M_LLD(abi_registers_integer_argument[p], REG_SP, p * 8); + + for (p = 0; p < FLT_ARG_CNT; p++) + M_DLD(abi_registers_float_argument[p], REG_SP, (INT_ARG_CNT + p) * 8); + + M_LDA(REG_SP, REG_SP, (INT_ARG_CNT + FLT_ARG_CNT) * 8); + } +#endif +} +#endif + + +/** + * Generates synchronization code to leave a monitor. + */ +#if defined(ENABLE_THREADS) +void emit_monitor_exit(jitdata* jd, int32_t syncslot_offset) +{ + int32_t disp; + + // Get required compiler data. + methodinfo* m = jd->m; + codegendata* cd = jd->cd; + + M_ALD(REG_A0, REG_SP, syncslot_offset); + + methoddesc* md = m->parseddesc; + + switch (md->returntype.type) { + case TYPE_INT: + case TYPE_LNG: + case TYPE_ADR: + M_LST(REG_RESULT, REG_SP, syncslot_offset); + break; + case TYPE_FLT: + case TYPE_DBL: + M_DST(REG_FRESULT, REG_SP, syncslot_offset); + break; + } + + disp = dseg_add_functionptr(cd, LOCK_monitor_exit); + M_ALD(REG_PV, REG_PV, disp); + M_JSR(REG_RA, REG_PV); + emit_recompute_pv(cd); + + switch (md->returntype.type) { + case TYPE_INT: + case TYPE_LNG: + case TYPE_ADR: + M_LLD(REG_RESULT, REG_SP, syncslot_offset); + break; + case TYPE_FLT: + case TYPE_DBL: + M_DLD(REG_FRESULT, REG_SP, syncslot_offset); + break; + } +} +#endif + + /* emit_verbosecall_enter ****************************************************** Generates the code for the call trace. diff --git a/src/vm/jit/alpha/md.h b/src/vm/jit/alpha/md.h index e939d3803..08d4cca2e 100644 --- a/src/vm/jit/alpha/md.h +++ b/src/vm/jit/alpha/md.h @@ -47,6 +47,21 @@ extern bool has_ext_instr_set; /* inline functions ***********************************************************/ +/** + * Returns the size (in bytes) of the current stackframe, specified by + * the passed codeinfo structure. + */ +inline static int32_t md_stacktrace_get_framesize(codeinfo* code) +{ + // Check for the asm_vm_call_method special case. + if (code == NULL) + return 0; + + // On Alpha we use 8-byte stackslots. + return code->stackframesize * 8; +} + + /* md_stacktrace_get_returnaddress ********************************************* Returns the return address of the current stackframe, specified by diff --git a/src/vm/jit/arm/arch.h b/src/vm/jit/arm/arch.h index 8cd876903..2d282f957 100644 --- a/src/vm/jit/arm/arch.h +++ b/src/vm/jit/arm/arch.h @@ -113,6 +113,14 @@ #define SUPPORT_HARDWARE_DIVIDE_BY_ZERO 0 +/* stackframe *****************************************************************/ + +#define STACKFRMAE_RA_BETWEEN_FRAMES 0 +#define STACKFRAME_RA_TOP_OF_FRAME 1 +#define STACKFRAME_LEAFMETHODS_RA_REGISTER 1 +#define STACKFRAME_SYNC_NEEDS_TWO_SLOTS 0 + + /* replacement ****************************************************************/ #define REPLACEMENT_PATCH_SIZE 4 /* bytes */ diff --git a/src/vm/jit/arm/codegen.c b/src/vm/jit/arm/codegen.c index 34bf177ca..05d3613cf 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-2005, 2006, 2007, 2008, 2009 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO This file is part of CACAO. @@ -61,124 +61,55 @@ #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; + 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. + codeinfo* code = jd->code; + 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); @@ -1385,26 +1210,6 @@ bool codegen_emit(jitdata *jd) 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) @@ -1437,58 +1242,6 @@ bool codegen_emit(jitdata *jd) 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,16 +1389,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); - -#ifdef ENABLE_VERIFIER - if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - unresolved_class *uc = iptr->sx.s23.s2.uc; - patcher_add_patch_ref(jd, PATCHER_resolve_class, uc, 0); - } -#endif /* ENABLE_VERIFIER */ - disp = dseg_add_functionptr(cd, asm_handle_exception); M_DSEG_LOAD(REG_ITMP3, disp); M_MOV(REG_ITMP2_XPC, REG_PC); @@ -1654,37 +1397,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); @@ -1693,7 +1405,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); @@ -1713,7 +1425,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); @@ -1721,7 +1433,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); @@ -1747,7 +1459,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); @@ -1755,7 +1467,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); @@ -1777,7 +1489,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); @@ -1785,7 +1497,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); @@ -1817,7 +1529,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); @@ -1825,7 +1537,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); @@ -1846,7 +1558,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); @@ -1855,28 +1567,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 */ @@ -2016,7 +1706,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 */ @@ -2035,407 +1725,146 @@ 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); - } - 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; - - 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 - - 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; - - case ICMD_ARETURN: /* ..., retvalue ==> ... */ - - REPLACEMENT_POINT_RETURN(cd, iptr); - s1 = emit_load_s1(jd, iptr, REG_RESULT); - M_INTMOVE(s1, REG_RESULT); - -#ifdef ENABLE_VERIFIER - if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - unresolved_class *uc = iptr->sx.s23.s2.uc; - patcher_add_patch_ref(jd, PATCHER_resolve_class, uc, 0); + case ICMD_BUILTIN: + bte = iptr->sx.s23.s3.bte; + if (bte->stub == NULL) { + disp = dseg_add_functionptr(cd, bte->fp); + } else { + disp = dseg_add_functionptr(cd, bte->stub); } -#endif /* ENABLE_VERIFIER */ - goto ICMD_RETURN_do; + M_DSEG_LOAD(REG_PV, disp); /* pointer to built-in-function */ - case ICMD_RETURN: /* ... ==> ... */ + /* generate the actual call */ - REPLACEMENT_POINT_RETURN(cd, iptr); - ICMD_RETURN_do: + M_MOV(REG_LR, REG_PC); + M_MOV(REG_PC, REG_PV); -#if !defined(NDEBUG) - if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) - emit_verbosecall_exit(jd); +#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 (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 - -#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); - - /* 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; + /* 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); } } #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< ... */ - - bte = iptr->sx.s23.s3.bte; - md = bte->md; - goto ICMD_INVOKE_do; - - case ICMD_INVOKESTATIC: /* ..., [arg1, [arg2 ...]] ==> ... */ - case ICMD_INVOKESPECIAL:/* ..., objectref, [arg1, [arg2 ...]] ==> ... */ - case ICMD_INVOKEVIRTUAL:/* op1 = arg count, val.a = method pointer */ - case ICMD_INVOKEINTERFACE: - - REPLACEMENT_POINT_INVOKE(cd, iptr); + case ICMD_INVOKESPECIAL: + emit_nullpointer_check(cd, iptr, REG_A0); + /* fall through */ + case ICMD_INVOKESTATIC: if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - lm = NULL; um = iptr->sx.s23.s3.um; - md = um->methodref->parseddesc.md; + disp = dseg_add_unique_address(cd, NULL); + + patcher_add_patch_ref(jd, PATCHER_invokestatic_special, + um, disp); } else { lm = iptr->sx.s23.s3.fmiref->p.method; - um = NULL; - md = lm->parseddesc; + disp = dseg_add_address(cd, lm->stubroutine); } - 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; + M_DSEG_LOAD(REG_PV, disp); /* Pointer to method */ - if (var->flags & PREALLOC) /* argument was precolored? */ - continue; + /* generate the actual call */ - /* 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) */ - } - - 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) { - int32_t disp = dseg_add_unique_s4(cd, 0); - patcher_add_patch_ref(jd, PATCHER_invokevirtual, um, disp); - - // 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_MOV(REG_LR, REG_PC); + M_MOV(REG_PC, REG_PV); + break; - // Sanity check. - assert(REG_ITMP1 != REG_METHODPTR); - assert(REG_ITMP2 == REG_METHODPTR); + 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); - M_DSEG_LOAD(REG_ITMP1, disp); - M_ADD(REG_METHODPTR, REG_METHODPTR, REG_ITMP1); + // 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)); - // 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 { - s1 = OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * lm->vftblindex; + // Sanity check. + assert(REG_ITMP1 != REG_METHODPTR); + assert(REG_ITMP2 == REG_METHODPTR); - // 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); - } + M_DSEG_LOAD(REG_ITMP1, disp); + M_ADD(REG_METHODPTR, REG_METHODPTR, REG_ITMP1); - // 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; + // 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, table[0]) + sizeof(methodptr) * lm->vftblindex; - case ICMD_INVOKEINTERFACE: - if (lm == NULL) { - int32_t disp = dseg_add_unique_s4(cd, 0); - int32_t disp2 = dseg_add_unique_s4(cd, 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)); + M_LDR(REG_PV, REG_METHODPTR, s1); + } - // XXX We need two displacements. - assert(disp2 == disp - 4); - patcher_add_patch_ref(jd, PATCHER_invokeinterface, um, disp); + // Generate the actual call. + M_MOV(REG_LR, REG_PC); + M_MOV(REG_PC, REG_PV); + break; - // 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_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); - // Sanity check. - assert(REG_ITMP1 != REG_METHODPTR); - assert(REG_ITMP2 == REG_METHODPTR); - assert(REG_ITMP3 != REG_METHODPTR); + // XXX We need two displacements. + assert(disp2 == disp - 4); + patcher_add_patch_ref(jd, PATCHER_invokeinterface, um, disp); - M_DSEG_LOAD(REG_ITMP1, disp); - M_LDR_REG(REG_METHODPTR, REG_METHODPTR, REG_ITMP1); + // 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_DSEG_LOAD(REG_ITMP3, disp2); - M_ADD(REG_METHODPTR, REG_METHODPTR, REG_ITMP3); + // Sanity check. + assert(REG_ITMP1 != REG_METHODPTR); + assert(REG_ITMP2 == REG_METHODPTR); + assert(REG_ITMP3 != REG_METHODPTR); - // 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 { - s1 = OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr*) * lm->clazz->index; - s2 = sizeof(methodptr) * (lm - lm->clazz->methods); + M_DSEG_LOAD(REG_ITMP1, disp); + M_LDR_REG(REG_METHODPTR, REG_METHODPTR, REG_ITMP1); - // 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); - } + M_DSEG_LOAD(REG_ITMP3, disp2); + M_ADD(REG_METHODPTR, REG_METHODPTR, REG_ITMP3); - // 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; + // 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 */ @@ -2648,9 +2077,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); @@ -2929,8 +2356,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 */ @@ -2943,29 +2369,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 */ } @@ -3052,8 +2458,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 */ @@ -3135,8 +2540,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); + emit_recompute_pv(cd); #if !defined(__SOFTFP__) /* TODO: this is only a hack, since we use R0/R1 for float return! */ @@ -3171,8 +2575,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); diff --git a/src/vm/jit/arm/codegen.h b/src/vm/jit/arm/codegen.h index 0191858b8..f7fd56ab0 100644 --- a/src/vm/jit/arm/codegen.h +++ b/src/vm/jit/arm/codegen.h @@ -78,22 +78,15 @@ codegen_increase(cd); \ } while (0) +#define ALIGNCODENOP /* empty */ /* TODO: correct this! */ #define IS_IMM(val) ( ((val) >= 0) && ((val) <= 255) ) #define IS_OFFSET(off,max) ((s4)(off) <= (max) && (s4)(off) >= -(max)) -#if !defined(NDEBUG) -# define CHECK_INT_REG(r) if ((r)<0 || (r)>15) printf("CHECK_INT_REG: this is not an integer register: %d\n", r); assert((r)>=0 && (r)<=15) -# define CHECK_FLT_REG(r) if ((r)<0 || (r)>7) printf("CHECK_FLT_REG: this is not an float register: %d\n", r); assert((r)>=0 && (r)<=7) -# define CHECK_OFFSET(off,max) \ - if (!IS_OFFSET(off,max)) printf("CHECK_OFFSET: offset out of range: %x (>%x) SEVERE ERROR!!!\n", ((off)<0)?-(off):off, max); \ - assert(IS_OFFSET(off,max)) -#else -# define CHECK_INT_REG(r) -# define CHECK_FLT_REG(r) -# define CHECK_OFFSET(off,max) -#endif +#define CHECK_INT_REG(r) assert((r)>=0 && (r)<=15) +#define CHECK_FLT_REG(r) assert((r)>=0 && (r)<=7) +#define CHECK_OFFSET(off,max) assert(IS_OFFSET(off,max)) /* branch defines *************************************************************/ @@ -1105,66 +1098,6 @@ do { \ #endif /* !defined(ENABLE_SOFTFLOAT) */ -/* M_RECOMPUTE_PV: - used to recompute our PV (we use the IP for this) out of the current PC - ATTENTION: if you change this, you have to look at other functions as well! - Following things depend on it: md_codegen_get_pv_from_pc(); -*/ -#define M_RECOMPUTE_PV(disp) \ - disp += 8; /* we use PC relative addr. */ \ - assert((disp & 0x03) == 0); \ - assert(disp >= 0 && disp <= 0x03ffffff); \ - if (disp > 0x0003ffff) { \ - M_SUB_IMM(REG_PV, REG_PC, IMM_ROTL(disp >> 18, 9)); \ - M_SUB_IMM(REG_PV, REG_PV, IMM_ROTL(disp >> 10, 5)); \ - M_SUB_IMM(REG_PV, REG_PV, IMM_ROTL(disp >> 2, 1)); \ - } else if (disp > 0x000003ff) { \ - M_SUB_IMM(REG_PV, REG_PC, IMM_ROTL(disp >> 10, 5)); \ - M_SUB_IMM(REG_PV, REG_PV, IMM_ROTL(disp >> 2, 1)); \ - } else { \ - M_SUB_IMM(REG_PV, REG_PC, IMM_ROTL(disp >> 2, 1)); \ - } - -/* M_INTMOVE: - generates an integer-move from register a to b. - if a and b are the same int-register, no code will be generated. -*/ - -#define M_INTMOVE(a,b) \ - do { \ - if ((a) != (b)) \ - M_MOV(b, a); \ - } while (0) - -#define M_LNGMOVE(a,b) \ - do { \ - if (GET_HIGH_REG(a) == GET_LOW_REG(b)) { \ - assert((GET_LOW_REG(a) != GET_HIGH_REG(b))); \ - M_INTMOVE(GET_HIGH_REG(a), GET_HIGH_REG(b)); \ - M_INTMOVE(GET_LOW_REG(a), GET_LOW_REG(b)); \ - } else { \ - M_INTMOVE(GET_LOW_REG(a), GET_LOW_REG(b)); \ - M_INTMOVE(GET_HIGH_REG(a), GET_HIGH_REG(b)); \ - } \ - } while (0) - - -/* M_COMPARE: - generates the compare part of an if-sequece - uses M_CMP or M_CMP_IMM to do the compare - ATTENTION: uses REG_ITMP3 as intermediate register -*/ -#define M_COMPARE(reg, val) \ - if (IS_IMM(val)) { \ - M_CMP_IMM(reg, (val)); \ - } else if(IS_IMM(-(val))) { \ - M_CMN_IMM(reg, -(val)); \ - } else { \ - assert((reg) != REG_ITMP3); \ - ICONST(REG_ITMP3, (val)); \ - M_CMP(reg, REG_ITMP3); \ - } - /* M_LONGBRANCH: performs a long branch to an absolute address with return address in LR takes up 3 bytes of code space; address is hard-coded into code @@ -1203,6 +1136,7 @@ do { \ #define M_ALD(a,b,c) M_ILD(a,b,c) #define M_ALD_INTERN(a,b,c) M_ILD_INTERN(a,b,c) +#define M_ALD_DSEG(a,c) M_DSEG_LOAD(a,c) #define M_IST(a,b,c) M_STR(a,b,c) @@ -1215,6 +1149,13 @@ do { \ #define M_AST_INTERN(a,b,c) M_IST_INTERN(a,b,c) +#define M_ACMP(a,b) M_CMP(a,b) +#define M_ICMP(a,b) M_CMP(a,b) + + +#define M_TEST(a) M_TEQ_IMM(a, 0); + + #if !defined(ENABLE_SOFTFLOAT) #define M_FLD(a,b,c) M_LDFS(a,b,c) diff --git a/src/vm/jit/arm/emit.c b/src/vm/jit/arm/emit.c index 9f11ca5c2..6a196037c 100644 --- a/src/vm/jit/arm/emit.c +++ b/src/vm/jit/arm/emit.c @@ -383,6 +383,27 @@ void emit_iconst(codegendata *cd, s4 d, s4 value) } +/** + * Emits code updating the condition register by comparing one integer + * register to an immediate integer value. + */ +void emit_icmp_imm(codegendata* cd, int reg, int32_t value) +{ + int32_t disp; + + if (IS_IMM(value)) { + M_CMP_IMM(reg, value); + } else if (IS_IMM(-value)) { + M_CMN_IMM(reg, -value); + } else { + assert(reg != REG_ITMP3); + disp = dseg_add_s4(cd, value); + M_DSEG_LOAD(REG_ITMP3, disp); + M_CMP(reg, REG_ITMP3); + } +} + + /* emit_branch ***************************************************************** Emits the code for conditional and unconditional branchs. @@ -614,6 +635,126 @@ uint32_t emit_trap(codegendata *cd) } +/** + * Emit code to recompute the procedure vector. + */ +void emit_recompute_pv(codegendata *cd) +{ + // This is used to recompute our PV (we use the IP for this) out + // of the current PC. + int32_t disp = (int32_t) (cd->mcodeptr - cd->mcodebase); + + // We use PC relative addressing. + disp += 8; + + // Sanity checks. + assert((disp & 0x03) == 0); + assert(disp >= 0 && disp <= 0x03ffffff); + + // ATTENTION: If you change this, you have to look at other functions + // as well! Following things depend on it: md_codegen_get_pv_from_pc(); + if (disp > 0x0003ffff) { + M_SUB_IMM(REG_PV, REG_PC, IMM_ROTL(disp >> 18, 9)); + M_SUB_IMM(REG_PV, REG_PV, IMM_ROTL(disp >> 10, 5)); + M_SUB_IMM(REG_PV, REG_PV, IMM_ROTL(disp >> 2, 1)); + } else if (disp > 0x000003ff) { + M_SUB_IMM(REG_PV, REG_PC, IMM_ROTL(disp >> 10, 5)); + M_SUB_IMM(REG_PV, REG_PV, IMM_ROTL(disp >> 2, 1)); + } else { + M_SUB_IMM(REG_PV, REG_PC, IMM_ROTL(disp >> 2, 1)); + } +} + + +/** + * Generates synchronization code to enter a monitor. + */ +#if defined(ENABLE_THREADS) +void emit_monitor_enter(jitdata* jd, int32_t syncslot_offset) +{ + int32_t disp; + + // Get required compiler data. + methodinfo* m = jd->m; + codegendata* cd = jd->cd; + +# if !defined(NDEBUG) + if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) { + M_STMFD(BITMASK_ARGS, REG_SP); + syncslot_offset += 4 * 4; + } +# endif + + /* get the correct lock object */ + + if (m->flags & ACC_STATIC) { + disp = dseg_add_address(cd, &m->clazz->object.header); + M_DSEG_LOAD(REG_A0, disp); + } + else { + emit_nullpointer_check_force(cd, NULL, REG_A0); + } + + M_STR(REG_A0, REG_SP, syncslot_offset); + disp = dseg_add_functionptr(cd, LOCK_monitor_enter); + M_DSEG_BRANCH(disp); + emit_recompute_pv(cd); + +# if !defined(NDEBUG) + if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) + M_LDMFD(BITMASK_ARGS, REG_SP); +# endif +} +#endif + + +/** + * Generates synchronization code to leave a monitor. + */ +#if defined(ENABLE_THREADS) +void emit_monitor_exit(jitdata* jd, int32_t syncslot_offset) +{ + int32_t disp; + + // Get required compiler data. + methodinfo* m = jd->m; + codegendata* cd = jd->cd; + + /* we need to save the proper return value */ + + methoddesc* md = m->parseddesc; + + switch (md->returntype.type) { + case TYPE_INT: + case TYPE_ADR: + case TYPE_LNG: + case TYPE_FLT: /* XXX TWISTI: is that correct? */ + case TYPE_DBL: + M_STMFD(BITMASK_RESULT, REG_SP); + syncslot_offset += 2 * 4; + break; + } + + M_LDR(REG_A0, REG_SP, syncslot_offset); + disp = dseg_add_functionptr(cd, LOCK_monitor_exit); + M_DSEG_BRANCH(disp); + + /* we no longer need PV here, no more loading */ + /*emit_recompute_pv(cd);*/ + + switch (md->returntype.type) { + case TYPE_INT: + case TYPE_ADR: + case TYPE_LNG: + case TYPE_FLT: /* XXX TWISTI: is that correct? */ + case TYPE_DBL: + M_LDMFD(BITMASK_RESULT, REG_SP); + break; + } +} +#endif + + /* emit_verbosecall_enter ****************************************************** Generates the code for the call trace. @@ -688,7 +829,7 @@ void emit_verbosecall_enter(jitdata *jd) disp = dseg_add_address(cd, m); M_DSEG_LOAD(REG_A0, disp); M_MOV(REG_A1, REG_SP); - M_ADD_IMM(REG_A2, REG_SP, md->paramcount * 8 + 2 * 4 + cd->stackframesize); + M_ADD_IMM(REG_A2, REG_SP, md->paramcount * 8 + 2 * 4 + cd->stackframesize * 8); M_LONGBRANCH(trace_java_call_enter); /* restore argument registers */ diff --git a/src/vm/jit/arm/md.h b/src/vm/jit/arm/md.h index 9ce156470..9ef90a93e 100644 --- a/src/vm/jit/arm/md.h +++ b/src/vm/jit/arm/md.h @@ -37,6 +37,21 @@ #include "vm/jit/codegen-common.hpp" +/** + * Returns the size (in bytes) of the current stackframe, specified by + * the passed codeinfo structure. + */ +inline static int32_t md_stacktrace_get_framesize(codeinfo* code) +{ + // Check for the asm_vm_call_method special case. + if (code == NULL) + return 0; + + // On ARM we use 8-byte stackslots. + return code->stackframesize * 8; +} + + /* md_stacktrace_get_returnaddress ********************************************* Returns the return address of the current stackframe, specified by diff --git a/src/vm/jit/code.hpp b/src/vm/jit/code.hpp index 9a940457e..46530ebae 100644 --- a/src/vm/jit/code.hpp +++ b/src/vm/jit/code.hpp @@ -73,13 +73,20 @@ struct codeinfo { u1 optlevel; /* optimization level of this code */ s4 basicblockcount; /* number of basic blocks */ - int32_t synchronizedoffset; /* stack offset of synchronized obj. */ - /* machine code */ u1 *mcode; /* pointer to machine code */ u1 *entrypoint; /* machine code entry point */ s4 mcodelength; /* length of generated machine code */ + /* runtime information */ + int32_t stackframesize; /* size of the stackframe in slots */ + int32_t synchronizedoffset; /* stack offset of synchronized obj. */ + uint8_t savedintcount; /* number of callee saved int regs */ + uint8_t savedfltcount; /* number of callee saved flt regs */ +# if defined(HAS_ADDRESS_REGISTER_FILE) + uint8_t savedadrcount; /* number of callee saved adr regs */ +# endif + exceptiontable_t *exceptiontable; LinenumberTable* linenumbertable; @@ -90,9 +97,7 @@ struct codeinfo { LockedList* patchers; #endif - /* replacement */ - s4 stackframesize; /* size of the stackframe in slots */ - + /* replacement */ #if defined(ENABLE_REPLACEMENT) rplpoint *rplpoints; /* replacement points */ rplalloc *regalloc; /* register allocation info */ @@ -100,11 +105,6 @@ struct codeinfo { s4 globalcount; /* number of global allocations */ s4 regalloccount; /* number of total allocations */ s4 memuse; /* number of arg + local slots */ - u1 savedintcount; /* number of callee saved int regs */ - u1 savedfltcount; /* number of callee saved flt regs */ -# if defined(HAS_ADDRESS_REGISTER_FILE) - u1 savedadrcount; /* number of callee saved adr regs */ -# endif u1 *savedmcode; /* saved code under patches */ #endif diff --git a/src/vm/jit/codegen-common.cpp b/src/vm/jit/codegen-common.cpp index a6f80b60f..b9dffac2d 100644 --- a/src/vm/jit/codegen-common.cpp +++ b/src/vm/jit/codegen-common.cpp @@ -1,7 +1,8 @@ /* src/vm/jit/codegen-common.cpp - architecture independent code generator stuff - Copyright (C) 1996-2005, 2006, 2007, 2008 + Copyright (C) 1996-2005, 2006, 2007, 2008, 2009 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO + Copyright (C) 2009 Theobroma Systems Ltd. This file is part of CACAO. @@ -67,11 +68,9 @@ #include "vm/exceptions.hpp" #include "vm/method.hpp" #include "vm/options.h" +#include "vm/statistics.h" #include "vm/string.hpp" -# include "vm/statistics.h" - - #include "vm/jit/abi.h" #include "vm/jit/asmpart.h" #include "vm/jit/code.hpp" @@ -89,12 +88,18 @@ #include "vm/jit/methodtree.h" #include "vm/jit/patcher-common.hpp" #include "vm/jit/replace.hpp" +#include "vm/jit/show.hpp" +#include "vm/jit/stacktrace.hpp" +#include "vm/jit/trace.hpp" + +#include "vm/jit/optimizing/profile.h" + #if defined(ENABLE_SSA) # include "vm/jit/optimizing/lsra.h" # include "vm/jit/optimizing/ssa.h" +#elif defined(ENABLE_LSRA) +# include "vm/jit/allocator/lsra.h" #endif -#include "vm/jit/stacktrace.hpp" -#include "vm/jit/trace.hpp" #if defined(ENABLE_INTRP) #include "vm/jit/intrp/intrp.h" @@ -104,8 +109,6 @@ #include #endif -#include "show.hpp" - /* codegen_init **************************************************************** @@ -288,7 +291,7 @@ bool codegen_generate(jitdata *jd) return false; } else { - vm_abort("codegen_generate: unknown error occurred during codegen_emit: flags=%x\n", cd->flags); + os::abort("codegen_generate: unknown error occurred during codegen_emit: flags=%x\n", cd->flags); } #if !defined(NDEBUG) @@ -544,21 +547,20 @@ void codegen_set_replacement_point(codegendata *cd) void codegen_finish(jitdata *jd) { - codeinfo *code; - codegendata *cd; - s4 mcodelen; + s4 mcodelen; #if defined(ENABLE_INTRP) - s4 ncodelen; + s4 ncodelen; #endif - s4 alignedmcodelen; - jumpref *jr; - u1 *epoint; - s4 alignedlen; + s4 alignedmcodelen; + jumpref *jr; + u1 *epoint; + s4 alignedlen; - /* get required compiler data */ + /* Get required compiler data. */ - code = jd->code; - cd = jd->cd; + codeinfo* code = jd->code; + codegendata* cd = jd->cd; + registerdata* rd = jd->rd; /* prevent compiler warning */ @@ -641,6 +643,16 @@ void codegen_finish(jitdata *jd) } #endif + /* Fill runtime information about generated code. */ + + code->stackframesize = cd->stackframesize; + code->synchronizedoffset = rd->memuse * 8; + code->savedintcount = INT_SAV_CNT - rd->savintreguse; + code->savedfltcount = FLT_SAV_CNT - rd->savfltreguse; +#if defined(HAS_ADDRESS_REGISTER_FILE) + code->savedadrcount = ADR_SAV_CNT - rd->savadrreguse; +#endif + /* Create the exception table. */ exceptiontable_create(jd); @@ -723,6 +735,7 @@ java_handle_t *codegen_start_native_call(u1 *sp, u1 *pv) { stackframeinfo_t *sfi; localref_table *lrt; + codeinfo *code; methodinfo *m; int32_t framesize; @@ -733,16 +746,17 @@ java_handle_t *codegen_start_native_call(u1 *sp, u1 *pv) STATISTICS(count_calls_java_to_native++); - /* Get the methodinfo. */ + // Get information from method header. + code = code_get_codeinfo_for_pv(pv); + assert(code != NULL); - m = code_get_methodinfo_for_pv(pv); + framesize = md_stacktrace_get_framesize(code); + assert(framesize >= (int32_t) (sizeof(stackframeinfo_t) + sizeof(localref_table))); + // Get the methodinfo. + m = code_get_methodinfo_for_pv(pv); assert(m); - framesize = *((int32_t *) (pv + FrameSize)); - - assert(framesize >= (int32_t) (sizeof(stackframeinfo_t) + sizeof(localref_table))); - /* calculate needed values */ #if defined(__ALPHA__) || defined(__ARM__) @@ -783,7 +797,7 @@ java_handle_t *codegen_start_native_call(u1 *sp, u1 *pv) #else /* XXX is was unable to do this port for SPARC64, sorry. (-michi) */ /* XXX maybe we need to pass the RA as argument there */ - vm_abort("codegen_start_native_call: unsupported architecture"); + os::abort("codegen_start_native_call: unsupported architecture"); #endif /* get data structures from stack */ @@ -850,18 +864,15 @@ java_object_t *codegen_finish_native_call(u1 *sp, u1 *pv) uint8_t *datasp; uint64_t *ret_regs; - /* get information from method header */ - + // Get information from method header. code = code_get_codeinfo_for_pv(pv); + assert(code != NULL); - framesize = *((int32_t *) (pv + FrameSize)); - - assert(code); - - /* get the methodinfo */ + framesize = md_stacktrace_get_framesize(code); + // Get the methodinfo. m = code->m; - assert(m); + assert(m != NULL); /* calculate needed values */ @@ -895,7 +906,7 @@ java_object_t *codegen_finish_native_call(u1 *sp, u1 *pv) datasp = sp + framesize; ret_regs = (uint64_t *) (sp + PA_SIZE + LA_SIZE + 2 * SIZEOF_VOID_P); #else - vm_abort("codegen_finish_native_call: unsupported architecture"); + os::abort("codegen_finish_native_call: unsupported architecture"); #endif /* get data structures from stack */ @@ -950,7 +961,7 @@ java_object_t *codegen_finish_native_call(u1 *sp, u1 *pv) register, this register will be returned. Otherwise (when v is spilled) this function returns tempregnum. If not already done, regoff and flags are set in the stack location. - + *******************************************************************************/ s4 codegen_reg_of_var(u2 opcode, varinfo *v, s4 tempregnum) @@ -970,7 +981,7 @@ s4 codegen_reg_of_var(u2 opcode, varinfo *v, s4 tempregnum) register, this register will be returned. Otherwise (when it is spilled) this function returns tempregnum. If not already done, regoff and flags are set in the stack location. - + *******************************************************************************/ s4 codegen_reg_of_dst(jitdata *jd, instruction *iptr, s4 tempregnum) @@ -979,6 +990,1182 @@ s4 codegen_reg_of_dst(jitdata *jd, instruction *iptr, s4 tempregnum) } +/** + * Generates machine code. + */ +bool codegen_emit(jitdata *jd) +{ + varinfo* var; + builtintable_entry* bte; + methoddesc* md; + int32_t s1, s2, /*s3,*/ d; + int32_t fieldtype; + int32_t disp; + int i; + + // Get required compiler data. + //methodinfo* m = jd->m; + codeinfo* code = jd->code; + codegendata* cd = jd->cd; + registerdata* rd = jd->rd; +#if defined(ENABLE_SSA) + lsradata* ls = jd->ls; + bool last_cmd_was_goto = false; +#endif + + // Space to save used callee saved registers. + int32_t savedregs_num = 0; + savedregs_num += (INT_SAV_CNT - rd->savintreguse); + savedregs_num += (FLT_SAV_CNT - rd->savfltreguse); +#ifdef HAS_ADDRESS_REGISTER_FILE + savedregs_num += (ADR_SAV_CNT - rd->savadrreguse); +#endif + + // Calculate size of stackframe. + cd->stackframesize = rd->memuse + savedregs_num; + + // Space to save the return address. +#if STACKFRAME_RA_TOP_OF_FRAME +# if STACKFRAME_LEAFMETHODS_RA_REGISTER + if (!code_is_leafmethod(code)) +# endif + cd->stackframesize += 1; +#endif + + // Space to save argument of monitor_enter. +#if defined(ENABLE_THREADS) + if (checksync && code_is_synchronized(code)) +# if STACKFRAME_SYNC_NEEDS_TWO_SLOTS + /* On some architectures the stack position for the argument can + not be shared with place to save the return register values to + survive monitor_exit since both values reside in the same register. */ + cd->stackframesize += 2; +# else + cd->stackframesize += 1; +# endif +#endif + + // Keep stack of non-leaf functions 16-byte aligned for calls into + // native code. + if (!code_is_leafmethod(code) || JITDATA_HAS_FLAG_VERBOSECALL(jd)) +#if STACKFRMAE_RA_BETWEEN_FRAMES + ALIGN_ODD(cd->stackframesize); +#else + ALIGN_EVEN(cd->stackframesize); +#endif + +#if defined(SPECIALMEMUSE) + // On architectures having a linkage area, we can get rid of the whole + // stackframe in leaf functions without saved registers. + if (code_is_leafmethod(code) && (cd->stackframesize == LA_SIZE_IN_POINTERS)) + cd->stackframesize = 0; +#endif + + /* + * SECTION 1: Method header generation. + */ + + // The method header was reduced to the bare minimum of one pointer + // to the codeinfo structure, which in turn contains all runtime + // information. However this section together with the methodheader.h + // file will be kept alive for historical reasons. It might come in + // handy at some point. + + (void) dseg_add_unique_address(cd, code); ///< CodeinfoPointer + + // XXX, REMOVEME: We still need it for exception handling in assembler. + // XXX ARM, M68K: (void) dseg_add_unique_s4(cd, cd->stackframesize); +#if defined(__I386__) + int align_off = (cd->stackframesize != 0) ? 4 : 0; + (void) dseg_add_unique_s4(cd, cd->stackframesize * 8 + align_off); /* FrameSize */ +#else + (void) dseg_add_unique_s4(cd, cd->stackframesize * 8); /* FrameSize */ +#endif + // XXX M68K: We use the IntSave as a split field for the adr now + // (void) dseg_add_unique_s4(cd, (ADR_SAV_CNT - rd->savadrreguse) << 16 | (INT_SAV_CNT - rd->savintreguse)); /* IntSave */ + (void) dseg_add_unique_s4(cd, code_is_leafmethod(code) ? 1 : 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 */ + + /* + * SECTION 2: Method prolog generation. + */ + +#if defined(ENABLE_PROFILING) + // Generate method profiling code. + if (JITDATA_HAS_FLAG_INSTRUMENT(jd)) { + + // Count method frequency. + emit_profile_method(cd, code); + +# if defined(__X86_64__) + // Start CPU cycle counting. + emit_profile_cycle_start(); +# endif + } +#endif + + // Emit code for the method prolog. + codegen_emit_prolog(jd); + +#if defined(ENABLE_THREADS) + // Emit code to call monitorenter function. + if (checksync && code_is_synchronized(code)) + emit_monitor_enter(jd, rd->memuse * 8); +#endif + +#if !defined(NDEBUG) + // Call trace function. + if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) + emit_verbosecall_enter(jd); +#endif + +#if defined(ENABLE_SSA) + // With SSA the header is basicblock 0, insert phi moves if necessary. + if (ls != NULL) + codegen_emit_phi_moves(jd, ls->basicblocks[0]); +#endif + + // Create replacement points. + REPLACEMENT_POINTS_INIT(cd, jd); + + /* + * SECTION 3: ICMD code generation. + */ + + // Walk through all basic blocks. + for (basicblock* bptr = jd->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); + +#if defined(ENABLE_REPLACEMENT) && defined(__I386__) + // Generate countdown trap code. + methodinfo* m = jd->m; + if (bptr->bitflags & BBFLAG_REPLACEMENT) { + if (cd->replacementpoint[-1].flags & RPLPOINT_FLAG_COUNTDOWN) { + MCODECHECK(32); + emit_trap_countdown(cd, &(m->hitcountdown)); + } + } +#endif + +#if defined(ENABLE_PROFILING) + // Generate basicblock profiling code. + if (JITDATA_HAS_FLAG_INSTRUMENT(jd)) { + + // Count basicblock frequency. + emit_profile_basicblock(cd, code, bptr); + +# if defined(__X86_64__) + // If this is an exception handler, start profiling again. + if (bptr->type == BBTYPE_EXH) + emit_profile_cycle_start(); +# endif + } +#endif + + // Copy interface registers to their destination. + int32_t indepth = bptr->indepth; + // XXX Check if this is true for all archs. + MCODECHECK(64+indepth); // All + MCODECHECK(128+indepth); // PPC64 + MCODECHECK(512); // I386, X86_64, S390 +#if defined(ENABLE_SSA) + // XXX Check if this is correct and add a propper comment! + if (ls != NULL) { + last_cmd_was_goto = false; + } else { +#elif defined(ENABLE_LSRA) + if (opt_lsra) { + while (indepth > 0) { + indepth--; + var = VAR(bptr->invars[indepth]); + if ((indepth == bptr->indepth-1) && (bptr->type == BBTYPE_EXH)) { + if (!IS_INMEMORY(src->flags)) + d = var->vv.regoff; + else + d = REG_ITMP1_XPTR; + // XXX M68K: Actually this is M_ADRMOVE(REG_ATMP1_XPTR, d); + // XXX Sparc64: Here we use REG_ITMP2_XPTR, fix this! + // XXX S390: Here we use REG_ITMP3_XPTR, fix this! + emit_imove(cd, REG_ITMP1_XPTR, d); + emit_store(jd, NULL, var, d); + } + } + } else { +#endif + while (indepth > 0) { + indepth--; + var = VAR(bptr->invars[indepth]); + if ((indepth == bptr->indepth-1) && (bptr->type == BBTYPE_EXH)) { + d = codegen_reg_of_var(0, var, REG_ITMP1_XPTR); + // XXX M68K: Actually this is M_ADRMOVE(REG_ATMP1_XPTR, d); + // XXX Sparc64: Here we use REG_ITMP2_XPTR, fix this! + // XXX S390: Here we use REG_ITMP3_XPTR, fix this! + emit_imove(cd, REG_ITMP1_XPTR, d); + emit_store(jd, NULL, var, d); + } + else { + assert((var->flags & INOUT)); + } + } +#if defined(ENABLE_SSA) || defined(ENABLE_LSRA) + } +#endif + + // Walk through all instructions. + int32_t len = bptr->icount; + uint16_t currentline = 0; + for (instruction* iptr = bptr->iinstr; len > 0; len--, iptr++) { + + // Add line number. + if (iptr->line != currentline) { + linenumbertable_list_entry_add(cd, iptr->line); + currentline = iptr->line; + } + + // An instruction usually needs < 64 words. + // XXX Check if this is true for all archs. + MCODECHECK(64); // All + MCODECHECK(128); // PPC64 + MCODECHECK(1024); // I386, X86_64, M68K, S390 /* 1kB should be enough */ + + // The big switch. + switch (iptr->opc) { + + case ICMD_NOP: /* ... ==> ... */ + case ICMD_POP: /* ..., value ==> ... */ + case ICMD_POP2: /* ..., value, value ==> ... */ + break; + + case ICMD_CHECKNULL: /* ..., objectref ==> ..., objectref */ + + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + emit_nullpointer_check(cd, iptr, s1); + break; + +#if defined(ENABLE_SSA) + case ICMD_GETEXCEPTION: + + d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); + emit_imove(cd, REG_ITMP1, d); + emit_store_dst(jd, iptr, d); + break; +#endif + + /* inline operations **********************************************/ + + case ICMD_INLINE_START: + + REPLACEMENT_POINT_INLINE_START(cd, iptr); + break; + + case ICMD_INLINE_BODY: + + REPLACEMENT_POINT_INLINE_BODY(cd, iptr); + linenumbertable_list_entry_add_inline_start(cd, iptr); + linenumbertable_list_entry_add(cd, iptr->line); + break; + + case ICMD_INLINE_END: + + linenumbertable_list_entry_add_inline_end(cd, iptr); + linenumbertable_list_entry_add(cd, iptr->line); + break; + + + /* 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_LCONST: /* ... ==> ..., constant */ + + d = codegen_reg_of_dst(jd, iptr, REG_LTMP12); + LCONST(d, iptr->sx.val.l); + emit_store_dst(jd, iptr, d); + break; + + + /* load/store/copy/move operations ********************************/ + + case ICMD_COPY: + case ICMD_MOVE: + case ICMD_ILOAD: /* ... ==> ..., content of local variable */ + case ICMD_LLOAD: /* s1 = local variable */ + case ICMD_FLOAD: + case ICMD_DLOAD: + case ICMD_ALOAD: + case ICMD_ISTORE: /* ..., value ==> ... */ + case ICMD_LSTORE: + case ICMD_FSTORE: + case ICMD_DSTORE: + + emit_copy(jd, iptr); + break; + + case ICMD_ASTORE: + + if (!(iptr->flags.bits & INS_FLAG_RETADDR)) + emit_copy(jd, iptr); + break; + + + /* integer operations *********************************************/ + + case ICMD_FCONST: /* ... ==> ..., constant */ + case ICMD_DCONST: /* ... ==> ..., constant */ + case ICMD_ACONST: /* ... ==> ..., constant */ + case ICMD_INEG: /* ..., value ==> ..., - value */ + case ICMD_LNEG: /* ..., value ==> ..., - value */ + case ICMD_I2L: /* ..., value ==> ..., value */ + case ICMD_L2I: /* ..., value ==> ..., value */ + case ICMD_INT2BYTE: /* ..., value ==> ..., value */ + case ICMD_INT2CHAR: /* ..., value ==> ..., value */ + case ICMD_INT2SHORT: /* ..., value ==> ..., value */ + case ICMD_IADD: /* ..., val1, val2 ==> ..., val1 + val2 */ + case ICMD_IINC: + case ICMD_IADDCONST: /* ..., value ==> ..., value + constant */ + /* sx.val.i = constant */ + case ICMD_LADD: /* ..., val1, val2 ==> ..., val1 + val2 */ + case ICMD_LADDCONST: /* ..., value ==> ..., value + constant */ + /* sx.val.l = constant */ + case ICMD_ISUB: /* ..., val1, val2 ==> ..., val1 - val2 */ + case ICMD_ISUBCONST: /* ..., value ==> ..., value + constant */ + /* sx.val.i = constant */ + case ICMD_LSUB: /* ..., val1, val2 ==> ..., val1 - val2 */ + case ICMD_LSUBCONST: /* ..., value ==> ..., value - constant */ + /* sx.val.l = constant */ + case ICMD_IMUL: /* ..., val1, val2 ==> ..., val1 * val2 */ + case ICMD_IMULCONST: /* ..., value ==> ..., value * constant */ + /* sx.val.i = constant */ + case ICMD_LMUL: /* ..., val1, val2 ==> ..., val1 * val2 */ + case ICMD_LMULCONST: /* ..., value ==> ..., value * constant */ + /* sx.val.l = constant */ + case ICMD_IDIV: /* ..., val1, val2 ==> ..., val1 / val2 */ + case ICMD_IREM: /* ..., val1, val2 ==> ..., val1 % val2 */ + case ICMD_IDIVPOW2: /* ..., value ==> ..., value >> constant */ + /* sx.val.i = constant */ + case ICMD_IREMPOW2: /* ..., value ==> ..., value % constant */ + /* sx.val.i = constant */ + case ICMD_LDIV: /* ..., val1, val2 ==> ..., val1 / val2 */ + case ICMD_LREM: /* ..., val1, val2 ==> ..., val1 % val2 */ + case ICMD_LDIVPOW2: /* ..., value ==> ..., value >> constant */ + /* sx.val.i = constant */ + case ICMD_LREMPOW2: /* ..., value ==> ..., value % constant */ + /* sx.val.l = constant */ + case ICMD_ISHL: /* ..., val1, val2 ==> ..., val1 << val2 */ + case ICMD_ISHLCONST: /* ..., value ==> ..., value << constant */ + /* sx.val.i = constant */ + case ICMD_ISHR: /* ..., val1, val2 ==> ..., val1 >> val2 */ + case ICMD_ISHRCONST: /* ..., value ==> ..., value >> constant */ + /* sx.val.i = constant */ + case ICMD_IUSHR: /* ..., val1, val2 ==> ..., val1 >>> val2 */ + case ICMD_IUSHRCONST: /* ..., value ==> ..., value >>> constant */ + /* sx.val.i = constant */ + case ICMD_LSHL: /* ..., val1, val2 ==> ..., val1 << val2 */ + case ICMD_LSHLCONST: /* ..., value ==> ..., value << constant */ + /* sx.val.i = constant */ + case ICMD_LSHR: /* ..., val1, val2 ==> ..., val1 >> val2 */ + case ICMD_LSHRCONST: /* ..., value ==> ..., value >> constant */ + /* sx.val.i = constant */ + case ICMD_LUSHR: /* ..., val1, val2 ==> ..., val1 >>> val2 */ + case ICMD_LUSHRCONST: /* ..., value ==> ..., value >>> constant */ + /* sx.val.l = constant */ + case ICMD_IAND: /* ..., val1, val2 ==> ..., val1 & val2 */ + case ICMD_IANDCONST: /* ..., value ==> ..., value & constant */ + /* sx.val.i = constant */ + case ICMD_LAND: /* ..., val1, val2 ==> ..., val1 & val2 */ + case ICMD_LANDCONST: /* ..., value ==> ..., value & constant */ + /* sx.val.l = constant */ + case ICMD_IOR: /* ..., val1, val2 ==> ..., val1 | val2 */ + case ICMD_IORCONST: /* ..., value ==> ..., value | constant */ + /* sx.val.i = constant */ + case ICMD_LOR: /* ..., val1, val2 ==> ..., val1 | val2 */ + case ICMD_LORCONST: /* ..., value ==> ..., value | constant */ + /* sx.val.l = constant */ + case ICMD_IXOR: /* ..., val1, val2 ==> ..., val1 ^ val2 */ + case ICMD_IXORCONST: /* ..., value ==> ..., value ^ constant */ + /* sx.val.i = constant */ + case ICMD_LXOR: /* ..., val1, val2 ==> ..., val1 ^ val2 */ + case ICMD_LXORCONST: /* ..., value ==> ..., value ^ constant */ + /* sx.val.l = constant */ + + // Generate architecture specific instructions. + codegen_emit_instruction(jd, iptr); + break; + + + /* floating operations ********************************************/ + +#if !defined(ENABLE_SOFTFLOAT) + case ICMD_FNEG: /* ..., value ==> ..., - value */ + case ICMD_DNEG: + case ICMD_FADD: /* ..., val1, val2 ==> ..., val1 + val2 */ + case ICMD_DADD: + case ICMD_FSUB: /* ..., val1, val2 ==> ..., val1 - val2 */ + case ICMD_DSUB: + case ICMD_FMUL: /* ..., val1, val2 ==> ..., val1 * val2 */ + case ICMD_DMUL: + case ICMD_FDIV: /* ..., val1, val2 ==> ..., val1 / val2 */ + case ICMD_DDIV: + case ICMD_FREM: /* ..., val1, val2 ==> ..., val1 % val2 */ + case ICMD_DREM: + case ICMD_I2F: /* ..., value ==> ..., (float) value */ + case ICMD_I2D: /* ..., value ==> ..., (double) value */ + case ICMD_L2F: /* ..., value ==> ..., (float) value */ + case ICMD_L2D: /* ..., value ==> ..., (double) value */ + case ICMD_F2I: /* ..., value ==> ..., (int) value */ + case ICMD_D2I: + case ICMD_F2L: /* ..., value ==> ..., (long) value */ + case ICMD_D2L: + case ICMD_F2D: /* ..., value ==> ..., (double) value */ + case ICMD_D2F: /* ..., value ==> ..., (float) value */ + case ICMD_FCMPL: /* ..., val1, val2 ==> ..., val1 fcmpg val2 */ + case ICMD_DCMPL: /* == => 0, < => 1, > => -1 */ + case ICMD_FCMPG: /* ..., val1, val2 ==> ..., val1 fcmpl val2 */ + case ICMD_DCMPG: /* == => 0, < => 1, > => -1 */ + + // Generate architecture specific instructions. + codegen_emit_instruction(jd, iptr); + break; +#endif /* !defined(ENABLE_SOFTFLOAT) */ + + + /* 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 */ + // XXX PPC64: Here we had an explicit null-pointer check + // which I think was obsolete, please confirm. Otherwise: + // emit_nullpointer_check(cd, iptr, s1); + M_ILD(d, s1, OFFSET(java_array_t, size)); + emit_store_dst(jd, iptr, d); + break; + + case ICMD_BALOAD: /* ..., arrayref, index ==> ..., value */ + case ICMD_CALOAD: /* ..., arrayref, index ==> ..., value */ + case ICMD_SALOAD: /* ..., arrayref, index ==> ..., value */ + case ICMD_IALOAD: /* ..., arrayref, index ==> ..., value */ + case ICMD_LALOAD: /* ..., arrayref, index ==> ..., value */ + case ICMD_FALOAD: /* ..., arrayref, index ==> ..., value */ + case ICMD_DALOAD: /* ..., arrayref, index ==> ..., value */ + case ICMD_AALOAD: /* ..., arrayref, index ==> ..., value */ + case ICMD_BASTORE: /* ..., arrayref, index, value ==> ... */ + case ICMD_CASTORE: /* ..., arrayref, index, value ==> ... */ + case ICMD_SASTORE: /* ..., arrayref, index, value ==> ... */ + case ICMD_IASTORE: /* ..., arrayref, index, value ==> ... */ + case ICMD_LASTORE: /* ..., arrayref, index, value ==> ... */ + case ICMD_FASTORE: /* ..., arrayref, index, value ==> ... */ + case ICMD_DASTORE: /* ..., arrayref, index, value ==> ... */ + case ICMD_AASTORE: /* ..., arrayref, index, value ==> ... */ + case ICMD_BASTORECONST: /* ..., arrayref, index ==> ... */ + case ICMD_CASTORECONST: /* ..., arrayref, index ==> ... */ + case ICMD_SASTORECONST: /* ..., arrayref, index ==> ... */ + case ICMD_IASTORECONST: /* ..., arrayref, index ==> ... */ + case ICMD_LASTORECONST: /* ..., arrayref, index ==> ... */ + case ICMD_FASTORECONST: /* ..., arrayref, index ==> ... */ + case ICMD_DASTORECONST: /* ..., arrayref, index ==> ... */ + case ICMD_AASTORECONST: /* ..., arrayref, index ==> ... */ + case ICMD_GETFIELD: /* ... ==> ..., value */ + case ICMD_PUTFIELD: /* ..., value ==> ... */ + case ICMD_PUTFIELDCONST: /* ..., objectref ==> ... */ + /* val = value (in current instruction) */ + case ICMD_PUTSTATICCONST: /* ... ==> ... */ + /* val = value (in current instruction) */ + + // Generate architecture specific instructions. + codegen_emit_instruction(jd, iptr); + break; + + case ICMD_GETSTATIC: /* ... ==> ..., value */ + +#if defined(__I386__) + // Generate architecture specific instructions. + codegen_emit_instruction(jd, iptr); +#else + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + unresolved_field* uf = iptr->sx.s23.s3.uf; + fieldtype = uf->fieldref->parseddesc.fd->type; + disp = dseg_add_unique_address(cd, 0); + + patcher_add_patch_ref(jd, PATCHER_get_putstatic, uf, disp); + } + else { + fieldinfo* 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)) { + PROFILE_CYCLE_STOP; + patcher_add_patch_ref(jd, PATCHER_initialize_class, fi->clazz, 0); + PROFILE_CYCLE_START; + } + } + + // XXX X86_64: Here We had this: + /* This approach is much faster than moving the field + address inline into a register. */ + + // XXX ARM: M_DSEG_LOAD(REG_ITMP3, disp); + M_ALD_DSEG(REG_ITMP1, disp); + + switch (fieldtype) { + case TYPE_ADR: + d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); + M_ALD(d, REG_ITMP1, 0); + break; + case TYPE_INT: + d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); + M_ILD(d, REG_ITMP1, 0); + break; + case TYPE_LNG: + d = codegen_reg_of_dst(jd, iptr, REG_LTMP23); + M_LLD(d, REG_ITMP1, 0); + break; + case TYPE_FLT: + d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); + M_FLD(d, REG_ITMP1, 0); + break; + case TYPE_DBL: + d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); + M_DLD(d, REG_ITMP1, 0); + break; + } + emit_store_dst(jd, iptr, d); +#endif + break; + + case ICMD_PUTSTATIC: /* ..., value ==> ... */ + +#if defined(__I386__) + // Generate architecture specific instructions. + codegen_emit_instruction(jd, iptr); +#else + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + unresolved_field* uf = iptr->sx.s23.s3.uf; + fieldtype = uf->fieldref->parseddesc.fd->type; + disp = dseg_add_unique_address(cd, 0); + + patcher_add_patch_ref(jd, PATCHER_get_putstatic, uf, disp); + } + else { + fieldinfo* 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)) { + PROFILE_CYCLE_STOP; + patcher_add_patch_ref(jd, PATCHER_initialize_class, fi->clazz, 0); + PROFILE_CYCLE_START; + } + } + + // XXX X86_64: Here We had this: + /* This approach is much faster than moving the field + address inline into a register. */ + + // XXX ARM: M_DSEG_LOAD(REG_ITMP3, disp); + M_ALD_DSEG(REG_ITMP1, disp); + + switch (fieldtype) { + case TYPE_ADR: + s1 = emit_load_s1(jd, iptr, REG_ITMP2); + M_AST(s1, REG_ITMP1, 0); + break; + case TYPE_INT: + s1 = emit_load_s1(jd, iptr, REG_ITMP2); + M_IST(s1, REG_ITMP1, 0); + break; + case TYPE_LNG: + s1 = emit_load_s1(jd, iptr, REG_LTMP23); + M_LST(s1, REG_ITMP1, 0); + break; + case TYPE_FLT: + s1 = emit_load_s1(jd, iptr, REG_FTMP2); + M_FST(s1, REG_ITMP1, 0); + break; + case TYPE_DBL: + s1 = emit_load_s1(jd, iptr, REG_FTMP2); + M_DST(s1, REG_ITMP1, 0); + break; + } +#endif + break; + + /* branch operations **********************************************/ + + case ICMD_ATHROW: /* ..., objectref ==> ... (, objectref) */ + + // We might leave this method, stop profiling. + PROFILE_CYCLE_STOP; + + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + // XXX M68K: Actually this is M_ADRMOVE(s1, REG_ATMP1_XPTR); + // XXX Sparc64: We use REG_ITMP2_XPTR here, fix me! + emit_imove(cd, s1, REG_ITMP1_XPTR); + +#ifdef ENABLE_VERIFIER + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + unresolved_class *uc = iptr->sx.s23.s2.uc; + patcher_add_patch_ref(jd, PATCHER_resolve_class, uc, 0); + } +#endif /* ENABLE_VERIFIER */ + + // Generate architecture specific instructions. + codegen_emit_instruction(jd, iptr); + ALIGNCODENOP; + break; + + case ICMD_GOTO: /* ... ==> ... */ + case ICMD_RET: /* ... ==> ... */ + +#if defined(ENABLE_SSA) + // In case of a goto, phimoves have to be inserted + // before the jump. + if (ls != NULL) { + last_cmd_was_goto = true; + codegen_emit_phi_moves(jd, bptr); + } +#endif + emit_br(cd, iptr->dst.block); + ALIGNCODENOP; + break; + + case ICMD_JSR: /* ... ==> ... */ + + emit_br(cd, iptr->sx.s23.s3.jsrtarget.block); + ALIGNCODENOP; + break; + + case ICMD_IFNULL: /* ..., value ==> ... */ + case ICMD_IFNONNULL: + + s1 = emit_load_s1(jd, iptr, REG_ITMP1); +#if SUPPORT_BRANCH_CONDITIONAL_ONE_INTEGER_REGISTER + emit_bccz(cd, iptr->dst.block, iptr->opc - ICMD_IFNULL, s1, BRANCH_OPT_NONE); +#elif SUPPORT_BRANCH_CONDITIONAL_CONDITION_REGISTER + M_TEST(s1); + emit_bcc(cd, iptr->dst.block, iptr->opc - ICMD_IFNULL, BRANCH_OPT_NONE); +#else +# error Unable to generate code for this configuration! +#endif + break; + + case ICMD_IFEQ: /* ..., value ==> ... */ + case ICMD_IFNE: + case ICMD_IFLT: + case ICMD_IFLE: + case ICMD_IFGT: + case ICMD_IFGE: + + // XXX Sparc64: int compares must not branch on the + // register directly. Reason is, that register content is + // not 32-bit clean. Fix this! + +#if SUPPORT_BRANCH_CONDITIONAL_ONE_INTEGER_REGISTER + if (iptr->sx.val.i == 0) { + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + emit_bccz(cd, iptr->dst.block, iptr->opc - ICMD_IFEQ, s1, BRANCH_OPT_NONE); + } else { + // Generate architecture specific instructions. + codegen_emit_instruction(jd, iptr); + } +#elif SUPPORT_BRANCH_CONDITIONAL_CONDITION_REGISTER + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + emit_icmp_imm(cd, s1, iptr->sx.val.i); + emit_bcc(cd, iptr->dst.block, iptr->opc - ICMD_IFEQ, BRANCH_OPT_NONE); +#else +# error Unable to generate code for this configuration! +#endif + break; + + case ICMD_IF_LEQ: /* ..., value ==> ... */ + case ICMD_IF_LNE: + case ICMD_IF_LLT: + case ICMD_IF_LGE: + case ICMD_IF_LGT: + case ICMD_IF_LLE: + + // Generate architecture specific instructions. + codegen_emit_instruction(jd, iptr); + break; + + case ICMD_IF_ACMPEQ: /* ..., value, value ==> ... */ + case ICMD_IF_ACMPNE: /* op1 = target JavaVM pc */ + + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); +#if SUPPORT_BRANCH_CONDITIONAL_TWO_INTEGER_REGISTERS + switch (iptr->opc) { + case ICMD_IF_ACMPEQ: + emit_beq(cd, iptr->dst.block, s1, s2); + break; + case ICMD_IF_ACMPNE: + emit_bne(cd, iptr->dst.block, s1, s2); + break; + } +#elif SUPPORT_BRANCH_CONDITIONAL_CONDITION_REGISTER + M_ACMP(s1, s2); + emit_bcc(cd, iptr->dst.block, iptr->opc - ICMD_IF_ACMPEQ, BRANCH_OPT_NONE); +#elif SUPPORT_BRANCH_CONDITIONAL_ONE_INTEGER_REGISTER + M_CMPEQ(s1, s2, REG_ITMP1); + switch (iptr->opc) { + case ICMD_IF_ACMPEQ: + emit_bnez(cd, iptr->dst.block, REG_ITMP1); + break; + case ICMD_IF_ACMPNE: + emit_beqz(cd, iptr->dst.block, REG_ITMP1); + break; + } +#else +# error Unable to generate code for this configuration! +#endif + break; + + case ICMD_IF_ICMPEQ: /* ..., value, value ==> ... */ + case ICMD_IF_ICMPNE: /* op1 = target JavaVM pc */ + +#if SUPPORT_BRANCH_CONDITIONAL_TWO_INTEGER_REGISTERS + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + switch (iptr->opc) { + case ICMD_IF_ICMPEQ: + emit_beq(cd, iptr->dst.block, s1, s2); + break; + case ICMD_IF_ICMPNE: + emit_bne(cd, iptr->dst.block, s1, s2); + break; + } + break; +#else + /* fall-through */ +#endif + + case ICMD_IF_ICMPLT: /* ..., value, value ==> ... */ + case ICMD_IF_ICMPGT: /* op1 = target JavaVM pc */ + case ICMD_IF_ICMPLE: + case ICMD_IF_ICMPGE: + + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); +#if SUPPORT_BRANCH_CONDITIONAL_CONDITION_REGISTER +# if defined(__I386__) || defined(__M68K__) || defined(__X86_64__) + // XXX Fix this soon!!! + M_ICMP(s2, s1); +# else + M_ICMP(s1, s2); +# endif + emit_bcc(cd, iptr->dst.block, iptr->opc - ICMD_IF_ICMPEQ, BRANCH_OPT_NONE); +#elif SUPPORT_BRANCH_CONDITIONAL_ONE_INTEGER_REGISTER + // Generate architecture specific instructions. + codegen_emit_instruction(jd, iptr); +#else +# error Unable to generate code for this configuration! +#endif + break; + + case ICMD_IF_LCMPEQ: /* ..., value, value ==> ... */ + case ICMD_IF_LCMPNE: /* op1 = target JavaVM pc */ + case ICMD_IF_LCMPLT: + case ICMD_IF_LCMPGT: + case ICMD_IF_LCMPLE: + case ICMD_IF_LCMPGE: + + // Generate architecture specific instructions. + codegen_emit_instruction(jd, iptr); + break; + + case ICMD_RETURN: /* ... ==> ... */ + + REPLACEMENT_POINT_RETURN(cd, iptr); + goto nowperformreturn; + + case ICMD_ARETURN: /* ..., retvalue ==> ... */ + + REPLACEMENT_POINT_RETURN(cd, iptr); + s1 = emit_load_s1(jd, iptr, REG_RESULT); + // XXX M68K: This should actually be M_ADR2INTMOVE(s1, REG_RESULT); + // XXX Sparc64: Here this should be REG_RESULT_CALLEE! + emit_imove(cd, s1, REG_RESULT); + +#ifdef ENABLE_VERIFIER + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + PROFILE_CYCLE_STOP; + unresolved_class *uc = iptr->sx.s23.s2.uc; + patcher_add_patch_ref(jd, PATCHER_resolve_class, uc, 0); + PROFILE_CYCLE_START; + } +#endif /* ENABLE_VERIFIER */ + goto nowperformreturn; + + case ICMD_IRETURN: /* ..., retvalue ==> ... */ + + REPLACEMENT_POINT_RETURN(cd, iptr); + s1 = emit_load_s1(jd, iptr, REG_RESULT); + // XXX Sparc64: Here this should be REG_RESULT_CALLEE! + emit_imove(cd, s1, REG_RESULT); + goto nowperformreturn; + + case ICMD_LRETURN: /* ..., retvalue ==> ... */ + + REPLACEMENT_POINT_RETURN(cd, iptr); + s1 = emit_load_s1(jd, iptr, REG_LRESULT); + // XXX Sparc64: Here this should be REG_RESULT_CALLEE! + emit_lmove(cd, s1, REG_LRESULT); + goto nowperformreturn; + + case ICMD_FRETURN: /* ..., retvalue ==> ... */ + + REPLACEMENT_POINT_RETURN(cd, iptr); + s1 = emit_load_s1(jd, iptr, REG_FRESULT); + // XXX ARM: Here this was M_CAST_F2I(s1, REG_RESULT); + emit_fmove(cd, s1, REG_FRESULT); + goto nowperformreturn; + + case ICMD_DRETURN: /* ..., retvalue ==> ... */ + + REPLACEMENT_POINT_RETURN(cd, iptr); + s1 = emit_load_s1(jd, iptr, REG_FRESULT); + // XXX ARM: Here this was M_CAST_D2L(s1, REG_RESULT_PACKED); + emit_dmove(cd, s1, REG_FRESULT); + goto nowperformreturn; + +nowperformreturn: +#if !defined(NDEBUG) + // Call trace function. + if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) + emit_verbosecall_exit(jd); +#endif + +#if defined(ENABLE_THREADS) + // Emit code to call monitorexit function. + if (checksync && code_is_synchronized(code)) { + emit_monitor_exit(jd, rd->memuse * 8); + } +#endif + + // Generate method profiling code. + PROFILE_CYCLE_STOP; + + // Emit code for the method epilog. + codegen_emit_epilog(jd); + ALIGNCODENOP; + break; + + case ICMD_BUILTIN: /* ..., [arg1, [arg2 ...]] ==> ... */ + + REPLACEMENT_POINT_FORGC_BUILTIN(cd, iptr); + + bte = iptr->sx.s23.s3.bte; + md = bte->md; + +#if defined(ENABLE_ESCAPE_REASON) && defined(__I386__) + if (bte->fp == BUILTIN_escape_reason_new) { + void set_escape_reasons(void *); + M_ASUB_IMM(8, REG_SP); + M_MOV_IMM(iptr->escape_reasons, REG_ITMP1); + M_AST(EDX, REG_SP, 4); + M_AST(REG_ITMP1, REG_SP, 0); + M_MOV_IMM(set_escape_reasons, REG_ITMP1); + M_CALL(REG_ITMP1); + M_ALD(EDX, REG_SP, 4); + M_AADD_IMM(8, REG_SP); + } +#endif + + goto gen_method; + + case ICMD_INVOKESTATIC: /* ..., [arg1, [arg2 ...]] ==> ... */ + case ICMD_INVOKESPECIAL:/* ..., objectref, [arg1, [arg2 ...]] ==> ... */ + case ICMD_INVOKEVIRTUAL:/* op1 = arg count, val.a = method pointer */ + case ICMD_INVOKEINTERFACE: + + REPLACEMENT_POINT_INVOKE(cd, iptr); + + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + unresolved_method* um = iptr->sx.s23.s3.um; + md = um->methodref->parseddesc.md; + } + else { + methodinfo* lm = iptr->sx.s23.s3.fmiref->p.method; + md = lm->parseddesc; + } + +gen_method: + i = md->paramcount; + + // XXX Check this again! + MCODECHECK((i << 1) + 64); // PPC + + // Copy arguments to registers or stack location. + for (i = i - 1; i >= 0; i--) { + var = VAR(iptr->sx.s23.s2.args[i]); + d = md->params[i].regoff; + + // Already pre-allocated? + if (var->flags & PREALLOC) + continue; + + if (!md->params[i].inmemory) { + assert(ARG_CNT > 0); + s1 = emit_load(jd, iptr, var, d); + + switch (var->type) { + case TYPE_ADR: + case TYPE_INT: + assert(INT_ARG_CNT > 0); + emit_imove(cd, s1, d); + break; + +#if 0 //XXX For ARM: +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); +} +#endif //XXX End of ARM! + + case TYPE_LNG: + emit_lmove(cd, s1, d); + break; + + case TYPE_FLT: + emit_fmove(cd, s1, d); + break; + + case TYPE_DBL: + emit_dmove(cd, s1, d); + break; + } + } + else { + switch (var->type) { + case TYPE_ADR: + s1 = emit_load(jd, iptr, var, REG_ITMP1); + // XXX M68K: This should actually be like this: + // s1 = emit_load(jd, iptr, var, REG_ATMP1); + // XXX Sparc64: Here this actually was: + // M_STX(s1, REG_SP, JITSTACK + d); + M_AST(s1, REG_SP, d); + break; + + case TYPE_INT: +#if SIZEOF_VOID_P == 4 + s1 = emit_load(jd, iptr, var, REG_ITMP1); + M_IST(s1, REG_SP, d); + break; +#else + /* fall-through */ +#endif + + case TYPE_LNG: + s1 = emit_load(jd, iptr, var, REG_LTMP12); + // XXX Sparc64: Here this actually was: + // M_STX(s1, REG_SP, JITSTACK + d); + M_LST(s1, REG_SP, d); + break; + + case TYPE_FLT: +#if SIZEOF_VOID_P == 4 + s1 = emit_load(jd, iptr, var, REG_FTMP1); + M_FST(s1, REG_SP, d); + break; +#else + /* fall-through */ +#endif + + case TYPE_DBL: + s1 = emit_load(jd, iptr, var, REG_FTMP1); + // XXX Sparc64: Here this actually was: + // M_DST(s1, REG_SP, JITSTACK + d); + M_DST(s1, REG_SP, d); + break; + } + } + } + + // Generate method profiling code. + PROFILE_CYCLE_STOP; + + // Generate architecture specific instructions. + codegen_emit_instruction(jd, iptr); + + // Generate method profiling code. + PROFILE_CYCLE_START; + + // Store size of call code in replacement point. + REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr); + REPLACEMENT_POINT_FORGC_BUILTIN_RETURN(cd, iptr); + + // Recompute the procedure vector (PV). + emit_recompute_pv(cd); + + // Store return value. +#if defined(ENABLE_SSA) + if ((ls == NULL) /* || (!IS_TEMPVAR_INDEX(iptr->dst.varindex)) */ || + (ls->lifetime[iptr->dst.varindex].type != UNUSED)) + /* a "living" stackslot */ +#endif + switch (md->returntype.type) { + case TYPE_INT: + case TYPE_ADR: + s1 = codegen_reg_of_dst(jd, iptr, REG_RESULT); + // XXX Sparc64: This should actually be REG_RESULT_CALLER, fix this! + emit_imove(cd, REG_RESULT, s1); + emit_store_dst(jd, iptr, s1); + break; + + case TYPE_LNG: + s1 = codegen_reg_of_dst(jd, iptr, REG_LRESULT); + // XXX Sparc64: This should actually be REG_RESULT_CALLER, fix this! + emit_lmove(cd, REG_LRESULT, s1); + emit_store_dst(jd, iptr, s1); + break; + +#if 0 //XXX For ARM!!! +#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) */ +#endif //XXX End of ARM + + case TYPE_FLT: + s1 = codegen_reg_of_dst(jd, iptr, REG_FRESULT); + emit_fmove(cd, REG_FRESULT, s1); + emit_store_dst(jd, iptr, s1); + break; + + case TYPE_DBL: + s1 = codegen_reg_of_dst(jd, iptr, REG_FRESULT); + emit_dmove(cd, REG_FRESULT, s1); + emit_store_dst(jd, iptr, s1); + break; + + case TYPE_VOID: + break; + } + + break; + + case ICMD_TABLESWITCH: /* ..., index ==> ... */ + + // Generate architecture specific instructions. + codegen_emit_instruction(jd, iptr); + break; + + case ICMD_LOOKUPSWITCH: /* ..., key ==> ... */ + + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + i = iptr->sx.s23.s2.lookupcount; + + // XXX Again we need to check this + MCODECHECK((i<<2)+8); // Alpha, ARM, i386, MIPS, M68K, Sparc64 + MCODECHECK((i<<3)+8); // PPC64 + MCODECHECK(8 + ((7 + 6) * i) + 5); // X86_64, S390 + + // Compare keys. + for (lookup_target_t* lookup = iptr->dst.lookup; i > 0; ++lookup, --i) { +#if SUPPORT_BRANCH_CONDITIONAL_CONDITION_REGISTER + emit_icmp_imm(cd, s1, lookup->value); + emit_beq(cd, lookup->target.block); +#elif SUPPORT_BRANCH_CONDITIONAL_TWO_INTEGER_REGISTERS + ICONST(REG_ITMP2, lookup->value); + emit_beq(cd, lookup->target.block, s1, REG_ITMP2); +#elif SUPPORT_BRANCH_CONDITIONAL_ONE_INTEGER_REGISTER + emit_icmpeq_imm(cd, s1, lookup->value, REG_ITMP2); + emit_bnez(cd, lookup->target.block, REG_ITMP2); +#else +# error Unable to generate code for this configuration! +#endif + } + + // Default branch. + emit_br(cd, iptr->sx.s23.s3.lookupdefault.block); + ALIGNCODENOP; + break; + + case ICMD_CHECKCAST: /* ..., objectref ==> ..., objectref */ + case ICMD_INSTANCEOF: /* ..., objectref ==> ..., intresult */ + case ICMD_MULTIANEWARRAY:/* ..., cnt1, [cnt2, ...] ==> ..., arrayref */ + + // Generate architecture specific instructions. + codegen_emit_instruction(jd, iptr); + break; + + default: + exceptions_throw_internalerror("Unknown ICMD %d during code generation", + iptr->opc); + return false; + + } // the big switch + + } // for all instructions + +#if defined(ENABLE_SSA) + // By edge splitting, in blocks with phi moves there can only + // be a goto as last command, no other jump/branch command. + if (ls != NULL) { + if (!last_cmd_was_goto) + codegen_emit_phi_moves(jd, bptr); + } +#endif + +#if defined(__I386__) || defined(__M68K__) || defined(__MIPS__) || defined(__S390__) || defined(__SPARC_64__) || defined(__X86_64__) + // XXX Again!!! + /* XXX require a lower number? */ + MCODECHECK(64); // I386, MIPS, Sparc64 + MCODECHECK(512); // S390, X86_64 + + /* XXX We can remove that when we don't use UD2 anymore on i386 + and x86_64. */ + + /* At the end of a basic block we may have to append some nops, + because the patcher stub calling code might be longer than the + actual instruction. So codepatching does not change the + following block unintentionally. */ + + if (cd->mcodeptr < cd->lastmcodeptr) { + while (cd->mcodeptr < cd->lastmcodeptr) { + M_NOP; + } + } +#endif + + } // for all basic blocks + + // Generate traps. + emit_patcher_traps(jd); + + // Everything's ok. + return true; +} + + /* codegen_emit_phi_moves **************************************************** Emits phi moves at the end of the basicblock. diff --git a/src/vm/jit/codegen-common.hpp b/src/vm/jit/codegen-common.hpp index b988853b3..68fc49bdf 100644 --- a/src/vm/jit/codegen-common.hpp +++ b/src/vm/jit/codegen-common.hpp @@ -71,6 +71,19 @@ typedef struct dataref dataref; #define GET_LOW_REG(a) ((a) & 0x0000ffff) #define GET_HIGH_REG(a) (((a) & 0xffff0000) >> 16) +/* All 32-bit machines we support use packed registers to store + return values and temporary values. */ + +#if SIZEOF_VOID_P == 8 +# define REG_LRESULT REG_RESULT +# define REG_LTMP12 REG_ITMP1 +# define REG_LTMP23 REG_ITMP2 +#else +# define REG_LRESULT REG_RESULT_PACKED +# define REG_LTMP12 REG_ITMP12_PACKED +# define REG_LTMP23 REG_ITMP23_PACKED +#endif + /* branch conditions **********************************************************/ @@ -211,6 +224,10 @@ void codegen_setup(jitdata *jd); bool codegen_generate(jitdata *jd); bool codegen_emit(jitdata *jd); +void codegen_emit_prolog(jitdata* jd); +void codegen_emit_epilog(jitdata* jd); +void codegen_emit_instruction(jitdata* jd, instruction* iptr); + #if defined(ENABLE_INTRP) bool intrp_codegen(jitdata *jd); #endif diff --git a/src/vm/jit/emit-common.hpp b/src/vm/jit/emit-common.hpp index c3c3af73d..24f6b1510 100644 --- a/src/vm/jit/emit-common.hpp +++ b/src/vm/jit/emit-common.hpp @@ -1,7 +1,8 @@ /* src/vm/jit/emit-common.hpp - common code emitter functions - Copyright (C) 2006, 2007, 2008 + Copyright (C) 2006, 2007, 2008, 2009 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO + Copyright (C) 2009 Theobroma Systems Ltd. This file is part of CACAO. @@ -23,13 +24,14 @@ */ -#ifndef _EMIT_COMMON_H -#define _EMIT_COMMON_H +#ifndef _EMIT_COMMON_HPP +#define _EMIT_COMMON_HPP #include "config.h" #include "vm/types.h" #include "arch.h" +#include "codegen.h" #include "vm/jit/codegen-common.hpp" #include "vm/jit/jit.hpp" @@ -106,6 +108,18 @@ void emit_copy(jitdata *jd, instruction *iptr); void emit_iconst(codegendata *cd, s4 d, s4 value); void emit_lconst(codegendata *cd, s4 d, s8 value); +/* compare-emitting functions targeting an integer register */ + +#if SUPPORT_BRANCH_CONDITIONAL_ONE_INTEGER_REGISTER +void emit_icmpeq_imm(codegendata* cd, int reg, int32_t value, int d); +#endif + +/* compare-emitting functions targeting the condition register */ + +#if SUPPORT_BRANCH_CONDITIONAL_CONDITION_REGISTER +void emit_icmp_imm(codegendata* cd, int reg, int32_t value); +#endif + /* branch-emitting functions */ void emit_bccz(codegendata *cd, basicblock *target, s4 condition, s4 reg, u4 options); void emit_bcc(codegendata *cd, basicblock *target, s4 condition, u4 options); @@ -197,6 +211,20 @@ uint32_t emit_trap(codegendata *cd); void emit_patcher_traps(jitdata *jd); +void emit_recompute_pv(codegendata* cd); + +#if defined(ENABLE_THREADS) +void emit_monitor_enter(jitdata* jd, int32_t syncslot_offset); +void emit_monitor_exit(jitdata* jd, int32_t syncslot_offset); +#endif + +#if defined(ENABLE_PROFILING) +void emit_profile_method(codegendata* cd, codeinfo* code); +void emit_profile_basicblock(codegendata* cd, codeinfo* code, basicblock* bptr); +void emit_profile_cycle_start(); +void emit_profile_cycle_stop(); +#endif + void emit_verbosecall_enter(jitdata *jd); void emit_verbosecall_exit(jitdata *jd); @@ -204,7 +232,77 @@ void emit_verbosecall_exit(jitdata *jd); } #endif -#endif /* _EMIT_COMMON_H */ + +/* inline code generation functions *******************************************/ + +/** + * Generates an integer-move from register s to d. If s and d are + * the same registers, no code will be generated. + */ +static inline void emit_imove(codegendata* cd, int s, int d) +{ + if (s != d) +#if defined(__ARM__) + // XXX Fix this!!! + M_MOV(d, s); +#else + M_MOV(s, d); +#endif +} + + +/** + * Generates a long-move from register s to d. If s and d are + * the same registers, no code will be generated. + */ +static inline void emit_lmove(codegendata* cd, int s, int d) +{ +#if SIZEOF_VOID_P == 8 + emit_imove(cd, s, d); +#else + if (GET_HIGH_REG(s) == GET_LOW_REG(d)) { + assert((GET_LOW_REG(s) != GET_HIGH_REG(d))); + emit_imove(cd, GET_HIGH_REG(s), GET_HIGH_REG(d)); + emit_imove(cd, GET_LOW_REG(s), GET_LOW_REG(d)); + } else { + emit_imove(cd, GET_LOW_REG(s), GET_LOW_REG(d)); + emit_imove(cd, GET_HIGH_REG(s), GET_HIGH_REG(d)); + } +#endif +} + + +/** + * Generates a float-move from register s to d. If s and d are + * the same registers, no code will be generated. + */ +static inline void emit_fmove(codegendata* cd, int s, int d) +{ + if (s != d) + M_FMOV(s, d); +} + + +/** + * Generates an double-move from register s to d. If s and d are + * the same registers, no code will be generated. + */ +static inline void emit_dmove(codegendata* cd, int s, int d) +{ + if (s != d) + M_DMOV(s, d); +} + + +/* preserve compatibility with legacy code ************************************/ + +#define M_INTMOVE(a, b) emit_imove(cd, a, b) +#define M_LNGMOVE(a, b) emit_lmove(cd, a, b) +#define M_FLTMOVE(a, b) emit_fmove(cd, a, b) +#define M_DBLMOVE(a, b) emit_dmove(cd, a, b) + + +#endif /* _EMIT_COMMON_HPP */ /* diff --git a/src/vm/jit/i386/arch.h b/src/vm/jit/i386/arch.h index f0bcdfc99..a3a91be15 100644 --- a/src/vm/jit/i386/arch.h +++ b/src/vm/jit/i386/arch.h @@ -133,6 +133,14 @@ #define SUPPORT_HARDWARE_DIVIDE_BY_ZERO 1 +/* stackframe *****************************************************************/ + +#define STACKFRMAE_RA_BETWEEN_FRAMES 1 +#define STACKFRAME_RA_TOP_OF_FRAME 0 +#define STACKFRAME_LEAFMETHODS_RA_REGISTER 0 +#define STACKFRAME_SYNC_NEEDS_TWO_SLOTS 0 + + /* replacement ****************************************************************/ #define REPLACEMENT_PATCH_SIZE 2 /* bytes */ diff --git a/src/vm/jit/i386/codegen.c b/src/vm/jit/i386/codegen.c index 14340d7a4..2eb99c0d4 100644 --- a/src/vm/jit/i386/codegen.c +++ b/src/vm/jit/i386/codegen.c @@ -63,129 +63,36 @@ #include "vm/jit/parse.hpp" #include "vm/jit/patcher-common.hpp" #include "vm/jit/reg.h" -#include "vm/jit/replace.hpp" #include "vm/jit/stacktrace.hpp" #include "vm/jit/trap.hpp" -#if defined(ENABLE_SSA) -# include "vm/jit/optimizing/lsra.h" -# include "vm/jit/optimizing/ssa.h" -#elif 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 len, s1, s2, s3, d, disp; - int align_off; /* offset for alignment compensation */ - varinfo *var, *var1; - basicblock *bptr; - instruction *iptr; - u2 currentline; - methodinfo *lm; /* local methodinfo for ICMD_INVOKE* */ - builtintable_entry *bte; - methoddesc *md; - fieldinfo *fi; - unresolved_field *uf; - s4 fieldtype; - s4 varindex; -#if defined(ENABLE_SSA) - lsradata *ls; - bool last_cmd_was_goto; - - last_cmd_was_goto = false; - ls = jd->ls; -#endif - - /* get required compiler data */ - - m = jd->m; - code = jd->code; - cd = jd->cd; - rd = jd->rd; - - /* prevent compiler warnings */ - - s1 = 0; - s2 = 0; - d = 0; - currentline = 0; - lm = NULL; - bte = NULL; - - { - s4 i, p, t, l; - s4 savedregs_num = 0; - s4 stack_off = 0; - - /* space to save used callee saved registers */ - - savedregs_num += (INT_SAV_CNT - rd->savintreguse); - savedregs_num += (FLT_SAV_CNT - rd->savfltreguse); - - cd->stackframesize = rd->memuse + savedregs_num; + varinfo* var; + methoddesc* md; + int32_t s1, d; + int32_t p, t, l; + int32_t varindex; + int i; + int align_off; + + // Get required compiler data. + methodinfo* m = jd->m; + codegendata* cd = jd->cd; + registerdata* rd = jd->rd; - -#if defined(ENABLE_THREADS) - /* space to save argument of monitor_enter */ - - if (checksync && code_is_synchronized(code)) - cd->stackframesize++; -#endif - - /* create method header */ - - /* Keep stack of non-leaf functions 16-byte aligned. */ - - if (!code_is_leafmethod(code)) { - ALIGN_ODD(cd->stackframesize); - } + /* create stack frame (if necessary) */ align_off = cd->stackframesize ? 4 : 0; - (void) dseg_add_unique_address(cd, code); /* CodeinfoPointer */ - (void) dseg_add_unique_s4( - cd, cd->stackframesize * 8 + align_off); /* 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); /* IsLeaf */ - else - (void) dseg_add_unique_s4(cd, 0); /* 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 */ - -#if defined(ENABLE_PROFILING) - /* generate method profiling code */ - - if (JITDATA_HAS_FLAG_INSTRUMENT(jd)) { - /* count frequency */ - - M_MOV_IMM(code, REG_ITMP3); - M_IADD_IMM_MEMBASE(1, REG_ITMP3, OFFSET(codeinfo, frequency)); - } -#endif - - /* create stack frame (if necessary) */ - - if (cd->stackframesize) - /* align_off == 4 */ + if (cd->stackframesize) { + assert(align_off == 4); M_ASUB_IMM(cd->stackframesize * 8 + 4, REG_SP); + } /* save return address and used callee saved registers */ @@ -201,9 +108,8 @@ bool codegen_emit(jitdata *jd) md = m->parseddesc; - stack_off = 0; - for (p = 0, l = 0; p < md->paramcount; p++) { - t = md->paramtypes[p].type; + for (p = 0, l = 0; p < md->paramcount; p++) { + t = md->paramtypes[p].type; varindex = jd->local_map[l * 5 + t]; #if defined(ENABLE_SSA) @@ -346,204 +252,76 @@ bool codegen_emit(jitdata *jd) } } } +} - /* call monitorenter function */ - -#if defined(ENABLE_THREADS) - if (checksync && code_is_synchronized(code)) { - s1 = rd->memuse; - - if (m->flags & ACC_STATIC) { - M_MOV_IMM(&m->clazz->object.header, REG_ITMP1); - } - else { - M_ALD(REG_ITMP1, REG_SP, cd->stackframesize * 8 + 4 + align_off); - M_TEST(REG_ITMP1); - M_BNE(6); - M_ALD_MEM(REG_ITMP1, TRAP_NullPointerException); - } - - M_AST(REG_ITMP1, REG_SP, s1 * 8); - M_AST(REG_ITMP1, REG_SP, 0 * 4); - M_MOV_IMM(LOCK_monitor_enter, REG_ITMP3); - M_CALL(REG_ITMP3); - } -#endif - -#if !defined(NDEBUG) - emit_verbosecall_enter(jd); -#endif - - } - -#if defined(ENABLE_SSA) - /* with SSA the Header is Basic Block 0 - insert phi Moves if necessary */ - if ( ls != NULL) - codegen_emit_phi_moves(jd, ls->basicblocks[0]); -#endif - - /* end of header generation */ - - /* create replacement points */ - - REPLACEMENT_POINTS_INIT(cd, jd); - - /* walk through all basic blocks */ - - for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) { - - bptr->mpc = (s4) (cd->mcodeptr - cd->mcodebase); - - if (bptr->flags >= BBREACHED) { - /* branch resolving */ - - codegen_resolve_branchrefs(cd, bptr); - - /* handle replacement points */ - - REPLACEMENT_POINT_BLOCK_START(cd, bptr); -#if defined(ENABLE_REPLACEMENT) - if (bptr->bitflags & BBFLAG_REPLACEMENT) { - if (cd->replacementpoint[-1].flags & RPLPOINT_FLAG_COUNTDOWN) { - MCODECHECK(32); - emit_trap_countdown(cd, &(m->hitcountdown)); - } - } -#endif +/** + * Generates machine code for the method epilog. + */ +void codegen_emit_epilog(jitdata* jd) +{ + methoddesc* md; + int32_t p; + int i; - /* copy interface registers to their destination */ + // Get required compiler data. + methodinfo* m = jd->m; + codegendata* cd = jd->cd; + registerdata* rd = jd->rd; - len = bptr->indepth; - MCODECHECK(512); + p = cd->stackframesize; + md = m->parseddesc; -#if defined(ENABLE_PROFILING) - /* generate basic block profiling code */ + /* restore saved registers */ - if (JITDATA_HAS_FLAG_INSTRUMENT(jd)) { - /* count frequency */ + for (i = INT_SAV_CNT - 1; i >= rd->savintreguse; i--) { + p--; M_ALD(rd->savintregs[i], REG_SP, p * 8); + } - M_MOV_IMM(code->bbfrequency, REG_ITMP3); - M_IADD_IMM_MEMBASE(1, REG_ITMP3, bptr->nr * 4); + for (i = FLT_SAV_CNT - 1; i >= rd->savfltreguse; i--) { + p--; + emit_fldl_membase(cd, REG_SP, p * 8); + if (md->returntype.type == TYPE_FLT || md->returntype.type == TYPE_DBL) { + assert(0); +/* emit_fstp_reg(cd, rd->savfltregs[i] + fpu_st_offset + 1); */ + } else { + assert(0); +/* emit_fstp_reg(cd, rd->savfltregs[i] + fpu_st_offset); */ } -#endif - -#if defined(ENABLE_LSRA) || defined(ENABLE_SSA) -# if defined(ENABLE_LSRA) && !defined(ENABLE_SSA) - if (opt_lsra) { -# endif -# if defined(ENABLE_SSA) - if (ls != NULL) { - last_cmd_was_goto = false; -# endif - if (len > 0) { - len--; - var = VAR(bptr->invars[len]); - if (bptr->type != BBTYPE_STD) { - if (!IS_2_WORD_TYPE(var->type)) { -#if !defined(ENABLE_SSA) - if (bptr->type == BBTYPE_EXH) { - d = codegen_reg_of_var(0, var, REG_ITMP1); - M_INTMOVE(REG_ITMP1, d); - emit_store(jd, NULL, var, d); - } -#endif - } - else { - log_text("copy interface registers(EXH, SBR): longs \ - have to be in memory (begin 1)"); - assert(0); - } - } - } - - } - else -#endif /* defined(ENABLE_LSRA) || defined(ENABLE_SSA) */ - { - while (len) { - len--; - var = VAR(bptr->invars[len]); - if ((len == bptr->indepth-1) && (bptr->type != BBTYPE_STD)) { - if (!IS_2_WORD_TYPE(var->type)) { - if (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 { - log_text("copy interface registers: longs have to be in \ - memory (begin 1)"); - assert(0); - } - - } - else { - assert((var->flags & INOUT)); - } - } /* while (len) */ - } /* */ - - /* walk through all instructions */ - - len = bptr->icount; - currentline = 0; - - for (iptr = bptr->iinstr; len > 0; len--, iptr++) { - if (iptr->line != currentline) { - linenumbertable_list_entry_add(cd, iptr->line); - currentline = iptr->line; - } - - MCODECHECK(1024); /* 1kB should be enough */ - - switch (iptr->opc) { - case ICMD_NOP: /* ... ==> ... */ - case ICMD_POP: /* ..., value ==> ... */ - case ICMD_POP2: /* ..., value, value ==> ... */ - break; - - case ICMD_INLINE_START: - - REPLACEMENT_POINT_INLINE_START(cd, iptr); - break; - - case ICMD_INLINE_BODY: + } - REPLACEMENT_POINT_INLINE_BODY(cd, iptr); - linenumbertable_list_entry_add_inline_start(cd, iptr); - linenumbertable_list_entry_add(cd, iptr->line); - break; + /* deallocate stack */ - case ICMD_INLINE_END: + if (cd->stackframesize) + M_AADD_IMM(cd->stackframesize * 8 + 4, REG_SP); - linenumbertable_list_entry_add_inline_end(cd, iptr); - linenumbertable_list_entry_add(cd, iptr->line); - break; + M_RET; +} - case ICMD_CHECKNULL: /* ..., objectref ==> ..., objectref */ - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - emit_nullpointer_check(cd, iptr, s1); - break; +/** + * Generates machine code for one ICMD. + */ +void codegen_emit_instruction(jitdata* jd, instruction* iptr) +{ + varinfo* var; + varinfo* var1; + builtintable_entry* bte; + 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; + + 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_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 */ d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); @@ -620,29 +398,6 @@ bool codegen_emit(jitdata *jd) break; - /* load/store/copy/move operations ************************************/ - - case ICMD_ILOAD: - case ICMD_ALOAD: - case ICMD_LLOAD: - case ICMD_FLOAD: - case ICMD_DLOAD: - case ICMD_ISTORE: - case ICMD_LSTORE: - case ICMD_FSTORE: - 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_INEG: /* ..., value ==> ..., - value */ @@ -988,7 +743,6 @@ bool codegen_emit(jitdata *jd) emit_arithmetic_check(cd, iptr, REG_ITMP3); bte = iptr->sx.s23.s3.bte; - md = bte->md; M_LST(s2, REG_SP, 2 * 4); @@ -1894,15 +1648,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_ITMP1); - /* implicit null-pointer check */ - M_ILD(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); @@ -2436,16 +2181,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); - -#ifdef ENABLE_VERIFIER - if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - patcher_add_patch_ref(jd, PATCHER_resolve_class, - iptr->sx.s23.s2.uc, 0); - } -#endif /* ENABLE_VERIFIER */ - M_CALL_IMM(0); /* passing exception pc */ M_POP(REG_ITMP2_XPC); @@ -2453,49 +2188,6 @@ bool codegen_emit(jitdata *jd) M_JMP(REG_ITMP3); break; - case ICMD_GOTO: /* ... ==> ... */ - case ICMD_RET: /* ... ==> ... */ - -#if defined(ENABLE_SSA) - if ( ls != NULL ) { - last_cmd_was_goto = true; - - /* In case of a Goto phimoves have to be inserted before the */ - /* jump */ - - codegen_emit_phi_moves(jd, bptr); - } -#endif - emit_br(cd, iptr->dst.block); - ALIGNCODENOP; - break; - - case ICMD_JSR: /* ... ==> ... */ - - emit_br(cd, iptr->sx.s23.s3.jsrtarget.block); - ALIGNCODENOP; - break; - - case ICMD_IFNULL: /* ..., value ==> ... */ - case ICMD_IFNONNULL: - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - M_TEST(s1); - emit_bcc(cd, iptr->dst.block, iptr->opc - ICMD_IFNULL, BRANCH_OPT_NONE); - break; - - case ICMD_IFEQ: /* ..., value ==> ... */ - case ICMD_IFLT: - case ICMD_IFLE: - case ICMD_IFNE: - case ICMD_IFGT: - case ICMD_IFGE: - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - M_CMP_IMM(iptr->sx.val.i, s1); - emit_bcc(cd, iptr->dst.block, iptr->opc - ICMD_IFEQ, BRANCH_OPT_NONE); - break; - case ICMD_IF_LEQ: /* ..., value ==> ... */ s1 = emit_load_s1(jd, iptr, REG_ITMP12_PACKED); @@ -2586,28 +2278,6 @@ bool codegen_emit(jitdata *jd) } break; - case ICMD_IF_ICMPEQ: /* ..., value, value ==> ... */ - case ICMD_IF_ICMPNE: - case ICMD_IF_ICMPLT: - case ICMD_IF_ICMPGT: - case ICMD_IF_ICMPGE: - case ICMD_IF_ICMPLE: - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - s2 = emit_load_s2(jd, iptr, REG_ITMP2); - M_CMP(s2, s1); - 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(s2, s1); - emit_bcc(cd, iptr->dst.block, iptr->opc - ICMD_IF_ACMPEQ, BRANCH_OPT_NONE); - break; - case ICMD_IF_LCMPEQ: /* ..., value, value ==> ... */ s1 = emit_load_s1_low(jd, iptr, REG_ITMP1); @@ -2688,134 +2358,6 @@ bool codegen_emit(jitdata *jd) emit_buge(cd, iptr->dst.block); break; - - case ICMD_IRETURN: /* ..., retvalue ==> ... */ - - REPLACEMENT_POINT_RETURN(cd, iptr); - s1 = emit_load_s1(jd, iptr, REG_RESULT); - M_INTMOVE(s1, REG_RESULT); - goto nowperformreturn; - - 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 nowperformreturn; - - case ICMD_ARETURN: /* ..., retvalue ==> ... */ - - REPLACEMENT_POINT_RETURN(cd, iptr); - s1 = emit_load_s1(jd, iptr, REG_RESULT); - M_INTMOVE(s1, REG_RESULT); - -#ifdef ENABLE_VERIFIER - if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - patcher_add_patch_ref(jd, PATCHER_resolve_class, - iptr->sx.s23.s2.uc, 0); - } -#endif /* ENABLE_VERIFIER */ - goto nowperformreturn; - - case ICMD_FRETURN: /* ..., retvalue ==> ... */ - case ICMD_DRETURN: - - REPLACEMENT_POINT_RETURN(cd, iptr); - s1 = emit_load_s1(jd, iptr, REG_FRESULT); - goto nowperformreturn; - - case ICMD_RETURN: /* ... ==> ... */ - - REPLACEMENT_POINT_RETURN(cd, iptr); - -nowperformreturn: - { - s4 i, p; - - p = cd->stackframesize; - -#if !defined(NDEBUG) - emit_verbosecall_exit(jd); -#endif - -#if defined(ENABLE_THREADS) - if (checksync && code_is_synchronized(code)) { - M_ALD(REG_ITMP2, REG_SP, rd->memuse * 8); - - /* we need to save the proper return value */ - switch (iptr->opc) { - case ICMD_IRETURN: - case ICMD_ARETURN: - M_IST(REG_RESULT, REG_SP, rd->memuse * 8); - break; - - case ICMD_LRETURN: - M_LST(REG_RESULT_PACKED, REG_SP, rd->memuse * 8); - break; - - case ICMD_FRETURN: - emit_fstps_membase(cd, REG_SP, rd->memuse * 8); - break; - - case ICMD_DRETURN: - emit_fstpl_membase(cd, REG_SP, rd->memuse * 8); - break; - } - - M_AST(REG_ITMP2, REG_SP, 0); - M_MOV_IMM(LOCK_monitor_exit, REG_ITMP3); - M_CALL(REG_ITMP3); - - /* and now restore the proper return value */ - switch (iptr->opc) { - case ICMD_IRETURN: - case ICMD_ARETURN: - M_ILD(REG_RESULT, REG_SP, rd->memuse * 8); - break; - - case ICMD_LRETURN: - M_LLD(REG_RESULT_PACKED, REG_SP, rd->memuse * 8); - break; - - case ICMD_FRETURN: - emit_flds_membase(cd, REG_SP, rd->memuse * 8); - break; - - case ICMD_DRETURN: - emit_fldl_membase(cd, REG_SP, rd->memuse * 8); - break; - } - } -#endif - - /* restore saved registers */ - - for (i = INT_SAV_CNT - 1; i >= rd->savintreguse; i--) { - p--; M_ALD(rd->savintregs[i], REG_SP, p * 8); - } - - for (i = FLT_SAV_CNT - 1; i >= rd->savfltreguse; i--) { - p--; - emit_fldl_membase(cd, REG_SP, p * 8); - if (iptr->opc == ICMD_FRETURN || iptr->opc == ICMD_DRETURN) { - assert(0); -/* emit_fstp_reg(cd, rd->savfltregs[i] + fpu_st_offset + 1); */ - } else { - assert(0); -/* emit_fstp_reg(cd, rd->savfltregs[i] + fpu_st_offset); */ - } - } - - /* deallocate stack */ - - if (cd->stackframesize) - M_AADD_IMM(cd->stackframesize * 8 + 4, REG_SP); - - M_RET; - } - break; - - case ICMD_TABLESWITCH: /* ..., index ==> ... */ { s4 i, l; @@ -2858,243 +2400,95 @@ nowperformreturn: } break; - - case ICMD_LOOKUPSWITCH: /* ..., key ==> ... */ - { - s4 i; - lookup_target_t *lookup; - - lookup = iptr->dst.lookup; - - i = iptr->sx.s23.s2.lookupcount; - - MCODECHECK((i<<2)+8); - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - - while (--i >= 0) { - M_CMP_IMM(lookup->value, s1); - emit_beq(cd, lookup->target.block); - lookup++; - } - - emit_br(cd, iptr->sx.s23.s3.lookupdefault.block); - ALIGNCODENOP; + case ICMD_BUILTIN: + bte = iptr->sx.s23.s3.bte; + if (bte->stub == NULL) { + M_MOV_IMM(bte->fp, REG_ITMP1); } - break; - - case ICMD_BUILTIN: /* ..., [arg1, [arg2 ...]] ==> ... */ - - REPLACEMENT_POINT_FORGC_BUILTIN(cd, iptr); + else { + M_MOV_IMM(bte->stub, REG_ITMP1); + } + M_CALL(REG_ITMP1); - bte = iptr->sx.s23.s3.bte; - md = bte->md; - -#if defined(ENABLE_ESCAPE_REASON) - if (bte->fp == BUILTIN_escape_reason_new) { - void set_escape_reasons(void *); - M_ASUB_IMM(8, REG_SP); - M_MOV_IMM(iptr->escape_reasons, REG_ITMP1); - M_AST(EDX, REG_SP, 4); - M_AST(REG_ITMP1, REG_SP, 0); - M_MOV_IMM(set_escape_reasons, REG_ITMP1); - M_CALL(REG_ITMP1); - M_ALD(EDX, REG_SP, 4); - M_AADD_IMM(8, REG_SP); +#if defined(ENABLE_ESCAPE_CHECK) + if (bte->opcode == ICMD_NEW || bte->opcode == ICMD_NEWARRAY) { + /*emit_escape_annotate_object(cd, m);*/ } #endif + break; - goto gen_method; - - case ICMD_INVOKESTATIC: /* ..., [arg1, [arg2 ...]] ==> ... */ + case ICMD_INVOKESPECIAL: + M_ALD(REG_ITMP1, REG_SP, 0 * 8); + emit_nullpointer_check(cd, iptr, REG_ITMP1); + /* fall through */ - case ICMD_INVOKESPECIAL:/* ..., objectref, [arg1, [arg2 ...]] ==> ... */ - case ICMD_INVOKEVIRTUAL:/* op1 = arg count, val.a = method pointer */ - case ICMD_INVOKEINTERFACE: + case ICMD_INVOKESTATIC: + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + um = iptr->sx.s23.s3.um; - REPLACEMENT_POINT_INVOKE(cd, iptr); + patcher_add_patch_ref(jd, PATCHER_invokestatic_special, + um, 0); - if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - md = iptr->sx.s23.s3.um->methodref->parseddesc.md; - lm = NULL; + disp = 0; } else { lm = iptr->sx.s23.s3.fmiref->p.method; - md = lm->parseddesc; + disp = (ptrint) lm->stubroutine; } -gen_method: - s3 = md->paramcount; - - MCODECHECK((s3 << 1) + 64); - - /* copy arguments to registers or stack location */ - - for (s3 = s3 - 1; s3 >= 0; s3--) { - var = VAR(iptr->sx.s23.s2.args[s3]); - - /* Already Preallocated (ARGVAR) ? */ - if (var->flags & PREALLOC) - continue; - if (IS_INT_LNG_TYPE(var->type)) { - if (!md->params[s3].inmemory) { - log_text("No integer argument registers available!"); - assert(0); - - } else { - if (IS_2_WORD_TYPE(var->type)) { - d = emit_load(jd, iptr, var, REG_ITMP12_PACKED); - M_LST(d, REG_SP, md->params[s3].regoff); - } else { - d = emit_load(jd, iptr, var, REG_ITMP1); - M_IST(d, REG_SP, md->params[s3].regoff); - } - } - - } else { - if (!md->params[s3].inmemory) { - s1 = md->params[s3].regoff; - d = emit_load(jd, iptr, var, s1); - M_FLTMOVE(d, s1); - - } else { - d = emit_load(jd, iptr, var, REG_FTMP1); - if (IS_2_WORD_TYPE(var->type)) - M_DST(d, REG_SP, md->params[s3].regoff); - else - M_FST(d, REG_SP, md->params[s3].regoff); - } - } - } /* end of for */ - - switch (iptr->opc) { - case ICMD_BUILTIN: - d = md->returntype.type; - - if (bte->stub == NULL) { - M_MOV_IMM(bte->fp, REG_ITMP1); - } - else { - M_MOV_IMM(bte->stub, REG_ITMP1); - } - M_CALL(REG_ITMP1); - -#if defined(ENABLE_ESCAPE_CHECK) - if (bte->opcode == ICMD_NEW || bte->opcode == ICMD_NEWARRAY) { - /*emit_escape_annotate_object(cd, m);*/ - } -#endif - break; - - case ICMD_INVOKESPECIAL: - M_ALD(REG_ITMP1, REG_SP, 0 * 8); - emit_nullpointer_check(cd, iptr, REG_ITMP1); - /* fall through */ - - case ICMD_INVOKESTATIC: - if (lm == NULL) { - unresolved_method *um = iptr->sx.s23.s3.um; - - patcher_add_patch_ref(jd, PATCHER_invokestatic_special, - um, 0); - - disp = 0; - d = md->returntype.type; - } - else { - disp = (ptrint) lm->stubroutine; - d = lm->parseddesc->returntype.type; - } - - M_MOV_IMM2(disp, REG_ITMP2); - M_CALL(REG_ITMP2); - break; - - case ICMD_INVOKEVIRTUAL: - M_ALD(REG_ITMP1, REG_SP, 0 * 8); - emit_nullpointer_check(cd, iptr, s1); - - if (lm == NULL) { - unresolved_method *um = iptr->sx.s23.s3.um; - - patcher_add_patch_ref(jd, PATCHER_invokevirtual, um, 0); + M_MOV_IMM2(disp, REG_ITMP2); + M_CALL(REG_ITMP2); + break; - s1 = 0; - d = md->returntype.type; - } - else { - s1 = OFFSET(vftbl_t, table[0]) + - sizeof(methodptr) * lm->vftblindex; - d = md->returntype.type; - } + case ICMD_INVOKEVIRTUAL: + M_ALD(REG_ITMP1, REG_SP, 0 * 8); + emit_nullpointer_check(cd, iptr, s1); - M_ALD(REG_METHODPTR, REG_ITMP1, - OFFSET(java_object_t, vftbl)); - M_ALD32(REG_ITMP3, REG_METHODPTR, s1); - M_CALL(REG_ITMP3); - break; + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + um = iptr->sx.s23.s3.um; - case ICMD_INVOKEINTERFACE: - M_ALD(REG_ITMP1, REG_SP, 0 * 8); - emit_nullpointer_check(cd, iptr, s1); + patcher_add_patch_ref(jd, PATCHER_invokevirtual, um, 0); - if (lm == NULL) { - unresolved_method *um = iptr->sx.s23.s3.um; + s1 = 0; + } + else { + lm = iptr->sx.s23.s3.fmiref->p.method; + s1 = OFFSET(vftbl_t, table[0]) + + sizeof(methodptr) * lm->vftblindex; + } - patcher_add_patch_ref(jd, PATCHER_invokeinterface, um, 0); + M_ALD(REG_METHODPTR, REG_ITMP1, + OFFSET(java_object_t, vftbl)); + M_ALD32(REG_ITMP3, REG_METHODPTR, s1); + M_CALL(REG_ITMP3); + break; - s1 = 0; - s2 = 0; - d = md->returntype.type; - } - else { - s1 = OFFSET(vftbl_t, interfacetable[0]) - - sizeof(methodptr) * lm->clazz->index; + case ICMD_INVOKEINTERFACE: + M_ALD(REG_ITMP1, REG_SP, 0 * 8); + emit_nullpointer_check(cd, iptr, s1); - s2 = sizeof(methodptr) * (lm - lm->clazz->methods); + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + um = iptr->sx.s23.s3.um; - d = md->returntype.type; - } + patcher_add_patch_ref(jd, PATCHER_invokeinterface, um, 0); - M_ALD(REG_METHODPTR, REG_ITMP1, - OFFSET(java_object_t, vftbl)); - M_ALD32(REG_METHODPTR, REG_METHODPTR, s1); - M_ALD32(REG_ITMP3, REG_METHODPTR, s2); - M_CALL(REG_ITMP3); - break; + s1 = 0; + s2 = 0; } + else { + lm = iptr->sx.s23.s3.fmiref->p.method; + s1 = OFFSET(vftbl_t, interfacetable[0]) - + sizeof(methodptr) * lm->clazz->index; - /* store size of call code in replacement point */ - - REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr); - REPLACEMENT_POINT_FORGC_BUILTIN_RETURN(cd, iptr); - - /* d contains return type */ - - if (d != TYPE_VOID) { -#if defined(ENABLE_SSA) - if ((ls == NULL) /* || (!IS_TEMPVAR_INDEX(iptr->dst.varindex)) */ || - (ls->lifetime[iptr->dst.varindex].type != UNUSED)) - /* a "living" stackslot */ -#endif - { - if (IS_INT_LNG_TYPE(d)) { - 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); - } - } - else { - s1 = codegen_reg_of_dst(jd, iptr, REG_NULL); - } - emit_store_dst(jd, iptr, s1); - } + s2 = sizeof(methodptr) * (lm - lm->clazz->methods); } - break; + M_ALD(REG_METHODPTR, REG_ITMP1, + OFFSET(java_object_t, vftbl)); + M_ALD32(REG_METHODPTR, REG_METHODPTR, s1); + M_ALD32(REG_ITMP3, REG_METHODPTR, s2); + M_CALL(REG_ITMP3); + break; case ICMD_CHECKCAST: /* ..., objectref ==> ..., objectref */ @@ -3491,59 +2885,9 @@ gen_method: emit_store_dst(jd, iptr, s1); break; -#if defined(ENABLE_SSA) - case ICMD_GETEXCEPTION: - d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); - M_INTMOVE(REG_ITMP1, d); - emit_store_dst(jd, iptr, d); - break; -#endif default: - exceptions_throw_internalerror("Unknown ICMD %d during code generation", - iptr->opc); - return false; + vm_abort("Unknown ICMD %d during code generation", iptr->opc); } /* switch */ - - } /* for instruction */ - - MCODECHECK(64); - -#if defined(ENABLE_LSRA) && !defined(ENABLE_SSA) - if (!opt_lsra) -#endif -#if defined(ENABLE_SSA) - if ( ls != NULL ) { - - /* by edge splitting, in Blocks with phi moves there can only */ - /* be a goto as last command, no other Jump/Branch Command */ - - if (!last_cmd_was_goto) - codegen_emit_phi_moves(jd, bptr); - } - -#endif - - /* At the end of a basic block we may have to append some nops, - because the patcher stub calling code might be longer than the - actual instruction. So codepatching does not change the - following block unintentionally. */ - - if (cd->mcodeptr < cd->lastmcodeptr) { - while (cd->mcodeptr < cd->lastmcodeptr) { - M_NOP; - } - } - - } /* if (bptr -> flags >= BBREACHED) */ - } /* for basic block */ - - /* generate stubs */ - - emit_patcher_traps(jd); - - /* everything's ok */ - - return true; } @@ -3588,7 +2932,7 @@ void codegen_emit_stub_native(jitdata *jd, methoddesc *nmd, functionptr f, int s /* create method header */ (void) dseg_add_unique_address(cd, code); /* CodeinfoPointer */ - (void) dseg_add_unique_s4(cd, cd->stackframesize * 8 + 4); /* FrameSize */ + (void) dseg_add_unique_s4(cd, cd->stackframesize * 8); /* FrameSize */ (void) dseg_add_unique_s4(cd, 0); /* IsLeaf */ (void) dseg_add_unique_s4(cd, 0); /* IntSave */ (void) dseg_add_unique_s4(cd, 0); /* FltSave */ diff --git a/src/vm/jit/i386/codegen.h b/src/vm/jit/i386/codegen.h index 3f61d96a8..375154c05 100644 --- a/src/vm/jit/i386/codegen.h +++ b/src/vm/jit/i386/codegen.h @@ -69,43 +69,13 @@ } while (0) -/* M_INTMOVE: - generates an integer-move from register a to b. - if a and b are the same int-register, no code will be generated. -*/ - -#define M_INTMOVE(a,b) \ - do { \ - if ((a) != (b)) \ - M_MOV(a, b); \ - } while (0) - -#define M_LNGMOVE(a,b) \ - do { \ - if (GET_HIGH_REG(a) == GET_LOW_REG(b)) { \ - assert((GET_LOW_REG(a) != GET_HIGH_REG(b))); \ - M_INTMOVE(GET_HIGH_REG(a), GET_HIGH_REG(b)); \ - M_INTMOVE(GET_LOW_REG(a), GET_LOW_REG(b)); \ - } else { \ - M_INTMOVE(GET_LOW_REG(a), GET_LOW_REG(b)); \ - M_INTMOVE(GET_HIGH_REG(a), GET_HIGH_REG(b)); \ - } \ - } while (0) - - -/* M_FLTMOVE: - generates a floating-point-move from register a to b. - if a and b are the same float-register, no code will be generated -*/ - -#define M_FLTMOVE(reg,dreg) \ +#define M_FMOV(reg,dreg) \ do { \ - if ((reg) != (dreg)) { \ - log_text("M_FLTMOVE"); \ - assert(0); \ - } \ + log_text("M_FMOV"); \ + assert(0); \ } while (0) +#define M_DMOV(a,b) M_FMOV(a,b) #define ICONST(d,c) \ do { \ @@ -319,6 +289,9 @@ #define M_CALL_IMM(a) emit_call_imm(cd, (a)) #define M_RET M_BYTE1(0xc3) +#define M_ACMP(a,b) M_CMP(a,b) + +#define M_ICMP(a,b) M_CMP(a,b) #define M_ICMP_IMM(a,b) emit_alu_imm_reg(cd, ALU_CMP, (a), (b)) #define M_BEQ(a) emit_jcc(cd, CC_E, (a)) diff --git a/src/vm/jit/i386/emit.c b/src/vm/jit/i386/emit.c index cfddc22a7..d69217920 100644 --- a/src/vm/jit/i386/emit.c +++ b/src/vm/jit/i386/emit.c @@ -332,6 +332,16 @@ void emit_copy(jitdata *jd, instruction *iptr) } +/** + * Emits code updating the condition register by comparing one integer + * register to an immediate integer value. + */ +void emit_icmp_imm(codegendata* cd, int reg, int32_t value) +{ + M_CMP_IMM(value, reg); +} + + /* emit_branch ***************************************************************** Emits the code for conditional and unconditional branchs. @@ -577,6 +587,125 @@ uint32_t emit_trap(codegendata *cd) } +/** + * Generates synchronization code to enter a monitor. + */ +#if defined(ENABLE_THREADS) +void emit_monitor_enter(jitdata* jd, int32_t syncslot_offset) +{ + int align_off; + + // Get required compiler data. + methodinfo* m = jd->m; + codegendata* cd = jd->cd; + + align_off = cd->stackframesize ? 4 : 0; + + if (m->flags & ACC_STATIC) { + M_MOV_IMM(&m->clazz->object.header, REG_ITMP1); + } + else { + M_ALD(REG_ITMP1, REG_SP, cd->stackframesize * 8 + 4 + align_off); + M_TEST(REG_ITMP1); + M_BNE(6); + M_ALD_MEM(REG_ITMP1, TRAP_NullPointerException); + } + + M_AST(REG_ITMP1, REG_SP, syncslot_offset); + M_AST(REG_ITMP1, REG_SP, 0 * 4); + M_MOV_IMM(LOCK_monitor_enter, REG_ITMP3); + M_CALL(REG_ITMP3); +} +#endif + + +/** + * Generates synchronization code to leave a monitor. + */ +#if defined(ENABLE_THREADS) +void emit_monitor_exit(jitdata* jd, int32_t syncslot_offset) +{ + // Get required compiler data. + methodinfo* m = jd->m; + codegendata* cd = jd->cd; + + M_ALD(REG_ITMP2, REG_SP, syncslot_offset); + + /* we need to save the proper return value */ + + methoddesc* md = m->parseddesc; + + switch (md->returntype.type) { + case TYPE_INT: + case TYPE_ADR: + M_IST(REG_RESULT, REG_SP, syncslot_offset); + break; + + case TYPE_LNG: + M_LST(REG_RESULT_PACKED, REG_SP, syncslot_offset); + break; + + case TYPE_FLT: + emit_fstps_membase(cd, REG_SP, syncslot_offset); + break; + + case TYPE_DBL: + emit_fstpl_membase(cd, REG_SP, syncslot_offset); + break; + } + + M_AST(REG_ITMP2, REG_SP, 0); + M_MOV_IMM(LOCK_monitor_exit, REG_ITMP3); + M_CALL(REG_ITMP3); + + /* and now restore the proper return value */ + + switch (md->returntype.type) { + case TYPE_INT: + case TYPE_ADR: + M_ILD(REG_RESULT, REG_SP, syncslot_offset); + break; + + case TYPE_LNG: + M_LLD(REG_RESULT_PACKED, REG_SP, syncslot_offset); + break; + + case TYPE_FLT: + emit_flds_membase(cd, REG_SP, syncslot_offset); + break; + + case TYPE_DBL: + emit_fldl_membase(cd, REG_SP, syncslot_offset); + break; + } +} +#endif + + +/** + * Emit profiling code for method frequency counting. + */ +#if defined(ENABLE_PROFILING) +void emit_profile_method(codegendata* cd, codeinfo* code) +{ + M_MOV_IMM(code, REG_ITMP3); + M_IADD_IMM_MEMBASE(1, REG_ITMP3, OFFSET(codeinfo, frequency)); +} +#endif + + +/** + * Emit profiling code for basicblock frequency counting. + */ +#if defined(ENABLE_PROFILING) +void emit_profile_basicblock(codegendata* cd, codeinfo* code, basicblock* bptr) +{ + M_MOV_IMM(code->bbfrequency, REG_ITMP3); + M_IADD_IMM_MEMBASE(1, REG_ITMP3, bptr->nr * 4); +} +#endif + + /* emit_verbosecall_enter ****************************************************** Generates the code for the call trace. diff --git a/src/vm/jit/i386/emit.h b/src/vm/jit/i386/emit.h index c17c0229f..8438d0dd1 100644 --- a/src/vm/jit/i386/emit.h +++ b/src/vm/jit/i386/emit.h @@ -1,9 +1,7 @@ -/* src/vm/jit/i386/emitfuncs.h - emit function prototypes +/* src/vm/jit/i386/emit.h - machine dependent emit function prototypes - Copyright (C) 1996-2005, 2006 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-2005, 2006 + CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO This file is part of CACAO. @@ -22,18 +20,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - Changes: - */ -#ifndef _EMITFUNCS_H -#define _EMITFUNCS_H +#ifndef _MD_EMIT_H +#define _MD_EMIT_H +#include "config.h" #include "vm/types.h" #include "vm/jit/codegen-common.hpp" @@ -149,6 +142,9 @@ #define emit_reg(reg,rm) emit_address_byte(3,(reg),(rm)) +#ifdef __cplusplus +extern "C" { +#endif /* integer instructions */ @@ -304,7 +300,19 @@ void emit_escape_check(codegendata *cd, s4 reg); void emit_escape_annotate_object(codegendata *cd, methodinfo *m); #endif -#endif /* _EMITFUNCS_H */ + +/** + * Emit code to recompute the procedure vector. This is a nop, + * because we do not use a procedure vector. + */ +static inline void emit_recompute_pv(codegendata* cd) {} + + +#ifdef __cplusplus +} +#endif + +#endif /* _MD_EMIT_H */ /* diff --git a/src/vm/jit/i386/md.h b/src/vm/jit/i386/md.h index 562736be4..9bfa13373 100644 --- a/src/vm/jit/i386/md.h +++ b/src/vm/jit/i386/md.h @@ -1,6 +1,6 @@ /* src/vm/jit/i386/md.h - machine dependent i386 functions - Copyright (C) 1996-2005, 2006, 2007, 2008 + Copyright (C) 1996-2005, 2006, 2007, 2008, 2009 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO This file is part of CACAO. @@ -37,6 +37,30 @@ /* inline functions ***********************************************************/ +/** + * Returns the size (in bytes) of the current stackframe, specified by + * the passed codeinfo structure. + */ +inline static int32_t md_stacktrace_get_framesize(codeinfo* code) +{ + int32_t stackframesize; + + // Check for the asm_vm_call_method special case. + if (code == NULL) + return 0; + + // On i386 we use 8-byte stackslots. + stackframesize = code->stackframesize * 8; + + // If there is a stackframe present, we need to take the alignment + // compensation for the stored return address into account. + if (stackframesize != 0) + stackframesize += 4; + + return stackframesize; +} + + /* md_stacktrace_get_returnaddress ********************************************* Returns the return address of the current stackframe, specified by diff --git a/src/vm/jit/m68k/arch.h b/src/vm/jit/m68k/arch.h index 5498aabee..77a189f25 100644 --- a/src/vm/jit/m68k/arch.h +++ b/src/vm/jit/m68k/arch.h @@ -96,6 +96,15 @@ #define SUPPORT_BRANCH_CONDITIONAL_ONE_INTEGER_REGISTER 0 #define SUPPORT_BRANCH_CONDITIONAL_TWO_INTEGER_REGISTERS 0 + +/* stackframe *****************************************************************/ + +#define STACKFRMAE_RA_BETWEEN_FRAMES 1 +#define STACKFRAME_RA_TOP_OF_FRAME 0 +#define STACKFRAME_LEAFMETHODS_RA_REGISTER 0 +#define STACKFRAME_SYNC_NEEDS_TWO_SLOTS 1 + + #define TRACE_ARGS_NUM 8 #define REG_ZERO -1 diff --git a/src/vm/jit/m68k/codegen.c b/src/vm/jit/m68k/codegen.c index 12fd51840..0633aefc4 100644 --- a/src/vm/jit/m68k/codegen.c +++ b/src/vm/jit/m68k/codegen.c @@ -1,6 +1,6 @@ -/* src/vm/jit/m68k/codegen.c +/* src/vm/jit/m68k/codegen.c - machine code generator for m68k - Copyright (C) 1996-2005, 2006, 2007, 2008 + Copyright (C) 1996-2005, 2006, 2007, 2008, 2009 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO This file is part of CACAO. @@ -59,313 +59,195 @@ #include "vm/jit/abi.h" #include "vm/jit/parse.hpp" #include "vm/jit/reg.h" -#include "vm/jit/replace.hpp" #include "vm/jit/stacktrace.hpp" #include "vm/jit/trap.hpp" -bool codegen_emit(jitdata *jd) -{ - methodinfo *m; - codeinfo *code; - codegendata *cd; - registerdata *rd; - s4 len, s1, s2, s3, d, disp; - varinfo *var; - basicblock *bptr; - instruction *iptr; - u2 currentline; - methodinfo *lm; /* local methodinfo for ICMD_INVOKE* */ - unresolved_method *um; - builtintable_entry *bte; - methoddesc *md; - s4 fieldtype; - s4 varindex; - unresolved_field *uf; - fieldinfo *fi; - - /* get required compiler data */ - - m = jd->m; - code = jd->code; - cd = jd->cd; - rd = jd->rd; - - /* prevent compiler warnings */ - - d = 0; - lm = NULL; - bte = NULL; - - { - s4 i, p, t, l; - /* save calle saved registers */ - s4 savedregs_num = 0; - - savedregs_num += (INT_SAV_CNT - rd->savintreguse); - savedregs_num += (ADR_SAV_CNT - rd->savadrreguse); - savedregs_num += (FLT_SAV_CNT - rd->savfltreguse); - - cd->stackframesize = rd->memuse + savedregs_num; - - /* we always add 2 stack slots. - * 1 word the lock word, which may be unused and resides @ rd->memuse * 8 - * + 2 words to either save the return value for LOCK_monitor_exit @ rd->memuse * 8 + 8 - * on the other hand we could use 2 words when a builtin returns a doulbe which are - * returned in %d0, %d1 and need to be stored onto the stack and read in used a fmovemd - * so we always _need_ at least 2 slots, and this keeps the code simple */ - cd->stackframesize += 2; - - cd->stackframesize *= 8; /* we use 8 byte stack slots */ - -#if 0 -#if defined(ENABLE_THREADS) - /* we need additional space to save argument of monitor_enter */ - if (checksync && code_is_synchronized(code)) { - if (IS_2_WORD_TYPE(m->parseddesc->returntype.type)) { - cd->stackframesize += 2; - } else { - cd->stackframesize += 1; - } - } -#endif -#endif - - /* 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); - - /* XXX we use the IntSave a split field for the adr now */ - (void) dseg_add_unique_s4(cd, (ADR_SAV_CNT - rd->savadrreguse) << 16 | (INT_SAV_CNT - rd->savintreguse)); /* IntSave */ - (void) dseg_add_unique_s4(cd, FLT_SAV_CNT - rd->savfltreguse); /* FltSave */ - -#if defined(ENABLE_PROFILING) - assert(0); -#endif - -#if !defined(NDEBUG) - emit_verbosecall_enter(jd); -#endif - /* create stack frame */ - M_AADD_IMM(-(cd->stackframesize), REG_SP); - - /* save used callee saved registers */ - p = cd->stackframesize; - for (i=INT_SAV_CNT-1; i>=rd->savintreguse; --i) { - p-=8; M_IST(rd->savintregs[i], REG_SP, p); - } - for (i=ADR_SAV_CNT-1; i>=rd->savadrreguse; --i) { - p-=8; M_AST(rd->savadrregs[i], REG_SP, p); - } +/** + * Generates machine code for the method prolog. + */ +void codegen_emit_prolog(jitdata* jd) +{ + varinfo* var; + methoddesc* md; + int32_t s1; + int32_t p, t, l; + 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; + + // XXX XXX + // XXX Fix the below stuff, cd->stackframesize is a slot counter + // and not a byte counter!!! + // XXX XXX + + /* create stack frame */ + M_AADD_IMM(-(cd->stackframesize), REG_SP); + + /* save used callee saved registers */ + p = cd->stackframesize; + for (i=INT_SAV_CNT-1; i>=rd->savintreguse; --i) { + p-=8; M_IST(rd->savintregs[i], REG_SP, p); + } + for (i=ADR_SAV_CNT-1; i>=rd->savadrreguse; --i) { + p-=8; M_AST(rd->savadrregs[i], REG_SP, p); + } #if !defined(ENABLE_SOFTFLOAT) - for (i=FLT_SAV_CNT-1; i>=rd->savfltreguse; --i) { - p-=8; M_FSTORE(rd->savfltregs[i], REG_SP, p); - } + for (i=FLT_SAV_CNT-1; i>=rd->savfltreguse; --i) { + p-=8; M_FSTORE(rd->savfltregs[i], REG_SP, p); + } #else - assert(FLT_SAV_CNT == 0); - assert(rd->savfltreguse == 0); + assert(FLT_SAV_CNT == 0); + assert(rd->savfltreguse == 0); #endif - /* take arguments out of stack frame */ - md = m->parseddesc; - for (p = 0, l = 0; p < md->paramcount; p++) { - t = md->paramtypes[p].type; - varindex = jd->local_map[l * 5 + t]; - - l++; - if (IS_2_WORD_TYPE(t)) /* increment local counter for 2 word types */ - l++; + /* take arguments out of stack frame */ + md = m->parseddesc; + for (p = 0, l = 0; p < md->paramcount; p++) { + t = md->paramtypes[p].type; + varindex = jd->local_map[l * 5 + t]; - if (varindex == UNUSED) - continue; + l++; + if (IS_2_WORD_TYPE(t)) /* increment local counter for 2 word types */ + l++; - var = VAR(varindex); - - s1 = md->params[p].regoff; - assert(md->params[p].inmemory); /* all args are on stack */ + if (varindex == UNUSED) + continue; + + var = VAR(varindex); - switch (t) { + s1 = md->params[p].regoff; + assert(md->params[p].inmemory); /* all args are on stack */ + + switch (t) { #if defined(ENABLE_SOFTFLOAT) - case TYPE_FLT: - case TYPE_DBL: + case TYPE_FLT: + case TYPE_DBL: #endif - case TYPE_LNG: - case TYPE_INT: - if (!IS_INMEMORY(var->flags)) { /* stack arg -> register */ - if (IS_2_WORD_TYPE(t)) { - M_LLD(var->vv.regoff, REG_SP, cd->stackframesize + s1 + 4); - } else { - M_ILD(var->vv.regoff, REG_SP, cd->stackframesize + s1 + 4); - } - } else { /* stack arg -> spilled */ - M_ILD(REG_ITMP1, REG_SP, cd->stackframesize + s1 + 4); - M_IST(REG_ITMP1, REG_SP, var->vv.regoff); - if (IS_2_WORD_TYPE(t)) { - M_ILD(REG_ITMP1, REG_SP, cd->stackframesize + s1 + 4 + 4); - M_IST(REG_ITMP1, REG_SP, var->vv.regoff + 4); - } - } - break; + case TYPE_LNG: + case TYPE_INT: + if (!IS_INMEMORY(var->flags)) { /* stack arg -> register */ + if (IS_2_WORD_TYPE(t)) { + M_LLD(var->vv.regoff, REG_SP, cd->stackframesize + s1 + 4); + } else { + M_ILD(var->vv.regoff, REG_SP, cd->stackframesize + s1 + 4); + } + } else { /* stack arg -> spilled */ + M_ILD(REG_ITMP1, REG_SP, cd->stackframesize + s1 + 4); + M_IST(REG_ITMP1, REG_SP, var->vv.regoff); + if (IS_2_WORD_TYPE(t)) { + M_ILD(REG_ITMP1, REG_SP, cd->stackframesize + s1 + 4 + 4); + M_IST(REG_ITMP1, REG_SP, var->vv.regoff + 4); + } + } + break; #if !defined(ENABLE_SOFTFLOAT) - case TYPE_FLT: - case TYPE_DBL: - if (!IS_INMEMORY(var->flags)) { /* stack-arg -> register */ - if (IS_2_WORD_TYPE(t)) { - M_DLD(var->vv.regoff, REG_SP, cd->stackframesize + s1 + 4); - } else { - M_FLD(var->vv.regoff, REG_SP, cd->stackframesize + s1 + 4); - } - } else { /* stack-arg -> spilled */ - if (IS_2_WORD_TYPE(t)) { - M_DLD(REG_FTMP1, REG_SP, cd->stackframesize + s1 + 4); - M_DST(REG_FTMP1, REG_SP, var->vv.regoff); - } else { - M_FLD(REG_FTMP1, REG_SP, cd->stackframesize + s1 + 4); - M_FST(REG_FTMP1, REG_SP, var->vv.regoff); - } + case TYPE_FLT: + case TYPE_DBL: + if (!IS_INMEMORY(var->flags)) { /* stack-arg -> register */ + if (IS_2_WORD_TYPE(t)) { + M_DLD(var->vv.regoff, REG_SP, cd->stackframesize + s1 + 4); + } else { + M_FLD(var->vv.regoff, REG_SP, cd->stackframesize + s1 + 4); } - break; -#endif /* SOFTFLOAT */ - case TYPE_ADR: - if (!IS_INMEMORY(var->flags)) { /* stack-arg -> register */ - M_ALD(var->vv.regoff, REG_SP, cd->stackframesize + s1 + 4); - } else { /* stack-arg -> spilled */ - M_ALD(REG_ATMP1, REG_SP, cd->stackframesize + s1 + 4); - M_AST(REG_ATMP1, REG_SP, var->vv.regoff); + } else { /* stack-arg -> spilled */ + if (IS_2_WORD_TYPE(t)) { + M_DLD(REG_FTMP1, REG_SP, cd->stackframesize + s1 + 4); + M_DST(REG_FTMP1, REG_SP, var->vv.regoff); + } else { + M_FLD(REG_FTMP1, REG_SP, cd->stackframesize + s1 + 4); + M_FST(REG_FTMP1, REG_SP, var->vv.regoff); } - break; - default: assert(0); } - } /* end for argument out of stack*/ - -#if defined(ENABLE_THREADS) - /* call lock_monitor_enter function */ - if (checksync && code_is_synchronized(code)) { - if (m->flags & ACC_STATIC) { - M_AMOV_IMM((&m->clazz->object.header), REG_ATMP1); - } else { - /* for non-static case the first arg is the object */ - M_ALD(REG_ATMP1, REG_SP, cd->stackframesize + 4); - M_ATST(REG_ATMP1); - M_BNE(2); - M_TRAP(TRAP_NullPointerException); + break; +#endif /* SOFTFLOAT */ + case TYPE_ADR: + if (!IS_INMEMORY(var->flags)) { /* stack-arg -> register */ + M_ALD(var->vv.regoff, REG_SP, cd->stackframesize + s1 + 4); + } else { /* stack-arg -> spilled */ + M_ALD(REG_ATMP1, REG_SP, cd->stackframesize + s1 + 4); + M_AST(REG_ATMP1, REG_SP, var->vv.regoff); + } + break; + default: assert(0); } + } /* end for argument out of stack*/ +} - M_AST(REG_ATMP1, REG_SP, rd->memuse * 8); - M_AST(REG_ATMP1, REG_SP, 0 * 4); - M_JSR_IMM(LOCK_monitor_enter); - } -#endif - } +/** + * Generates machine code for the method epilog. + */ +void codegen_emit_epilog(jitdata* jd) +{ + int32_t p; + int i; - /* create replacement points */ - REPLACEMENT_POINTS_INIT(cd, jd); + // Get required compiler data. + codeinfo* code = jd->code; + codegendata* cd = jd->cd; + registerdata* rd = jd->rd; - /* foreach basic block */ - for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) { - - bptr->mpc = (s4) (cd->mcodeptr - cd->mcodebase); + p = cd->stackframesize; - if (bptr->flags >= BBREACHED) { - - /* branch resolving */ - codegen_resolve_branchrefs(cd, bptr); + /* restore return address */ - /* handle replacement points */ - REPLACEMENT_POINT_BLOCK_START(cd, bptr); +#if 0 + if (!code_is_leafmethod(code)) { + /* ATTENTION: Don't use REG_ZERO (r0) here, as M_ALD + may have a displacement overflow. */ -#if defined(ENABLE_PROFILING) - assert(0); + M_ALD(REG_ITMP1, REG_SP, p * 4 + LA_LR_OFFSET); + M_MTLR(REG_ITMP1); + } #endif - /* FIXME there are still some constrcuts to copy in here */ -#if defined(ENABLE_LSRA) - assert(0); -#endif + /* restore saved registers */ - /* copy interface registers to their destination */ - len = bptr->indepth; - MCODECHECK(64+len); - - while (len > 0) { - len--; - var = VAR(bptr->invars[len]); - if ((len == bptr->indepth-1) && (bptr->type == BBTYPE_EXH)) { - d = codegen_reg_of_var(0, var, REG_ATMP1_XPTR); - M_ADRMOVE(REG_ATMP1_XPTR, d); - emit_store(jd, NULL, var, d); - } - else { - assert((var->flags & INOUT)); - } + for (i = INT_SAV_CNT - 1; i >= rd->savintreguse; i--) { + p-=8; M_ILD(rd->savintregs[i], REG_SP, p); } + for (i = ADR_SAV_CNT - 1; i >= rd->savadrreguse; --i) { + p-=8; M_ALD(rd->savadrregs[i], REG_SP, p); + } +#if !defined(ENABLE_SOFTFLOAT) + for (i = FLT_SAV_CNT - 1; i >= rd->savfltreguse; i--) { + p-=8; M_FLOAD(rd->savfltregs[i], REG_SP, p); + } +#endif - /* walk through all instructions */ - len = bptr->icount; - currentline = 0; - - for (iptr = bptr->iinstr; len > 0; len--, iptr++) { - if (iptr->line != currentline) { - linenumbertable_list_entry_add(cd, iptr->line); - currentline = iptr->line; - } - - MCODECHECK(1024); /* 1kB should be enough */ - - switch (iptr->opc) { - case ICMD_NOP: /* ... ==> ... */ - case ICMD_POP: /* ..., value ==> ... */ - case ICMD_POP2: /* ..., value, value ==> ... */ - break; - - case ICMD_INLINE_START: - - REPLACEMENT_POINT_INLINE_START(cd, iptr); - break; - - case ICMD_INLINE_BODY: - - REPLACEMENT_POINT_INLINE_BODY(cd, iptr); - linenumbertable_list_entry_add_intern(cd, iptr); - linenumbertable_list_entry_add(cd, iptr->line); - break; - - case ICMD_INLINE_END: - - linenumbertable_list_entry_add_inline(cd, iptr); - linenumbertable_list_entry_add(cd, iptr->line); - break; - - case ICMD_CHECKNULL: /* ..., objectref ==> ..., objectref */ + /* deallocate stack */ + M_AADD_IMM(cd->stackframesize, REG_SP); + M_RET; +} - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - assert(VAROP(iptr->s1)->type == TYPE_ADR); - emit_nullpointer_check(cd, iptr, s1); - break; +/** + * Generates machine code for one ICMD. + */ +void codegen_emit_instruction(jitdata* jd, instruction* iptr) +{ + varinfo* var; + builtintable_entry* bte; + 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. + codeinfo* code = jd->code; + codegendata* cd = jd->cd; + + switch (iptr->opc) { /* CONST **************************************************************/ - case ICMD_ICONST: /* ... ==> ..., constant */ - d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); - M_IMOV_IMM(iptr->sx.val.i, d); - emit_store_dst(jd, iptr, d); - break; - - case ICMD_LCONST: /* ... ==> ..., constant */ - - d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED); - LCONST(iptr->sx.val.l, d); - emit_store_dst(jd, iptr, d); - break; case ICMD_FCONST: /* ... ==> ..., constant */ @@ -876,9 +758,9 @@ 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_FTMP2); - M_FLTMOVE(s2, REG_FTMP2); + emit_fmove(cd, s2, REG_FTMP2); M_FMUL(s1, REG_FTMP2); - M_FLTMOVE(REG_FTMP2, d); + emit_fmove(cd, REG_FTMP2, d); emit_store_dst(jd, iptr, d); break; @@ -886,9 +768,9 @@ 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_FTMP2); - M_DBLMOVE(s2, REG_FTMP2); + emit_dmove(cd, s2, REG_FTMP2); M_DMUL(s1, REG_FTMP2); - M_DBLMOVE(REG_FTMP2, d); + emit_dmove(cd, REG_FTMP2, d); emit_store_dst(jd, iptr, d); break; @@ -896,9 +778,9 @@ 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_FLTMOVE(s1, REG_FTMP1); + emit_fmove(cd, s1, REG_FTMP1); M_FDIV(s2, REG_FTMP1); - M_FLTMOVE(REG_FTMP1, d); + emit_fmove(cd, REG_FTMP1, d); emit_store_dst(jd, iptr, d); break; @@ -906,9 +788,9 @@ 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_DBLMOVE(s1, REG_FTMP1); + emit_dmove(cd, s1, REG_FTMP1); M_DDIV(s2, REG_FTMP1); - M_DBLMOVE(REG_FTMP1, d); + emit_dmove(cd, REG_FTMP1, d); emit_store_dst(jd, iptr, d); break; @@ -916,9 +798,9 @@ 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_FTMP2); - M_FLTMOVE(s2, REG_FTMP2); + emit_fmove(cd, s2, REG_FTMP2); M_FADD(s1, REG_FTMP2); - M_FLTMOVE(REG_FTMP2, d); + emit_fmove(cd, REG_FTMP2, d); emit_store_dst(jd, iptr, d); break; @@ -926,9 +808,9 @@ 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_FTMP2); - M_DBLMOVE(s2, REG_FTMP2); + emit_dmove(cd, s2, REG_FTMP2); M_DADD(s1, REG_FTMP2); - M_DBLMOVE(REG_FTMP2, d); + emit_dmove(cd, REG_FTMP2, d); emit_store_dst(jd, iptr, d); break; @@ -936,9 +818,9 @@ 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_FTMP2); - M_FLTMOVE(s1, REG_FTMP1); + emit_fmove(cd, s1, REG_FTMP1); M_FSUB(s2, REG_FTMP1); - M_FLTMOVE(REG_FTMP1, d); + emit_fmove(cd, REG_FTMP1, d); emit_store_dst(jd, iptr, d); break; @@ -946,9 +828,9 @@ 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_FTMP2); - M_DBLMOVE(s1, REG_FTMP1); + emit_dmove(cd, s1, REG_FTMP1); M_DSUB(s2, REG_FTMP1); - M_DBLMOVE(REG_FTMP1, d); + emit_dmove(cd, REG_FTMP1, d); emit_store_dst(jd, iptr, d); break; @@ -982,29 +864,6 @@ bool codegen_emit(jitdata *jd) #endif - /* load/store/copy/move operations ************************************/ - - case ICMD_ILOAD: /* ... ==> ..., content of local variable */ - case ICMD_ALOAD: /* s1 = local variable */ - case ICMD_LLOAD: - case ICMD_FLOAD: - case ICMD_DLOAD: - case ICMD_ISTORE: /* ..., value ==> ... */ - case ICMD_LSTORE: - case ICMD_FSTORE: - 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; - case ICMD_ACONST: /* ... ==> ..., constant */ d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); @@ -1022,83 +881,13 @@ bool codegen_emit(jitdata *jd) case ICMD_ATHROW: /* ..., objectref ==> ... (, objectref) */ - s1 = emit_load_s1(jd, iptr, REG_ATMP1); - M_ADRMOVE(s1, REG_ATMP1_XPTR); - -#ifdef ENABLE_VERIFIER - if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - unresolved_class *uc = iptr->sx.s23.s2.uc; - - patcher_add_patch_ref(jd, PATCHER_resolve_class, uc, 0); - } -#endif /* ENABLE_VERIFIER */ M_JSR_PCREL(2); /* get current PC */ M_APOP(REG_ATMP2); M_AMOV_IMM(asm_handle_exception, REG_ATMP3); M_JMP(REG_ATMP3); - ALIGNCODENOP; - break; - - case ICMD_GOTO: /* ... ==> ... */ - case ICMD_RET: /* ... ==> ... */ - - emit_br(cd, iptr->dst.block); - ALIGNCODENOP; - break; - - case ICMD_JSR: /* ... ==> ... */ - - emit_br(cd, iptr->sx.s23.s3.jsrtarget.block); - ALIGNCODENOP; break; - - - case ICMD_IFNULL: /* ..., value ==> ... */ - case ICMD_IFNONNULL: - assert(IS_ADR_TYPE(VAROP(iptr->s1)->type)); - s1 = emit_load_s1(jd, iptr, REG_ATMP1); - M_ATST(s1); - emit_bcc(cd, iptr->dst.block, iptr->opc - ICMD_IFNULL, BRANCH_OPT_NONE); - break; - - case ICMD_IFLT: - case ICMD_IFLE: - case ICMD_IFNE: - case ICMD_IFGT: - case ICMD_IFGE: - case ICMD_IFEQ: /* ..., value ==> ... */ - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - assert (VAROP(iptr->s1)->type == TYPE_INT); - M_ICMP_IMM(iptr->sx.val.i, s1); - emit_bcc(cd, iptr->dst.block, iptr->opc - ICMD_IFEQ, BRANCH_OPT_NONE); - break; - - case ICMD_IF_ICMPEQ: /* ..., value, value ==> ... */ - case ICMD_IF_ICMPNE: - case ICMD_IF_ICMPLT: - case ICMD_IF_ICMPGT: - case ICMD_IF_ICMPLE: - case ICMD_IF_ICMPGE: - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - s2 = emit_load_s2(jd, iptr, REG_ITMP2); - M_ICMP(s2, s1); - emit_bcc(cd, iptr->dst.block, iptr->opc - ICMD_IF_ICMPEQ, BRANCH_OPT_NONE); - break; - - case ICMD_IF_ACMPEQ: /* op1 = target JavaVM pc */ - case ICMD_IF_ACMPNE: - - s1 = emit_load_s1(jd, iptr, REG_ATMP1); - s2 = emit_load_s2(jd, iptr, REG_ATMP2); - M_ACMP(s1, s2); - emit_bcc(cd, iptr->dst.block, iptr->opc - ICMD_IF_ACMPEQ, BRANCH_OPT_NONE); - break; - - /* MEMORY *************************************************************/ case ICMD_GETSTATIC: /* ... ==> ..., value */ @@ -1316,15 +1105,6 @@ bool codegen_emit(jitdata *jd) } break; - case ICMD_ARRAYLENGTH: /* ..., arrayref ==> ..., length */ - - s1 = emit_load_s1(jd, iptr, REG_ATMP1); - d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); - /* implicit null-pointer check */ - M_ILD(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_ATMP1); @@ -1605,172 +1385,81 @@ bool codegen_emit(jitdata *jd) /* METHOD INVOCATION *********************************************************/ case ICMD_BUILTIN: /* ..., [arg1, [arg2 ...]] ==> ... */ - REPLACEMENT_POINT_FORGC_BUILTIN(cd, iptr); - bte = iptr->sx.s23.s3.bte; - md = bte->md; - goto gen_method; + if (bte->stub == NULL) + disp = (ptrint) bte->fp; + else + disp = (ptrint) bte->stub; + M_JSR_IMM(disp); + break; - case ICMD_INVOKESTATIC: /* ..., [arg1, [arg2 ...]] ==> ... */ case ICMD_INVOKESPECIAL:/* ..., objectref, [arg1, [arg2 ...]] ==> ... */ - case ICMD_INVOKEVIRTUAL:/* op1 = arg count, val.a = method pointer */ - case ICMD_INVOKEINTERFACE: - REPLACEMENT_POINT_INVOKE(cd, iptr); + /* adress register for sure */ + M_ALD(REG_ATMP1, REG_SP, 0); + emit_nullpointer_check(cd, iptr, REG_ATMP1); + /* fall through */ + case ICMD_INVOKESTATIC: /* ..., [arg1, [arg2 ...]] ==> ... */ if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - lm = NULL; um = iptr->sx.s23.s3.um; - md = um->methodref->parseddesc.md; - } - else { + patcher_add_patch_ref(jd, PATCHER_invokestatic_special, um, 0); + disp = 0; + M_AMOV_IMM(disp, REG_ATMP1); + } else { lm = iptr->sx.s23.s3.fmiref->p.method; - um = NULL; - md = lm->parseddesc; + disp = lm->stubroutine; + M_AMOV_IMM(disp, REG_ATMP1); } - gen_method: - s3 = md->paramcount; - - MCODECHECK((s3 << 1) + 64); - /* copy arguments to stack */ - for (s3 = s3 - 1; s3 >= 0; s3--) { - var = VAR(iptr->sx.s23.s2.args[s3]); - /* already preallocated */ - if (var->flags & PREALLOC) continue; - - if (!md->params[s3].inmemory) assert(0); + /* generate the actual call */ + M_JSR(REG_ATMP1); + break; - switch (var->type) { -#if defined(ENABLE_SOFTFLOAT) - case TYPE_DBL: -#endif - case TYPE_LNG: - d = emit_load(jd, iptr, var, REG_ITMP12_PACKED); - M_LST(d, REG_SP, md->params[s3].regoff); - break; -#if defined(ENABLE_SOFTFLOAT) - case TYPE_FLT: -#endif - case TYPE_INT: - d = emit_load(jd, iptr, var, REG_ITMP1); - M_IST(d, REG_SP, md->params[s3].regoff); - break; - case TYPE_ADR: - d = emit_load(jd, iptr, var, REG_ATMP1); - M_AST(d, REG_SP, md->params[s3].regoff); - break; -#if !defined(ENABLE_SOFTFLOAT) - case TYPE_FLT: - d = emit_load(jd, iptr, var, REG_FTMP1); - M_FST(d, REG_SP, md->params[s3].regoff); - break; - case TYPE_DBL: - d = emit_load(jd, iptr, var, REG_FTMP1); - M_DST(d, REG_SP, md->params[s3].regoff); - break; -#endif - default: - assert(0); - } + case ICMD_INVOKEVIRTUAL:/* op1 = arg count, val.a = method pointer */ + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + um = iptr->sx.s23.s3.um; + patcher_add_patch_ref(jd, PATCHER_invokevirtual, um, 0); + s1 = 0; + } else { + lm = iptr->sx.s23.s3.fmiref->p.method; + s1 = OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * lm->vftblindex; } + /* load object pointer (==argument 0) */ + M_ALD(REG_ATMP1, REG_SP, 0); + /* implicit null-pointer check */ + M_ALD(REG_METHODPTR, REG_ATMP1, OFFSET(java_object_t, vftbl)); + M_ALD(REG_ATMP3, REG_METHODPTR, s1); + /* generate the actual call */ + M_JSR(REG_ATMP3); + break; - /* arguments in place now */ - switch(iptr->opc) { - case ICMD_BUILTIN: - if (bte->stub == NULL) - disp = (ptrint) bte->fp; - else - disp = (ptrint) bte->stub; - d = md->returntype.type; - M_JSR_IMM(disp); - - REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr); - break; - - case ICMD_INVOKESPECIAL: - /* adress register for sure */ - M_ALD(REG_ATMP1, REG_SP, 0); - emit_nullpointer_check(cd, iptr, REG_ATMP1); - /* fall through */ - case ICMD_INVOKESTATIC: - if (lm == NULL) { - patcher_add_patch_ref(jd, PATCHER_invokestatic_special, um, 0); - disp = 0; - M_AMOV_IMM(disp, REG_ATMP1); - } else { - disp = lm->stubroutine; - M_AMOV_IMM(disp, REG_ATMP1); - } - - /* generate the actual call */ - M_JSR(REG_ATMP1); - REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr); - 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; - } - /* load object pointer (==argument 0) */ - M_ALD(REG_ATMP1, REG_SP, 0); - /* implicit null-pointer check */ - M_ALD(REG_METHODPTR, REG_ATMP1, OFFSET(java_object_t, vftbl)); - M_ALD(REG_ATMP3, REG_METHODPTR, s1); - /* generate the actual call */ - M_JSR(REG_ATMP3); - break; - case ICMD_INVOKEINTERFACE: - if (lm == NULL) { - patcher_add_patch_ref(jd, PATCHER_invokeinterface, um, 0); - - s1 = 0; - s2 = 0; - } else { - s1 = OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr*) * lm->clazz->index; - s2 = sizeof(methodptr) * (lm - lm->clazz->methods); - } - /* load object pointer (==argument 0) */ - M_ALD(REG_ATMP1, REG_SP, 0); + case ICMD_INVOKEINTERFACE: + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + um = iptr->sx.s23.s3.um; + patcher_add_patch_ref(jd, PATCHER_invokeinterface, um, 0); - /* implicit null-pointer check */ - M_ALD(REG_METHODPTR, REG_ATMP1, OFFSET(java_object_t, vftbl)); - M_ALD(REG_METHODPTR, REG_METHODPTR, s1); - M_ALD(REG_ATMP3, REG_METHODPTR, s2); + s1 = 0; + s2 = 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); + } + /* load object pointer (==argument 0) */ + M_ALD(REG_ATMP1, REG_SP, 0); - /* generate the actual call */ - M_JSR(REG_ATMP3); - REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr); - break; + /* implicit null-pointer check */ + M_ALD(REG_METHODPTR, REG_ATMP1, OFFSET(java_object_t, vftbl)); + M_ALD(REG_METHODPTR, REG_METHODPTR, s1); + M_ALD(REG_ATMP3, REG_METHODPTR, s2); - default: assert(0); - } /* switch (iptr->opc) */ + /* generate the actual call */ + M_JSR(REG_ATMP3); + break; - REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr); - REPLACEMENT_POINT_FORGC_BUILTIN_RETURN(cd, iptr); - - /* store return value */ - d = md->returntype.type; +XXXXXX switch (d) { - case TYPE_VOID: break; -#if defined(ENABLE_SOFTFLOAT) - case TYPE_FLT: -#endif - case TYPE_INT: - s1 = codegen_reg_of_dst(jd, iptr, REG_RESULT); - M_INTMOVE(REG_RESULT, s1); - break; -#if defined(ENABLE_SOFTFLOAT) - case TYPE_DBL: -#endif - case TYPE_LNG: - s1 = codegen_reg_of_dst(jd, iptr, REG_RESULT_PACKED); - M_LNGMOVE(REG_RESULT_PACKED, s1); - break; case TYPE_ADR: s1 = codegen_reg_of_dst(jd, iptr, REG_ATMP1); /* all stuff is returned in %d0 */ @@ -1786,7 +1475,7 @@ bool codegen_emit(jitdata *jd) if (iptr->opc == ICMD_BUILTIN) { M_INT2FLTMOVE(REG_FRESULT, s1); } else { - M_FLTMOVE(REG_FRESULT, s1); + emit_fmove(cd, REG_FRESULT, s1); } break; case TYPE_DBL: @@ -1795,172 +1484,13 @@ bool codegen_emit(jitdata *jd) M_LST(REG_RESULT_PACKED, REG_SP, rd->memuse * 4 + 4); M_DLD(s1, REG_SP, rd->memuse * 4 + 4); } else { - M_DBLMOVE(REG_FRESULT, s1); + emit_dmove(cd, REG_FRESULT, s1); } break; #endif - default: - assert(0); } - if (d != TYPE_VOID) emit_store_dst(jd, iptr, s1); - break; /* ICMD_INVOKE* */ -#if defined(ENABLE_SOFTFLOAT) - case ICMD_FRETURN: -#endif - case ICMD_IRETURN: /* ..., retvalue ==> ... */ - - REPLACEMENT_POINT_RETURN(cd, iptr); - s1 = emit_load_s1(jd, iptr, REG_RESULT); - M_INTMOVE(s1, REG_RESULT); - goto nowperformreturn; - - case ICMD_ARETURN: /* ..., retvalue ==> ... */ - - REPLACEMENT_POINT_RETURN(cd, iptr); - s1 = emit_load_s1(jd, iptr, REG_RESULT); - assert(VAROP(iptr->s1)->type == TYPE_ADR); - M_ADR2INTMOVE(s1, REG_RESULT); - -#ifdef ENABLE_VERIFIER - if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - unresolved_class *uc = iptr->sx.s23.s2.uc; - - patcher_add_patch_ref(jd, PATCHER_resolve_class, uc, 0); - } -#endif /* ENABLE_VERIFIER */ - goto nowperformreturn; - -#if defined(ENABLE_SOFTFLOAT) - case ICMD_DRETURN: -#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 nowperformreturn; - -#if !defined(ENABLE_SOFTFLOAT) - case ICMD_FRETURN: /* ..., retvalue ==> ... */ - REPLACEMENT_POINT_RETURN(cd, iptr); - s1 = emit_load_s1(jd, iptr, REG_FRESULT); - M_FLTMOVE(s1, REG_FRESULT); - goto nowperformreturn; - - case ICMD_DRETURN: - REPLACEMENT_POINT_RETURN(cd, iptr); - s1 = emit_load_s1(jd, iptr, REG_FRESULT); - M_DBLMOVE(s1, REG_FRESULT); - goto nowperformreturn; - -#endif - - case ICMD_RETURN: /* ... ==> ... */ - - REPLACEMENT_POINT_RETURN(cd, iptr); - -nowperformreturn: - { - s4 i, p; - - p = cd->stackframesize; - - /* call trace function */ -#if !defined(NDEBUG) - emit_verbosecall_exit(jd); -#endif - -#if defined(ENABLE_THREADS) - /* call lock_monitor_exit */ - if (checksync && code_is_synchronized(code)) { - M_ILD(REG_ITMP3, REG_SP, rd->memuse * 8); - - /* we need to save the proper return value */ - /* we do not care for the long -> doubel convert space here */ - switch (iptr->opc) { -#if defined(ENABLE_SOFTFLOAT) - case ICMD_DRETURN: -#endif - case ICMD_LRETURN: - M_LST(REG_RESULT_PACKED, REG_SP, rd->memuse * 8 + 8); - break; -#if defined(ENABLE_SOFTFLOAT) - case ICMD_FRETURN: -#endif - case ICMD_IRETURN: - case ICMD_ARETURN: - M_IST(REG_RESULT , REG_SP, rd->memuse * 8 + 8); - break; -#if !defined(ENABLE_SOFTFLOAT) - case ICMD_FRETURN: - M_FST(REG_FRESULT, REG_SP, rd->memuse * 8 + 8); - break; - case ICMD_DRETURN: - M_DST(REG_FRESULT, REG_SP, rd->memuse * 8 + 8); - break; -#endif - } - - M_IST(REG_ITMP3, REG_SP, 0 * 4); - M_JSR_IMM(LOCK_monitor_exit); - - /* and now restore the proper return value */ - switch (iptr->opc) { - -#if defined(ENABLE_SOFTFLOAT) - case ICMD_DRETURN: -#endif - case ICMD_LRETURN: - M_LLD(REG_RESULT_PACKED, REG_SP, rd->memuse * 8 + 8); - break; -#if defined(ENABLE_SOFTFLOAT) - case ICMD_FRETURN: -#endif - case ICMD_IRETURN: - case ICMD_ARETURN: - M_ILD(REG_RESULT , REG_SP, rd->memuse * 8 + 8); - break; -#if !defined(ENABLE_SOFTFLOAT) - case ICMD_FRETURN: - M_FLD(REG_FRESULT, REG_SP, rd->memuse * 8 + 8); - break; - case ICMD_DRETURN: - M_DLD(REG_FRESULT, REG_SP, rd->memuse * 8 + 8); - break; -#endif - } - } -#endif - - - /* restore return address */ -#if 0 - if (!code_is_leafmethod(code)) { - /* ATTENTION: Don't use REG_ZERO (r0) here, as M_ALD - may have a displacement overflow. */ - - M_ALD(REG_ITMP1, REG_SP, p * 4 + LA_LR_OFFSET); - M_MTLR(REG_ITMP1); - } -#endif - /* restore saved registers */ - - for (i = INT_SAV_CNT - 1; i >= rd->savintreguse; i--) { - p-=8; M_ILD(rd->savintregs[i], REG_SP, p); - } - for (i=ADR_SAV_CNT-1; i>=rd->savadrreguse; --i) { - p-=8; M_ALD(rd->savadrregs[i], REG_SP, p); - } -#if !defined(ENABLE_SOFTFLOAT) - for (i = FLT_SAV_CNT - 1; i >= rd->savfltreguse; i--) { - p-=8; M_FLOAD(rd->savfltregs[i], REG_SP, p); - } -#endif - /* deallocate stack */ - M_AADD_IMM(cd->stackframesize, REG_SP); - M_RET; - } - break; +XXXXXXX /* the evil ones */ case ICMD_INSTANCEOF: /* ..., objectref ==> ..., intresult */ @@ -2257,29 +1787,6 @@ nowperformreturn: } break; - case ICMD_LOOKUPSWITCH: /* ..., key ==> ... */ - { - s4 i; - lookup_target_t *lookup; - - lookup = iptr->dst.lookup; - - i = iptr->sx.s23.s2.lookupcount; - - MCODECHECK((i<<2)+8); - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - - while (--i >= 0) { - M_ICMP_IMM(lookup->value, s1); - emit_beq(cd, lookup->target.block); - lookup++; - } - - emit_br(cd, iptr->sx.s23.s3.lookupdefault.block); - ALIGNCODENOP; - break; - } - case ICMD_MULTIANEWARRAY:/* ..., cnt1, [cnt2, ...] ==> ..., arrayref */ /* check for negative sizes and copy sizes to stack if necessary */ @@ -2327,34 +1834,11 @@ nowperformreturn: default: - printf("UNKNOWN OPCODE %d\n", iptr->opc); - exceptions_throw_internalerror("Unknown ICMD %d during code generation", iptr->opc); - return false; + vm_abort("Unknown ICMD %d during code generation", iptr->opc); } /* switch */ - /* M_TPF; */ /* nop after each ICMD */ - } /* for each instruction */ - - /* At the end of a basic block we may have to append some nops, - because the patcher stub calling code might be longer than the - actual instruction. So codepatching does not change the - following block unintentionally. */ - - if (cd->mcodeptr < cd->lastmcodeptr) { - while (cd->mcodeptr < cd->lastmcodeptr) { - M_NOP; - } - } - - - } /* if (btpre->flags >= BBREACHED) */ - } /* for each basic block */ - - /* generate stubs */ - emit_patcher_traps(jd); - - return true; } + /* codegen_emit_stub_native **************************************************** Emits a stub routine which calls a native method. diff --git a/src/vm/jit/m68k/codegen.h b/src/vm/jit/m68k/codegen.h index 0cb13d0fa..b9cdc12c2 100644 --- a/src/vm/jit/m68k/codegen.h +++ b/src/vm/jit/m68k/codegen.h @@ -242,15 +242,6 @@ #define M_INEG(a) OPWORD(0x112, 0, (a)) /* neg.l */ #define M_INEGX(a) OPWORD(0x102, 0, (a)) /* neg.l */ -/* only generate opcode when condition true */ -#define OPWORD_COND(c, u,v,w) \ - do { \ - if ( (c) ) { OPWORD( (u),(v),(w) ) } \ - } while(0); -#define OPWORD_IMM16_COND(c, u,v,w,x) \ - do { \ - if ( (c) ) { OPWORD_IMM16( (u),(v),(w),(x) ) } \ - } while(0); /* assert on the opcode */ #define OPWORD_ASSERT(a, u,v,w) \ do { \ @@ -259,19 +250,15 @@ } while(0); /* M_XMOVE....M_XMOVE(sourcereg, destreg) */ -#define M_INTMOVE(a,b) OPWORD_COND(((a) != (b)), ( ( 2<<6) | ((b) << 3) | 0), 0, (a)); -#define M_ADRMOVE(a,b) OPWORD_COND(((a) != (b)), ( ( 2<<6) | ((b) << 3) | 1), 1, (a)); +#define M_MOV(a,b) OPWORD( ( ( 2<<6) | ((b) << 3) | 0), 0, (a)); +#define M_AMOV(a,b) OPWORD( ( ( 2<<6) | ((b) << 3) | 1), 1, (a)); #define M_INT2ADRMOVE(a,b) OPWORD( ( (2<<6) | ((b) << 3) | 1), 0, (a)); #define M_ADR2INTMOVE(a,b) OPWORD( ( (2<<6) | ((b) << 3) | 0), 1, (a)); -#define M_LNGMOVE(a,b) do {\ - M_INTMOVE(GET_LOW_REG (a), GET_LOW_REG (b));\ - M_INTMOVE(GET_HIGH_REG(a), GET_HIGH_REG(b));\ - } while(0); #if !defined(ENABLE_SOFTLFOAT) - #define M_FLTMOVE(a,b) OPWORD_IMM16_COND( ((a)!=(b)), 0x3c8, 0, 0, ((a)<<10) | ((b)<<7) | 0x40) + #define M_FMOV(a,b) OPWORD_IMM16( 0x3c8, 0, 0, ((a)<<10) | ((b)<<7) | 0x40) #define M_INT2FLTMOVE(a,b) OPWORD_IMM16( 0x3c8, 0, (a), ((0x11 << 10) | ((b) << 7) | 0x40 )) - #define M_DBLMOVE(a,b) OPWORD_IMM16_COND( ((a)!=(b)), 0x3c8, 0, 0, ((a)<<10) | ((b)<<7) | 0x44) + #define M_DMOV(a,b) OPWORD_IMM16( 0x3c8, 0, 0, ((a)<<10) | ((b)<<7) | 0x44) #endif /* M_XTST....M_XTST(register) */ #define M_ITST(a) OPWORD(0x12a, 0, (a)) /* tst.l */ @@ -403,6 +390,8 @@ cd->mcodeptr += 2; \ } while(0); +#define M_TEST(a) M_ATST(a) + #if !defined(ENABLE_SOFTFLOAT) diff --git a/src/vm/jit/m68k/emit.c b/src/vm/jit/m68k/emit.c index f0e3e5fbe..00b0d5afe 100644 --- a/src/vm/jit/m68k/emit.c +++ b/src/vm/jit/m68k/emit.c @@ -310,6 +310,18 @@ s4 emit_load_high(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg) } return reg; } + + +/** + * Emits code updating the condition register by comparing one integer + * register to an immediate integer value. + */ +void emit_icmp_imm(codegendata* cd, int reg, int32_t value) +{ + M_ICMP_IMM(value, reg); +} + + /* emit_branch ***************************************************************** Emits the code for conditional and unconditional branchs. @@ -701,6 +713,115 @@ uint32_t emit_trap(codegendata *cd) } +/** + * Emit code to recompute the procedure vector. + */ +void emit_recompute_pv(codegendata *cd) +{ + // This is a nop, because we do not use a procedure vector. +} + + +/** + * Generates synchronization code to enter a monitor. + */ +#if defined(ENABLE_THREADS) +void emit_monitor_enter(jitdata* jd, int32_t syncslot_offset) +{ + // Get required compiler data. + methodinfo* m = jd->m; + codegendata* cd = jd->cd; + + if (m->flags & ACC_STATIC) { + M_AMOV_IMM((&m->clazz->object.header), REG_ATMP1); + } else { + /* for non-static case the first arg is the object */ + M_ALD(REG_ATMP1, REG_SP, cd->stackframesize + 4); + M_ATST(REG_ATMP1); + M_BNE(2); + M_TRAP(TRAP_NullPointerException); + } + + M_AST(REG_ATMP1, REG_SP, syncslot_offset); + M_AST(REG_ATMP1, REG_SP, 0 * 4); + M_JSR_IMM(LOCK_monitor_enter); +} +#endif + + +/** + * Generates synchronization code to leave a monitor. + */ +#if defined(ENABLE_THREADS) +void emit_monitor_exit(jitdata* jd, int32_t syncslot_offset) +{ + // Get required compiler data. + methodinfo* m = jd->m; + codegendata* cd = jd->cd; + + M_ILD(REG_ITMP3, REG_SP, syncslot_offset); + + /* we need to save the proper return value */ + /* we do not care for the long -> doubel convert space here */ + + methoddesc* md = m->parseddesc; + + switch (md->returntype.type) { +#if defined(ENABLE_SOFTFLOAT) + case TYPE_DBL: +#endif + case TYPE_LNG: + M_LST(REG_RESULT_PACKED, REG_SP, syncslot_offset + 8); + break; +#if defined(ENABLE_SOFTFLOAT) + case TYPE_FLT: +#endif + case TYPE_INT: + case TYPE_ADR: + M_IST(REG_RESULT , REG_SP, syncslot_offset + 8); + break; +#if !defined(ENABLE_SOFTFLOAT) + case TYPE_FLT: + M_FST(REG_FRESULT, REG_SP, syncslot_offset + 8); + break; + case TYPE_DBL: + M_DST(REG_FRESULT, REG_SP, syncslot_offset + 8); + break; +#endif + } + + M_IST(REG_ITMP3, REG_SP, 0 * 4); + M_JSR_IMM(LOCK_monitor_exit); + + /* and now restore the proper return value */ + + switch (md->returntype.type) { + +#if defined(ENABLE_SOFTFLOAT) + case TYPE_DBL: +#endif + case TYPE_LNG: + M_LLD(REG_RESULT_PACKED, REG_SP, syncslot_offset + 8); + break; +#if defined(ENABLE_SOFTFLOAT) + case TYPE_FLT: +#endif + case TYPE_INT: + case TYPE_ADR: + M_ILD(REG_RESULT , REG_SP, syncslot_offset + 8); + break; +#if !defined(ENABLE_SOFTFLOAT) + case TYPE_FLT: + M_FLD(REG_FRESULT, REG_SP, syncslot_offset + 8); + break; + case TYPE_DBL: + M_DLD(REG_FRESULT, REG_SP, syncslot_offset + 8); + break; +#endif + } +} +#endif + /* * These are local overrides for various environment variables in Emacs. diff --git a/src/vm/jit/m68k/md.h b/src/vm/jit/m68k/md.h index 5514cc4b8..63c9eb626 100644 --- a/src/vm/jit/m68k/md.h +++ b/src/vm/jit/m68k/md.h @@ -37,6 +37,22 @@ #include "vm/jit/methodtree.h" +/** + * Returns the size (in bytes) of the current stackframe, specified by + * the passed codeinfo structure. + */ +inline static int32_t md_stacktrace_get_framesize(codeinfo* code) +{ + // Check for the asm_vm_call_method special case. + if (code == NULL) + return 0; + + // On M68K we use 8-byte stackslots. +#error Verify the below line, then remove this error! + return code->stackframesize * 8; +} + + /* md_stacktrace_get_returnaddress ********************************************* Returns the return address of the current stackframe, specified by diff --git a/src/vm/jit/mips/arch.h b/src/vm/jit/mips/arch.h index 37b90494b..6f6cad855 100644 --- a/src/vm/jit/mips/arch.h +++ b/src/vm/jit/mips/arch.h @@ -169,6 +169,14 @@ #define SUPPORT_HARDWARE_DIVIDE_BY_ZERO 0 +/* stackframe *****************************************************************/ + +#define STACKFRMAE_RA_BETWEEN_FRAMES 0 +#define STACKFRAME_RA_TOP_OF_FRAME 1 +#define STACKFRAME_LEAFMETHODS_RA_REGISTER 1 +#define STACKFRAME_SYNC_NEEDS_TWO_SLOTS 1 + + /* replacement ****************************************************************/ #define REPLACEMENT_PATCH_SIZE (2*4) /* bytes */ diff --git a/src/vm/jit/mips/codegen.c b/src/vm/jit/mips/codegen.c index 29e3a4137..cf207a347 100644 --- a/src/vm/jit/mips/codegen.c +++ b/src/vm/jit/mips/codegen.c @@ -57,7 +57,6 @@ #include "vm/jit/linenumbertable.hpp" #include "vm/jit/patcher-common.hpp" #include "vm/jit/reg.h" -#include "vm/jit/replace.hpp" #include "vm/jit/trap.hpp" #if defined(ENABLE_LSRA) @@ -73,56 +72,10 @@ bool codegen_emit(jitdata *jd) { - methodinfo *m; - codeinfo *code; - codegendata *cd; - registerdata *rd; - s4 len, s1, s2, s3, d, disp; - varinfo *var; - basicblock *bptr; - instruction *iptr; - u2 currentline; - constant_classref *cr; - unresolved_class *uc; - methodinfo *lm; /* local methodinfo for ICMD_INVOKE* */ - unresolved_method *um; - builtintable_entry *bte; - methoddesc *md; - fieldinfo *fi; - unresolved_field *uf; - s4 fieldtype; - s4 varindex; - /* get required compiler data */ - - m = jd->m; - code = jd->code; - cd = jd->cd; - rd = jd->rd; - - /* prevent compiler warnings */ - - s1 = 0; - d = 0; - fieldtype = 0; - lm = NULL; - um = NULL; - bte = NULL; - currentline = 0; - uf = NULL; - - { - s4 i, p, t, l; - s4 savedregs_num; savedregs_num = code_is_leafmethod(code) ? 0 : 1; /* space to save the RA */ - /* space to save used callee saved registers */ - - savedregs_num += (INT_SAV_CNT - rd->savintreguse); - savedregs_num += (FLT_SAV_CNT - rd->savfltreguse); - - cd->stackframesize = rd->memuse + savedregs_num; #if defined(ENABLE_THREADS) /* space to save argument of monitor_enter */ @@ -142,22 +95,39 @@ bool codegen_emit(jitdata *jd) if (cd->stackframesize & 1) cd->stackframesize++; - /* create method header */ - (void) dseg_add_unique_address(cd, code); /* CodeinfoPointer */ - (void) dseg_add_unique_s4(cd, cd->stackframesize * 8); /* 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 */ + + + + + + + + + + + +/** + * Generates machine code for the method prolog. + */ +void codegen_emit_prolog(jitdata* jd) +{ + varinfo* var; + methoddesc* md; + int32_t s1; + int32_t p, t, l; + 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; /* create stack frame (if necessary) */ @@ -237,9 +207,9 @@ bool codegen_emit(jitdata *jd) if (!md->params[p].inmemory) { if (!(var->flags & INMEMORY)) { if (IS_2_WORD_TYPE(t)) - M_DBLMOVE(s1, var->vv.regoff); + emit_dmove(cd, s1, var->vv.regoff); else - M_FLTMOVE(s1, var->vv.regoff); + emit_fmove(cd, s1, var->vv.regoff); } else { if (IS_2_WORD_TYPE(t)) @@ -260,181 +230,88 @@ bool codegen_emit(jitdata *jd) } } } +} - /* call monitorenter function */ - -#if defined(ENABLE_THREADS) - if (checksync && code_is_synchronized(code)) { - /* stack offset for monitor argument */ - - s1 = rd->memuse; - -# if !defined(NDEBUG) - if (opt_verbosecall) { - M_LDA(REG_SP, REG_SP, -(INT_ARG_CNT + FLT_ARG_CNT) * 8); - - for (p = 0; p < INT_ARG_CNT; p++) - M_AST(abi_registers_integer_argument[p], REG_SP, p * 8); - - for (p = 0; p < FLT_ARG_CNT; p++) - M_DST(abi_registers_float_argument[p], REG_SP, (INT_ARG_CNT + p) * 8); - s1 += INT_ARG_CNT + FLT_ARG_CNT; - } -# endif +/** + * Generates machine code for the method epilog. + */ +void codegen_emit_epilog(jitdata* jd) +{ + int32_t p; + int i; - /* get correct lock object */ + // Get required compiler data. + codeinfo* code = jd->code; + codegendata* cd = jd->cd; + registerdata* rd = jd->rd; - if (m->flags & ACC_STATIC) { - disp = dseg_add_address(cd, &m->clazz->object.header); - M_ALD(REG_A0, REG_PV, disp); - disp = dseg_add_functionptr(cd, LOCK_monitor_enter); - M_ALD(REG_ITMP3, REG_PV, disp); - } - else { -/* emit_nullpointer_check(cd, iptr, REG_A0); */ - M_BNEZ(REG_A0, 2); - disp = dseg_add_functionptr(cd, LOCK_monitor_enter); - M_ALD(REG_ITMP3, REG_PV, disp); /* branch delay */ - M_ALD_INTERN(REG_ZERO, REG_ZERO, TRAP_NullPointerException); - } - - M_JSR(REG_RA, REG_ITMP3); - M_AST(REG_A0, REG_SP, s1 * 8); /* branch delay */ + p = cd->stackframesize; -# if !defined(NDEBUG) - if (opt_verbosecall) { - for (p = 0; p < INT_ARG_CNT; p++) - M_ALD(abi_registers_integer_argument[p], REG_SP, p * 8); + /* restore return address */ - for (p = 0; p < FLT_ARG_CNT; p++) - M_DLD(abi_registers_float_argument[p], REG_SP, (INT_ARG_CNT + p) * 8); + if (!code_is_leafmethod(code)) { + p--; M_ALD(REG_RA, REG_SP, p * 8); + } + /* restore saved registers */ - M_LDA(REG_SP, REG_SP, (INT_ARG_CNT + FLT_ARG_CNT) * 8); - } -# endif + for (i = INT_SAV_CNT - 1; i >= rd->savintreguse; i--) { + p--; M_ALD(rd->savintregs[i], REG_SP, p * 8); } -#endif + for (i = FLT_SAV_CNT - 1; i >= rd->savfltreguse; i--) { + p--; M_DLD(rd->savfltregs[i], REG_SP, p * 8); } -#if !defined(NDEBUG) - if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) - emit_verbosecall_enter(jd); -#endif - - /* end of header generation */ - - /* create replacement points */ - - REPLACEMENT_POINTS_INIT(cd, jd); + /* deallocate stack and return */ - /* walk through all basic blocks */ + if (cd->stackframesize) { + int32_t lo, hi; - for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) { + disp = cd->stackframesize * 8; + lo = (short) (disp); + hi = (short) (((disp) - lo) >> 16); - /* handle replacement points */ - - REPLACEMENT_POINT_BLOCK_START(cd, bptr); - - /* store relative start of block */ - - bptr->mpc = (s4) (cd->mcodeptr - cd->mcodebase); - - if (bptr->flags >= BBREACHED) { - /* branch resolving */ - - codegen_resolve_branchrefs(cd, bptr); - - /* copy interface registers to their destination */ - - len = bptr->indepth; - MCODECHECK(64+len); -#if defined(ENABLE_LSRA) - if (opt_lsra) { - while (len) { - len--; - src = bptr->invars[len]; - if ((len == bptr->indepth-1) && (bptr->type == BBTYPE_EXH)) { - /* d = reg_of_var(m, src, REG_ITMP1); */ - if (!(src->flags & INMEMORY)) - d = src->vv.regoff; - else - d = REG_ITMP1; - M_INTMOVE(REG_ITMP1, d); - emit_store(jd, NULL, src, d); - } - } + if (hi == 0) { + M_RET(REG_RA); + M_AADD_IMM(REG_SP, lo, REG_SP); /* delay slot */ } else { -#endif - while (len) { - len--; - var = VAR(bptr->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)); - } + M_LUI(REG_ITMP3,hi); + M_AADD_IMM(REG_ITMP3,lo,REG_ITMP3); + M_RET(REG_RA); + M_AADD(REG_ITMP3,REG_SP,REG_SP); /* delay slot */ } -#if defined(ENABLE_LSRA) - } -#endif - /* walk through all instructions */ - - len = bptr->icount; -/* currentline = 0; */ - - for (iptr = bptr->iinstr; len > 0; len--, iptr++) { - if (iptr->line != currentline) { - linenumbertable_list_entry_add(cd, iptr->line); - currentline = iptr->line; - } - - MCODECHECK(64); /* an instruction usually needs < 64 words */ - - switch (iptr->opc) { - case ICMD_NOP: /* ... ==> ... */ - case ICMD_POP: /* ..., value ==> ... */ - case ICMD_POP2: /* ..., value, value ==> ... */ - break; - - case ICMD_INLINE_START: - - REPLACEMENT_POINT_INLINE_START(cd, iptr); - break; - - case ICMD_INLINE_BODY: - - REPLACEMENT_POINT_INLINE_BODY(cd, iptr); - linenumbertable_list_entry_add_inline_start(cd, iptr); - linenumbertable_list_entry_add(cd, iptr->line); - break; - - case ICMD_INLINE_END: - - linenumbertable_list_entry_add_inline_end(cd, iptr); - linenumbertable_list_entry_add(cd, iptr->line); - break; + } else { + M_RET(REG_RA); + M_NOP; + } +} - case ICMD_CHECKNULL: /* ..., objectref ==> ..., objectref */ - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - emit_nullpointer_check(cd, iptr, s1); - break; +/** + * Generates machine code for one ICMD. + */ +void codegen_emit_instruction(jitdata* jd, instruction* iptr) +{ + varinfo* var; + builtintable_entry* bte; + 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. + codeinfo* code = jd->code; + codegendata* cd = jd->cd; + + 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_LCONST: /* ... ==> ..., constant */ #if SIZEOF_VOID_P == 8 @@ -467,7 +344,7 @@ bool codegen_emit(jitdata *jd) d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - cr = iptr->sx.val.c.ref; + constant_classref *cr = iptr->sx.val.c.ref; disp = dseg_add_unique_address(cd, cr); patcher_add_patch_ref(jd, PATCHER_resolve_classref_to_classinfo, @@ -487,29 +364,6 @@ bool codegen_emit(jitdata *jd) break; - /* load/store/copy/move operations ************************************/ - - case ICMD_ILOAD: /* ... ==> ..., content of local variable */ - case ICMD_LLOAD: - case ICMD_ALOAD: - case ICMD_FLOAD: - case ICMD_DLOAD: - case ICMD_ISTORE: /* ..., value ==> ... */ - case ICMD_LSTORE: - case ICMD_FSTORE: - 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_INEG: /* ..., value ==> ..., - value */ @@ -2245,17 +2099,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); - -#ifdef ENABLE_VERIFIER - if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - uc = iptr->sx.s23.s2.uc; - - patcher_add_patch_ref(jd, PATCHER_resolve_class, uc, 0); - } -#endif /* ENABLE_VERIFIER */ - // Some processor implementations seem to have a problem when using // the JALR instruction with (reg_dest == reg_src), so avoid that. disp = dseg_add_functionptr(cd, asm_handle_exception); @@ -2264,117 +2107,72 @@ bool codegen_emit(jitdata *jd) M_NOP; M_NOP; /* nop ensures that XPC is less than the end */ /* of basic block */ - ALIGNCODENOP; - break; - - case ICMD_GOTO: /* ... ==> ... */ - case ICMD_RET: /* ... ==> ... */ - - emit_br(cd, iptr->dst.block); - ALIGNCODENOP; - break; - - case ICMD_JSR: /* ... ==> ... */ - - emit_br(cd, iptr->sx.s23.s3.jsrtarget.block); - ALIGNCODENOP; - break; - - case ICMD_IFNULL: /* ..., value ==> ... */ - case ICMD_IFNONNULL: - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - emit_bccz(cd, iptr->dst.block, iptr->opc - ICMD_IFNULL, s1, BRANCH_OPT_NONE); break; case ICMD_IFEQ: /* ..., value ==> ... */ s1 = emit_load_s1(jd, iptr, REG_ITMP1); - if (iptr->sx.val.i == 0) - emit_beqz(cd, iptr->dst.block, s1); - else { - ICONST(REG_ITMP2, iptr->sx.val.i); - emit_beq(cd, iptr->dst.block, s1, REG_ITMP2); - } + ICONST(REG_ITMP2, iptr->sx.val.i); + emit_beq(cd, iptr->dst.block, s1, REG_ITMP2); break; case ICMD_IFLT: /* ..., value ==> ... */ s1 = emit_load_s1(jd, iptr, REG_ITMP1); - if (iptr->sx.val.i == 0) - emit_bltz(cd, iptr->dst.block, s1); + if ((iptr->sx.val.i >= -32768) && (iptr->sx.val.i <= 32767)) + M_CMPLT_IMM(s1, iptr->sx.val.i, REG_ITMP1); else { - if ((iptr->sx.val.i >= -32768) && (iptr->sx.val.i <= 32767)) - M_CMPLT_IMM(s1, iptr->sx.val.i, REG_ITMP1); - else { - ICONST(REG_ITMP2, iptr->sx.val.i); - M_CMPLT(s1, REG_ITMP2, REG_ITMP1); - } - emit_bnez(cd, iptr->dst.block, REG_ITMP1); + ICONST(REG_ITMP2, iptr->sx.val.i); + M_CMPLT(s1, REG_ITMP2, REG_ITMP1); } + emit_bnez(cd, iptr->dst.block, REG_ITMP1); break; case ICMD_IFLE: /* ..., value ==> ... */ s1 = emit_load_s1(jd, iptr, REG_ITMP1); - if (iptr->sx.val.i == 0) - emit_blez(cd, iptr->dst.block, s1); + if ((iptr->sx.val.i >= -32769) && (iptr->sx.val.i <= 32766)) { + M_CMPLT_IMM(s1, iptr->sx.val.i + 1, REG_ITMP1); + emit_bnez(cd, iptr->dst.block, REG_ITMP1); + } else { - if ((iptr->sx.val.i >= -32769) && (iptr->sx.val.i <= 32766)) { - M_CMPLT_IMM(s1, iptr->sx.val.i + 1, REG_ITMP1); - emit_bnez(cd, iptr->dst.block, REG_ITMP1); - } - else { - ICONST(REG_ITMP2, iptr->sx.val.i); - M_CMPGT(s1, REG_ITMP2, REG_ITMP1); - emit_beqz(cd, iptr->dst.block, REG_ITMP1); - } + ICONST(REG_ITMP2, iptr->sx.val.i); + M_CMPGT(s1, REG_ITMP2, REG_ITMP1); + emit_beqz(cd, iptr->dst.block, REG_ITMP1); } break; case ICMD_IFNE: /* ..., value ==> ... */ s1 = emit_load_s1(jd, iptr, REG_ITMP1); - if (iptr->sx.val.i == 0) - emit_bnez(cd, iptr->dst.block, s1); - else { - ICONST(REG_ITMP2, iptr->sx.val.i); - emit_bne(cd, iptr->dst.block, s1, REG_ITMP2); - } + ICONST(REG_ITMP2, iptr->sx.val.i); + emit_bne(cd, iptr->dst.block, s1, REG_ITMP2); break; case ICMD_IFGT: /* ..., value ==> ... */ s1 = emit_load_s1(jd, iptr, REG_ITMP1); - if (iptr->sx.val.i == 0) - emit_bgtz(cd, iptr->dst.block, s1); + if ((iptr->sx.val.i >= -32769) && (iptr->sx.val.i <= 32766)) { + M_CMPLT_IMM(s1, iptr->sx.val.i + 1, REG_ITMP1); + emit_beqz(cd, iptr->dst.block, REG_ITMP1); + } else { - if ((iptr->sx.val.i >= -32769) && (iptr->sx.val.i <= 32766)) { - M_CMPLT_IMM(s1, iptr->sx.val.i + 1, REG_ITMP1); - emit_beqz(cd, iptr->dst.block, REG_ITMP1); - } - else { - ICONST(REG_ITMP2, iptr->sx.val.i); - M_CMPGT(s1, REG_ITMP2, REG_ITMP1); - emit_bnez(cd, iptr->dst.block, REG_ITMP1); - } + ICONST(REG_ITMP2, iptr->sx.val.i); + M_CMPGT(s1, REG_ITMP2, REG_ITMP1); + emit_bnez(cd, iptr->dst.block, REG_ITMP1); } break; case ICMD_IFGE: /* ..., value ==> ... */ s1 = emit_load_s1(jd, iptr, REG_ITMP1); - if (iptr->sx.val.i == 0) - emit_bgez(cd, iptr->dst.block, s1); + if ((iptr->sx.val.i >= -32768) && (iptr->sx.val.i <= 32767)) + M_CMPLT_IMM(s1, iptr->sx.val.i, REG_ITMP1); else { - if ((iptr->sx.val.i >= -32768) && (iptr->sx.val.i <= 32767)) - M_CMPLT_IMM(s1, iptr->sx.val.i, REG_ITMP1); - else { - ICONST(REG_ITMP2, iptr->sx.val.i); - M_CMPLT(s1, REG_ITMP2, REG_ITMP1); - } - emit_beqz(cd, iptr->dst.block, REG_ITMP1); + ICONST(REG_ITMP2, iptr->sx.val.i); + M_CMPLT(s1, REG_ITMP2, REG_ITMP1); } + emit_beqz(cd, iptr->dst.block, REG_ITMP1); break; case ICMD_IF_LEQ: /* ..., value ==> ... */ @@ -2588,8 +2386,6 @@ bool codegen_emit(jitdata *jd) #endif break; - case ICMD_IF_ICMPEQ: /* ..., value, value ==> ... */ - case ICMD_IF_ACMPEQ: /* op1 = target JavaVM pc */ #if SIZEOF_VOID_P == 8 case ICMD_IF_LCMPEQ: #endif @@ -2613,8 +2409,6 @@ bool codegen_emit(jitdata *jd) break; #endif - case ICMD_IF_ICMPNE: /* ..., value, value ==> ... */ - case ICMD_IF_ACMPNE: /* op1 = target JavaVM pc */ #if SIZEOF_VOID_P == 8 case ICMD_IF_LCMPNE: #endif @@ -2749,171 +2543,6 @@ bool codegen_emit(jitdata *jd) break; #endif - case ICMD_IRETURN: /* ..., retvalue ==> ... */ -#if SIZEOF_VOID_P == 8 - case ICMD_LRETURN: -#endif - - REPLACEMENT_POINT_RETURN(cd, iptr); - s1 = emit_load_s1(jd, iptr, REG_RESULT); - M_INTMOVE(s1, REG_RESULT); - goto nowperformreturn; - - case ICMD_ARETURN: /* ..., retvalue ==> ... */ - - REPLACEMENT_POINT_RETURN(cd, iptr); - s1 = emit_load_s1(jd, iptr, REG_RESULT); - M_INTMOVE(s1, REG_RESULT); - -#ifdef ENABLE_VERIFIER - if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - uc = iptr->sx.s23.s2.uc; - - patcher_add_patch_ref(jd, PATCHER_resolve_class, uc, 0); - } -#endif /* ENABLE_VERIFIER */ - goto nowperformreturn; - -#if SIZEOF_VOID_P == 4 - case ICMD_LRETURN: /* ..., retvalue ==> ... */ - - s1 = emit_load_s1(jd, iptr, REG_RESULT_PACKED); - M_LNGMOVE(s1, REG_RESULT_PACKED); - goto nowperformreturn; -#endif - - case ICMD_FRETURN: /* ..., retvalue ==> ... */ - REPLACEMENT_POINT_RETURN(cd, iptr); - s1 = emit_load_s1(jd, iptr, REG_FRESULT); - M_FLTMOVE(s1, REG_FRESULT); - goto nowperformreturn; - - case ICMD_DRETURN: /* ..., retvalue ==> ... */ - - REPLACEMENT_POINT_RETURN(cd, iptr); - s1 = emit_load_s1(jd, iptr, REG_FRESULT); - M_DBLMOVE(s1, REG_FRESULT); - goto nowperformreturn; - - case ICMD_RETURN: /* ... ==> ... */ - - REPLACEMENT_POINT_RETURN(cd, iptr); - -nowperformreturn: - { - s4 i, p; - - p = cd->stackframesize; - -#if !defined(NDEBUG) - if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) - emit_verbosecall_exit(jd); -#endif - -#if defined(ENABLE_THREADS) - if (checksync && code_is_synchronized(code)) { - disp = dseg_add_functionptr(cd, LOCK_monitor_exit); - M_ALD(REG_ITMP3, REG_PV, disp); - - /* we need to save the proper return value */ - - switch (iptr->opc) { - case ICMD_IRETURN: - case ICMD_ARETURN: -#if SIZEOF_VOID_P == 8 - case ICMD_LRETURN: -#endif - M_ALD(REG_A0, REG_SP, rd->memuse * 8); - M_JSR(REG_RA, REG_ITMP3); - M_AST(REG_RESULT, REG_SP, rd->memuse * 8); /* delay slot */ - break; -#if SIZEOF_VOID_P == 4 - case ICMD_LRETURN: - M_ALD(REG_A0, REG_SP, rd->memuse * 8); - M_LST(REG_RESULT_PACKED, REG_SP, rd->memuse * 8); - M_JSR(REG_RA, REG_ITMP3); - M_NOP; - break; -#endif - case ICMD_FRETURN: - case ICMD_DRETURN: - M_ALD(REG_A0, REG_SP, rd->memuse * 8); - M_JSR(REG_RA, REG_ITMP3); - M_DST(REG_FRESULT, REG_SP, rd->memuse * 8); /* delay slot */ - break; - case ICMD_RETURN: - M_JSR(REG_RA, REG_ITMP3); - M_ALD(REG_A0, REG_SP, rd->memuse * 8); /* delay*/ - break; - } - - /* and now restore the proper return value */ - - switch (iptr->opc) { - case ICMD_IRETURN: - case ICMD_ARETURN: -#if SIZEOF_VOID_P == 8 - case ICMD_LRETURN: -#endif - M_ALD(REG_RESULT, REG_SP, rd->memuse * 8); - break; -#if SIZEOF_VOID_P == 4 - case ICMD_LRETURN: - M_LLD(REG_RESULT_PACKED, REG_SP, rd->memuse * 8); - break; -#endif - case ICMD_FRETURN: - case ICMD_DRETURN: - M_DLD(REG_FRESULT, REG_SP, rd->memuse * 8); - break; - } - } -#endif - - /* restore return address */ - - if (!code_is_leafmethod(code)) { - p--; M_ALD(REG_RA, REG_SP, p * 8); - } - - /* restore saved registers */ - - for (i = INT_SAV_CNT - 1; i >= rd->savintreguse; i--) { - p--; M_ALD(rd->savintregs[i], REG_SP, p * 8); - } - for (i = FLT_SAV_CNT - 1; i >= rd->savfltreguse; i--) { - p--; M_DLD(rd->savfltregs[i], REG_SP, p * 8); - } - - /* deallocate stack and return */ - - if (cd->stackframesize) { - s4 lo, hi; - - disp = cd->stackframesize * 8; - lo = (short) (disp); - hi = (short) (((disp) - lo) >> 16); - - if (hi == 0) { - M_RET(REG_RA); - M_AADD_IMM(REG_SP, lo, REG_SP); /* delay slot */ - } else { - M_LUI(REG_ITMP3,hi); - M_AADD_IMM(REG_ITMP3,lo,REG_ITMP3); - M_RET(REG_RA); - M_AADD(REG_ITMP3,REG_SP,REG_SP); /* delay slot */ - } - - } else { - M_RET(REG_RA); - M_NOP; - } - - ALIGNCODENOP; - } - break; - - case ICMD_TABLESWITCH: /* ..., index ==> ... */ { s4 i, l; @@ -2963,249 +2592,113 @@ nowperformreturn: ALIGNCODENOP; break; + case ICMD_BUILTIN: + bte = iptr->sx.s23.s3.bte; + if (bte->stub == NULL) { + disp = dseg_add_functionptr(cd, bte->fp); + M_ALD(REG_ITMP3, REG_PV, disp); /* built-in-function pointer */ - case ICMD_LOOKUPSWITCH: /* ..., key ==> ... */ - { - s4 i; - lookup_target_t *lookup; - - lookup = iptr->dst.lookup; - - i = iptr->sx.s23.s2.lookupcount; - - MCODECHECK((i<<2)+8); - s1 = emit_load_s1(jd, iptr, REG_ITMP1); + /* generate the actual call */ - while (--i >= 0) { - ICONST(REG_ITMP2, lookup->value); - emit_beq(cd, lookup->target.block, s1, REG_ITMP2); - ++lookup; - } + /* TWISTI: i actually don't know the reason for using + REG_ITMP3 here instead of REG_PV. */ - emit_br(cd, iptr->sx.s23.s3.lookupdefault.block); - ALIGNCODENOP; - break; + M_JSR(REG_RA, REG_ITMP3); + M_NOP; } + else { + disp = dseg_add_functionptr(cd, bte->stub); + M_ALD(REG_PV, REG_PV, disp); /* method pointer in pv */ + /* generate the actual call */ - case ICMD_BUILTIN: /* ..., arg1 ==> ... */ - - bte = iptr->sx.s23.s3.bte; - md = bte->md; - goto gen_method; - - case ICMD_INVOKESTATIC: /* ..., [arg1, [arg2 ...]] ==> ... */ - - case ICMD_INVOKESPECIAL:/* ..., objectref, [arg1, [arg2 ...]] ==> ... */ - case ICMD_INVOKEVIRTUAL:/* op1 = arg count, val.a = method pointer */ - case ICMD_INVOKEINTERFACE: + M_JSR(REG_RA, REG_PV); + M_NOP; + } + break; - REPLACEMENT_POINT_INVOKE(cd, iptr); + case ICMD_INVOKESPECIAL: + emit_nullpointer_check(cd, iptr, REG_A0); + /* fall through */ + case ICMD_INVOKESTATIC: if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - lm = NULL; um = iptr->sx.s23.s3.um; - md = um->methodref->parseddesc.md; + disp = dseg_add_unique_address(cd, um); + + patcher_add_patch_ref(jd, PATCHER_invokestatic_special, um, + disp); } else { lm = iptr->sx.s23.s3.fmiref->p.method; - um = NULL; - md = lm->parseddesc; + disp = dseg_add_address(cd, lm->stubroutine); } -gen_method: - s3 = md->paramcount; + M_ALD(REG_PV, REG_PV, disp); /* method pointer in pv */ - MCODECHECK((s3 << 1) + 64); + /* generate the actual call */ - /* copy arguments to registers or stack location */ - - for (s3 = s3 - 1; s3 >= 0; s3--) { - var = VAR(iptr->sx.s23.s2.args[s3]); - d = md->params[s3].regoff; + M_JSR(REG_RA, REG_PV); + M_NOP; + break; - if (var->flags & PREALLOC) - continue; + case ICMD_INVOKEVIRTUAL: + emit_nullpointer_check(cd, iptr, REG_A0); - if (IS_INT_LNG_TYPE(var->type)) { -#if SIZEOF_VOID_P == 8 - if (!md->params[s3].inmemory) { - s1 = emit_load(jd, iptr, var, d); - M_INTMOVE(s1, d); - } - else { - s1 = emit_load(jd, iptr, var, REG_ITMP1); - M_LST(s1, REG_SP, d); - } -#else - if (!md->params[s3].inmemory) { - s1 = emit_load(jd, iptr, var, d); + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + um = iptr->sx.s23.s3.um; + patcher_add_patch_ref(jd, PATCHER_invokevirtual, um, 0); - 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); - } - } -#endif - } - else { - if (!md->params[s3].inmemory) { - s1 = emit_load(jd, iptr, var, d); - if (IS_2_WORD_TYPE(var->type)) - M_DBLMOVE(s1, d); - else - M_FLTMOVE(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); - } - } + s1 = 0; + } + else { + lm = iptr->sx.s23.s3.fmiref->p.method; + s1 = OFFSET(vftbl_t, table[0]) + + sizeof(methodptr) * lm->vftblindex; } - switch (iptr->opc) { - case ICMD_BUILTIN: - if (bte->stub == NULL) { - disp = dseg_add_functionptr(cd, bte->fp); - M_ALD(REG_ITMP3, REG_PV, disp); /* built-in-function pointer */ - - /* generate the actual call */ - - /* TWISTI: i actually don't know the reason for using - REG_ITMP3 here instead of REG_PV. */ - - M_JSR(REG_RA, REG_ITMP3); - M_NOP; - } - else { - disp = dseg_add_functionptr(cd, bte->stub); - M_ALD(REG_PV, REG_PV, disp); /* method pointer in pv */ - - /* generate the actual call */ - - M_JSR(REG_RA, REG_PV); - M_NOP; - } - - REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr); - disp = (s4) (cd->mcodeptr - cd->mcodebase); - M_LDA(REG_PV, REG_RA, -disp); - 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, um); - - patcher_add_patch_ref(jd, PATCHER_invokestatic_special, um, - disp); - } - else - disp = dseg_add_address(cd, lm->stubroutine); - - M_ALD(REG_PV, REG_PV, disp); /* method pointer in pv */ - - /* generate the actual call */ - - M_JSR(REG_RA, REG_PV); - M_NOP; - REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr); - disp = (s4) (cd->mcodeptr - cd->mcodebase); - M_LDA(REG_PV, REG_RA, -disp); - break; - - case ICMD_INVOKEVIRTUAL: - emit_nullpointer_check(cd, iptr, REG_A0); - - 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_ALD(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl)); + M_ALD(REG_PV, REG_METHODPTR, s1); - /* implicit null-pointer check */ - M_ALD(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl)); - M_ALD(REG_PV, REG_METHODPTR, s1); + /* generate the actual call */ - /* generate the actual call */ - - M_JSR(REG_RA, REG_PV); - M_NOP; - REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr); - disp = (s4) (cd->mcodeptr - cd->mcodebase); - M_LDA(REG_PV, REG_RA, -disp); - break; + M_JSR(REG_RA, REG_PV); + M_NOP; + break; - case ICMD_INVOKEINTERFACE: - emit_nullpointer_check(cd, iptr, REG_A0); + case ICMD_INVOKEINTERFACE: + emit_nullpointer_check(cd, iptr, REG_A0); - if (lm == NULL) { - patcher_add_patch_ref(jd, PATCHER_invokeinterface, um, 0); + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + um = iptr->sx.s23.s3.um; + patcher_add_patch_ref(jd, PATCHER_invokeinterface, um, 0); - s1 = 0; - s2 = 0; - } - else { - s1 = OFFSET(vftbl_t, interfacetable[0]) - - sizeof(methodptr*) * lm->clazz->index; + s1 = 0; + s2 = 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); - } + s2 = sizeof(methodptr) * (lm - lm->clazz->methods); + } - /* implicit null-pointer check */ - M_ALD(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl)); - M_ALD(REG_METHODPTR, REG_METHODPTR, s1); - M_ALD(REG_PV, REG_METHODPTR, s2); + /* implicit null-pointer check */ + M_ALD(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl)); + M_ALD(REG_METHODPTR, REG_METHODPTR, s1); + M_ALD(REG_PV, REG_METHODPTR, s2); - /* generate the actual call */ + /* generate the actual call */ - M_JSR(REG_RA, REG_PV); - M_NOP; - REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr); - disp = (s4) (cd->mcodeptr - cd->mcodebase); - M_LDA(REG_PV, REG_RA, -disp); - break; - } + M_JSR(REG_RA, REG_PV); + M_NOP; + break; - /* store return value */ - d = md->returntype.type; - if (d != TYPE_VOID) { - if (IS_INT_LNG_TYPE(d)) { -#if SIZEOF_VOID_P == 8 - s1 = codegen_reg_of_dst(jd, iptr, REG_RESULT); - M_INTMOVE(REG_RESULT, s1); -#else - 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); - } -#endif - } +XXX else { s1 = codegen_reg_of_dst(jd, iptr, REG_FRESULT); if (IS_2_WORD_TYPE(d)) @@ -3240,7 +2733,7 @@ gen_method: if (super == NULL) { emit_label_beqz(cd, BRANCH_LABEL_1, s1); - cr = iptr->sx.s23.s3.c.ref; + constant_classref *cr = iptr->sx.s23.s3.c.ref; disp = dseg_add_unique_s4(cd, 0); /* super->flags */ patcher_add_patch_ref(jd, PATCHER_resolve_classref_to_flags, @@ -3255,7 +2748,7 @@ gen_method: if ((super == NULL) || (super->flags & ACC_INTERFACE)) { if (super == NULL) { - cr = iptr->sx.s23.s3.c.ref; + constant_classref *cr = iptr->sx.s23.s3.c.ref; patcher_add_patch_ref(jd, PATCHER_checkcast_interface, cr, 0); @@ -3287,7 +2780,7 @@ gen_method: if (super == NULL) { emit_label(cd, BRANCH_LABEL_2); - cr = iptr->sx.s23.s3.c.ref; + constant_classref *cr = iptr->sx.s23.s3.c.ref; disp = dseg_add_unique_address(cd, NULL); patcher_add_patch_ref(jd, @@ -3386,7 +2879,7 @@ gen_method: M_INTMOVE(s1, REG_A0); if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - cr = iptr->sx.s23.s3.c.ref; + constant_classref *cr = iptr->sx.s23.s3.c.ref; disp = dseg_add_unique_address(cd, NULL); patcher_add_patch_ref(jd, @@ -3445,7 +2938,7 @@ gen_method: if (super == NULL) { emit_label_beqz(cd, BRANCH_LABEL_1, s1); - cr = iptr->sx.s23.s3.c.ref; + constant_classref *cr = iptr->sx.s23.s3.c.ref; disp = dseg_add_unique_s4(cd, 0); /* super->flags */ patcher_add_patch_ref(jd, PATCHER_resolve_classref_to_flags, @@ -3460,7 +2953,7 @@ gen_method: if ((super == NULL) || (super->flags & ACC_INTERFACE)) { if (super == NULL) { - cr = iptr->sx.s23.s3.c.ref; + constant_classref * iptr->sx.s23.s3.c.ref; patcher_add_patch_ref(jd, PATCHER_instanceof_interface, cr, 0); @@ -3492,7 +2985,7 @@ gen_method: if (super == NULL) { emit_label(cd, BRANCH_LABEL_2); - cr = iptr->sx.s23.s3.c.ref; + constant_classref *cr = iptr->sx.s23.s3.c.ref; disp = dseg_add_unique_address(cd, NULL); patcher_add_patch_ref(jd, PATCHER_resolve_classref_to_vftbl, @@ -3619,7 +3112,7 @@ gen_method: /* is patcher function set? */ if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - cr = iptr->sx.s23.s3.c.ref; + constant_classref *cr = iptr->sx.s23.s3.c.ref; disp = dseg_add_unique_address(cd, NULL); patcher_add_patch_ref(jd, PATCHER_resolve_classref_to_classinfo, @@ -3656,35 +3149,8 @@ gen_method: break; default: - exceptions_throw_internalerror("Unknown ICMD %d during code generation", - iptr->opc); - return false; + vm_abort("Unknown ICMD %d during code generation", iptr->opc); } /* switch */ - - } /* for instruction */ - - MCODECHECK(64); /* XXX require smaller number? */ - - /* At the end of a basic block we may have to append some nops, - because the patcher stub calling code might be longer than the - actual instruction. So codepatching does not change the - following block unintentionally. */ - - if (cd->mcodeptr < cd->lastmcodeptr) { - while (cd->mcodeptr < cd->lastmcodeptr) - M_NOP; - } - - } /* if (bptr -> flags >= BBREACHED) */ - } /* for basic block */ - - /* generate traps */ - - emit_patcher_traps(jd); - - /* everything's ok */ - - return true; } diff --git a/src/vm/jit/mips/codegen.h b/src/vm/jit/mips/codegen.h index f1819f848..8c215be81 100644 --- a/src/vm/jit/mips/codegen.h +++ b/src/vm/jit/mips/codegen.h @@ -48,44 +48,6 @@ M_NOP; \ } -#define M_INTMOVE(a,b) \ - do { \ - if ((a) != (b)) \ - M_MOV(a, b); \ - } while (0) - -#if SIZEOF_VOID_P == 8 - -#define M_LNGMOVE(a,b) M_INTMOVE(a,b) - -#else /* SIZEOF_VOID_P == 8 */ - -#define M_LNGMOVE(a,b) \ - do { \ - if (GET_LOW_REG(b) == GET_HIGH_REG(a)) { \ - assert(GET_HIGH_REG(b) == GET_LOW_REG(a)); \ - M_INTMOVE(GET_HIGH_REG(a), GET_HIGH_REG(b)); \ - M_INTMOVE(GET_LOW_REG(a), GET_LOW_REG(b)); \ - } else { \ - M_INTMOVE(GET_LOW_REG(a), GET_LOW_REG(b)); \ - M_INTMOVE(GET_HIGH_REG(a), GET_HIGH_REG(b)); \ - } \ - } while (0) - -#endif /* SIZEOF_VOID_P == 8 */ - -#define M_FLTMOVE(a,b) \ - do { \ - if ((a) != (b)) \ - M_FMOV(a, b); \ - } while (0) - -#define M_DBLMOVE(a,b) \ - do { \ - if ((a) != (b)) \ - M_DMOV(a, b); \ - } while (0) - #define ICONST(r,c) emit_iconst(cd, (r), (c)) #define LCONST(r,c) emit_lconst(cd, (r), (c)) diff --git a/src/vm/jit/mips/emit.c b/src/vm/jit/mips/emit.c index d2edc03ee..9798b2222 100644 --- a/src/vm/jit/mips/emit.c +++ b/src/vm/jit/mips/emit.c @@ -642,6 +642,152 @@ uint32_t emit_trap(codegendata *cd) } +/** + * Emit code to recompute the procedure vector. + */ +void emit_recompute_pv(codegendata *cd) +{ + int32_t disp = (int32_t) (cd->mcodeptr - cd->mcodebase); + + M_LDA(REG_PV, REG_RA, -disp); +} + + +/** + * Generates synchronization code to enter a monitor. + */ +#if defined(ENABLE_THREADS) +void emit_monitor_enter(jitdata* jd, int32_t syncslot_offset) +{ + int32_t p; + int32_t disp; + + // Get required compiler data. + methodinfo* m = jd->m; + codegendata* cd = jd->cd; + +# if !defined(NDEBUG) + if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) { + M_LDA(REG_SP, REG_SP, -(INT_ARG_CNT + FLT_ARG_CNT) * 8); + + for (p = 0; p < INT_ARG_CNT; p++) + M_AST(abi_registers_integer_argument[p], REG_SP, p * 8); + + for (p = 0; p < FLT_ARG_CNT; p++) + M_DST(abi_registers_float_argument[p], REG_SP, (INT_ARG_CNT + p) * 8); + + syncslot_offset += (INT_ARG_CNT + FLT_ARG_CNT) * 8; + } +# endif + + /* get correct lock object */ + + if (m->flags & ACC_STATIC) { + disp = dseg_add_address(cd, &m->clazz->object.header); + M_ALD(REG_A0, REG_PV, disp); + disp = dseg_add_functionptr(cd, LOCK_monitor_enter); + M_ALD(REG_ITMP3, REG_PV, disp); + } + else { +/* emit_nullpointer_check(cd, iptr, REG_A0); */ + M_BNEZ(REG_A0, 2); + disp = dseg_add_functionptr(cd, LOCK_monitor_enter); + M_ALD(REG_ITMP3, REG_PV, disp); /* branch delay */ + M_ALD_INTERN(REG_ZERO, REG_ZERO, TRAP_NullPointerException); + } + + M_JSR(REG_RA, REG_ITMP3); + M_AST(REG_A0, REG_SP, syncslot_offset); /* branch delay */ + +# if !defined(NDEBUG) + if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) { + for (p = 0; p < INT_ARG_CNT; p++) + M_ALD(abi_registers_integer_argument[p], REG_SP, p * 8); + + for (p = 0; p < FLT_ARG_CNT; p++) + M_DLD(abi_registers_float_argument[p], REG_SP, (INT_ARG_CNT + p) * 8); + + + M_LDA(REG_SP, REG_SP, (INT_ARG_CNT + FLT_ARG_CNT) * 8); + } +# endif +} +#endif + + +/** + * Generates synchronization code to leave a monitor. + */ +#if defined(ENABLE_THREADS) +void emit_monitor_exit(jitdata* jd, int32_t syncslot_offset) +{ + int32_t disp; + + // Get required compiler data. + methodinfo* m = jd->m; + codegendata* cd = jd->cd; + + disp = dseg_add_functionptr(cd, LOCK_monitor_exit); + M_ALD(REG_ITMP3, REG_PV, disp); + + /* we need to save the proper return value */ + + methoddesc* md = m->parseddesc; + + switch (md->returntype.type) { + case TYPE_INT: + case TYPE_ADR: +#if SIZEOF_VOID_P == 8 + case TYPE_LNG: +#endif + M_ALD(REG_A0, REG_SP, syncslot_offset); + M_JSR(REG_RA, REG_ITMP3); + M_AST(REG_RESULT, REG_SP, syncslot_offset); /* delay slot */ + break; +#if SIZEOF_VOID_P == 4 + case TYPE_LNG: + M_ALD(REG_A0, REG_SP, syncslot_offset); + M_LST(REG_RESULT_PACKED, REG_SP, syncslot_offset); + M_JSR(REG_RA, REG_ITMP3); + M_NOP; + break; +#endif + case TYPE_FLT: + case TYPE_DBL: + M_ALD(REG_A0, REG_SP, syncslot_offset); + M_JSR(REG_RA, REG_ITMP3); + M_DST(REG_FRESULT, REG_SP, syncslot_offset); /* delay slot */ + break; + default: + M_JSR(REG_RA, REG_ITMP3); + M_ALD(REG_A0, REG_SP, syncslot_offset); /* delay*/ + break; + } + + /* and now restore the proper return value */ + + switch (md->returntype.type) { + case TYPE_INT: + case TYPE_ADR: +#if SIZEOF_VOID_P == 8 + case TYPE_LNG: +#endif + M_ALD(REG_RESULT, REG_SP, syncslot_offset); + break; +#if SIZEOF_VOID_P == 4 + case TYPE_LNG: + M_LLD(REG_RESULT_PACKED, REG_SP, syncslot_offset); + break; +#endif + case TYPE_FLT: + case TYPE_DBL: + M_DLD(REG_FRESULT, REG_SP, syncslot_offset); + break; + } +} +#endif + + /* emit_verbosecall_enter ****************************************************** Generates the code for the call trace. diff --git a/src/vm/jit/mips/md.h b/src/vm/jit/mips/md.h index 100be5e30..67bb24cdc 100644 --- a/src/vm/jit/mips/md.h +++ b/src/vm/jit/mips/md.h @@ -38,6 +38,21 @@ #include "vm/vm.hpp" +/** + * Returns the size (in bytes) of the current stackframe, specified by + * the passed codeinfo structure. + */ +inline static int32_t md_stacktrace_get_framesize(codeinfo* code) +{ + // Check for the asm_vm_call_method special case. + if (code == NULL) + return 0; + + // On MIPS we use 8-byte stackslots. + return code->stackframesize * 8; +} + + /* md_stacktrace_get_returnaddress ********************************************* Returns the return address of the current stackframe, specified by diff --git a/src/vm/jit/optimizing/profile.c b/src/vm/jit/optimizing/profile.c index ea8101067..5268c8d75 100644 --- a/src/vm/jit/optimizing/profile.c +++ b/src/vm/jit/optimizing/profile.c @@ -95,6 +95,7 @@ static void profile_thread(void) // Lock the thread lists. ThreadList_lock(); +#if 0 /* iterate over all started threads */ for (t = ThreadList_first(); t != NULL; t = ThreadList_next(t)) { @@ -153,6 +154,7 @@ static void profile_thread(void) } } } +#endif // Unlock the thread lists. ThreadList_unlock(); @@ -207,6 +209,7 @@ void profile_printstats(void) frequency = 0; cycles = 0; +#if 0 /* create new method list */ // TODO Use a sorted container. List* l = List_new(); @@ -297,6 +300,7 @@ void profile_printstats(void) j, code->bbfrequency[j]); } } +#endif printf("----------- -------------- \n"); printf("%10d %12ld\n", frequency, (long) cycles); diff --git a/src/vm/jit/optimizing/profile.h b/src/vm/jit/optimizing/profile.h index a235afacd..06a672a80 100644 --- a/src/vm/jit/optimizing/profile.h +++ b/src/vm/jit/optimizing/profile.h @@ -37,6 +37,50 @@ extern "C" { #include "vm/global.h" +/* CPU cycle counting macros **************************************************/ + +#if defined(ENABLE_PROFILING) && defined(__X86_64__) + +#define PROFILE_CYCLE_START \ + do { \ + if (JITDATA_HAS_FLAG_INSTRUMENT(jd)) { \ + M_PUSH(RAX); \ + M_PUSH(RDX); \ + \ + M_MOV_IMM(code, REG_ITMP3); \ + M_RDTSC; \ + M_ISUB_MEMBASE(RAX, REG_ITMP3, OFFSET(codeinfo, cycles)); \ + M_ISBB_MEMBASE(RDX, REG_ITMP3, OFFSET(codeinfo, cycles) + 4); \ + \ + M_POP(RDX); \ + M_POP(RAX); \ + } \ + } while (0) + +#define PROFILE_CYCLE_STOP \ + do { \ + if (JITDATA_HAS_FLAG_INSTRUMENT(jd)) { \ + M_PUSH(RAX); \ + M_PUSH(RDX); \ + \ + M_MOV_IMM(code, REG_ITMP3); \ + M_RDTSC; \ + M_IADD_MEMBASE(RAX, REG_ITMP3, OFFSET(codeinfo, cycles)); \ + M_IADC_MEMBASE(RDX, REG_ITMP3, OFFSET(codeinfo, cycles) + 4); \ + \ + M_POP(RDX); \ + M_POP(RAX); \ + } \ + } while (0) + +#else + +#define PROFILE_CYCLE_START +#define PROFILE_CYCLE_STOP + +#endif + + /* function prototypes ********************************************************/ bool profile_init(void); diff --git a/src/vm/jit/powerpc/arch.h b/src/vm/jit/powerpc/arch.h index e9259c4af..6e0f1fce5 100644 --- a/src/vm/jit/powerpc/arch.h +++ b/src/vm/jit/powerpc/arch.h @@ -109,6 +109,14 @@ #define SUPPORT_HARDWARE_DIVIDE_BY_ZERO 0 +/* stackframe *****************************************************************/ + +#define STACKFRMAE_RA_BETWEEN_FRAMES 0 +#define STACKFRAME_RA_TOP_OF_FRAME 0 +#define STACKFRAME_LEAFMETHODS_RA_REGISTER 0 +#define STACKFRAME_SYNC_NEEDS_TWO_SLOTS 1 + + /* replacement ****************************************************************/ #define REPLACEMENT_PATCH_SIZE 4 /* bytes */ diff --git a/src/vm/jit/powerpc/codegen.c b/src/vm/jit/powerpc/codegen.c index 53d4a37d8..48a1ff2a4 100644 --- a/src/vm/jit/powerpc/codegen.c +++ b/src/vm/jit/powerpc/codegen.c @@ -1,6 +1,6 @@ /* src/vm/jit/powerpc/codegen.c - machine code generator for 32-bit PowerPC - Copyright (C) 1996-2005, 2006, 2007, 2008 + Copyright (C) 1996-2005, 2006, 2007, 2008, 2009 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO This file is part of CACAO. @@ -62,120 +62,27 @@ #include "vm/jit/parse.hpp" #include "vm/jit/patcher-common.hpp" #include "vm/jit/reg.h" -#include "vm/jit/replace.hpp" #include "vm/jit/stacktrace.hpp" #include "vm/jit/trap.hpp" -#if defined(ENABLE_LSRA) -# include "vm/jit/allocator/lsra.h" -#endif - - -/* codegen ********************************************************************* - - 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 len, s1, s2, s3, d, disp; - varinfo *var; - basicblock *bptr; - instruction *iptr; - u2 currentline; - methodinfo *lm; /* local methodinfo for ICMD_INVOKE* */ - unresolved_method *um; - builtintable_entry *bte; - methoddesc *md; - fieldinfo *fi; - unresolved_field *uf; - s4 fieldtype; - s4 varindex; - int i; - - /* get required compiler data */ - - m = jd->m; - code = jd->code; - cd = jd->cd; - rd = jd->rd; - - /* prevent compiler warnings */ - - d = 0; - fieldtype = 0; - lm = NULL; - um = NULL; - uf = NULL; - bte = NULL; - - { - s4 i, p, t, l; - s4 savedregs_num; - - savedregs_num = 0; - - /* space to save used callee saved registers */ - - savedregs_num += (INT_SAV_CNT - rd->savintreguse); - savedregs_num += (FLT_SAV_CNT - rd->savfltreguse); - - cd->stackframesize = rd->memuse + savedregs_num; - -#if defined(ENABLE_THREADS) - /* Space to save argument of monitor_enter and Return Values to - survive monitor_exit. The stack position for the argument can - not be shared with place to save the return register on PPC, - since both values reside in R3. */ - - if (checksync && code_is_synchronized(code)) - cd->stackframesize += 2; -#endif - - /* create method header */ - - /* align stack to 16-bytes */ - - if (!code_is_leafmethod(code) || JITDATA_HAS_FLAG_VERBOSECALL(jd)) - ALIGN_2(cd->stackframesize); - - else if (code_is_leafmethod(code) && (cd->stackframesize == LA_SIZE_IN_POINTERS)) - cd->stackframesize = 0; - - (void) dseg_add_unique_address(cd, code); /* CodeinfoPointer */ - (void) dseg_add_unique_s4(cd, cd->stackframesize * 8); /* 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 */ - -#if defined(ENABLE_PROFILING) - /* generate method profiling code */ - - if (JITDATA_HAS_FLAG_INSTRUMENT(jd)) { - /* count frequency */ - - M_ALD(REG_ITMP1, REG_PV, CodeinfoPointer); - M_ALD(REG_ITMP2, REG_ITMP1, OFFSET(codeinfo, frequency)); - M_IADD_IMM(REG_ITMP2, 1, REG_ITMP2); - M_AST(REG_ITMP2, REG_ITMP1, OFFSET(codeinfo, frequency)); - -/* PROFILE_CYCLE_START; */ - } -#endif + varinfo* var; + methoddesc* md; + int32_t s1; + int32_t p, t, l; + 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; /* create stack frame (if necessary) */ @@ -255,7 +162,7 @@ bool codegen_emit(jitdata *jd) else { if (!md->params[p].inmemory) { if (!IS_INMEMORY(var->flags)) - M_FLTMOVE(s1, var->vv.regoff); + emit_fmove(cd, s1, var->vv.regoff); else M_DST(s1, REG_SP, var->vv.regoff); } @@ -274,204 +181,76 @@ bool codegen_emit(jitdata *jd) } } } +} -#if defined(ENABLE_THREADS) - /* call monitorenter function */ - - if (checksync && code_is_synchronized(code)) { - /* stack offset for monitor argument */ - - s1 = rd->memuse; - -# if !defined(NDEBUG) - if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) { - M_AADD_IMM(REG_SP, -((LA_SIZE_IN_POINTERS + ARG_CNT) * 8), REG_SP); - - for (p = 0; p < INT_ARG_CNT; p++) - M_IST(abi_registers_integer_argument[p], REG_SP, LA_SIZE + p * 8); - - for (p = 0; p < FLT_ARG_CNT; p++) - M_DST(abi_registers_float_argument[p], REG_SP, LA_SIZE + (INT_ARG_CNT + p) * 8); - - s1 += LA_SIZE_IN_POINTERS + ARG_CNT; - } -# endif - - disp = dseg_add_functionptr(cd, LOCK_monitor_enter); - M_ALD(REG_ITMP3, REG_PV, disp); - M_MTCTR(REG_ITMP3); - /* get or test the lock object */ +/** + * Generates machine code for the method epilog. + */ +void codegen_emit_epilog(jitdata* jd) +{ + int32_t p; + int i; - if (m->flags & ACC_STATIC) { - disp = dseg_add_address(cd, &m->clazz->object.header); - M_ALD(REG_A0, REG_PV, disp); - } - else { - M_TST(REG_A0); - M_BNE(1); - M_ALD_INTERN(REG_ZERO, REG_ZERO, TRAP_NullPointerException); - } + // Get required compiler data. + codeinfo* code = jd->code; + codegendata* cd = jd->cd; + registerdata* rd = jd->rd; - M_AST(REG_A0, REG_SP, s1 * 8); - M_JSR; + p = cd->stackframesize; -# if !defined(NDEBUG) - if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) { - for (p = 0; p < INT_ARG_CNT; p++) - M_ILD(abi_registers_integer_argument[p], REG_SP, LA_SIZE + p * 8); + /* restore return address */ - for (p = 0; p < FLT_ARG_CNT; p++) - M_DLD(abi_registers_float_argument[p], REG_SP, LA_SIZE + (INT_ARG_CNT + p) * 8); + if (!code_is_leafmethod(code)) { + /* ATTENTION: Don't use REG_ZERO (r0) here, as M_ALD + may have a displacement overflow. */ - M_AADD_IMM(REG_SP, (LA_SIZE_IN_POINTERS + ARG_CNT) * 8, REG_SP); - } -# endif + M_ALD(REG_ITMP1, REG_SP, p * 8 + LA_LR_OFFSET); + M_MTLR(REG_ITMP1); } -#endif /* defined(ENABLE_THREADS) */ - /* call trace function */ + /* restore saved registers */ - emit_verbosecall_enter(jd); + for (i = INT_SAV_CNT - 1; i >= rd->savintreguse; i--) { + p--; M_ILD(rd->savintregs[i], REG_SP, p * 8); + } + for (i = FLT_SAV_CNT - 1; i >= rd->savfltreguse; i--) { + p--; M_DLD(rd->savfltregs[i], REG_SP, p * 8); } - /* end of header generation */ - - /* create replacement points */ - - REPLACEMENT_POINTS_INIT(cd, jd); - - /* walk through all basic blocks */ - - for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) { - - bptr->mpc = (s4) (cd->mcodeptr - cd->mcodebase); - - if (bptr->flags >= BBREACHED) { - /* branch resolving */ - - codegen_resolve_branchrefs(cd, bptr); - - /* handle replacement points */ - - REPLACEMENT_POINT_BLOCK_START(cd, bptr); - -#if defined(ENABLE_PROFILING) - /* generate basicblock profiling code */ - - if (JITDATA_HAS_FLAG_INSTRUMENT(jd)) { - /* count frequency */ - - disp = dseg_add_address(cd, code->bbfrequency); - M_ALD(REG_ITMP2, REG_PV, disp); - M_ALD(REG_ITMP3, REG_ITMP2, bptr->nr * 4); - M_IADD_IMM(REG_ITMP3, 1, REG_ITMP3); - M_AST(REG_ITMP3, REG_ITMP2, bptr->nr * 4); - - /* if this is an exception handler, start profiling again */ - -/* if (bptr->type == BBTYPE_EXH) */ -/* PROFILE_CYCLE_START; */ - } -#endif - - /* copy interface registers to their destination */ - - len = bptr->indepth; - MCODECHECK(64+len); - -#if defined(ENABLE_LSRA) - if (opt_lsra) { - while (src != NULL) { - len--; - if ((len == bptr->indepth-1) && (bptr->type == BBTYPE_EXH)) { - /* d = reg_of_var(m, src, REG_ITMP1); */ - if (!IS_INMEMORY(src->flags)) - d = src->vv.regoff; - else - d = REG_ITMP1; - M_INTMOVE(REG_ITMP1, d); - emit_store(jd, NULL, src, d); - } - src = src->prev; - } - } else { -#endif - while (len > 0) { - len--; - var = VAR(bptr->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 - /* walk through all instructions */ - - len = bptr->icount; - currentline = 0; - - for (iptr = bptr->iinstr; len > 0; len--, iptr++) { - if (iptr->line != currentline) { - linenumbertable_list_entry_add(cd, iptr->line); - currentline = iptr->line; - } - - MCODECHECK(64); /* an instruction usually needs < 64 words */ - - switch (iptr->opc) { - case ICMD_NOP: /* ... ==> ... */ - case ICMD_POP: /* ..., value ==> ... */ - case ICMD_POP2: /* ..., value, value ==> ... */ - break; - - case ICMD_INLINE_START: - - REPLACEMENT_POINT_INLINE_START(cd, iptr); - break; - - case ICMD_INLINE_BODY: - - REPLACEMENT_POINT_INLINE_BODY(cd, iptr); - linenumbertable_list_entry_add_inline_start(cd, iptr); - linenumbertable_list_entry_add(cd, iptr->line); - break; + /* deallocate stack */ - case ICMD_INLINE_END: + if (cd->stackframesize) + M_LDA(REG_SP, REG_SP, cd->stackframesize * 8); - linenumbertable_list_entry_add_inline_end(cd, iptr); - linenumbertable_list_entry_add(cd, iptr->line); - break; + M_RET; +} - case ICMD_CHECKNULL: /* ..., objectref ==> ..., objectref */ - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - emit_nullpointer_check(cd, iptr, s1); - break; +/** + * Generates machine code for one ICMD. + */ +void codegen_emit_instruction(jitdata* jd, instruction* iptr) +{ + varinfo* var; + builtintable_entry* bte; + 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. + codeinfo* code = jd->code; + 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_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 */ d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); @@ -508,30 +287,6 @@ bool codegen_emit(jitdata *jd) break; - /* load/store/copy/move operations ************************************/ - - case ICMD_ILOAD: /* ... ==> ..., content of local variable */ - case ICMD_ALOAD: /* s1 = local variable */ - case ICMD_LLOAD: - case ICMD_FLOAD: - case ICMD_DLOAD: - case ICMD_ISTORE: /* ..., value ==> ... */ - case ICMD_LSTORE: - case ICMD_FSTORE: - 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_INEG: /* ..., value ==> ..., - value */ @@ -1208,7 +963,7 @@ bool codegen_emit(jitdata *jd) s1 = emit_load_s1(jd, iptr, REG_FTMP1); d = codegen_reg_of_dst(jd, iptr, REG_FTMP3); - M_FLTMOVE(s1, d); + emit_fmove(cd, s1, d); emit_store_dst(jd, iptr, d); break; @@ -1255,15 +1010,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(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); @@ -1482,97 +1228,16 @@ bool codegen_emit(jitdata *jd) M_STWX(s3, s1, REG_ITMP2); break; - +#if 0 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, uf); - - 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, disp); - } - - M_ALD(REG_ITMP1, REG_PV, disp); - switch (fieldtype) { - case TYPE_INT: - d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); - M_ILD_INTERN(d, REG_ITMP1, 0); - break; case TYPE_LNG: d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED); M_ILD_INTERN(GET_LOW_REG(d), REG_ITMP1, 4);/* keep this order */ M_ILD_INTERN(GET_HIGH_REG(d), REG_ITMP1, 0);/*keep this order */ break; - case TYPE_ADR: - d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); - M_ALD_INTERN(d, REG_ITMP1, 0); - break; - case TYPE_FLT: - d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); - M_FLD_INTERN(d, REG_ITMP1, 0); - break; - case TYPE_DBL: - d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); - M_DLD_INTERN(d, REG_ITMP1, 0); - break; - } - 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, uf); - - 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, disp); - } - - M_ALD(REG_ITMP1, REG_PV, disp); - switch (fieldtype) { - case TYPE_INT: - s1 = emit_load_s1(jd, iptr, REG_ITMP2); - M_IST_INTERN(s1, REG_ITMP1, 0); - break; - case TYPE_LNG: - s1 = emit_load_s1(jd, iptr, REG_ITMP23_PACKED); - M_LST_INTERN(s1, REG_ITMP1, 0); - break; - case TYPE_ADR: - s1 = emit_load_s1(jd, iptr, REG_ITMP2); - M_AST_INTERN(s1, REG_ITMP1, 0); - break; - case TYPE_FLT: - s1 = emit_load_s1(jd, iptr, REG_FTMP2); - M_FST_INTERN(s1, REG_ITMP1, 0); - break; - case TYPE_DBL: - s1 = emit_load_s1(jd, iptr, REG_FTMP2); - M_DST_INTERN(s1, REG_ITMP1, 0); - break; - } - break; - +#endif case ICMD_GETFIELD: /* ... ==> ..., value */ @@ -1677,17 +1342,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); - -#ifdef ENABLE_VERIFIER - if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - unresolved_class *uc = iptr->sx.s23.s2.uc; - - patcher_add_patch_ref(jd, PATCHER_resolve_class, uc, 0); - } -#endif /* ENABLE_VERIFIER */ - disp = dseg_add_functionptr(cd, asm_handle_exception); M_ALD(REG_ITMP2, REG_PV, disp); M_MTCTR(REG_ITMP2); @@ -1702,20 +1356,6 @@ bool codegen_emit(jitdata *jd) M_MTLR(REG_ITMP3); /* restore LR */ M_RTS; /* jump to CTR */ - ALIGNCODENOP; - break; - - case ICMD_GOTO: /* ... ==> ... */ - case ICMD_RET: /* ... ==> ... */ - - emit_br(cd, iptr->dst.block); - ALIGNCODENOP; - break; - - case ICMD_JSR: /* ... ==> ... */ - - emit_br(cd, iptr->sx.s23.s3.jsrtarget.block); - ALIGNCODENOP; break; case ICMD_IFNULL: /* ..., value ==> ... */ @@ -1726,24 +1366,6 @@ bool codegen_emit(jitdata *jd) emit_bcc(cd, iptr->dst.block, iptr->opc - ICMD_IFNULL, BRANCH_OPT_NONE); break; - case ICMD_IFLT: - case ICMD_IFLE: - case ICMD_IFNE: - case ICMD_IFGT: - case ICMD_IFGE: - case ICMD_IFEQ: /* ..., value ==> ... */ - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - if ((iptr->sx.val.i >= -32768) && (iptr->sx.val.i <= 32767)) - M_CMPI(s1, iptr->sx.val.i); - else { - ICONST(REG_ITMP2, iptr->sx.val.i); - M_CMP(s1, REG_ITMP2); - } - emit_bcc(cd, iptr->dst.block, iptr->opc - ICMD_IFEQ, BRANCH_OPT_NONE); - break; - - case ICMD_IF_LEQ: /* ..., value ==> ... */ s1 = emit_load_s1_low(jd, iptr, REG_ITMP1); @@ -1900,28 +1522,6 @@ bool codegen_emit(jitdata *jd) } break; - case ICMD_IF_ICMPEQ: /* ..., value, value ==> ... */ - case ICMD_IF_ICMPNE: - case ICMD_IF_ICMPLT: - case ICMD_IF_ICMPGT: - case ICMD_IF_ICMPLE: - 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: /* op1 = target JavaVM pc */ - 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 ==> ... */ s1 = emit_load_s1_high(jd, iptr, REG_ITMP1); @@ -2003,130 +1603,6 @@ bool codegen_emit(jitdata *jd) emit_label(cd, BRANCH_LABEL_1); break; - case ICMD_IRETURN: /* ..., retvalue ==> ... */ - - REPLACEMENT_POINT_RETURN(cd, iptr); - s1 = emit_load_s1(jd, iptr, REG_RESULT); - M_INTMOVE(s1, REG_RESULT); - goto nowperformreturn; - - case ICMD_ARETURN: /* ..., retvalue ==> ... */ - - REPLACEMENT_POINT_RETURN(cd, iptr); - s1 = emit_load_s1(jd, iptr, REG_RESULT); - M_INTMOVE(s1, REG_RESULT); - -#ifdef ENABLE_VERIFIER - if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - unresolved_class *uc = iptr->sx.s23.s2.uc; - - patcher_add_patch_ref(jd, PATCHER_resolve_class, uc, 0); - } -#endif /* ENABLE_VERIFIER */ - goto nowperformreturn; - - 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 nowperformreturn; - - case ICMD_FRETURN: /* ..., retvalue ==> ... */ - case ICMD_DRETURN: - - REPLACEMENT_POINT_RETURN(cd, iptr); - s1 = emit_load_s1(jd, iptr, REG_FRESULT); - M_FLTMOVE(s1, REG_FRESULT); - goto nowperformreturn; - - case ICMD_RETURN: /* ... ==> ... */ - - REPLACEMENT_POINT_RETURN(cd, iptr); - -nowperformreturn: - { - s4 i, p; - - p = cd->stackframesize; - - /* call trace function */ - - emit_verbosecall_exit(jd); - -#if defined(ENABLE_THREADS) - if (checksync && code_is_synchronized(code)) { - disp = dseg_add_functionptr(cd, LOCK_monitor_exit); - M_ALD(REG_ITMP3, REG_PV, disp); - M_MTCTR(REG_ITMP3); - - /* we need to save the proper return value */ - - switch (iptr->opc) { - case ICMD_LRETURN: - M_IST(REG_RESULT2, REG_SP, rd->memuse * 8 + 8); - /* fall through */ - case ICMD_IRETURN: - case ICMD_ARETURN: - M_IST(REG_RESULT , REG_SP, rd->memuse * 8 + 4); - break; - case ICMD_FRETURN: - case ICMD_DRETURN: - M_DST(REG_FRESULT, REG_SP, rd->memuse * 8 + 4); - break; - } - - M_ALD(REG_A0, REG_SP, rd->memuse * 8); - M_JSR; - - /* and now restore the proper return value */ - - switch (iptr->opc) { - case ICMD_LRETURN: - M_ILD(REG_RESULT2, REG_SP, rd->memuse * 8 + 8); - /* fall through */ - case ICMD_IRETURN: - case ICMD_ARETURN: - M_ILD(REG_RESULT , REG_SP, rd->memuse * 8 + 4); - break; - case ICMD_FRETURN: - case ICMD_DRETURN: - M_DLD(REG_FRESULT, REG_SP, rd->memuse * 8 + 4); - break; - } - } -#endif - - /* restore return address */ - - if (!code_is_leafmethod(code)) { - /* ATTENTION: Don't use REG_ZERO (r0) here, as M_ALD - may have a displacement overflow. */ - - M_ALD(REG_ITMP1, REG_SP, p * 8 + LA_LR_OFFSET); - M_MTLR(REG_ITMP1); - } - - /* restore saved registers */ - - for (i = INT_SAV_CNT - 1; i >= rd->savintreguse; i--) { - p--; M_ILD(rd->savintregs[i], REG_SP, p * 8); - } - for (i = FLT_SAV_CNT - 1; i >= rd->savfltreguse; i--) { - p--; M_DLD(rd->savfltregs[i], REG_SP, p * 8); - } - - /* deallocate stack */ - - if (cd->stackframesize) - M_LDA(REG_SP, REG_SP, cd->stackframesize * 8); - - M_RET; - ALIGNCODENOP; - } - break; - - case ICMD_TABLESWITCH: /* ..., index ==> ... */ { s4 i, l; @@ -2175,251 +1651,96 @@ nowperformreturn: break; - case ICMD_LOOKUPSWITCH: /* ..., key ==> ... */ - { - s4 i; - lookup_target_t *lookup; - - lookup = iptr->dst.lookup; - - i = iptr->sx.s23.s2.lookupcount; - - MCODECHECK((i<<2)+8); - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - - while (--i >= 0) { - if ((lookup->value >= -32768) && (lookup->value <= 32767)) { - M_CMPI(s1, lookup->value); - } - else { - disp = dseg_add_s4(cd, lookup->value); - M_ILD(REG_ITMP2, REG_PV, disp); - M_CMP(s1, REG_ITMP2); - } - emit_beq(cd, lookup->target.block); - lookup++; - } - - emit_br(cd, iptr->sx.s23.s3.lookupdefault.block); - ALIGNCODENOP; - break; - } - - case ICMD_BUILTIN: /* ..., [arg1, [arg2 ...]] ==> ... */ + bte = iptr->sx.s23.s3.bte; + if (bte->stub == NULL) + disp = dseg_add_functionptr(cd, bte->fp); + else + disp = dseg_add_functionptr(cd, bte->stub); - REPLACEMENT_POINT_FORGC_BUILTIN(cd, iptr); + M_ALD(REG_PV, REG_PV, disp); /* pointer to built-in-function */ - bte = iptr->sx.s23.s3.bte; - md = bte->md; - goto gen_method; + /* generate the actual call */ - case ICMD_INVOKESTATIC: /* ..., [arg1, [arg2 ...]] ==> ... */ + M_MTCTR(REG_PV); + M_JSR; + break; case ICMD_INVOKESPECIAL:/* ..., objectref, [arg1, [arg2 ...]] ==> ... */ - case ICMD_INVOKEVIRTUAL:/* op1 = arg count, val.a = method pointer */ - case ICMD_INVOKEINTERFACE: - - REPLACEMENT_POINT_INVOKE(cd, iptr); + emit_nullpointer_check(cd, iptr, REG_A0); + /* fall-through */ + case ICMD_INVOKESTATIC: /* ..., [arg1, [arg2 ...]] ==> ... */ if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - lm = NULL; um = iptr->sx.s23.s3.um; - md = um->methodref->parseddesc.md; + disp = dseg_add_unique_address(cd, um); + + patcher_add_patch_ref(jd, PATCHER_invokestatic_special, + um, disp); } else { lm = iptr->sx.s23.s3.fmiref->p.method; - um = NULL; - md = lm->parseddesc; + disp = dseg_add_address(cd, lm->stubroutine); } -gen_method: - i = md->paramcount; - - MCODECHECK((i << 1) + 64); - - /* Copy arguments to registers or stack location. */ - - for (i = i - 1; i >= 0; i--) { - var = VAR(iptr->sx.s23.s2.args[i]); - d = md->params[i].regoff; - - /* Already pre-allocated? */ + M_ALD(REG_PV, REG_PV, disp); - if (var->flags & PREALLOC) - continue; + /* generate the actual call */ - if (!md->params[i].inmemory) { - s1 = emit_load(jd, iptr, var, d); - - switch (var->type) { - case TYPE_INT: - case TYPE_ADR: - M_INTMOVE(s1, d); - break; + M_MTCTR(REG_PV); + M_JSR; + break; - case TYPE_LNG: - M_LNGMOVE(s1, d); - break; + case ICMD_INVOKEVIRTUAL:/* op1 = arg count, val.a = method pointer */ + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + um = iptr->sx.s23.s3.um; + patcher_add_patch_ref(jd, PATCHER_invokevirtual, um, 0); - case TYPE_FLT: - case TYPE_DBL: - M_FLTMOVE(s1, d); - break; - } - } - else { - switch (var->type) { - case TYPE_INT: - case TYPE_ADR: - s1 = emit_load(jd, iptr, var, REG_ITMP1); - M_IST(s1, REG_SP, d); - break; - - case TYPE_LNG: - s1 = emit_load(jd, iptr, var, REG_ITMP12_PACKED); - M_LST(s1, REG_SP, d); - break; - - case TYPE_FLT: - case TYPE_DBL: - s1 = emit_load(jd, iptr, var, REG_FTMP1); - M_DST(s1, REG_SP, d); - break; - } - } + s1 = 0; + } + else { + lm = iptr->sx.s23.s3.fmiref->p.method; + s1 = OFFSET(vftbl_t, table[0]) + + sizeof(methodptr) * lm->vftblindex; } - 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_ALD(REG_PV, REG_PV, disp); /* pointer to built-in-function */ - - /* generate the actual call */ - - M_MTCTR(REG_PV); - M_JSR; - REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr); - REPLACEMENT_POINT_FORGC_BUILTIN_RETURN(cd, iptr); - disp = (s4) (cd->mcodeptr - cd->mcodebase); - M_MFLR(REG_ITMP1); - M_LDA(REG_PV, REG_ITMP1, -disp); - 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, um); - - patcher_add_patch_ref(jd, PATCHER_invokestatic_special, - um, disp); - } - else - disp = dseg_add_address(cd, lm->stubroutine); - - M_ALD(REG_PV, REG_PV, disp); - - /* generate the actual call */ - - M_MTCTR(REG_PV); - M_JSR; - REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr); - disp = (s4) (cd->mcodeptr - cd->mcodebase); - M_MFLR(REG_ITMP1); - M_LDA(REG_PV, REG_ITMP1, -disp); - 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_ALD(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl)); - M_ALD(REG_PV, REG_METHODPTR, s1); - - /* generate the actual call */ - - M_MTCTR(REG_PV); - M_JSR; - REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr); - disp = (s4) (cd->mcodeptr - cd->mcodebase); - M_MFLR(REG_ITMP1); - M_LDA(REG_PV, REG_ITMP1, -disp); - break; - - case ICMD_INVOKEINTERFACE: - if (lm == NULL) { - patcher_add_patch_ref(jd, PATCHER_invokeinterface, um, 0); - - s1 = 0; - s2 = 0; - } - else { - s1 = OFFSET(vftbl_t, interfacetable[0]) - - sizeof(methodptr*) * lm->clazz->index; + /* implicit null-pointer check */ + M_ALD(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl)); + M_ALD(REG_PV, REG_METHODPTR, s1); - s2 = sizeof(methodptr) * (lm - lm->clazz->methods); - } + /* generate the actual call */ - /* implicit null-pointer check */ - M_ALD(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl)); - M_ALD(REG_METHODPTR, REG_METHODPTR, s1); - M_ALD(REG_PV, REG_METHODPTR, s2); + M_MTCTR(REG_PV); + M_JSR; + break; - /* generate the actual call */ + case ICMD_INVOKEINTERFACE: + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + um = iptr->sx.s23.s3.um; + patcher_add_patch_ref(jd, PATCHER_invokeinterface, um, 0); - M_MTCTR(REG_PV); - M_JSR; - REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr); - disp = (s4) (cd->mcodeptr - cd->mcodebase); - M_MFLR(REG_ITMP1); - M_LDA(REG_PV, REG_ITMP1, -disp); - break; + s1 = 0; + s2 = 0; } + else { + lm = iptr->sx.s23.s3.fmiref->p.method; + s1 = OFFSET(vftbl_t, interfacetable[0]) - + sizeof(methodptr*) * lm->clazz->index; - /* Store return value. */ + s2 = sizeof(methodptr) * (lm - lm->clazz->methods); + } - switch (md->returntype.type) { - case TYPE_INT: - case TYPE_ADR: - s1 = codegen_reg_of_dst(jd, iptr, REG_RESULT); - M_INTMOVE(REG_RESULT, s1); - emit_store_dst(jd, iptr, s1); - break; + /* implicit null-pointer check */ + M_ALD(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl)); + M_ALD(REG_METHODPTR, REG_METHODPTR, s1); + M_ALD(REG_PV, REG_METHODPTR, s2); - case TYPE_LNG: - s1 = codegen_reg_of_dst(jd, iptr, REG_RESULT_PACKED); - M_LNGMOVE(REG_RESULT_PACKED, s1); - emit_store_dst(jd, iptr, s1); - break; + /* generate the actual call */ - case TYPE_FLT: - case TYPE_DBL: - s1 = codegen_reg_of_dst(jd, iptr, REG_FRESULT); - M_FLTMOVE(REG_FRESULT, s1); - emit_store_dst(jd, iptr, s1); - break; - - case TYPE_VOID: - break; - } + M_MTCTR(REG_PV); + M_JSR; break; - case ICMD_CHECKCAST: /* ..., objectref ==> ..., objectref */ if (!(iptr->flags.bits & INS_FLAG_ARRAY)) { @@ -2827,23 +2148,8 @@ gen_method: break; default: - exceptions_throw_internalerror("Unknown ICMD %d during code generation", - iptr->opc); - return false; + vm_abort("Unknown ICMD %d during code generation", iptr->opc); } /* switch */ - - } /* for instruction */ - - } /* if (bptr -> flags >= BBREACHED) */ - } /* for basic block */ - - /* generate traps */ - - emit_patcher_traps(jd); - - /* everything's ok */ - - return true; } diff --git a/src/vm/jit/powerpc/codegen.h b/src/vm/jit/powerpc/codegen.h index 6081382ea..d8326aa4d 100644 --- a/src/vm/jit/powerpc/codegen.h +++ b/src/vm/jit/powerpc/codegen.h @@ -47,50 +47,13 @@ } while (0) -/* M_INTMOVE: - generates an integer-move from register a to b. - if a and b are the same int-register, no code will be generated. -*/ - -#define M_INTMOVE(a,b) \ - do { \ - if ((a) != (b)) { \ - M_MOV(a, b); \ - } \ - } while (0) - -#define M_LNGMOVE(a,b) \ - do { \ - if (GET_HIGH_REG(a) == GET_LOW_REG(b)) { \ - assert((GET_LOW_REG(a) != GET_HIGH_REG(b))); \ - M_INTMOVE(GET_HIGH_REG(a), GET_HIGH_REG(b)); \ - M_INTMOVE(GET_LOW_REG(a), GET_LOW_REG(b)); \ - } else { \ - M_INTMOVE(GET_LOW_REG(a), GET_LOW_REG(b)); \ - M_INTMOVE(GET_HIGH_REG(a), GET_HIGH_REG(b)); \ - } \ - } while (0) - - -/* M_FLTMOVE: - generates a floating-point-move from register a to b. - if a and b are the same float-register, no code will be generated -*/ - -#define M_FLTMOVE(a,b) \ - do { \ - if ((a) != (b)) { \ - M_FMOV(a, b); \ - } \ - } while (0) - - #define ICONST(d,c) emit_iconst(cd, (d), (c)) #define LCONST(reg,c) \ ICONST(GET_HIGH_REG((reg)), (s4) ((s8) (c) >> 32)); \ ICONST(GET_LOW_REG((reg)), (s4) ((s8) (c))); +#define M_DMOV(a,b) M_FMOV(a,b) #define ALIGNCODENOP \ if ((s4) ((ptrint) cd->mcodeptr & 7)) { \ @@ -407,6 +370,12 @@ #define M_AST_INTERN(a,b,disp) M_IST_INTERN(a,b,disp) #define M_AST(a,b,disp) M_IST(a,b,disp) +#define M_ACMP(a,b) M_CMP(a,b) +#define M_ICMP(a,b) M_CMP(a,b) + +#define M_TEST(a) M_TST(a) +#define M_ALD_DSEG(a,disp) M_ALD(a,REG_PV,disp); + /* floating point instructions ************************************************/ diff --git a/src/vm/jit/powerpc/emit.c b/src/vm/jit/powerpc/emit.c index 74adff082..1e35669c8 100644 --- a/src/vm/jit/powerpc/emit.c +++ b/src/vm/jit/powerpc/emit.c @@ -298,6 +298,26 @@ void emit_iconst(codegendata *cd, s4 d, s4 value) } +/** + * Emits code updating the condition register by comparing one integer + * register to an immediate integer value. + */ +void emit_icmp_imm(codegendata* cd, int reg, int32_t value) +{ + int32_t disp; + + if ((value >= -32768) && (value <= 32767)) { + M_CMPI(reg, value); + } + else { + assert(reg != REG_ITMP2); + disp = dseg_add_s4(cd, value); + M_ILD(REG_ITMP2, REG_PV, disp); + M_CMP(reg, REG_ITMP2); + } +} + + /* emit_branch ***************************************************************** Emits the code for conditional and unconditional branchs. @@ -556,6 +576,165 @@ uint32_t emit_trap(codegendata *cd) } +/** + * Emit code to recompute the procedure vector. + */ +void emit_recompute_pv(codegendata *cd) +{ + int32_t disp = (int32_t) (cd->mcodeptr - cd->mcodebase); + + M_MFLR(REG_ITMP1); + M_LDA(REG_PV, REG_ITMP1, -disp); +} + + +/** + * Generates synchronization code to enter a monitor. + */ +#if defined(ENABLE_THREADS) +void emit_monitor_enter(jitdata* jd, int32_t syncslot_offset) +{ + int32_t p; + int32_t disp; + + // Get required compiler data. + methodinfo* m = jd->m; + codegendata* cd = jd->cd; + +# if !defined(NDEBUG) + if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) { + M_AADD_IMM(REG_SP, -((LA_SIZE_IN_POINTERS + ARG_CNT) * 8), REG_SP); + + for (p = 0; p < INT_ARG_CNT; p++) + M_IST(abi_registers_integer_argument[p], REG_SP, LA_SIZE + p * 8); + + for (p = 0; p < FLT_ARG_CNT; p++) + M_DST(abi_registers_float_argument[p], REG_SP, LA_SIZE + (INT_ARG_CNT + p) * 8); + + syncslot_offset += (LA_SIZE_IN_POINTERS + ARG_CNT) * 8; + } +# endif + + disp = dseg_add_functionptr(cd, LOCK_monitor_enter); + M_ALD(REG_ITMP3, REG_PV, disp); + M_MTCTR(REG_ITMP3); + + /* get or test the lock object */ + + if (m->flags & ACC_STATIC) { + disp = dseg_add_address(cd, &m->clazz->object.header); + M_ALD(REG_A0, REG_PV, disp); + } + else { + M_TST(REG_A0); + M_BNE(1); + M_ALD_INTERN(REG_ZERO, REG_ZERO, TRAP_NullPointerException); + } + + M_AST(REG_A0, REG_SP, syncslot_offset); + M_JSR; + +# if !defined(NDEBUG) + if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) { + for (p = 0; p < INT_ARG_CNT; p++) + M_ILD(abi_registers_integer_argument[p], REG_SP, LA_SIZE + p * 8); + + for (p = 0; p < FLT_ARG_CNT; p++) + M_DLD(abi_registers_float_argument[p], REG_SP, LA_SIZE + (INT_ARG_CNT + p) * 8); + + M_AADD_IMM(REG_SP, (LA_SIZE_IN_POINTERS + ARG_CNT) * 8, REG_SP); + } +# endif +} +#endif + + +/** + * Generates synchronization code to leave a monitor. + */ +#if defined(ENABLE_THREADS) +void emit_monitor_exit(jitdata* jd, int32_t syncslot_offset) +{ + int32_t disp; + + // Get required compiler data. + methodinfo* m = jd->m; + codegendata* cd = jd->cd; + + disp = dseg_add_functionptr(cd, LOCK_monitor_exit); + M_ALD(REG_ITMP3, REG_PV, disp); + M_MTCTR(REG_ITMP3); + + /* we need to save the proper return value */ + + methoddesc* md = m->parseddesc; + + switch (md->returntype.type) { + case TYPE_LNG: + M_IST(REG_RESULT2, REG_SP, syncslot_offset + 8); + /* fall through */ + case TYPE_INT: + case TYPE_ADR: + M_IST(REG_RESULT , REG_SP, syncslot_offset + 4); + break; + case TYPE_FLT: + case TYPE_DBL: + M_DST(REG_FRESULT, REG_SP, syncslot_offset + 4); + break; + } + + M_ALD(REG_A0, REG_SP, syncslot_offset); + M_JSR; + + /* and now restore the proper return value */ + + switch (md->returntype.type) { + case TYPE_LNG: + M_ILD(REG_RESULT2, REG_SP, syncslot_offset + 8); + /* fall through */ + case TYPE_INT: + case TYPE_ADR: + M_ILD(REG_RESULT , REG_SP, syncslot_offset + 4); + break; + case TYPE_FLT: + case TYPE_DBL: + M_DLD(REG_FRESULT, REG_SP, syncslot_offset + 4); + break; + } +} +#endif + + +/** + * Emit profiling code for method frequency counting. + */ +#if defined(ENABLE_PROFILING) +void emit_profile_method(codegendata* cd, codeinfo* code) +{ + M_ALD(REG_ITMP1, REG_PV, CodeinfoPointer); + M_ALD(REG_ITMP2, REG_ITMP1, OFFSET(codeinfo, frequency)); + M_IADD_IMM(REG_ITMP2, 1, REG_ITMP2); + M_AST(REG_ITMP2, REG_ITMP1, OFFSET(codeinfo, frequency)); +} +#endif + + +/** + * Emit profiling code for basicblock frequency counting. + */ +#if defined(ENABLE_PROFILING) +void emit_profile_basicblock(codegendata* cd, codeinfo* code, basicblock* bptr) +{ + int32_t disp = dseg_add_address(cd, code->bbfrequency); + + M_ALD(REG_ITMP2, REG_PV, disp); + M_ALD(REG_ITMP3, REG_ITMP2, bptr->nr * 4); + M_IADD_IMM(REG_ITMP3, 1, REG_ITMP3); + M_AST(REG_ITMP3, REG_ITMP2, bptr->nr * 4); +} +#endif + + /* emit_verbosecall_enter ****************************************************** Generates the code for the call trace. diff --git a/src/vm/jit/powerpc/md.h b/src/vm/jit/powerpc/md.h index 33724ab14..e4f805281 100644 --- a/src/vm/jit/powerpc/md.h +++ b/src/vm/jit/powerpc/md.h @@ -40,6 +40,21 @@ #include "vm/jit/codegen-common.hpp" +/** + * Returns the size (in bytes) of the current stackframe, specified by + * the passed codeinfo structure. + */ +inline static int32_t md_stacktrace_get_framesize(codeinfo* code) +{ + // Check for the asm_vm_call_method special case. + if (code == NULL) + return 0; + + // On PowerPC we use 8-byte stackslots. + return code->stackframesize * 8; +} + + /* md_stacktrace_get_returnaddress ********************************************* Returns the return address of the current stackframe, specified by diff --git a/src/vm/jit/powerpc64/arch.h b/src/vm/jit/powerpc64/arch.h index b10b650f9..0488a1d7c 100644 --- a/src/vm/jit/powerpc64/arch.h +++ b/src/vm/jit/powerpc64/arch.h @@ -93,6 +93,14 @@ #define SUPPORT_BRANCH_CONDITIONAL_TWO_INTEGER_REGISTERS 0 +/* stackframe *****************************************************************/ + +#define STACKFRMAE_RA_BETWEEN_FRAMES 0 +#define STACKFRAME_RA_TOP_OF_FRAME 0 +#define STACKFRAME_LEAFMETHODS_RA_REGISTER 0 +#define STACKFRAME_SYNC_NEEDS_TWO_SLOTS 1 + + /* exceptions *****************************************************************/ #define SUPPORT_HARDWARE_DIVIDE_BY_ZERO 0 diff --git a/src/vm/jit/powerpc64/codegen.c b/src/vm/jit/powerpc64/codegen.c index 1c7831631..3873d3f17 100644 --- a/src/vm/jit/powerpc64/codegen.c +++ b/src/vm/jit/powerpc64/codegen.c @@ -1,6 +1,6 @@ /* src/vm/jit/powerpc64/codegen.c - machine code generator for 64-bit PowerPC - Copyright (C) 1996-2005, 2006, 2007, 2008 + Copyright (C) 1996-2005, 2006, 2007, 2008, 2009 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO This file is part of CACAO. @@ -62,109 +62,27 @@ #include "vm/jit/parse.hpp" #include "vm/jit/patcher-common.hpp" #include "vm/jit/reg.h" -#include "vm/jit/replace.hpp" #include "vm/jit/stacktrace.hpp" #include "vm/jit/trap.hpp" -#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 len, s1, s2, s3, d, disp; - ptrint a; - varinfo *var; - basicblock *bptr; - instruction *iptr; - u2 currentline; - methodinfo *lm; /* local methodinfo for ICMD_INVOKE* */ - unresolved_method *um; - builtintable_entry *bte; - methoddesc *md; - s4 fieldtype; - s4 varindex; - unresolved_field *uf; - fieldinfo *fi; - - /* get required compiler data */ - - m = jd->m; - code = jd->code; - cd = jd->cd; - rd = jd->rd; - - /* prevent compiler warnings */ - - d = 0; - lm = NULL; - um = NULL; - bte = NULL; - uf = NULL; - - { - s4 i, p, t, l; - s4 savedregs_num; - - savedregs_num = 0; - - /* space to save used callee saved registers */ - - savedregs_num += (INT_SAV_CNT - rd->savintreguse); - savedregs_num += (FLT_SAV_CNT - rd->savfltreguse); - - cd->stackframesize = rd->memuse + savedregs_num; - -#if defined(ENABLE_THREADS) - /* space to save argument of monitor_enter and Return Values to survive */ - /* monitor_exit. The stack position for the argument can not be shared */ - /* with place to save the return register on PPC64, since both values */ - /* reside in R3 */ - if (checksync && code_is_synchronized(code)) { - /* reserve 2 slots for long/double return values for monitorexit */ - cd->stackframesize += 2; - } - -#endif - - /* create method header */ - - /* align stack to 16-bytes */ - -/* FIXME */ -/* if (!m->isleafmethod || opt_verbosecall) */ -/* stackframesize = (stackframesize + 3) & ~3; -*/ -/* else if (m->isleafmethod && (stackframesize == LA_WORD_SIZE)) */ -/* stackframesize = 0; */ - - (void) dseg_add_unique_address(cd, code); /* CodeinfoPointer */ - (void) dseg_add_unique_s4(cd, cd->stackframesize * 8); /* 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 */ - - /* create stack frame (if necessary) */ + varinfo* var; + methoddesc* md; + int32_t s1; + int32_t p, t, l; + 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; if (!code_is_leafmethod(code)) { M_MFLR(REG_ZERO); @@ -217,7 +135,7 @@ bool codegen_emit(jitdata *jd) else { if (!md->params[p].inmemory) { if (!IS_INMEMORY(var->flags)) - M_FLTMOVE(s1, var->vv.regoff); + emit_fmove(cd, s1, var->vv.regoff); else M_DST(s1, REG_SP, var->vv.regoff); } @@ -233,206 +151,88 @@ bool codegen_emit(jitdata *jd) } } } +} - /* save monitorenter argument */ - -#if defined(ENABLE_THREADS) - - if (checksync && code_is_synchronized(code)) { - - /* stackoffset for argument used for LOCK_monitor_exit */ - s1 = rd->memuse; - -#if !defined (NDEBUG) - if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) { - M_AADD_IMM(REG_SP, -((LA_SIZE_IN_POINTERS + PA_SIZE_IN_POINTERS + ARG_CNT) * 8), REG_SP); - - for (p = 0; p < INT_ARG_CNT; p++) - M_LST(abi_registers_integer_argument[p], REG_SP, LA_SIZE + PA_SIZE + p * 8); - - for (p = 0; p < FLT_ARG_CNT; p++) - M_DST(abi_registers_float_argument[p], REG_SP, LA_SIZE + PA_SIZE + (INT_ARG_CNT + p) * 8); - - /* used for LOCK_monitor_exit, adopt size because we created another stackframe */ - s1 += (LA_SIZE_IN_POINTERS + PA_SIZE_IN_POINTERS + ARG_CNT); - } -#endif - - p = dseg_add_functionptr(cd, LOCK_monitor_enter); - M_ALD(REG_ITMP3, REG_PV, p); - M_ALD(REG_ITMP3, REG_ITMP3, 0); /* TOC */ - M_MTCTR(REG_ITMP3); - /* get or test the lock object */ +/** + * Generates machine code for the method epilog. + */ +void codegen_emit_epilog(jitdata* jd) +{ + int32_t p; + int i; - if (m->flags & ACC_STATIC) { - p = dseg_add_address(cd, &m->clazz->object.header); - M_ALD(REG_A0, REG_PV, p); - } - else { - M_TST(REG_A0); - M_BNE(1); - M_ALD_INTERN(REG_ZERO, REG_ZERO, TRAP_NullPointerException); - } + // Get required compiler data. + codeinfo* code = jd->code; + codegendata* cd = jd->cd; + registerdata* rd = jd->rd; - M_AST(REG_A0, REG_SP, s1 * 8); /* rd->memuse * 8 */ - M_JSR; + p = cd->stackframesize; -#if !defined(NDEBUG) - if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) { - for (p = 0; p < INT_ARG_CNT; p++) - M_LLD(abi_registers_integer_argument[p], REG_SP, LA_SIZE + PA_SIZE + p * 8); + /* restore return address */ - for (p = 0; p < FLT_ARG_CNT; p++) - M_DLD(abi_registers_float_argument[p], REG_SP, LA_SIZE + PA_SIZE + (INT_ARG_CNT + p) * 8); + if (!code_is_leafmethod(code)) { + /* ATTENTION: Don't use REG_ZERO (r0) here, as M_ALD + may have a displacement overflow. */ - M_AADD_IMM(REG_SP, (LA_SIZE_IN_POINTERS + PA_SIZE_IN_POINTERS + ARG_CNT) * 8, REG_SP); - } -#endif + M_ALD(REG_ITMP1, REG_SP, p * 8 + LA_LR_OFFSET); + M_MTLR(REG_ITMP1); } -#endif - /* call trace function */ -#if !defined (NDEBUG) - if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) - emit_verbosecall_enter(jd); -#endif + /* restore saved registers */ + for (i = INT_SAV_CNT - 1; i >= rd->savintreguse; i--) { + p--; M_LLD(rd->savintregs[i], REG_SP, p * 8); + } + for (i = FLT_SAV_CNT - 1; i >= rd->savfltreguse; i--) { + p--; M_DLD(rd->savfltregs[i], REG_SP, p * 8); } - /* end of header generation */ - - /* create replacement points */ - - REPLACEMENT_POINTS_INIT(cd, jd); - - /* walk through all basic blocks */ - - for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) { - - bptr->mpc = (s4) (cd->mcodeptr - cd->mcodebase); - - if (bptr->flags >= BBREACHED) { - - /* branch resolving */ - codegen_resolve_branchrefs(cd, bptr); - - /* handle replacement points */ - - REPLACEMENT_POINT_BLOCK_START(cd, bptr); - - /* copy interface registers to their destination */ - - len = bptr->indepth; - MCODECHECK(128+len); - -#if defined(ENABLE_LSRA) - if (opt_lsra) { - while (len) { - len--; - var = VAR(bptr->invars[len]); - if ((len == bptr->indepth-1) && (bptr->type == BBTYPE_EXH)) { - /* d = reg_of_var(m, var, REG_ITMP1); */ - 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]); - 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 - /* walk through all instructions */ - - len = bptr->icount; - currentline = 0; - - for (iptr = bptr->iinstr; len > 0; len--, iptr++) { - if (iptr->line != currentline) { - linenumbertable_list_entry_add(cd, iptr->line); - currentline = iptr->line; - } - - MCODECHECK(128); /* an instruction usually needs < 64 words */ - - switch (iptr->opc) { - case ICMD_NOP: /* ... ==> ... */ - case ICMD_POP: /* ..., value ==> ... */ - case ICMD_POP2: /* ..., value, value ==> ... */ - break; - - case ICMD_INLINE_START: + /* deallocate stack */ - REPLACEMENT_POINT_INLINE_START(cd, iptr); - break; - - case ICMD_INLINE_BODY: - - REPLACEMENT_POINT_INLINE_BODY(cd, iptr); - linenumbertable_list_entry_add_inline_start(cd, iptr); - linenumbertable_list_entry_add(cd, iptr->line); - break; - - case ICMD_INLINE_END: + if (cd->stackframesize) + M_LDA(REG_SP, REG_SP, cd->stackframesize * 8); - linenumbertable_list_entry_add_inline_end(cd, iptr); - linenumbertable_list_entry_add(cd, iptr->line); - break; + M_RET; +} - case ICMD_CHECKNULL: /* ..., objectref ==> ..., objectref */ - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - M_TST(s1); - M_BEQ(0); - emit_nullpointer_check(cd, iptr, s1); - break; +/** + * Generates machine code for one ICMD. + */ +void codegen_emit_instruction(jitdata* jd, instruction* iptr) +{ + varinfo* var; + builtintable_entry* bte; + 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. + codeinfo* code = jd->code; + codegendata* cd = jd->cd; + + 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_LCONST: /* ... ==> ..., constant */ - - d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); - LCONST(d, iptr->sx.val.l); - emit_store_dst(jd, iptr, d); - break; - case ICMD_FCONST: /* ... ==> ..., constant */ d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); - a = dseg_add_float(cd, iptr->sx.val.f); - M_FLD(d, REG_PV, a); + disp = dseg_add_float(cd, iptr->sx.val.f); + M_FLD(d, REG_PV, disp); emit_store_dst(jd, iptr, d); break; case ICMD_DCONST: /* ... ==> ..., constant */ d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); - a = dseg_add_double(cd, iptr->sx.val.d); - M_DLD(d, REG_PV, a); + disp = dseg_add_double(cd, iptr->sx.val.d); + M_DLD(d, REG_PV, disp); emit_store_dst(jd, iptr, d); break; @@ -453,29 +253,6 @@ bool codegen_emit(jitdata *jd) break; - /* load/store/copy/move operations ************************************/ - - case ICMD_ILOAD: /* ... ==> ..., content of local variable */ - case ICMD_ALOAD: /* s1.localindex = local variable */ - case ICMD_LLOAD: - case ICMD_FLOAD: - case ICMD_DLOAD: - case ICMD_ISTORE: /* ..., value ==> ... */ - case ICMD_LSTORE: - case ICMD_FSTORE: - 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_INEG: /* ..., value ==> ..., - value */ @@ -1167,7 +944,7 @@ bool codegen_emit(jitdata *jd) s1 = emit_load_s1(jd, iptr, REG_FTMP1); d = codegen_reg_of_dst(jd, iptr, REG_FTMP3); - M_FLTMOVE(s1, d); + emit_fmove(cd, s1, d); emit_store_dst(jd, iptr, d); break; @@ -1214,15 +991,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); - emit_nullpointer_check(cd, iptr, s1); - M_ILD(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); @@ -1437,101 +1205,6 @@ bool codegen_emit(jitdata *jd) M_ASTX(s3, s1, REG_ITMP2); 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, - iptr->sx.s23.s3.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, disp); - } - } - - M_ALD(REG_ITMP1, REG_PV, disp); - switch (fieldtype) { - case TYPE_INT: - d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); - M_ILD_INTERN(d, REG_ITMP1, 0); - break; - case TYPE_LNG: - d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); - M_LLD(d, REG_ITMP1, 0); - break; - case TYPE_ADR: - d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); - M_ALD_INTERN(d, REG_ITMP1, 0); - break; - case TYPE_FLT: - d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); - M_FLD_INTERN(d, REG_ITMP1, 0); - break; - case TYPE_DBL: - d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); - M_DLD_INTERN(d, REG_ITMP1, 0); - break; - } - 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, - iptr->sx.s23.s3.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, disp); - } - } - - M_ALD(REG_ITMP1, REG_PV, disp); - switch (fieldtype) { - case TYPE_INT: - s1 = emit_load_s1(jd, iptr, REG_ITMP2); - M_IST_INTERN(s1, REG_ITMP1, 0); - break; - case TYPE_LNG: - s1 = emit_load_s1(jd, iptr, REG_ITMP2); - M_LST_INTERN(s1, REG_ITMP1, 0); - break; - case TYPE_ADR: - s1 = emit_load_s1(jd, iptr, REG_ITMP2); - M_AST_INTERN(s1, REG_ITMP1, 0); - break; - case TYPE_FLT: - s1 = emit_load_s1(jd, iptr, REG_FTMP2); - M_FST_INTERN(s1, REG_ITMP1, 0); - break; - case TYPE_DBL: - s1 = emit_load_s1(jd, iptr, REG_FTMP2); - M_DST_INTERN(s1, REG_ITMP1, 0); - break; - } - break; - - case ICMD_GETFIELD: /* ... ==> ..., value */ s1 = emit_load_s1(jd, iptr, REG_ITMP1); @@ -1626,16 +1299,6 @@ bool codegen_emit(jitdata *jd) case ICMD_ATHROW: /* ..., objectref ==> ... (, objectref) */ - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - M_LNGMOVE(s1, REG_ITMP1_XPTR); - -#ifdef ENABLE_VERIFIER - if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - patcher_add_patch_ref(jd, PATCHER_resolve_class, - iptr->sx.s23.s2.uc, 0); - } -#endif /* ENABLE_VERIFIER */ - disp = dseg_add_functionptr(cd, asm_handle_exception); M_ALD(REG_ITMP2, REG_PV, disp); M_MTCTR(REG_ITMP2); @@ -1650,53 +1313,8 @@ bool codegen_emit(jitdata *jd) M_MTLR(REG_ITMP3); /* restore LR */ M_RTS; /* jump to CTR */ - ALIGNCODENOP; - break; - - case ICMD_GOTO: /* ... ==> ... */ - case ICMD_RET: /* ... ==> ... */ - - emit_br(cd, iptr->dst.block); - ALIGNCODENOP; - break; - - case ICMD_JSR: /* ... ==> ... */ - - emit_br(cd, iptr->sx.s23.s3.jsrtarget.block); - ALIGNCODENOP; - break; - - case ICMD_IFNULL: /* ..., value ==> ... */ - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - M_TST(s1); - emit_beq(cd, iptr->dst.block); break; - case ICMD_IFNONNULL: /* ..., value ==> ... */ - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - M_TST(s1); - emit_bne(cd, iptr->dst.block); - break; - - case ICMD_IFLT: - case ICMD_IFLE: - case ICMD_IFNE: - case ICMD_IFGT: - case ICMD_IFGE: - case ICMD_IFEQ: /* ..., value ==> ... */ - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - if ((iptr->sx.val.i >= -32768) && (iptr->sx.val.i <= 32767)) - M_CMPI(s1, iptr->sx.val.i); - else { - ICONST(REG_ITMP2, iptr->sx.val.i); - M_CMP(s1, REG_ITMP2); - } - emit_bcc(cd, iptr->dst.block, iptr->opc - ICMD_IFEQ, BRANCH_OPT_NONE); - break; - case ICMD_IF_LEQ: /* ..., value ==> ... */ s1 = emit_load_s1(jd, iptr, REG_ITMP1); LCONST(REG_ITMP2, iptr->sx.val.l); @@ -1734,9 +1352,7 @@ bool codegen_emit(jitdata *jd) M_CMP(s1, REG_ITMP2); emit_bgt(cd, iptr->dst.block); break; - case ICMD_IF_ICMPEQ: /* ..., value, value ==> ... */ - case ICMD_IF_ACMPEQ: /* op1 = target JavaVM pc */ - case ICMD_IF_LCMPEQ: + case ICMD_IF_LCMPEQ: /* ..., value, value ==> ... */ s1 = emit_load_s1(jd, iptr, REG_ITMP1); s2 = emit_load_s2(jd, iptr, REG_ITMP2); @@ -1744,9 +1360,7 @@ bool codegen_emit(jitdata *jd) emit_beq(cd, iptr->dst.block); break; - case ICMD_IF_ICMPNE: /* ..., value, value ==> ... */ - case ICMD_IF_ACMPNE: /* op1 = target JavaVM pc */ - case ICMD_IF_LCMPNE: + case ICMD_IF_LCMPNE: /* ..., value, value ==> ... */ s1 = emit_load_s1(jd, iptr, REG_ITMP1); s2 = emit_load_s2(jd, iptr, REG_ITMP2); @@ -1755,8 +1369,7 @@ bool codegen_emit(jitdata *jd) break; - case ICMD_IF_ICMPLT: /* ..., value, value ==> ... */ - case ICMD_IF_LCMPLT: + case ICMD_IF_LCMPLT: /* ..., value, value ==> ... */ s1 = emit_load_s1(jd, iptr, REG_ITMP1); s2 = emit_load_s2(jd, iptr, REG_ITMP2); @@ -1764,8 +1377,7 @@ bool codegen_emit(jitdata *jd) emit_blt(cd, iptr->dst.block); break; - case ICMD_IF_ICMPGT: /* ..., value, value ==> ... */ - case ICMD_IF_LCMPGT: + case ICMD_IF_LCMPGT: /* ..., value, value ==> ... */ s1 = emit_load_s1(jd, iptr, REG_ITMP1); s2 = emit_load_s2(jd, iptr, REG_ITMP2); @@ -1773,8 +1385,7 @@ bool codegen_emit(jitdata *jd) emit_bgt(cd, iptr->dst.block); break; - case ICMD_IF_ICMPLE: /* ..., value, value ==> ... */ - case ICMD_IF_LCMPLE: + case ICMD_IF_LCMPLE: /* ..., value, value ==> ... */ s1 = emit_load_s1(jd, iptr, REG_ITMP1); s2 = emit_load_s2(jd, iptr, REG_ITMP2); @@ -1782,8 +1393,7 @@ bool codegen_emit(jitdata *jd) emit_ble(cd, iptr->dst.block); break; - case ICMD_IF_ICMPGE: /* ..., value, value ==> ... */ - case ICMD_IF_LCMPGE: + case ICMD_IF_LCMPGE: /* ..., value, value ==> ... */ s1 = emit_load_s1(jd, iptr, REG_ITMP1); s2 = emit_load_s2(jd, iptr, REG_ITMP2); @@ -1791,131 +1401,6 @@ bool codegen_emit(jitdata *jd) emit_bge(cd, iptr->dst.block); break; - - case ICMD_LRETURN: /* ..., retvalue ==> ... */ - case ICMD_IRETURN: /* ..., retvalue ==> ... */ - - REPLACEMENT_POINT_RETURN(cd, iptr); - s1 = emit_load_s1(jd, iptr, REG_RESULT); - M_LNGMOVE(s1, REG_RESULT); - goto nowperformreturn; - - case ICMD_ARETURN: /* ..., retvalue ==> ... */ - - REPLACEMENT_POINT_RETURN(cd, iptr); - s1 = emit_load_s1(jd, iptr, REG_RESULT); - M_LNGMOVE(s1, REG_RESULT); - -#ifdef ENABLE_VERIFIER - if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - patcher_add_patch_ref(jd, PATCHER_resolve_class, - iptr->sx.s23.s2.uc, 0); - } -#endif /* ENABLE_VERIFIER */ - - goto nowperformreturn; - - case ICMD_FRETURN: /* ..., retvalue ==> ... */ - case ICMD_DRETURN: - - REPLACEMENT_POINT_RETURN(cd, iptr); - s1 = emit_load_s1(jd, iptr, REG_FRESULT); - M_FLTMOVE(s1, REG_FRESULT); - goto nowperformreturn; - - case ICMD_RETURN: /* ... ==> ... */ - - REPLACEMENT_POINT_RETURN(cd, iptr); - -nowperformreturn: - { - s4 i, p; - - p = cd->stackframesize; - - /* call trace function */ - -#if !defined(NDEBUG) - if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) - emit_verbosecall_exit(jd); -#endif - -#if defined(ENABLE_THREADS) - if (checksync && code_is_synchronized(code)) { - disp = dseg_add_functionptr(cd, LOCK_monitor_exit); - M_ALD(REG_ITMP3, REG_PV, disp); - M_ALD(REG_ITMP3, REG_ITMP3, 0); /* TOC */ - M_MTCTR(REG_ITMP3); - - /* we need to save the proper return value */ - - switch (iptr->opc) { - case ICMD_LRETURN: - case ICMD_IRETURN: - case ICMD_ARETURN: - /* fall through */ - M_LST(REG_RESULT , REG_SP, rd->memuse * 8 + 8); - break; - case ICMD_FRETURN: - M_FST(REG_FRESULT, REG_SP, rd->memuse * 8 + 8); - break; - case ICMD_DRETURN: - M_DST(REG_FRESULT, REG_SP, rd->memuse * 8 + 8); - break; - } - - M_ALD(REG_A0, REG_SP, rd->memuse * 8); - M_JSR; - - /* and now restore the proper return value */ - - switch (iptr->opc) { - case ICMD_LRETURN: - case ICMD_IRETURN: - case ICMD_ARETURN: - /* fall through */ - M_LLD(REG_RESULT , REG_SP, rd->memuse * 8 + 8); - break; - case ICMD_FRETURN: - M_FLD(REG_FRESULT, REG_SP, rd->memuse * 8 + 8); - break; - case ICMD_DRETURN: - M_DLD(REG_FRESULT, REG_SP, rd->memuse * 8 + 8); - break; - } - } -#endif - - /* restore return address */ - - if (!code_is_leafmethod(code)) { - /* ATTENTION: Don't use REG_ZERO (r0) here, as M_ALD - may have a displacement overflow. */ - - M_ALD(REG_ITMP1, REG_SP, p * 8 + LA_LR_OFFSET); - M_MTLR(REG_ITMP1); - } - - /* restore saved registers */ - - for (i = INT_SAV_CNT - 1; i >= rd->savintreguse; i--) { - p--; M_LLD(rd->savintregs[i], REG_SP, p * 8); - } - for (i = FLT_SAV_CNT - 1; i >= rd->savfltreguse; i--) { - p--; M_DLD(rd->savfltregs[i], REG_SP, p * 8); - } - - /* deallocate stack */ - - if (cd->stackframesize) - M_LDA(REG_SP, REG_SP, cd->stackframesize * 8); - - M_RET; - ALIGNCODENOP; - } - break; - - case ICMD_TABLESWITCH: /* ..., index ==> ... */ { s4 i, l; @@ -1965,212 +1450,92 @@ nowperformreturn: break; - case ICMD_LOOKUPSWITCH: /* ..., key ==> ... */ - { - s4 i, val; - lookup_target_t *lookup; - - lookup = iptr->dst.lookup; - - i = iptr->sx.s23.s2.lookupcount; - - MCODECHECK((i<<3)+8); - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - while (--i >= 0) { - val = lookup->value; - if ((val >= -32768) && (val <= 32767)) { - M_CMPI(s1, val); - - } else { - a = dseg_add_s4(cd, val); - M_ILD(REG_ITMP2, REG_PV, a); - M_CMP(s1, REG_ITMP2); - } - emit_beq(cd, lookup->target.block); - ++lookup; + case ICMD_BUILTIN: /* ..., [arg1, [arg2 ...]] ==> ... */ + bte = iptr->sx.s23.s3.bte; + if (bte->stub == NULL) { + disp = dseg_add_functionptr(cd, bte->fp); + M_ALD(REG_PV, REG_PV, disp); + M_ALD(REG_PV, REG_PV, 0); /* TOC */ } - - emit_br(cd, iptr->sx.s23.s3.lookupdefault.block); - - ALIGNCODENOP; - break; + else { + disp = dseg_add_functionptr(cd, bte->stub); + M_ALD(REG_PV, REG_PV, disp); } + /* generate the actual call */ + M_MTCTR(REG_PV); + M_JSR; + break; - case ICMD_BUILTIN: /* ..., [arg1, [arg2 ...]] ==> ... */ - - bte = iptr->sx.s23.s3.bte; - md = bte->md; - goto gen_method; - - case ICMD_INVOKESTATIC: /* ..., [arg1, [arg2 ...]] ==> ... */ case ICMD_INVOKESPECIAL:/* ..., objectref, [arg1, [arg2 ...]] ==> ... */ - case ICMD_INVOKEVIRTUAL:/* op1 = arg count, val.a = method pointer */ - case ICMD_INVOKEINTERFACE: - - REPLACEMENT_POINT_INVOKE(cd, iptr); + emit_nullpointer_check(cd, iptr, REG_A0); + /* fall through */ + case ICMD_INVOKESTATIC: /* ..., [arg1, [arg2 ...]] ==> ... */ if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - lm = NULL; um = iptr->sx.s23.s3.um; - md = um->methodref->parseddesc.md; - } - else { + disp = dseg_add_unique_address(cd, um); + + patcher_add_patch_ref(jd, PATCHER_invokestatic_special, + um, disp); + } else { lm = iptr->sx.s23.s3.fmiref->p.method; - um = NULL; - md = lm->parseddesc; + disp = dseg_add_address(cd, lm->stubroutine); } + M_ALD(REG_PV, REG_PV, disp); -gen_method: - s3 = md->paramcount; - - MCODECHECK((s3 << 2) + 128); - - /* copy arguments to registers or stack location */ - - for (s3 = s3 - 1; s3 >= 0; s3--) { - var = VAR(iptr->sx.s23.s2.args[s3]); - d = md->params[s3].regoff; + /* generate the actual call */ - if (var->flags & PREALLOC) - continue; + M_MTCTR(REG_PV); + M_JSR; + break; - if (IS_INT_LNG_TYPE(var->type)) { - if (!md->params[s3].inmemory) { - s1 = emit_load(jd, iptr, var, d); - M_LNGMOVE(s1, d); - } - else { - s1 = emit_load(jd, iptr, var, REG_ITMP1); - M_LST(s1, REG_SP, d); - } - } - else { - if (!md->params[s3].inmemory) { - s1 = emit_load(jd, iptr, var, d); - M_FLTMOVE(s1, d); - } - else { - s1 = emit_load(jd, iptr, var, REG_FTMP1); - M_DST(s1, REG_SP, d); - } - } + case ICMD_INVOKEVIRTUAL:/* op1 = arg count, val.a = method pointer */ + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + um = iptr->sx.s23.s3.um; + patcher_add_patch_ref(jd, PATCHER_invokevirtual, um, 0); + s1 = 0; + } else { + lm = iptr->sx.s23.s3.fmiref->p.method; + s1 = OFFSET(vftbl_t, table[0]) + + sizeof(methodptr) * lm->vftblindex; } - switch (iptr->opc) { - case ICMD_BUILTIN: - if (bte->stub == NULL) { - disp = dseg_add_functionptr(cd, bte->fp); - M_ALD(REG_PV, REG_PV, disp); - M_ALD(REG_PV, REG_PV, 0); /* TOC */ - } - else { - disp = dseg_add_functionptr(cd, bte->stub); - M_ALD(REG_PV, REG_PV, disp); - } - - /* generate the actual call */ - M_MTCTR(REG_PV); - M_JSR; - REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr); - disp = (s4) (cd->mcodeptr - cd->mcodebase); - M_MFLR(REG_ITMP1); - M_LDA(REG_PV, REG_ITMP1, -disp); - 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, um); - - patcher_add_patch_ref(jd, PATCHER_invokestatic_special, - um, disp); - } else { - disp = dseg_add_address(cd, lm->stubroutine); - } - M_ALD(REG_PV, REG_PV, disp); - - /* generate the actual call */ - - M_MTCTR(REG_PV); - M_JSR; - REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr); - disp = (s4) (cd->mcodeptr - cd->mcodebase); - M_MFLR(REG_ITMP1); - M_LDA(REG_PV, REG_ITMP1, -disp); - 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_ALD(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl)); - M_ALD(REG_PV, REG_METHODPTR, s1); - - /* generate the actual call */ - - M_MTCTR(REG_PV); - M_JSR; - REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr); - disp = (s4) (cd->mcodeptr - cd->mcodebase); - M_MFLR(REG_ITMP1); - M_LDA(REG_PV, REG_ITMP1, -disp); - break; - - case ICMD_INVOKEINTERFACE: - if (lm == NULL) { - patcher_add_patch_ref(jd, PATCHER_invokeinterface, um, 0); + /* implicit null-pointer check */ + M_ALD(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl)); + M_ALD(REG_PV, REG_METHODPTR, s1); - s1 = 0; - s2 = 0; + /* generate the actual call */ - } else { - s1 = OFFSET(vftbl_t, interfacetable[0]) - - sizeof(methodptr*) * lm->clazz->index; - - s2 = sizeof(methodptr) * (lm - lm->clazz->methods); - } + M_MTCTR(REG_PV); + M_JSR; + break; - /* implicit null-pointer check */ - M_ALD(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl)); - M_ALD(REG_METHODPTR, REG_METHODPTR, s1); - M_ALD(REG_PV, REG_METHODPTR, s2); + case ICMD_INVOKEINTERFACE: + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + um = iptr->sx.s23.s3.um; + patcher_add_patch_ref(jd, PATCHER_invokeinterface, um, 0); - /* generate the actual call */ + s1 = 0; + s2 = 0; - M_MTCTR(REG_PV); - M_JSR; - REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr); - disp = (s4) (cd->mcodeptr - cd->mcodebase); - M_MFLR(REG_ITMP1); - M_LDA(REG_PV, REG_ITMP1, -disp); + } else { + lm = iptr->sx.s23.s3.fmiref->p.method; + s1 = OFFSET(vftbl_t, interfacetable[0]) - + sizeof(methodptr*) * lm->clazz->index; - break; + s2 = sizeof(methodptr) * (lm - lm->clazz->methods); } - /* store return value */ - d = md->returntype.type; + /* implicit null-pointer check */ + M_ALD(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl)); + M_ALD(REG_METHODPTR, REG_METHODPTR, s1); + M_ALD(REG_PV, REG_METHODPTR, s2); - if (d != TYPE_VOID) { - if (IS_INT_LNG_TYPE(d)) { - s1 = codegen_reg_of_dst(jd, iptr, REG_RESULT); - M_MOV(REG_RESULT, s1); - } - else { - s1 = codegen_reg_of_dst(jd, iptr, REG_FRESULT); - M_FLTMOVE(REG_FRESULT, s1); - } - emit_store_dst(jd, iptr, s1); - } + /* generate the actual call */ + + M_MTCTR(REG_PV); + M_JSR; break; case ICMD_CHECKCAST: /* ..., objectref ==> ..., objectref */ @@ -2605,23 +1970,8 @@ gen_method: break; default: - exceptions_throw_internalerror("Unknown ICMD %d during code generation", - iptr->opc); - return false; + vm_abort("Unknown ICMD %d during code generation", iptr->opc); } /* switch */ - - } /* for instruction */ - - } /* if (bptr -> flags >= BBREACHED) */ - } /* for basic block */ - - /* generate traps */ - - emit_patcher_traps(jd); - - /* everything's ok */ - - return true; } diff --git a/src/vm/jit/powerpc64/codegen.h b/src/vm/jit/powerpc64/codegen.h index ca1a20a0d..f8f47e9d3 100644 --- a/src/vm/jit/powerpc64/codegen.h +++ b/src/vm/jit/powerpc64/codegen.h @@ -47,34 +47,6 @@ } while (0) -/* M_INTMOVE: - generates an integer-move from register a to b. - if a and b are the same int-register, no code will be generated. -*/ - -#define M_INTMOVE(a,b) \ - do { \ - if ((a) != (b)) { \ - M_MOV(a, b); \ - } \ - } while (0) - -#define M_LNGMOVE(a,b) M_INTMOVE(a,b) - - -/* M_FLTMOVE: - generates a floating-point-move from register a to b. - if a and b are the same float-register, no code will be generated -*/ - -#define M_FLTMOVE(a,b) \ - do { \ - if ((a) != (b)) { \ - M_FMOV(a, b); \ - } \ - } while (0) - - #define ICONST(d,c) emit_iconst(cd, (d), (c)) #define LCONST(reg,c) emit_lconst(cd, (reg), (c)) @@ -322,6 +294,7 @@ #define M_ALD_INTERN(a,b,disp) M_LLD_INTERN(a,b,disp) #define M_ALD(a,b,disp) M_LLD(a,b,disp) +#define M_ALD_DSEG(a,disp) M_LLD(a,REG_PV,disp) #define M_ALDX(a,b,c) M_OP3(31, 21, 0, 0, a, b, c) /* LDX */ #define M_BST(a,b,c) M_OP2_IMM(38, a, b, c) /* STB */ @@ -470,6 +443,13 @@ #define M_CLR_HIGH(a) M_OP3(30, 0, 0, 0x20, (a), (a), 0); #define M_AADD_IMM(a,b,c) M_LADD_IMM(a, b, c) +#define M_DMOV(a,b) M_FMOV(a,b) + +#define M_ACMP(a,b) M_CMP(a,b) +#define M_ICMP(a,b) M_CMP(a,b) + +#define M_TEST(a) M_TST(a) + #endif /* _CODEGEN_H */ diff --git a/src/vm/jit/powerpc64/emit.c b/src/vm/jit/powerpc64/emit.c index a969a3bc5..62e2616a1 100644 --- a/src/vm/jit/powerpc64/emit.c +++ b/src/vm/jit/powerpc64/emit.c @@ -196,6 +196,146 @@ void emit_lconst(codegendata *cd, s4 d, s8 value) } +/** + * Emits code updating the condition register by comparing one integer + * register to an immediate integer value. + */ +void emit_icmp_imm(codegendata* cd, int reg, int32_t value) +{ + int32_t disp; + + if ((value >= -32768) && (value <= 32767)) { + M_CMPI(reg, value); + } else { + assert(reg != REG_ITMP2); + disp = dseg_add_s4(cd, value); + M_ILD(REG_ITMP2, REG_PV, disp); + M_CMP(reg, REG_ITMP2); + } +} + + +/** + * Generates synchronization code to enter a monitor. + */ +#if defined(ENABLE_THREADS) +void emit_monitor_enter(jitdata* jd, int32_t syncslot_offset) +{ + int32_t p; + + // Get required compiler data. + methodinfo* m = jd->m; + codegendata* cd = jd->cd; + +#if !defined (NDEBUG) + if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) { + M_AADD_IMM(REG_SP, -((LA_SIZE_IN_POINTERS + PA_SIZE_IN_POINTERS + ARG_CNT) * 8), REG_SP); + + for (p = 0; p < INT_ARG_CNT; p++) + M_LST(abi_registers_integer_argument[p], REG_SP, LA_SIZE + PA_SIZE + p * 8); + + for (p = 0; p < FLT_ARG_CNT; p++) + M_DST(abi_registers_float_argument[p], REG_SP, LA_SIZE + PA_SIZE + (INT_ARG_CNT + p) * 8); + + /* used for LOCK_monitor_exit, adopt size because we created another stackframe */ + syncslot_offset += (LA_SIZE_IN_POINTERS + PA_SIZE_IN_POINTERS + ARG_CNT) * 8; + } +#endif + + p = dseg_add_functionptr(cd, LOCK_monitor_enter); + M_ALD(REG_ITMP3, REG_PV, p); + M_ALD(REG_ITMP3, REG_ITMP3, 0); /* TOC */ + M_MTCTR(REG_ITMP3); + + /* get or test the lock object */ + + if (m->flags & ACC_STATIC) { + p = dseg_add_address(cd, &m->clazz->object.header); + M_ALD(REG_A0, REG_PV, p); + } + else { + M_TST(REG_A0); + M_BNE(1); + M_ALD_INTERN(REG_ZERO, REG_ZERO, TRAP_NullPointerException); + } + + M_AST(REG_A0, REG_SP, syncslot_offset); + M_JSR; + +#if !defined(NDEBUG) + if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) { + for (p = 0; p < INT_ARG_CNT; p++) + M_LLD(abi_registers_integer_argument[p], REG_SP, LA_SIZE + PA_SIZE + p * 8); + + for (p = 0; p < FLT_ARG_CNT; p++) + M_DLD(abi_registers_float_argument[p], REG_SP, LA_SIZE + PA_SIZE + (INT_ARG_CNT + p) * 8); + + M_AADD_IMM(REG_SP, (LA_SIZE_IN_POINTERS + PA_SIZE_IN_POINTERS + ARG_CNT) * 8, REG_SP); + } +#endif +} +#endif + + +/** + * Generates synchronization code to leave a monitor. + */ +#if defined(ENABLE_THREADS) +void emit_monitor_exit(jitdata* jd, int32_t syncslot_offset) +{ + int32_t disp; + + // Get required compiler data. + methodinfo* m = jd->m; + codegendata* cd = jd->cd; + + disp = dseg_add_functionptr(cd, LOCK_monitor_exit); + M_ALD(REG_ITMP3, REG_PV, disp); + M_ALD(REG_ITMP3, REG_ITMP3, 0); /* TOC */ + M_MTCTR(REG_ITMP3); + + /* we need to save the proper return value */ + + methoddesc* md = m->parseddesc; + + switch (md->returntype.type) { + case TYPE_LNG: + case TYPE_INT: + case TYPE_ADR: + /* fall through */ + M_LST(REG_RESULT , REG_SP, syncslot_offset + 8); + break; + case TYPE_FLT: + M_FST(REG_FRESULT, REG_SP, syncslot_offset + 8); + break; + case TYPE_DBL: + M_DST(REG_FRESULT, REG_SP, syncslot_offset + 8); + break; + } + + M_ALD(REG_A0, REG_SP, syncslot_offset); + M_JSR; + + /* and now restore the proper return value */ + + switch (md->returntype.type) { + case TYPE_LNG: + case TYPE_INT: + case TYPE_ADR: + /* fall through */ + M_LLD(REG_RESULT , REG_SP, syncslot_offset + 8); + break; + case TYPE_FLT: + M_FLD(REG_FRESULT, REG_SP, syncslot_offset + 8); + break; + case TYPE_DBL: + M_DLD(REG_FRESULT, REG_SP, syncslot_offset + 8); + break; + } +} +#endif + + /* emit_verbosecall_enter ****************************************************** Generates the code for the call trace. @@ -648,6 +788,18 @@ uint32_t emit_trap(codegendata *cd) } +/** + * Emit code to recompute the procedure vector. + */ +void emit_recompute_pv(codegendata *cd) +{ + int32_t disp = (int32_t) (cd->mcodeptr - cd->mcodebase); + + M_MFLR(REG_ITMP1); + M_LDA(REG_PV, REG_ITMP1, -disp); +} + + /* * These are local overrides for various environment variables in Emacs. * Please do not remove this and leave it at the end of the file, where diff --git a/src/vm/jit/powerpc64/md.h b/src/vm/jit/powerpc64/md.h index b70509f86..85c46b109 100644 --- a/src/vm/jit/powerpc64/md.h +++ b/src/vm/jit/powerpc64/md.h @@ -40,6 +40,21 @@ #include "vm/jit/jit.hpp" +/** + * Returns the size (in bytes) of the current stackframe, specified by + * the passed codeinfo structure. + */ +inline static int32_t md_stacktrace_get_framesize(codeinfo* code) +{ + // Check for the asm_vm_call_method special case. + if (code == NULL) + return 0; + + // On PowerPC64 we use 8-byte stackslots. + return code->stackframesize * 8; +} + + /* md_stacktrace_get_returnaddress ********************************************* Returns the return address of the current stackframe, specified by diff --git a/src/vm/jit/replace.cpp b/src/vm/jit/replace.cpp index 94b0b1edb..1e6650f20 100644 --- a/src/vm/jit/replace.cpp +++ b/src/vm/jit/replace.cpp @@ -74,25 +74,11 @@ /*** architecture-dependent configuration *************************************/ /* first unset the macros (default) */ -#undef REPLACE_RA_BETWEEN_FRAMES -#undef REPLACE_RA_TOP_OF_FRAME #undef REPLACE_RA_LINKAGE_AREA -#undef REPLACE_LEAFMETHODS_RA_REGISTER - -/* i386, x86_64 and m68k */ -#if defined(__I386__) || defined(__X86_64__) || defined(__M68K__) -#define REPLACE_RA_BETWEEN_FRAMES -/* alpha */ -#elif defined(__ALPHA__) -#define REPLACE_RA_TOP_OF_FRAME -#define REPLACE_LEAFMETHODS_RA_REGISTER + /* powerpc */ -#elif defined(__POWERPC__) -#define REPLACE_RA_LINKAGE_AREA -#define REPLACE_LEAFMETHODS_RA_REGISTER -/* s390 */ -#elif defined(__S390__) -#define REPLACE_RA_TOP_OF_FRAME +#if defined(__POWERPC__) +# define REPLACE_RA_LINKAGE_AREA #endif @@ -728,13 +714,7 @@ bool replace_create_replacement_points(jitdata *jd) code->regalloc = regalloc; code->regalloccount = alloccount; code->globalcount = 0; - code->savedintcount = INT_SAV_CNT - rd->savintreguse; - code->savedfltcount = FLT_SAV_CNT - rd->savfltreguse; -#if defined(HAS_ADDRESS_REGISTER_FILE) - code->savedadrcount = ADR_SAV_CNT - rd->savadrreguse; -#endif code->memuse = rd->memuse; - code->stackframesize = jd->cd->stackframesize; REPLACE_COUNT_DIST(stat_dist_method_rplpoints, count); REPLACE_COUNT_INC(stat_regallocs, alloccount); @@ -1512,7 +1492,7 @@ static void replace_write_executionstate(rplpoint *rp, void md_pop_stackframe(executionstate_t *es) { u1 *ra; - s4 ra_align_off; + s4 framesize; s4 reg; s4 i; stackslot_t *basesp; @@ -1520,23 +1500,18 @@ void md_pop_stackframe(executionstate_t *es) assert(es->code); - /* alignment offset of RA */ + /* calculate the size of the stackframe */ - ra_align_off = 0; -#if defined(REPLACE_RA_BETWEEN_FRAMES) - if (es->code->stackframesize) - ra_align_off = SIZE_OF_STACKSLOT - SIZEOF_VOID_P; -#endif + framesize = md_stacktrace_get_framesize(es->code); /* read the return address */ -#if defined(REPLACE_LEAFMETHODS_RA_REGISTER) +#if STACKFRAME_LEAFMETHODS_RA_REGISTER if (code_is_leafmethod(es->code)) ra = es->ra; else #endif - ra = (u1*) md_stacktrace_get_returnaddress(es->sp, - SIZE_OF_STACKSLOT * es->code->stackframesize + ra_align_off); + ra = (u1*) md_stacktrace_get_returnaddress(es->sp, framesize); /* calculate the base of the stack frame */ @@ -1545,17 +1520,17 @@ void md_pop_stackframe(executionstate_t *es) /* restore return address, if part of frame */ -#if defined(REPLACE_RA_TOP_OF_FRAME) -#if defined(REPLACE_LEAFMETHODS_RA_REGISTER) +#if STACKFRAME_RA_TOP_OF_FRAME +# if STACKFRAME_LEAFMETHODS_RA_REGISTER if (!code_is_leafmethod(es->code)) -#endif +# endif es->ra = (u1*) (ptrint) *--basesp; -#endif /* REPLACE_RA_TOP_OF_FRAME */ +#endif /* STACKFRAME_RA_TOP_OF_FRAME */ #if defined(REPLACE_RA_LINKAGE_AREA) -#if defined(REPLACE_LEAFMETHODS_RA_REGISTER) +# if STACKFRAME_LEAFMETHODS_RA_REGISTER if (!code_is_leafmethod(es->code)) -#endif +# endif es->ra = (u1*) (ptrint) basesp[LA_LR_OFFSET / sizeof(stackslot_t)]; #endif /* REPLACE_RA_LINKAGE_AREA */ @@ -1592,10 +1567,9 @@ void md_pop_stackframe(executionstate_t *es) /* adjust the stackpointer */ - es->sp += SIZE_OF_STACKSLOT * es->code->stackframesize; - -#if defined(REPLACE_RA_BETWEEN_FRAMES) - es->sp += ra_align_off + SIZEOF_VOID_P; /* skip return address */ + es->sp += framesize; +#if STACKFRMAE_RA_BETWEEN_FRAMES + es->sp += SIZEOF_VOID_P; /* skip return address */ #endif /* set the program counter to the return address */ @@ -1652,12 +1626,12 @@ void md_push_stackframe(executionstate_t *es, codeinfo *calleecode, u1 *ra) /* write the return address */ -#if defined(REPLACE_RA_BETWEEN_FRAMES) +#if STACKFRMAE_RA_BETWEEN_FRAMES es->sp -= SIZEOF_VOID_P; *((void **)es->sp) = (void *) ra; if (calleecode->stackframesize) es->sp -= (SIZE_OF_STACKSLOT - SIZEOF_VOID_P); -#endif /* REPLACE_RA_BETWEEN_FRAMES */ +#endif /* STACKFRAME_RA_BETWEEN_FRAMES */ es->ra = (u1*) (ptrint) ra; @@ -1692,17 +1666,17 @@ void md_push_stackframe(executionstate_t *es, codeinfo *calleecode, u1 *ra) /* save the return address register */ -#if defined(REPLACE_RA_TOP_OF_FRAME) -#if defined(REPLACE_LEAFMETHODS_RA_REGISTER) +#if STACKFRAME_RA_TOP_OF_FRAME +# if STACKFRAME_LEAFMETHODS_RA_REGISTER if (!code_is_leafmethod(calleecode)) -#endif +# endif *--basesp = (ptrint) ra; -#endif /* REPLACE_RA_TOP_OF_FRAME */ +#endif /* STACKFRAME_RA_TOP_OF_FRAME */ #if defined(REPLACE_RA_LINKAGE_AREA) -#if defined(REPLACE_LEAFMETHODS_RA_REGISTER) +# if STACKFRAME_LEAFMETHODS_RA_REGISTER if (!code_is_leafmethod(calleecode)) -#endif +# endif basesp[LA_LR_OFFSET / sizeof(stackslot_t)] = (ptrint) ra; #endif /* REPLACE_RA_LINKAGE_AREA */ @@ -2371,11 +2345,9 @@ static void replace_pop_native_frame(executionstate_t *es, /* restore sp, pv, pc and codeinfo of the parent method */ - /* XXX michi: use this instead: - es->sp = sfi->sp + code->stackframesize; */ - es->sp = (uint8_t*) (((uintptr_t) sfi->sp) + (*(s4 *) (((uintptr_t) sfi->pv) + FrameSize))); -#if defined(REPLACE_RA_BETWEEN_FRAMES) - es->sp += SIZE_OF_STACKSLOT; /* skip return address */ + es->sp = (uint8_t*) (((uintptr_t) sfi->sp) + md_stacktrace_get_framesize(code)); +#if STACKFRMAE_RA_BETWEEN_FRAMES + es->sp += SIZEOF_VOID_P; /* skip return address */ #endif es->pv = (uint8_t*) md_codegen_get_pv_from_pc(sfi->ra); es->pc = (uint8_t*) (((uintptr_t) ((sfi->xpc) ? sfi->xpc : sfi->ra)) - 1); @@ -2422,9 +2394,9 @@ static void replace_push_native_frame(executionstate_t *es, sourcestate_t *ss) /* skip sp for the native stub */ - es->sp -= (*(s4 *) (((uintptr_t) frame->sfi->pv) + FrameSize)); -#if defined(REPLACE_RA_BETWEEN_FRAMES) - es->sp -= SIZE_OF_STACKSLOT; /* skip return address */ + es->sp -= md_stacktrace_get_framesize(frame->sfi->code); +#if STACKFRMAE_RA_BETWEEN_FRAMES + es->sp -= SIZEOF_VOID_P; /* skip return address */ #endif /* assert that the native frame has not moved */ diff --git a/src/vm/jit/s390/arch.h b/src/vm/jit/s390/arch.h index 002ba7f95..e5c269955 100644 --- a/src/vm/jit/s390/arch.h +++ b/src/vm/jit/s390/arch.h @@ -101,6 +101,13 @@ #define SUPPORT_HARDWARE_DIVIDE_BY_ZERO 1 +/* stackframe *****************************************************************/ + +#define STACKFRMAE_RA_BETWEEN_FRAMES 0 +#define STACKFRAME_RA_TOP_OF_FRAME 1 +#define STACKFRAME_LEAFMETHODS_RA_REGISTER 0 +#define STACKFRAME_SYNC_NEEDS_TWO_SLOTS 1 + /* replacement ****************************************************************/ #define REPLACEMENT_PATCH_SIZE 5 /* bytes */ diff --git a/src/vm/jit/s390/codegen.c b/src/vm/jit/s390/codegen.c index 05055ba81..77c685e77 100644 --- a/src/vm/jit/s390/codegen.c +++ b/src/vm/jit/s390/codegen.c @@ -1,6 +1,6 @@ /* src/vm/jit/s390/codegen.c - machine code generator for s390 - Copyright (C) 1996-2005, 2006, 2007, 2008 + Copyright (C) 1996-2005, 2006, 2007, 2008, 2009 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO This file is part of CACAO. @@ -51,9 +51,6 @@ #include "vm/vm.hpp" #include "vm/jit/abi.h" -#if defined(ENABLE_LSRA) -# include "vm/jit/allocator/lsra.h" -#endif #include "vm/jit/asmpart.h" #include "vm/jit/codegen-common.hpp" #include "vm/jit/dseg.h" @@ -64,7 +61,6 @@ #include "vm/jit/parse.hpp" #include "vm/jit/patcher-common.hpp" #include "vm/jit/reg.h" -#include "vm/jit/replace.hpp" #include "vm/jit/stacktrace.hpp" #include "vm/jit/trap.hpp" @@ -94,12 +90,6 @@ static void do__log(u4 *regs) { /* #define SUPPORT_HERCULES 1 */ -/* codegen ********************************************************************* - - Generates machine code. - -*******************************************************************************/ - /* Layout of stackframe: @@ -125,100 +115,29 @@ local[0] 0 * 8 */ -bool codegen_emit(jitdata *jd) -{ - methodinfo *m; - codeinfo *code; - codegendata *cd; - registerdata *rd; - s4 len, s1, s2, s3, d, dd, disp; - u2 currentline; - varinfo *var; - basicblock *bptr; - instruction *iptr; - constant_classref *cr; - unresolved_class *uc; - methodinfo *lm; /* local methodinfo for ICMD_INVOKE* */ - unresolved_method *um; - builtintable_entry *bte; - methoddesc *md; - fieldinfo *fi; - unresolved_field *uf; - s4 fieldtype; -#if 0 - rplpoint *replacementpoint; -#endif - s4 varindex; - - /* get required compiler data */ - - m = jd->m; - code = jd->code; - cd = jd->cd; - rd = jd->rd; - - /* prevent compiler warnings */ - - d = 0; - lm = NULL; - um = NULL; - bte = NULL; - { - s4 i, p, t, l; - s4 savedregs_num; - - savedregs_num = 0; - - /* space to save used callee saved registers */ - - savedregs_num += (INT_SAV_CNT - rd->savintreguse); - savedregs_num += (FLT_SAV_CNT - rd->savfltreguse); - - cd->stackframesize = rd->memuse + savedregs_num + 1 /* space to save RA */; +/** + * Generates machine code for the method prolog. + */ +void codegen_emit_prolog(jitdata* jd) +{ + varinfo* var; + methoddesc* md; + int32_t s1; + int32_t p, t, l; + 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; /* CAUTION: * As REG_ITMP2 == REG_RA, do not touch REG_ITMP2, until it has been saved. */ -#if defined(ENABLE_THREADS) - /* Space to save argument of monitor_enter and Return Values to - survive monitor_exit. The stack position for the argument can - not be shared with place to save the return register - since both values reside in R2. */ - - if (checksync && code_is_synchronized(code)) { - /* 1 slot space to save argument of monitor_enter */ - /* 1 slot to temporary store return value before monitor_exit */ - cd->stackframesize += 2; - } -#endif - - /* Keep stack of non-leaf functions 16-byte aligned for calls into - native code e.g. libc or jni (alignment problems with - movaps). */ - - if (!code_is_leafmethod(code) || opt_verbosecall ) - /* TODO really 16 bytes ? */ - cd->stackframesize = (cd->stackframesize + 2) & ~2; - - /* create method header */ - - (void) dseg_add_unique_address(cd, code); /* CodeinfoPointer */ - (void) dseg_add_unique_s4(cd, cd->stackframesize * 8); /* 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 */ - /* Offset PV */ M_AADD_IMM(N_PV_OFFSET, REG_PV); @@ -233,20 +152,6 @@ bool codegen_emit(jitdata *jd) M_AST(REG_RA, REG_SP, (cd->stackframesize - 1) * 8); - /* generate method profiling code */ - -#if defined(ENABLE_PROFILING) - if (JITDATA_HAS_FLAG_INSTRUMENT(jd)) { - /* count frequency */ - M_ALD_DSEG(REG_ITMP1, CodeinfoPointer); - ICONST(REG_ITMP2, 1); - N_AL(REG_ITMP2, OFFSET(codeinfo, frequency), RN, REG_ITMP1); - M_IST(REG_ITMP2, REG_ITMP1, OFFSET(codeinfo, frequency)); - - PROFILE_CYCLE_START; - } -#endif - /* save used callee saved registers and return address */ p = cd->stackframesize - 1; @@ -318,7 +223,7 @@ bool codegen_emit(jitdata *jd) if (!md->params[p].inmemory) { /* register arguments */ s2 = s1; if (!IS_INMEMORY(var->flags)) { /* reg arg -> register */ - M_FLTMOVE(s2, var->vv.regoff); + emit_fmove(cd, s2, var->vv.regoff); } else { /* reg arg -> spilled */ if (IS_2_WORD_TYPE(t)) @@ -342,212 +247,68 @@ bool codegen_emit(jitdata *jd) } } } /* end for */ +} - /* save monitorenter argument */ - -#if defined(ENABLE_THREADS) - if (checksync && code_is_synchronized(code)) { - /* stack offset for monitor argument */ - - s1 = rd->memuse; - -#if !defined(NDEBUG) - if (opt_verbosecall) { - M_ASUB_IMM((INT_ARG_CNT + FLT_ARG_CNT) * 8, REG_SP); - - for (p = 0; p < INT_ARG_CNT; p++) - M_IST(abi_registers_integer_argument[p], REG_SP, p * 8); - - for (p = 0; p < FLT_ARG_CNT; p++) - M_DST(abi_registers_float_argument[p], REG_SP, (INT_ARG_CNT + p) * 8); - - s1 += ((INT_ARG_CNT + FLT_ARG_CNT)); - } -#endif - - /* decide which monitor enter function to call */ - if (m->flags & ACC_STATIC) { - disp = dseg_add_address(cd, &m->clazz->object.header); - M_ALD_DSEG(REG_A0, disp); - } - else { - M_TEST(REG_A0); - M_BNE(SZ_BRC + SZ_ILL); - M_ILL(TRAP_NullPointerException); - } +/** + * Generates machine code for the method epilog. + */ +void codegen_emit_epilog(jitdata* jd) +{ + int32_t p; + int i; - disp = dseg_add_functionptr(cd, LOCK_monitor_enter); - M_ALD_DSEG(REG_ITMP2, disp); + // Get required compiler data. + codegendata* cd = jd->cd; + registerdata* rd = jd->rd; - M_AST(REG_A0, REG_SP, s1 * 8); + p = cd->stackframesize; - M_ASUB_IMM(96, REG_SP); - M_CALL(REG_ITMP2); - M_AADD_IMM(96, REG_SP); + /* restore return address */ -#if !defined(NDEBUG) - if (opt_verbosecall) { - for (p = 0; p < INT_ARG_CNT; p++) - M_ILD(abi_registers_integer_argument[p], REG_SP, p * 8); + p--; M_ALD(REG_RA, REG_SP, p * 8); - for (p = 0; p < FLT_ARG_CNT; p++) - M_DLD(abi_registers_float_argument[p], REG_SP, (INT_ARG_CNT + p) * 8); + /* restore saved registers */ - M_AADD_IMM((INT_ARG_CNT + FLT_ARG_CNT) * 8, REG_SP); - } -#endif + for (i = INT_SAV_CNT - 1; i >= rd->savintreguse; i--) { + p--; M_ILD(rd->savintregs[i], REG_SP, p * 8); } -#endif - -#if !defined(NDEBUG) - if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) - emit_verbosecall_enter(jd); -#endif /* !defined(NDEBUG) */ - + for (i = FLT_SAV_CNT - 1; i >= rd->savfltreguse; i--) { + p--; M_DLD(rd->savfltregs[i], REG_SP, p * 8); } - /* end of header generation */ - - /* create replacement points */ - - REPLACEMENT_POINTS_INIT(cd, jd); - - /* walk through all basic blocks */ - - for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) { - - bptr->mpc = (u4) ((u1 *) cd->mcodeptr - cd->mcodebase); - - if (bptr->flags >= BBREACHED) { - - /* branch resolving */ - - codegen_resolve_branchrefs(cd, bptr); - - /* handle replacement points */ - - REPLACEMENT_POINT_BLOCK_START(cd, bptr); - - /* copy interface registers to their destination */ + /* deallocate stack */ - len = bptr->indepth; - MCODECHECK(512); + if (cd->stackframesize) + M_AADD_IMM(cd->stackframesize * 8, REG_SP); -#if defined(ENABLE_PROFILING) - /* generate basicblock profiling code */ - - if (JITDATA_HAS_FLAG_INSTRUMENT(jd)) { - /* count frequency */ - - M_ALD_DSEG(REG_ITMP1, CodeinfoPointer); - M_ALD(REG_ITMP1, REG_ITMP1, OFFSET(codeinfo, bbfrequency)); - ICONST(REG_ITMP2, 1); - N_AL(REG_ITMP2, bptr->nr * 4, RN, REG_ITMP1); - M_IST(REG_ITMP2, REG_ITMP1, bptr->nr * 4); - - /* if this is an exception handler, start profiling again */ - - if (bptr->type == BBTYPE_EXH) - PROFILE_CYCLE_START; - } -#endif - -#if defined(ENABLE_LSRA) - if (opt_lsra) { - while (len) { - len--; - src = bptr->invars[len]; - if ((len == bptr->indepth-1) && (bptr->type != BBTYPE_STD)) { - if (bptr->type == BBTYPE_EXH) { -/* d = reg_of_var(rd, src, REG_ITMP1); */ - if (!IS_INMEMORY(src->flags)) - d = src->vv.regoff; - else - d = REG_ITMP3_XPTR; - M_INTMOVE(REG_ITMP3_XPTR, d); - emit_store(jd, NULL, src, d); - } - } - } - - } else { -#endif - - while (len) { - len--; - var = VAR(bptr->invars[len]); - if ((len == bptr->indepth-1) && (bptr->type != BBTYPE_STD)) { - if (bptr->type == BBTYPE_EXH) { - d = codegen_reg_of_var(0, var, REG_ITMP3_XPTR); - M_INTMOVE(REG_ITMP3_XPTR, d); - emit_store(jd, NULL, var, d); - } - } - else { - assert((var->flags & INOUT)); - } - } -#if defined(ENABLE_LSRA) - } -#endif - /* walk through all instructions */ - - len = bptr->icount; - currentline = 0; - - for (iptr = bptr->iinstr; len > 0; len--, iptr++) { - if (iptr->line != currentline) { - linenumbertable_list_entry_add(cd, iptr->line); - currentline = iptr->line; - } - - MCODECHECK(1024); /* 1KB should be enough */ - - switch (iptr->opc) { - case ICMD_NOP: /* ... ==> ... */ - case ICMD_POP: /* ..., value ==> ... */ - case ICMD_POP2: /* ..., value, value ==> ... */ - break; - - case ICMD_INLINE_START: - - REPLACEMENT_POINT_INLINE_START(cd, iptr); - break; - - case ICMD_INLINE_BODY: - - REPLACEMENT_POINT_INLINE_BODY(cd, iptr); - linenumbertable_list_entry_add_inline_start(cd, iptr); - linenumbertable_list_entry_add(cd, iptr->line); - break; - - case ICMD_INLINE_END: + M_RET; +} - linenumbertable_list_entry_add_inline_end(cd, iptr); - linenumbertable_list_entry_add(cd, iptr->line); - break; - case ICMD_CHECKNULL: /* ..., objectref ==> ..., objectref */ - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - emit_nullpointer_check(cd, iptr, s1); - break; +/** + * Generates machine code for one ICMD. + */ +void codegen_emit_instruction(jitdata* jd, instruction* iptr) +{ + varinfo* var; + builtintable_entry* bte; + 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. + codeinfo* code = jd->code; + codegendata* cd = jd->cd; + + 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_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 */ d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); disp = dseg_add_float(cd, iptr->sx.val.f); @@ -566,7 +327,7 @@ bool codegen_emit(jitdata *jd) d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - cr = iptr->sx.val.c.ref; + constant_classref *cr = iptr->sx.val.c.ref; disp = dseg_add_unique_address(cd, cr); /* PROFILE_CYCLE_STOP; */ @@ -599,28 +360,6 @@ bool codegen_emit(jitdata *jd) break; - /* load/store/copy/move operations ************************************/ - - case ICMD_ILOAD: /* ... ==> ..., content of local variable */ - case ICMD_ALOAD: /* s1 = local variable */ - case ICMD_LLOAD: - case ICMD_FLOAD: - case ICMD_DLOAD: - case ICMD_ISTORE: /* ..., value ==> ... */ - case ICMD_LSTORE: - case ICMD_FSTORE: - 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_INEG: /* ..., value ==> ..., - value */ @@ -1444,7 +1183,7 @@ bool codegen_emit(jitdata *jd) if (s2 == d) M_FADD(s1, d); else { - M_FLTMOVE(s1, d); + emit_fmove(cd, s1, d); M_FADD(s2, d); } emit_store_dst(jd, iptr, d); @@ -1457,7 +1196,7 @@ bool codegen_emit(jitdata *jd) if (s2 == d) M_DADD(s1, d); else { - M_FLTMOVE(s1, d); + emit_fmove(cd, s1, d); M_DADD(s2, d); } emit_store_dst(jd, iptr, d); @@ -1468,7 +1207,7 @@ bool codegen_emit(jitdata *jd) d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); s2 = emit_load_s2_but(jd, iptr, REG_FTMP2, d); - M_FLTMOVE(s1, d); + emit_fmove(cd, s1, d); M_FSUB(s2, d); emit_store_dst(jd, iptr, d); break; @@ -1478,7 +1217,7 @@ bool codegen_emit(jitdata *jd) d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); s2 = emit_load_s2_but(jd, iptr, REG_FTMP2, d); - M_FLTMOVE(s1, d); + emit_fmove(cd, s1, d); M_DSUB(s2, d); emit_store_dst(jd, iptr, d); break; @@ -1490,7 +1229,7 @@ bool codegen_emit(jitdata *jd) if (s2 == d) M_FMUL(s1, d); else { - M_FLTMOVE(s1, d); + emit_fmove(cd, s1, d); M_FMUL(s2, d); } emit_store_dst(jd, iptr, d); @@ -1503,7 +1242,7 @@ bool codegen_emit(jitdata *jd) if (s2 == d) M_DMUL(s1, d); else { - M_FLTMOVE(s1, d); + emit_fmove(cd, s1, d); M_DMUL(s2, d); } emit_store_dst(jd, iptr, d); @@ -1514,7 +1253,7 @@ bool codegen_emit(jitdata *jd) d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); s2 = emit_load_s2_but(jd, iptr, REG_FTMP2, d); - M_FLTMOVE(s1, d); + emit_fmove(cd, s1, d); M_FDIV(s2, d); emit_store_dst(jd, iptr, d); break; @@ -1524,7 +1263,7 @@ bool codegen_emit(jitdata *jd) d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); s2 = emit_load_s2_but(jd, iptr, REG_FTMP2, d); - M_FLTMOVE(s1, d); + emit_fmove(cd, s1, d); M_DDIV(s2, d); emit_store_dst(jd, iptr, d); break; @@ -1700,17 +1439,6 @@ bool codegen_emit(jitdata *jd) /* memory operations **************************************************/ - case ICMD_ARRAYLENGTH: /* ..., arrayref ==> ..., (int) length */ - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - d = codegen_reg_of_dst(jd, iptr, REG_ITMP3); - /* TODO softnull */ - /* implicit null-pointer check */ - M_ILD(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); s2 = emit_load_s2(jd, iptr, REG_ITMP2); @@ -1982,109 +1710,6 @@ bool codegen_emit(jitdata *jd) */ 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); - -/* PROFILE_CYCLE_STOP; */ - - patcher_add_patch_ref(jd, PATCHER_get_putstatic, uf, disp); - -/* PROFILE_CYCLE_START; */ - } - 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)) { - PROFILE_CYCLE_STOP; - - patcher_add_patch_ref(jd, PATCHER_initialize_class, fi->clazz, 0); - - PROFILE_CYCLE_START; - } - } - - M_ALD_DSEG(REG_ITMP1, disp); - - switch (fieldtype) { - case TYPE_INT: - d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); - M_ILD(d, REG_ITMP1, 0); - break; - case TYPE_LNG: - d = codegen_reg_of_dst(jd, iptr, REG_ITMP23_PACKED); - M_LLD(d, REG_ITMP1, 0); - break; - case TYPE_ADR: - d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); - M_ALD(d, REG_ITMP1, 0); - break; - case TYPE_FLT: - d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); - M_FLD(d, REG_ITMP1, 0); - break; - case TYPE_DBL: - d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); - M_DLD(d, REG_ITMP1, 0); - break; - } - - 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, uf); - - 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)) { - PROFILE_CYCLE_STOP; - patcher_add_patch_ref(jd, PATCHER_initialize_class, fi->clazz, disp); - PROFILE_CYCLE_START; - } - } - - M_ALD_DSEG(REG_ITMP1, disp); - switch (fieldtype) { - case TYPE_INT: - s1 = emit_load_s1(jd, iptr, REG_ITMP2); - M_IST(s1, REG_ITMP1, 0); - break; - case TYPE_LNG: - s1 = emit_load_s1(jd, iptr, REG_ITMP23_PACKED); - M_LST(s1, REG_ITMP1, 0); - break; - case TYPE_ADR: - s1 = emit_load_s1(jd, iptr, REG_ITMP2); - M_AST(s1, REG_ITMP1, 0); - break; - case TYPE_FLT: - s1 = emit_load_s1(jd, iptr, REG_FTMP2); - M_FST(s1, REG_ITMP1, 0); - break; - case TYPE_DBL: - s1 = emit_load_s1(jd, iptr, REG_FTMP2); - M_DST(s1, REG_ITMP1, 0); - break; - } - break; - case ICMD_GETFIELD: /* ... ==> ..., value */ s1 = emit_load_s1(jd, iptr, REG_ITMP1); @@ -2207,19 +1832,6 @@ bool codegen_emit(jitdata *jd) case ICMD_ATHROW: /* ..., objectref ==> ... (, objectref) */ - /* PROFILE_CYCLE_STOP; */ - - s1 = emit_load_s1(jd, iptr, REG_ITMP3); - M_INTMOVE(s1, REG_ITMP3_XPTR); - -#ifdef ENABLE_VERIFIER - if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - uc = iptr->sx.s23.s2.uc; - - patcher_add_patch_ref(jd, PATCHER_resolve_class, uc, 0); - } -#endif /* ENABLE_VERIFIER */ - disp = dseg_add_functionptr(cd, asm_handle_exception); M_ALD_DSEG(REG_ITMP1, disp); M_JMP(REG_ITMP1_XPC, REG_ITMP1); @@ -2227,77 +1839,6 @@ bool codegen_emit(jitdata *jd) 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: /* ..., value ==> ... */ - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - M_TEST(s1); - switch (iptr->opc) { - case ICMD_IFNULL: - emit_beq(cd, iptr->dst.block); - break; - case ICMD_IFNONNULL: - emit_bne(cd, iptr->dst.block); - break; - } - break; - - case ICMD_IFEQ: /* ..., value ==> ... */ - case ICMD_IFLT: /* ..., value ==> ... */ - case ICMD_IFLE: /* ..., value ==> ... */ - case ICMD_IFNE: /* ..., value ==> ... */ - case ICMD_IFGT: /* ..., value ==> ... */ - case ICMD_IFGE: /* ..., value ==> ... */ - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - - if (N_VALID_IMM(iptr->sx.val.i)) - M_ICMP_IMM(s1, iptr->sx.val.i); - else { - disp = dseg_add_s4(cd, iptr->sx.val.i); - if (N_VALID_DSEG_DISP(disp)) { - N_C(s1, N_DSEG_DISP(disp), RN, REG_PV); - } else { - ICONST(REG_ITMP2, disp); - N_C(s1, -N_PV_OFFSET, REG_ITMP2, REG_PV); - } - } - - switch (iptr->opc) { - case ICMD_IFLT: - emit_blt(cd, iptr->dst.block); - break; - case ICMD_IFLE: - emit_ble(cd, iptr->dst.block); - break; - case ICMD_IFNE: - emit_bne(cd, iptr->dst.block); - break; - case ICMD_IFGT: - emit_bgt(cd, iptr->dst.block); - break; - case ICMD_IFGE: - emit_bge(cd, iptr->dst.block); - break; - case ICMD_IFEQ: - emit_beq(cd, iptr->dst.block); - break; - } - - break; - case ICMD_IF_LLT: /* ..., value ==> ... */ case ICMD_IF_LLE: /* op1 = target JavaVM pc, val.l = constant */ case ICMD_IF_LGT: @@ -2413,39 +1954,6 @@ bool codegen_emit(jitdata *jd) break; - case ICMD_IF_ICMPEQ: /* ..., value, value ==> ... */ - case ICMD_IF_ICMPNE: /* ..., value, value ==> ... */ - case ICMD_IF_ICMPLT: /* ..., value, value ==> ... */ - case ICMD_IF_ICMPGT: /* ..., value, value ==> ... */ - case ICMD_IF_ICMPLE: /* ..., value, value ==> ... */ - case ICMD_IF_ICMPGE: /* ..., value, value ==> ... */ - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - s2 = emit_load_s2(jd, iptr, REG_ITMP2); - M_CMP(s1, s2); - switch (iptr->opc) { - case ICMD_IF_ICMPEQ: - emit_beq(cd, iptr->dst.block); - break; - case ICMD_IF_ICMPNE: - emit_bne(cd, iptr->dst.block); - break; - case ICMD_IF_ICMPLT: - emit_blt(cd, iptr->dst.block); - break; - case ICMD_IF_ICMPGT: - emit_bgt(cd, iptr->dst.block); - break; - case ICMD_IF_ICMPLE: - emit_ble(cd, iptr->dst.block); - break; - case ICMD_IF_ICMPGE: - emit_bge(cd, iptr->dst.block); - break; - } - - break; - case ICMD_IF_LCMPLE: /* ..., value, value ==> ... */ case ICMD_IF_LCMPLT: /* ..., value, value ==> ... */ case ICMD_IF_LCMPGT: /* ..., value, value ==> ... */ @@ -2526,137 +2034,6 @@ bool codegen_emit(jitdata *jd) } break; - case ICMD_IRETURN: /* ..., retvalue ==> ... */ - - REPLACEMENT_POINT_RETURN(cd, iptr); - s1 = emit_load_s1(jd, iptr, REG_RESULT); - M_INTMOVE(s1, REG_RESULT); - goto nowperformreturn; - - case ICMD_ARETURN: /* ..., retvalue ==> ... */ - - REPLACEMENT_POINT_RETURN(cd, iptr); - s1 = emit_load_s1(jd, iptr, REG_RESULT); - M_INTMOVE(s1, REG_RESULT); - -#ifdef ENABLE_VERIFIER - if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - unresolved_class *uc = iptr->sx.s23.s2.uc; - - PROFILE_CYCLE_STOP; - patcher_add_patch_ref(jd, PATCHER_resolve_class, uc, 0); - PROFILE_CYCLE_START; - } -#endif /* ENABLE_VERIFIER */ - goto nowperformreturn; - - 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 nowperformreturn; - - case ICMD_FRETURN: /* ..., retvalue ==> ... */ - case ICMD_DRETURN: - - REPLACEMENT_POINT_RETURN(cd, iptr); - s1 = emit_load_s1(jd, iptr, REG_FRESULT); - M_FLTMOVE(s1, REG_FRESULT); - goto nowperformreturn; - - case ICMD_RETURN: /* ... ==> ... */ - - REPLACEMENT_POINT_RETURN(cd, iptr); - -nowperformreturn: - { - s4 i, p; - - p = cd->stackframesize; - - /* call trace function */ - -#if !defined(NDEBUG) - if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) - emit_verbosecall_exit(jd); -#endif /* !defined(NDEBUG) */ - -#if defined(ENABLE_THREADS) - if (checksync && code_is_synchronized(code)) { - /* we need to save the proper return value */ - - switch (iptr->opc) { - case ICMD_LRETURN: - M_IST(REG_RESULT2, REG_SP, ((rd->memuse + 1) * 8) + 4); - /* fall through */ - case ICMD_IRETURN: - case ICMD_ARETURN: - M_IST(REG_RESULT , REG_SP, (rd->memuse + 1) * 8); - break; - case ICMD_FRETURN: - M_FST(REG_FRESULT, REG_SP, (rd->memuse + 1) * 8); - break; - case ICMD_DRETURN: - M_DST(REG_FRESULT, REG_SP, (rd->memuse + 1) * 8); - break; - } - - M_ALD(REG_A0, REG_SP, rd->memuse * 8); - - disp = dseg_add_functionptr(cd, LOCK_monitor_exit); - M_ALD_DSEG(REG_ITMP2, disp); - - M_ASUB_IMM(96, REG_SP); - M_CALL(REG_ITMP2); - M_AADD_IMM(96, REG_SP); - - /* and now restore the proper return value */ - - switch (iptr->opc) { - case ICMD_LRETURN: - M_ILD(REG_RESULT2, REG_SP, ((rd->memuse + 1) * 8) + 4); - /* fall through */ - case ICMD_IRETURN: - case ICMD_ARETURN: - M_ILD(REG_RESULT , REG_SP, (rd->memuse + 1) * 8); - break; - case ICMD_FRETURN: - M_FLD(REG_FRESULT, REG_SP, (rd->memuse + 1) * 8); - break; - case ICMD_DRETURN: - M_DLD(REG_FRESULT, REG_SP, (rd->memuse + 1) * 8); - break; - } - } -#endif - - /* restore return address */ - - p--; M_ALD(REG_RA, REG_SP, p * 8); - - /* restore saved registers */ - - for (i = INT_SAV_CNT - 1; i >= rd->savintreguse; i--) { - p--; M_ILD(rd->savintregs[i], REG_SP, p * 8); - } - for (i = FLT_SAV_CNT - 1; i >= rd->savfltreguse; i--) { - p--; M_DLD(rd->savfltregs[i], REG_SP, p * 8); - } - - /* deallocate stack */ - - if (cd->stackframesize) - M_AADD_IMM(cd->stackframesize * 8, REG_SP); - - /* generate method profiling code */ - - PROFILE_CYCLE_STOP; - - M_RET; - } - break; - case ICMD_TABLESWITCH: /* ..., index ==> ... */ { s4 i, l; @@ -2709,255 +2086,116 @@ nowperformreturn: break; - case ICMD_LOOKUPSWITCH: /* ..., key ==> ... */ - { - s4 i; - lookup_target_t *lookup; - - lookup = iptr->dst.lookup; + case ICMD_BUILTIN: /* ..., [arg1, [arg2 ...]] ==> ... */ + bte = iptr->sx.s23.s3.bte; + if (bte->stub == NULL) { + disp = dseg_add_functionptr(cd, bte->fp); + M_ASUB_IMM(96, REG_SP); /* register save area as required by C abi */ + } else { + disp = dseg_add_functionptr(cd, bte->stub); + } - i = iptr->sx.s23.s2.lookupcount; - - MCODECHECK(8 + ((7 + 6) * i) + 5); - s1 = emit_load_s1(jd, iptr, REG_ITMP1); + if (N_VALID_DSEG_DISP(disp)) { + N_L(REG_PV, N_DSEG_DISP(disp), RN, REG_PV); + } else { + N_LHI(REG_ITMP1, disp); + N_L(REG_PV, -N_PV_OFFSET, REG_ITMP1, REG_PV); + } - while (--i >= 0) { - if (N_VALID_IMM(lookup->value)) { - M_ICMP_IMM(s1, lookup->value); - } else { - ICONST(REG_ITMP2, lookup->value); - M_ICMP(REG_ITMP2, s1); - } - emit_beq(cd, lookup->target.block); - lookup++; - } + /* generate the actual call */ + M_CALL(REG_PV); - emit_br(cd, iptr->sx.s23.s3.lookupdefault.block); + /* post call finalization */ + if (bte->stub == NULL) { + M_AADD_IMM(96, REG_SP); /* remove C abi register save area */ } break; - - case ICMD_BUILTIN: /* ..., [arg1, [arg2 ...]] ==> ... */ - - bte = iptr->sx.s23.s3.bte; - md = bte->md; - goto gen_method; - - case ICMD_INVOKESTATIC: /* ..., [arg1, [arg2 ...]] ==> ... */ case ICMD_INVOKESPECIAL:/* ..., objectref, [arg1, [arg2 ...]] ==> ... */ - case ICMD_INVOKEVIRTUAL:/* op1 = arg count, val.a = method pointer */ - case ICMD_INVOKEINTERFACE: - - REPLACEMENT_POINT_INVOKE(cd, iptr); + /* TODO softnull */ + /* Implicit NULL pointer check */ + M_ILD(REG_ITMP1, REG_A0, 0); + /* fall through */ + case ICMD_INVOKESTATIC: /* ..., [arg1, [arg2 ...]] ==> ... */ if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - lm = NULL; um = iptr->sx.s23.s3.um; - md = um->methodref->parseddesc.md; + disp = dseg_add_unique_address(cd, um); + + patcher_add_patch_ref(jd, PATCHER_invokestatic_special, + um, disp); } else { lm = iptr->sx.s23.s3.fmiref->p.method; - um = NULL; - md = lm->parseddesc; + disp = dseg_add_address(cd, lm->stubroutine); } -gen_method: - s3 = md->paramcount; - - MCODECHECK((s3 << 1) + 64); - - /* copy arguments to registers or stack location */ - - for (s3 = s3 - 1; s3 >= 0; s3--) { - var = VAR(iptr->sx.s23.s2.args[s3]); - - /* Already Preallocated? */ - if (var->flags & PREALLOC) - continue; - - if (IS_INT_LNG_TYPE(var->type)) { - if (!md->params[s3].inmemory) { - if (IS_2_WORD_TYPE(var->type)) { - s1 = PACK_REGS( - GET_LOW_REG(md->params[s3].regoff), - GET_HIGH_REG(md->params[s3].regoff) - ); - d = emit_load(jd, iptr, var, s1); - M_LNGMOVE(d, s1); - } - else { - s1 = md->params[s3].regoff; - d = emit_load(jd, iptr, var, s1); - M_INTMOVE(d, s1); - } - } - else { - if (IS_2_WORD_TYPE(var->type)) { - d = emit_load(jd, iptr, var, REG_ITMP12_PACKED); - M_LST(d, REG_SP, md->params[s3].regoff); - } - else { - d = emit_load(jd, iptr, var, REG_ITMP1); - M_IST(d, REG_SP, md->params[s3].regoff); - } - } - } - else { - if (!md->params[s3].inmemory) { - s1 = md->params[s3].regoff; - d = emit_load(jd, iptr, var, s1); - M_FLTMOVE(d, s1); - } - else { - d = emit_load(jd, iptr, var, REG_FTMP1); - if (IS_2_WORD_TYPE(var->type)) - M_DST(d, REG_SP, md->params[s3].regoff); - else - M_FST(d, REG_SP, md->params[s3].regoff); - } - } + if (N_VALID_DSEG_DISP(disp)) { + N_L(REG_PV, N_DSEG_DISP(disp), RN, REG_PV); + } else { + N_LHI(REG_ITMP1, disp); + N_L(REG_PV, -N_PV_OFFSET, REG_ITMP1, REG_PV); } - /* generate method profiling code */ - - PROFILE_CYCLE_STOP; - - switch (iptr->opc) { - case ICMD_BUILTIN: - if (bte->stub == NULL) { - disp = dseg_add_functionptr(cd, bte->fp); - M_ASUB_IMM(96, REG_SP); /* register save area as required by C abi */ - } else { - disp = dseg_add_functionptr(cd, bte->stub); - } - - if (N_VALID_DSEG_DISP(disp)) { - N_L(REG_PV, N_DSEG_DISP(disp), RN, REG_PV); - } else { - N_LHI(REG_ITMP1, disp); - N_L(REG_PV, -N_PV_OFFSET, REG_ITMP1, REG_PV); - } - break; - - case ICMD_INVOKESPECIAL: - /* TODO softnull */ - /* Implicit NULL pointer check */ - M_ILD(REG_ITMP1, REG_A0, 0); - - /* fall through */ - - case ICMD_INVOKESTATIC: - if (lm == NULL) { - disp = dseg_add_unique_address(cd, um); - - patcher_add_patch_ref(jd, PATCHER_invokestatic_special, - um, disp); - } - else - disp = dseg_add_address(cd, lm->stubroutine); - - if (N_VALID_DSEG_DISP(disp)) { - N_L(REG_PV, N_DSEG_DISP(disp), RN, REG_PV); - } else { - N_LHI(REG_ITMP1, disp); - N_L(REG_PV, -N_PV_OFFSET, REG_ITMP1, REG_PV); - } - break; - - case ICMD_INVOKEVIRTUAL: - /* TODO softnull REG_A0 */ - - 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_ALD(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl)); - M_ALD(REG_PV, REG_METHODPTR, s1); - break; - - case ICMD_INVOKEINTERFACE: - /* TODO softnull REG_A0 */ + /* generate the actual call */ + M_CALL(REG_PV); + break; - /* s1 will be negative here, so use (0xFFF + s1) as displacement - * and -0xFFF in index register (itmp1) - */ + case ICMD_INVOKEVIRTUAL:/* op1 = arg count, val.a = method pointer */ + /* TODO softnull REG_A0 */ - if (lm == NULL) { - patcher_add_patch_ref(jd, PATCHER_invokeinterface, um, 0); + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + um = iptr->sx.s23.s3.um; + patcher_add_patch_ref(jd, PATCHER_invokevirtual, um, 0); - s1 = 0; - s2 = 0; - } - else { - s1 = OFFSET(vftbl_t, interfacetable[0]) - - sizeof(methodptr*) * lm->clazz->index; + s1 = 0; + } + else { + lm = iptr->sx.s23.s3.fmiref->p.method; + s1 = OFFSET(vftbl_t, table[0]) + + sizeof(methodptr) * lm->vftblindex; + } - s2 = sizeof(methodptr) * (lm - lm->clazz->methods); - } + /* implicit null-pointer check */ - /* Implicit null-pointer check */ - M_ALD(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl)); - N_LHI(REG_ITMP2, s1); - N_L(REG_METHODPTR, 0, REG_ITMP2, REG_METHODPTR); - M_ALD(REG_PV, REG_METHODPTR, s2); - break; - } + M_ALD(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl)); + M_ALD(REG_PV, REG_METHODPTR, s1); /* generate the actual call */ - M_CALL(REG_PV); - emit_restore_pv(cd); - - /* post call finalization */ - - switch (iptr->opc) { - case ICMD_BUILTIN: - if (bte->stub == NULL) { - M_AADD_IMM(96, REG_SP); /* remove C abi register save area */ - } - break; - } - - /* generate method profiling code */ + break; - PROFILE_CYCLE_START; + case ICMD_INVOKEINTERFACE: + /* TODO softnull REG_A0 */ - /* store size of call code in replacement point */ + /* s1 will be negative here, so use (0xFFF + s1) as displacement + * and -0xFFF in index register (itmp1) + */ - REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr); - - /* store return value */ + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + um = iptr->sx.s23.s3.um; + patcher_add_patch_ref(jd, PATCHER_invokeinterface, um, 0); - d = md->returntype.type; + s1 = 0; + s2 = 0; + } + else { + lm = iptr->sx.s23.s3.fmiref->p.method; + s1 = OFFSET(vftbl_t, interfacetable[0]) - + sizeof(methodptr*) * lm->clazz->index; - if (d != TYPE_VOID) { - if (IS_INT_LNG_TYPE(d)) { - 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); - } - } - else { - s1 = codegen_reg_of_dst(jd, iptr, REG_FRESULT); - M_FLTMOVE(REG_FRESULT, s1); - } - emit_store_dst(jd, iptr, s1); + s2 = sizeof(methodptr) * (lm - lm->clazz->methods); } - break; + /* Implicit null-pointer check */ + M_ALD(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl)); + N_LHI(REG_ITMP2, s1); + N_L(REG_METHODPTR, 0, REG_ITMP2, REG_METHODPTR); + M_ALD(REG_PV, REG_METHODPTR, s2); + /* generate the actual call */ + M_CALL(REG_PV); + break; case ICMD_CHECKCAST: /* ..., objectref ==> ..., objectref */ @@ -3406,37 +2644,11 @@ gen_method: break; default: - exceptions_throw_internalerror("Unknown ICMD %d", iptr->opc); - return false; + vm_abort("Unknown ICMD %d during code generation", iptr->opc); } /* switch */ - - } /* for instruction */ - - MCODECHECK(512); /* XXX require a lower number? */ - - /* At the end of a basic block we may have to append some nops, - because the patcher stub calling code might be longer than the - actual instruction. So codepatching does not change the - following block unintentionally. */ - - if (cd->mcodeptr < cd->lastmcodeptr) { - while (cd->mcodeptr < cd->lastmcodeptr) { - M_NOP; - } - } - - } /* if (bptr -> flags >= BBREACHED) */ - } /* for basic block */ - - /* generate stubs */ - - emit_patcher_traps(jd); - - /* everything's ok */ - - return true; } + /* codegen_emit_stub_native **************************************************** Emits a stub routine which calls a native method. diff --git a/src/vm/jit/s390/codegen.h b/src/vm/jit/s390/codegen.h index 3e5262d45..fcaeba527 100644 --- a/src/vm/jit/s390/codegen.h +++ b/src/vm/jit/s390/codegen.h @@ -730,6 +730,7 @@ static inline uint8_t N_ILL_GET_TYPE(uint8_t *instrp) { #define M_ICMP(a, b) N_CR(a, b) #define M_ICMPU(a, b) N_CLR(a, b) #define M_ICMP_IMM(a, b) N_CHI(a, b) +#define M_ACMP(a, b) N_CR(a, b) #define M_CVTIF(src, dst) N_CEFBR(dst, src) #define M_CVTID(src, dst) N_CDFBR(dst, src) #define M_FMUL(a, dest) N_MEEBR(dest, a) @@ -803,42 +804,6 @@ static inline uint8_t N_ILL_GET_TYPE(uint8_t *instrp) { ICONST(GET_LOW_REG((reg)), (s4) ((s8) (c))); \ } while (0) -/* M_INTMOVE: - generates an integer-move from register a to b. - if a and b are the same int-register, no code will be generated. -*/ - -#define M_INTMOVE(reg,dreg) \ - do { \ - if ((reg) != (dreg)) { \ - M_MOV(reg, dreg); \ - } \ - } while (0) - -#define M_LNGMOVE(a, b) \ - do { \ - if (GET_HIGH_REG(a) == GET_LOW_REG(b)) { \ - assert((GET_LOW_REG(a) != GET_HIGH_REG(b))); \ - M_INTMOVE(GET_HIGH_REG(a), GET_HIGH_REG(b)); \ - M_INTMOVE(GET_LOW_REG(a), GET_LOW_REG(b)); \ - } else { \ - M_INTMOVE(GET_LOW_REG(a), GET_LOW_REG(b)); \ - M_INTMOVE(GET_HIGH_REG(a), GET_HIGH_REG(b)); \ - } \ - } while (0) - -/* M_FLTMOVE: - generates a floating-point-move from register a to b. - if a and b are the same float-register, no code will be generated -*/ - -#define M_FLTMOVE(reg,dreg) \ - do { \ - if ((reg) != (dreg)) { \ - M_FMOV(reg, dreg); \ - } \ - } while (0) - #define M_ISUB_IMM32(imm, tmpreg, reg) \ do { \ if (N_VALID_IMM(imm)) { \ diff --git a/src/vm/jit/s390/emit.c b/src/vm/jit/s390/emit.c index 0720e1387..358d154e6 100644 --- a/src/vm/jit/s390/emit.c +++ b/src/vm/jit/s390/emit.c @@ -215,6 +215,30 @@ void emit_copy(jitdata *jd, instruction *iptr) } } + +/** + * Emits code updating the condition register by comparing one integer + * register to an immediate integer value. + */ +void emit_icmp_imm(codegendata* cd, int reg, int32_t value) +{ + int32_t disp; + + if (N_VALID_IMM(value)) { + M_ICMP_IMM(reg, value); + } else { + disp = dseg_add_s4(cd, iptr->sx.val.i); + if (N_VALID_DSEG_DISP(disp)) { + N_C(s1, N_DSEG_DISP(disp), RN, REG_PV); + } else { + assert(reg != REG_ITMP2); + ICONST(REG_ITMP2, disp); + N_C(s1, -N_PV_OFFSET, REG_ITMP2, REG_PV); + } + } +} + + /* emit_trap ******************************************************************* Emit a trap instruction and return the original machine code. @@ -236,6 +260,160 @@ uint32_t emit_trap(codegendata *cd) } +/** + * Generates synchronization code to enter a monitor. + */ +#if defined(ENABLE_THREADS) +void emit_monitor_enter(jitdata* jd, int32_t syncslot_offset) +{ + int32_t p; + int32_t disp; + + // Get required compiler data. + methodinfo* m = jd->m; + codegendata* cd = jd->cd; + +#if !defined(NDEBUG) + if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) { + M_ASUB_IMM((INT_ARG_CNT + FLT_ARG_CNT) * 8, REG_SP); + + for (p = 0; p < INT_ARG_CNT; p++) + M_IST(abi_registers_integer_argument[p], REG_SP, p * 8); + + for (p = 0; p < FLT_ARG_CNT; p++) + M_DST(abi_registers_float_argument[p], REG_SP, (INT_ARG_CNT + p) * 8); + + syncslot_offset += (INT_ARG_CNT + FLT_ARG_CNT) * 8; + } +#endif + + /* decide which monitor enter function to call */ + + if (m->flags & ACC_STATIC) { + disp = dseg_add_address(cd, &m->clazz->object.header); + M_ALD_DSEG(REG_A0, disp); + } + else { + M_TEST(REG_A0); + M_BNE(SZ_BRC + SZ_ILL); + M_ILL(TRAP_NullPointerException); + } + + disp = dseg_add_functionptr(cd, LOCK_monitor_enter); + M_ALD_DSEG(REG_ITMP2, disp); + + M_AST(REG_A0, REG_SP, syncslot_offset); + + M_ASUB_IMM(96, REG_SP); + M_CALL(REG_ITMP2); + M_AADD_IMM(96, REG_SP); + +#if !defined(NDEBUG) + if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) { + for (p = 0; p < INT_ARG_CNT; p++) + M_ILD(abi_registers_integer_argument[p], REG_SP, p * 8); + + for (p = 0; p < FLT_ARG_CNT; p++) + M_DLD(abi_registers_float_argument[p], REG_SP, (INT_ARG_CNT + p) * 8); + + M_AADD_IMM((INT_ARG_CNT + FLT_ARG_CNT) * 8, REG_SP); + } +#endif +} +#endif + + +/** + * Generates synchronization code to leave a monitor. + */ +#if defined(ENABLE_THREADS) +void emit_monitor_exit(jitdata* jd, int32_t syncslot_offset) +{ + int32_t disp; + + // Get required compiler data. + methodinfo* m = jd->m; + codegendata* cd = jd->cd; + + /* we need to save the proper return value */ + + methoddesc* md = m->parseddesc; + + switch (md->returntype.type) { + case TYPE_LNG: + M_IST(REG_RESULT2, REG_SP, syncslot_offset + 8 + 4); + /* fall through */ + case TYPE_INT: + case TYPE_ADR: + M_IST(REG_RESULT , REG_SP, syncslot_offset + 8); + break; + case TYPE_FLT: + M_FST(REG_FRESULT, REG_SP, syncslot_offset + 8); + break; + case TYPE_DBL: + M_DST(REG_FRESULT, REG_SP, syncslot_offset + 8); + break; + } + + M_ALD(REG_A0, REG_SP, syncslot_offset); + + disp = dseg_add_functionptr(cd, LOCK_monitor_exit); + M_ALD_DSEG(REG_ITMP2, disp); + + M_ASUB_IMM(96, REG_SP); + M_CALL(REG_ITMP2); + M_AADD_IMM(96, REG_SP); + + /* and now restore the proper return value */ + + switch (md->returntype.type) { + case TYPE_LNG: + M_ILD(REG_RESULT2, REG_SP, syncslot_offset + 8 + 4); + /* fall through */ + case TYPE_INT: + case TYPE_ADR: + M_ILD(REG_RESULT , REG_SP, syncslot_offset + 8); + break; + case TYPE_FLT: + M_FLD(REG_FRESULT, REG_SP, syncslot_offset + 8); + break; + case TYPE_DBL: + M_DLD(REG_FRESULT, REG_SP, syncslot_offset + 8); + break; + } +} +#endif + + +/** + * Emit profiling code for method frequency counting. + */ +#if defined(ENABLE_PROFILING) +void emit_profile_method(codegendata* cd, codeinfo* code) +{ + M_ALD_DSEG(REG_ITMP1, CodeinfoPointer); + ICONST(REG_ITMP2, 1); + N_AL(REG_ITMP2, OFFSET(codeinfo, frequency), RN, REG_ITMP1); + M_IST(REG_ITMP2, REG_ITMP1, OFFSET(codeinfo, frequency)); +} +#endif + + +/** + * Emit profiling code for basicblock frequency counting. + */ +#if defined(ENABLE_PROFILING) +void emit_profile_basicblock(codegendata* cd, codeinfo* code, basicblock* bptr) +{ + M_ALD_DSEG(REG_ITMP1, CodeinfoPointer); + M_ALD(REG_ITMP1, REG_ITMP1, OFFSET(codeinfo, bbfrequency)); + ICONST(REG_ITMP2, 1); + N_AL(REG_ITMP2, bptr->nr * 4, RN, REG_ITMP1); + M_IST(REG_ITMP2, REG_ITMP1, bptr->nr * 4); +} +#endif + + /* emit_verbosecall_enter ****************************************************** Generates the code for the call trace. @@ -770,7 +948,7 @@ void emit_exception_check(codegendata *cd, instruction *iptr) } } -void emit_restore_pv(codegendata *cd) { +void emit_recompute_pv(codegendata *cd) { s4 offset, offset_imm; /* diff --git a/src/vm/jit/s390/md.h b/src/vm/jit/s390/md.h index cbb7f9b6d..7f6c131d7 100644 --- a/src/vm/jit/s390/md.h +++ b/src/vm/jit/s390/md.h @@ -35,6 +35,21 @@ #include "vm/jit/methodtree.h" +/** + * Returns the size (in bytes) of the current stackframe, specified by + * the passed codeinfo structure. + */ +inline static int32_t md_stacktrace_get_framesize(codeinfo* code) +{ + // Check for the asm_vm_call_method special case. + if (code == NULL) + return 0; + + // On S390 we use 8-byte stackslots. + return code->stackframesize * 8; +} + + /* md_stacktrace_get_returnaddress ********************************************* Returns the return address of the current stackframe, specified by diff --git a/src/vm/jit/sparc64/arch.h b/src/vm/jit/sparc64/arch.h index 5897ad13a..48c674101 100644 --- a/src/vm/jit/sparc64/arch.h +++ b/src/vm/jit/sparc64/arch.h @@ -97,6 +97,15 @@ #define SUPPORT_HARDWARE_DIVIDE_BY_ZERO 0 +/* stackframe *****************************************************************/ + +#error Set the values below correctly!!! +#define STACKFRMAE_RA_BETWEEN_FRAMES 0 +#define STACKFRAME_RA_TOP_OF_FRAME 0 +#define STACKFRAME_LEAFMETHODS_RA_REGISTER 0 +#define STACKFRAME_SYNC_NEEDS_TWO_SLOTS 0 + + /* replacement ****************************************************************/ #define REPLACEMENT_PATCH_SIZE 4 /* bytes */ diff --git a/src/vm/jit/sparc64/codegen.c b/src/vm/jit/sparc64/codegen.c index 1de656e74..5ca25f250 100644 --- a/src/vm/jit/sparc64/codegen.c +++ b/src/vm/jit/sparc64/codegen.c @@ -58,7 +58,6 @@ #include "vm/jit/parse.hpp" #include "vm/jit/patcher.h" #include "vm/jit/reg.h" -#include "vm/jit/replace.hpp" #include "vm/jit/stacktrace.hpp" #include "vm/jit/sparc64/solaris/macro_rename.h" @@ -121,41 +120,7 @@ bool check_13bit_imm(s8 imm) bool codegen_emit(jitdata *jd) { - methodinfo *m; - codeinfo *code; - codegendata *cd; - registerdata *rd; - s4 len, s1, s2, s3, d, disp, slots; - varinfo *var; - basicblock *bptr; - instruction *iptr; - u2 currentline; - constant_classref *cr; - methodinfo *lm; /* local methodinfo for ICMD_INVOKE* */ - unresolved_method *um; - builtintable_entry *bte; - methoddesc *md; - fieldinfo *fi; - unresolved_field *uf; - s4 fieldtype; - s4 varindex; - /* get required compiler data */ - - m = jd->m; - code = jd->code; - cd = jd->cd; - rd = jd->rd; - - /* prevent compiler warnings */ - - d = 0; - currentline = 0; - lm = NULL; - bte = NULL; - - { - s4 i, p, t, l; s4 savedregs_num; s4 framesize_disp; @@ -165,13 +130,6 @@ bool codegen_emit(jitdata *jd) savedregs_num = WINSAVE_CNT + ABIPARAMS_CNT; /* register-window save area */ - /* space to save used callee saved registers */ - - savedregs_num += (INT_SAV_CNT - rd->savintreguse); - savedregs_num += (FLT_SAV_CNT - rd->savfltreguse); - - cd->stackframesize = rd->memuse + savedregs_num; - #if defined(ENABLE_THREADS) /* space to save argument of monitor_enter */ if (checksync && code_is_synchronized(code)) cd->stackframesize++; @@ -182,22 +140,33 @@ bool codegen_emit(jitdata *jd) if (cd->stackframesize & 1) cd->stackframesize++; - /* create method header */ - (void) dseg_add_unique_address(cd, code); /* CodeinfoPointer */ - framesize_disp = dseg_add_unique_s4(cd, cd->stackframesize * 8); /* FrameSize */ - code->synchronizedoffset = JITSTACK + 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 */ + + + + + +/** + * Generates machine code for the method prolog. + */ +void codegen_emit_prolog(jitdata* jd) +{ + varinfo* var; + methoddesc* md; + int32_t s1; + int32_t p, t, l; + 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; /* save register window and create stack frame (if necessary) */ @@ -219,61 +188,6 @@ bool codegen_emit(jitdata *jd) } #endif -#if !defined(NDEBUG) - if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) - emit_verbosecall_enter(jd); -#endif - - - /* call monitorenter function */ -#if defined(ENABLE_THREADS) - if (checksync && code_is_synchronized(code)) { - /* stack offset for monitor argument */ - - s1 = rd->memuse; - - /* save float argument registers */ - - /* XXX jit-c-call */ - slots = FLT_ARG_CNT; - ALIGN_STACK_SLOTS(slots); - - M_LDA(REG_SP, REG_SP, -(slots * 8)); - for (i = 0; i < FLT_ARG_CNT; i++) - M_DST(abi_registers_float_argument[i], REG_SP, CSTACK + i * 8); - - s1 += slots; - - /* get correct lock object */ - - if (m->flags & ACC_STATIC) { - disp = dseg_add_address(cd, &m->clazz->object.header); - M_ALD(REG_OUT0, REG_PV, disp); - disp = dseg_add_functionptr(cd, LOCK_monitor_enter); - M_ALD(REG_ITMP3, REG_PV, disp); - } - else { - /* copy class pointer: $i0 -> $o0 */ - M_MOV(REG_RESULT_CALLEE, REG_OUT0); - M_BNEZ(REG_OUT0, 3); - disp = dseg_add_functionptr(cd, LOCK_monitor_enter); - M_ALD(REG_ITMP3, REG_PV, disp); /* branch delay */ - M_ALD_INTERN(REG_ZERO, REG_ZERO, TRAP_NullPointerException); - } - - M_JMP(REG_RA_CALLER, REG_ITMP3, REG_ZERO); - M_AST(REG_OUT0, REG_SP, CSTACK + s1 * 8); /* branch delay */ - - /* restore float argument registers */ - - for (i = 0; i < FLT_ARG_CNT; i++) - M_DLD(abi_registers_float_argument[i], REG_SP, CSTACK + i * 8); - - M_LDA(REG_SP, REG_SP, slots * 8); - } -#endif - - /* take arguments out of register or stack frame */ md = m->parseddesc; @@ -356,7 +270,7 @@ bool codegen_emit(jitdata *jd) } else { /* floating args */ if (!md->params[p].inmemory) { /* register arguments */ if (!(var->flags & INMEMORY)) { /* reg arg -> register */ - M_FLTMOVE(s1, var->vv.regoff); + emit_fmove(cd, s1, var->vv.regoff); } else { /* reg arg -> spilled */ M_DST(s1, REG_SP, JITSTACK + var->vv.regoff); @@ -372,107 +286,42 @@ bool codegen_emit(jitdata *jd) } } } /* end for */ - - - } - - /* end of header generation */ - - /* create replacement points */ - - REPLACEMENT_POINTS_INIT(cd, jd); - - /* walk through all basic blocks */ - - for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) { - - bptr->mpc = (s4) (cd->mcodeptr - cd->mcodebase); - - if (bptr->flags >= BBREACHED) { - - /* branch resolving */ - - codegen_resolve_branchrefs(cd, bptr); - - /* handle replacement points */ - - REPLACEMENT_POINT_BLOCK_START(cd, bptr); - - - /* copy interface registers to their destination */ - - len = bptr->indepth; - MCODECHECK(64+len); - -#if defined(ENABLE_LSRA) -#error XXX LSRA not tested yet - if (opt_lsra) { - while (len) { - len--; - src = bptr->invars[len]; - if ((len == bptr->indepth-1) && (bptr->type == BBTYPE_EXH)) { - /* d = reg_of_var(m, src, REG_ITMP1); */ - if (!(src->flags & INMEMORY)) - d = src->vv.regoff; - else - d = REG_ITMP1; - M_INTMOVE(REG_ITMP1, d); - emit_store(jd, NULL, src, d); - } - } - } else { -#endif - while (len) { - len--; - var = VAR(bptr->invars[len]); - if ((len == bptr->indepth-1) && (bptr->type == BBTYPE_EXH)) { - d = codegen_reg_of_var(0, var, REG_ITMP1); - M_INTMOVE(REG_ITMP2_XPTR, d); - emit_store(jd, NULL, var, d); - } - else { - assert((var->flags & INOUT)); - } - } -#if defined(ENABLE_LSRA) - } -#endif - /* walk through all instructions */ - - len = bptr->icount; - - for (iptr = bptr->iinstr; len > 0; len--, iptr++) { - if (iptr->line != currentline) { - linenumbertable_list_entry_add(cd, iptr->line); - currentline = iptr->line; - } - - MCODECHECK(64); /* an instruction usually needs < 64 words */ +} - switch (iptr->opc) { - case ICMD_INLINE_START: - case ICMD_INLINE_END: - break; +/** + * Generates machine code for the method epilog. + */ +void codegen_emit_epilog(jitdata* jd) +{ + M_RETURN(REG_RA_CALLEE, 8); /* implicit window restore */ + M_NOP; +} - case ICMD_NOP: /* ... ==> ... */ - break; - case ICMD_CHECKNULL: /* ..., objectref ==> ..., objectref */ +/** + * Generates machine code for one ICMD. + */ +void codegen_emit_instruction(jitdata* jd, instruction* iptr) +{ + varinfo* var; + builtintable_entry* bte; + 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. + codeinfo* code = jd->code; + codegendata* cd = jd->cd; + + switch (iptr->opc) { - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - emit_nullpointer_check(cd, iptr, s1); - break; - /* 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_LCONST: /* ... ==> ..., constant */ d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); @@ -501,7 +350,7 @@ bool codegen_emit(jitdata *jd) d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - cr = iptr->sx.val.c.ref; + constant_classref *cr = iptr->sx.val.c.ref; disp = dseg_add_unique_address(cd, cr); codegen_add_patch_ref(cd, PATCHER_aconst, cr, disp); @@ -522,38 +371,6 @@ bool codegen_emit(jitdata *jd) break; - /* load/store/copy/move operations ************************************/ - - case ICMD_ILOAD: /* ... ==> ..., content of local variable */ - case ICMD_LLOAD: - case ICMD_ALOAD: - case ICMD_FLOAD: - case ICMD_DLOAD: - case ICMD_ISTORE: /* ..., value ==> ... */ - case ICMD_LSTORE: - case ICMD_FSTORE: - 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/dup/swap 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_INEG: /* ..., value ==> ..., - value */ @@ -1886,133 +1703,14 @@ bool codegen_emit(jitdata *jd) case ICMD_ATHROW: /* ..., objectref ==> ... (, objectref) */ - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - M_INTMOVE(s1, REG_ITMP2_XPTR); - -#ifdef ENABLE_VERIFIER - if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - unresolved_class *uc = iptr->sx.s23.s2.uc; - - codegen_add_patch_ref(cd, PATCHER_athrow_areturn, uc, 0); - } -#endif /* ENABLE_VERIFIER */ - disp = dseg_add_functionptr(cd, asm_handle_exception); M_ALD(REG_ITMP1, REG_PV, disp); M_JMP(REG_ITMP3_XPC, REG_ITMP1, REG_ZERO); M_NOP; M_NOP; /* nop ensures that XPC is less than the end */ /* of basic block */ - ALIGNCODENOP; - break; - - case ICMD_GOTO: /* ... ==> ... */ - case ICMD_RET: /* ... ==> ... */ - - emit_br(cd, iptr->dst.block); - ALIGNCODENOP; - break; - - case ICMD_JSR: /* ... ==> ... */ - - emit_br(cd, iptr->sx.s23.s3.jsrtarget.block); - ALIGNCODENOP; - break; - - case ICMD_IFNULL: /* ..., value ==> ... */ - case ICMD_IFNONNULL: - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - emit_bccz(cd, iptr->dst.block, iptr->opc - ICMD_IFNULL, s1, BRANCH_OPT_NONE); - break; - - /* Note: int compares must not branch on the register directly. */ - /* Reason is, that register content is not 32-bit clean. */ - - case ICMD_IFEQ: /* ..., value ==> ... */ - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - - if ((iptr->sx.val.i >= -4096) && (iptr->sx.val.i <= 4095)) { - M_CMP_IMM(s1, iptr->sx.val.i); - } - else { - ICONST(REG_ITMP2, iptr->sx.val.i); - M_CMP(s1, REG_ITMP2); - } - emit_beq(cd, iptr->dst.block); break; - case ICMD_IFLT: /* ..., value ==> ... */ - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - - if ((iptr->sx.val.i >= -4096) && (iptr->sx.val.i <= 4095)) { - M_CMP_IMM(s1, iptr->sx.val.i); - } - else { - ICONST(REG_ITMP2, iptr->sx.val.i); - M_CMP(s1, REG_ITMP2); - } - emit_blt(cd, iptr->dst.block); - break; - - case ICMD_IFLE: /* ..., value ==> ... */ - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - - if ((iptr->sx.val.i >= -4096) && (iptr->sx.val.i <= 4095)) { - M_CMP_IMM(s1, iptr->sx.val.i); - } - else { - ICONST(REG_ITMP2, iptr->sx.val.i); - M_CMP(s1, REG_ITMP2); - } - emit_ble(cd, iptr->dst.block); - break; - - case ICMD_IFNE: /* ..., value ==> ... */ - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - - if ((iptr->sx.val.i >= -4096) && (iptr->sx.val.i <= 4095)) { - M_CMP_IMM(s1, iptr->sx.val.i); - } - else { - ICONST(REG_ITMP2, iptr->sx.val.i); - M_CMP(s1, REG_ITMP2); - } - emit_bne(cd, iptr->dst.block); - break; - - case ICMD_IFGT: /* ..., value ==> ... */ - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - - if ((iptr->sx.val.i >= -4096) && (iptr->sx.val.i <= 4095)) { - M_CMP_IMM(s1, iptr->sx.val.i); - } - else { - ICONST(REG_ITMP2, iptr->sx.val.i); - M_CMP(s1, REG_ITMP2); - } - emit_bgt(cd, iptr->dst.block); - break; - - case ICMD_IFGE: /* ..., value ==> ... */ - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - - if ((iptr->sx.val.i >= -4096) && (iptr->sx.val.i <= 4095)) { - M_CMP_IMM(s1, iptr->sx.val.i); - } - else { - ICONST(REG_ITMP2, iptr->sx.val.i); - M_CMP(s1, REG_ITMP2); - } - emit_bge(cd, iptr->dst.block); - break; - case ICMD_IF_LEQ: /* ..., value ==> ... */ s1 = emit_load_s1(jd, iptr, REG_ITMP1); @@ -2125,14 +1823,6 @@ bool codegen_emit(jitdata *jd) emit_beq_xcc(cd, iptr->dst.block); break; - case ICMD_IF_ICMPEQ: /* 32-bit compare */ - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - s2 = emit_load_s2(jd, iptr, REG_ITMP2); - M_CMP(s1, s2); - emit_beq(cd, iptr->dst.block); - break; - case ICMD_IF_ACMPNE: /* ..., value, value ==> ... */ case ICMD_IF_LCMPNE: /* op1 = target JavaVM pc */ @@ -2141,14 +1831,6 @@ bool codegen_emit(jitdata *jd) M_CMP(s1, s2); emit_bne_xcc(cd, iptr->dst.block); break; - - case ICMD_IF_ICMPNE: /* 32-bit compare */ - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - s2 = emit_load_s2(jd, iptr, REG_ITMP2); - M_CMP(s1, s2); - emit_bne(cd, iptr->dst.block); - break; case ICMD_IF_LCMPLT: /* ..., value, value ==> ... */ @@ -2157,14 +1839,6 @@ bool codegen_emit(jitdata *jd) M_CMP(s1, s2); emit_blt_xcc(cd, iptr->dst.block); break; - - case ICMD_IF_ICMPLT: /* 32-bit compare */ - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - s2 = emit_load_s2(jd, iptr, REG_ITMP2); - M_CMP(s1, s2); - emit_blt(cd, iptr->dst.block); - break; case ICMD_IF_LCMPGT: /* ..., value, value ==> ... */ @@ -2173,14 +1847,6 @@ bool codegen_emit(jitdata *jd) M_CMP(s1, s2); emit_bgt_xcc(cd, iptr->dst.block); break; - - case ICMD_IF_ICMPGT: /* 32-bit compare */ - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - s2 = emit_load_s2(jd, iptr, REG_ITMP2); - M_CMP(s1, s2); - emit_bgt(cd, iptr->dst.block); - break; case ICMD_IF_LCMPLE: /* ..., value, value ==> ... */ @@ -2189,15 +1855,6 @@ bool codegen_emit(jitdata *jd) M_CMP(s1, s2); emit_ble_xcc(cd, iptr->dst.block); break; - - case ICMD_IF_ICMPLE: /* 32-bit compare */ - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - s2 = emit_load_s2(jd, iptr, REG_ITMP2); - M_CMP(s1, s2); - emit_ble(cd, iptr->dst.block); - break; - case ICMD_IF_LCMPGE: /* ..., value, value ==> ... */ @@ -2206,105 +1863,6 @@ bool codegen_emit(jitdata *jd) M_CMP(s1, s2); emit_bge_xcc(cd, iptr->dst.block); break; - - case ICMD_IF_ICMPGE: /* 32-bit compare */ - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - s2 = emit_load_s2(jd, iptr, REG_ITMP2); - M_CMP(s1, s2); - emit_bge(cd, iptr->dst.block); - break; - - - case ICMD_IRETURN: /* ..., retvalue ==> ... */ - case ICMD_LRETURN: - - REPLACEMENT_POINT_RETURN(cd, iptr); - - s1 = emit_load_s1(jd, iptr, REG_RESULT_CALLEE); - M_INTMOVE(s1, REG_RESULT_CALLEE); - goto nowperformreturn; - - case ICMD_ARETURN: /* ..., retvalue ==> ... */ - - REPLACEMENT_POINT_RETURN(cd, iptr); - - s1 = emit_load_s1(jd, iptr, REG_RESULT_CALLEE); - M_INTMOVE(s1, REG_RESULT_CALLEE); - -#ifdef ENABLE_VERIFIER - if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - unresolved_class *uc = iptr->sx.s23.s2.uc; - - codegen_add_patch_ref(cd, PATCHER_athrow_areturn, uc, 0); - } -#endif /* ENABLE_VERIFIER */ - goto nowperformreturn; - - case ICMD_FRETURN: /* ..., retvalue ==> ... */ - case ICMD_DRETURN: - - REPLACEMENT_POINT_RETURN(cd, iptr); - - s1 = emit_load_s1(jd, iptr, REG_FRESULT); - M_DBLMOVE(s1, REG_FRESULT); - goto nowperformreturn; - - case ICMD_RETURN: /* ... ==> ... */ - - REPLACEMENT_POINT_RETURN(cd, iptr); - -nowperformreturn: - { - s4 i, p; - - p = cd->stackframesize; - -#if !defined(NDEBUG) - if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) - emit_verbosecall_exit(jd); -#endif - -#if defined(ENABLE_THREADS) - if (checksync && code_is_synchronized(code)) { - /* XXX jit-c-call */ - disp = dseg_add_functionptr(cd, LOCK_monitor_exit); - M_ALD(REG_ITMP3, REG_PV, disp); - - /* we need to save fp return value (int saved by window) */ - - switch (iptr->opc) { - case ICMD_FRETURN: - case ICMD_DRETURN: - M_ALD(REG_OUT0, REG_SP, CSTACK + rd->memuse * 8); - M_JMP(REG_RA_CALLER, REG_ITMP3, REG_ZERO); - M_DST(REG_FRESULT, REG_SP, CSTACK + rd->memuse * 8); /* delay */ - - /* restore the fp return value */ - - M_DLD(REG_FRESULT, REG_SP, CSTACK + rd->memuse * 8); - break; - case ICMD_IRETURN: - case ICMD_LRETURN: - case ICMD_ARETURN: - case ICMD_RETURN: - M_JMP(REG_RA_CALLER, REG_ITMP3, REG_ZERO); - M_ALD(REG_OUT0, REG_SP, CSTACK + rd->memuse * 8); /* delay */ - break; - default: - assert(false); - break; - } - } -#endif - - - - M_RETURN(REG_RA_CALLEE, 8); /* implicit window restore */ - M_NOP; - ALIGNCODENOP; - } - break; case ICMD_TABLESWITCH: /* ..., index ==> ... */ { @@ -2361,40 +1919,11 @@ nowperformreturn: M_NOP; ALIGNCODENOP; break; - - case ICMD_LOOKUPSWITCH: /* ..., key ==> ... */ - { - s4 i; - lookup_target_t *lookup; - - lookup = iptr->dst.lookup; - - i = iptr->sx.s23.s2.lookupcount; - - MCODECHECK((i<<2)+8); - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - - while (--i >= 0) { - if ((lookup->value >= -4096) && (lookup->value <= 4095)) { - M_CMP_IMM(s1, lookup->value); - } else { - ICONST(REG_ITMP2, lookup->value); - M_CMP(s1, REG_ITMP2); - } - emit_beq(cd, lookup->target.block); - ++lookup; - } - - emit_br(cd, iptr->sx.s23.s3.lookupdefault.block); - ALIGNCODENOP; - break; - } - + // XXX This is the old builtin invocation containing some + // special argument handling code, port me! case ICMD_BUILTIN: /* ..., arg1, arg2, arg3 ==> ... */ - REPLACEMENT_POINT_FORGC_BUILTIN(cd, iptr); - bte = iptr->sx.s23.s3.bte; md = bte->md; @@ -2442,41 +1971,11 @@ nowperformreturn: #else assert(md->argfltreguse == 0); #endif - - goto gen_method; - case ICMD_INVOKESTATIC: /* ..., [arg1, [arg2 ...]] ==> ... */ - case ICMD_INVOKESPECIAL:/* ..., objectref, [arg1, [arg2 ...]] ==> ... */ - case ICMD_INVOKEVIRTUAL:/* op1 = arg count, val.a = method pointer */ - case ICMD_INVOKEINTERFACE: - REPLACEMENT_POINT_INVOKE(cd, iptr); - if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - lm = NULL; - um = iptr->sx.s23.s3.um; - md = um->methodref->parseddesc.md; - } - else { - lm = iptr->sx.s23.s3.fmiref->p.method; - um = NULL; - md = lm->parseddesc; - } - -gen_method: - s3 = md->paramcount; - - MCODECHECK((s3 << 1) + 64); - - /* copy arguments to registers or stack location */ - - for (s3 = s3 - 1; s3 >= 0; s3--) { - var = VAR(iptr->sx.s23.s2.args[s3]); - d = md->params[s3].regoff; - - if (var->flags & PREALLOC) - continue; +XXXXXX if (IS_INT_LNG_TYPE(var->type)) { if (!md->params[s3].inmemory) { s1 = emit_load(jd, iptr, var, d); @@ -2487,159 +1986,122 @@ gen_method: M_STX(s1, REG_SP, JITSTACK + d); } } - else { -#ifdef BUILTIN_FLOAT_ARGS - if (iptr->opc == ICMD_BUILTIN) - continue; -#endif - - if (!md->params[s3].inmemory) { - s1 = emit_load(jd, iptr, var, d); - if (IS_2_WORD_TYPE(var->type)) - M_DMOV(s1, d); - else - M_FMOV(s1, d); - } - else { - s1 = emit_load(jd, iptr, var, REG_FTMP1); - M_DST(s1, REG_SP, JITSTACK + d); - } - } } +XXXXXX - 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); - } + case ICMD_BUILTIN: + bte = iptr->sx.s23.s3.bte; + if (bte->stub == NULL) { + disp = dseg_add_functionptr(cd, bte->fp); + } + else { + disp = dseg_add_functionptr(cd, bte->stub); + } - M_ALD(REG_PV_CALLER, REG_PV, disp); /* built-in-function pointer */ + M_ALD(REG_PV_CALLER, REG_PV, disp); /* built-in-function pointer */ - /* XXX jit-c-call */ - /* generate the actual call */ - - M_JMP(REG_RA_CALLER, REG_PV_CALLER, REG_ZERO); - M_NOP; - REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr); - REPLACEMENT_POINT_FORGC_BUILTIN_RETURN(cd, iptr); - disp = (s4) (cd->mcodeptr - cd->mcodebase); - /* REG_RA holds the value of the jmp instruction, therefore +8 */ - M_LDA(REG_ZERO, REG_RA_CALLER, -disp + 8); - - if (md->returntype.type == TYPE_FLT) { - /* special handling for float return value in %f0 */ - M_FMOV_INTERN(0,1); - } - break; + /* XXX jit-c-call */ + /* generate the actual call */ + + M_JMP(REG_RA_CALLER, REG_PV_CALLER, REG_ZERO); + M_NOP; - case ICMD_INVOKESPECIAL: - emit_nullpointer_check(cd, iptr, REG_OUT0); - /* fall-through */ + if (md->returntype.type == TYPE_FLT) { + /* special handling for float return value in %f0 */ + M_FMOV_INTERN(0,1); + } + break; - case ICMD_INVOKESTATIC: - if (lm == NULL) { - disp = dseg_add_unique_address(cd, NULL); + case ICMD_INVOKESPECIAL: + emit_nullpointer_check(cd, iptr, REG_OUT0); + /* fall-through */ - codegen_add_patch_ref(cd, PATCHER_invokestatic_special, - um, disp); - } - else - disp = dseg_add_address(cd, lm->stubroutine); + case ICMD_INVOKESTATIC: + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + um = iptr->sx.s23.s3.um; + disp = dseg_add_unique_address(cd, NULL); - M_ALD(REG_PV_CALLER, REG_PV, disp); /* method pointer in pv */ - - /* generate the actual call */ - - M_JMP(REG_RA_CALLER, REG_PV_CALLER, REG_ZERO); - M_NOP; - REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr); - disp = (s4) (cd->mcodeptr - cd->mcodebase); - /* REG_RA holds the value of the jmp instruction, therefore +8 */ - M_LDA(REG_ZERO, REG_RA_CALLER, -disp + 8); - break; + codegen_add_patch_ref(cd, PATCHER_invokestatic_special, + um, disp); + } + else { + lm = iptr->sx.s23.s3.fmiref->p.method; + disp = dseg_add_address(cd, lm->stubroutine); + } - case ICMD_INVOKEVIRTUAL: - emit_nullpointer_check(cd, iptr, REG_OUT0); + M_ALD(REG_PV_CALLER, REG_PV, disp); /* method pointer in pv */ + + /* generate the actual call */ + + M_JMP(REG_RA_CALLER, REG_PV_CALLER, REG_ZERO); + M_NOP; + break; - if (lm == NULL) { - codegen_add_patch_ref(cd, PATCHER_invokevirtual, um, 0); + case ICMD_INVOKEVIRTUAL: + emit_nullpointer_check(cd, iptr, REG_OUT0); - s1 = 0; - } - else - s1 = OFFSET(vftbl_t, table[0]) + - sizeof(methodptr) * lm->vftblindex; + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + um = iptr->sx.s23.s3.um; + codegen_add_patch_ref(cd, PATCHER_invokevirtual, um, 0); - /* implicit null-pointer check */ - M_ALD(REG_METHODPTR, REG_OUT0,OFFSET(java_object_t, vftbl)); - M_ALD(REG_PV_CALLER, REG_METHODPTR, s1); - - /* generate the actual call */ - - M_JMP(REG_RA_CALLER, REG_PV_CALLER, REG_ZERO); - M_NOP; - REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr); - disp = (s4) (cd->mcodeptr - cd->mcodebase); - /* REG_RA holds the value of the jmp instruction, therefore +8 */ - M_LDA(REG_ZERO, REG_RA_CALLER, -disp + 8); - break; + s1 = 0; + } + else { + lm = iptr->sx.s23.s3.fmiref->p.method; + s1 = OFFSET(vftbl_t, table[0]) + + sizeof(methodptr) * lm->vftblindex; + } - case ICMD_INVOKEINTERFACE: - emit_nullpointer_check(cd, iptr, REG_OUT0); + /* implicit null-pointer check */ + M_ALD(REG_METHODPTR, REG_OUT0,OFFSET(java_object_t, vftbl)); + M_ALD(REG_PV_CALLER, REG_METHODPTR, s1); + + /* generate the actual call */ + + M_JMP(REG_RA_CALLER, REG_PV_CALLER, REG_ZERO); + M_NOP; + break; - if (lm == NULL) { - codegen_add_patch_ref(cd, PATCHER_invokeinterface, um, 0); + case ICMD_INVOKEINTERFACE: + emit_nullpointer_check(cd, iptr, REG_OUT0); - s1 = 0; - s2 = 0; - } - else { - s1 = OFFSET(vftbl_t, interfacetable[0]) - - sizeof(methodptr*) * lm->clazz->index; + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + um = iptr->sx.s23.s3.um; + codegen_add_patch_ref(cd, PATCHER_invokeinterface, um, 0); - s2 = sizeof(methodptr) * (lm - lm->clazz->methods); - } + s1 = 0; + s2 = 0; + } + else { + lm = iptr->sx.s23.s3.fmiref->p.method; + s1 = OFFSET(vftbl_t, interfacetable[0]) - + sizeof(methodptr*) * lm->clazz->index; - /* implicit null-pointer check */ - M_ALD(REG_METHODPTR, REG_OUT0, OFFSET(java_object_t, vftbl)); - M_ALD(REG_METHODPTR, REG_METHODPTR, s1); - M_ALD(REG_PV_CALLER, REG_METHODPTR, s2); - - /* generate the actual call */ - - M_JMP(REG_RA_CALLER, REG_PV_CALLER, REG_ZERO); - M_NOP; - REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr); - disp = (s4) (cd->mcodeptr - cd->mcodebase); - /* REG_RA holds the value of the jmp instruction, therefore +8 */ - M_LDA(REG_ZERO, REG_RA_CALLER, -disp + 8); - break; + s2 = sizeof(methodptr) * (lm - lm->clazz->methods); } - /* store return value */ + /* implicit null-pointer check */ + M_ALD(REG_METHODPTR, REG_OUT0, OFFSET(java_object_t, vftbl)); + M_ALD(REG_METHODPTR, REG_METHODPTR, s1); + M_ALD(REG_PV_CALLER, REG_METHODPTR, s2); - d = md->returntype.type; + /* generate the actual call */ + + M_JMP(REG_RA_CALLER, REG_PV_CALLER, REG_ZERO); + M_NOP; + break; - if (d != TYPE_VOID) { - if (IS_INT_LNG_TYPE(d)) { - s1 = codegen_reg_of_dst(jd, iptr, REG_RESULT_CALLER); - M_INTMOVE(REG_RESULT_CALLER, s1); - } - else { - s1 = codegen_reg_of_dst(jd, iptr, REG_FRESULT); - if (IS_2_WORD_TYPE(d)) { - M_DBLMOVE(REG_FRESULT, s1); - } else { - M_FLTMOVE(REG_FRESULT, s1); - } +XXXXXX + /* store return value */ + else { + s1 = codegen_reg_of_dst(jd, iptr, REG_FRESULT); + if (IS_2_WORD_TYPE(d)) { + emit_dmove(cd, REG_FRESULT, s1); + } else { + emit_fmove(cd, REG_FRESULT, s1); } - emit_store_dst(jd, iptr, s1); } - break; - +XXXXX case ICMD_CHECKCAST: /* ..., objectref ==> ..., objectref */ /* val.a: (classinfo*) superclass */ @@ -2677,7 +2139,7 @@ gen_method: if (super == NULL) { emit_label_beqz(cd, BRANCH_LABEL_1, s1); - cr = iptr->sx.s23.s3.c.ref; + constant_classref *cr = iptr->sx.s23.s3.c.ref; disp = dseg_add_unique_s4(cd, 0); /* super->flags */ codegen_add_patch_ref(cd, PATCHER_checkcast_instanceof_flags, @@ -2692,7 +2154,7 @@ gen_method: if ((super == NULL) || (super->flags & ACC_INTERFACE)) { if (super == NULL) { - cr = iptr->sx.s23.s3.c.ref; + constant_classref *cr = iptr->sx.s23.s3.c.ref; codegen_add_patch_ref(cd, PATCHER_checkcast_interface, cr, 0); @@ -2724,7 +2186,7 @@ gen_method: if (super == NULL) { emit_label(cd, BRANCH_LABEL_2); - cr = iptr->sx.s23.s3.c.ref; + constant_classref *cr = iptr->sx.s23.s3.c.ref; disp = dseg_add_unique_address(cd, NULL); codegen_add_patch_ref(cd, @@ -2770,7 +2232,7 @@ gen_method: disp = dseg_add_address(cd, iptr->sx.s23.s3.c.cls); if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - cr = iptr->sx.s23.s3.c.ref; + constant_classref *cr = iptr->sx.s23.s3.c.ref; disp = dseg_add_unique_address(cd, NULL); codegen_add_patch_ref(cd, PATCHER_builtin_arraycheckcast, @@ -2842,7 +2304,7 @@ gen_method: if (super == NULL) { emit_label_beqz(cd, BRANCH_LABEL_1, s1); - cr = iptr->sx.s23.s3.c.ref; + constant_classref *cr = iptr->sx.s23.s3.c.ref; disp = dseg_add_unique_s4(cd, 0); /* super->flags */ codegen_add_patch_ref(cd, PATCHER_checkcast_instanceof_flags, @@ -2857,7 +2319,7 @@ gen_method: if ((super == NULL) || (super->flags & ACC_INTERFACE)) { if (super == NULL) { - cr = iptr->sx.s23.s3.c.ref; + constant_classref *cr = iptr->sx.s23.s3.c.ref; codegen_add_patch_ref(cd, PATCHER_instanceof_interface, cr, 0); @@ -2888,7 +2350,7 @@ gen_method: if (super == NULL) { emit_label(cd, BRANCH_LABEL_2); - cr = iptr->sx.s23.s3.c.ref; + constant_classref *cr = iptr->sx.s23.s3.c.ref; disp = dseg_add_unique_address(cd, NULL); codegen_add_patch_ref(cd, PATCHER_checkcast_instanceof_class, @@ -2984,37 +2446,8 @@ gen_method: break; default: - exceptions_throw_internalerror("Unknown ICMD %d during code generation", - iptr->opc); - return false; - + vm_abort("Unknown ICMD %d during code generation", iptr->opc); } /* switch */ - - } /* for instruction */ - - MCODECHECK(64); - - /* At the end of a basic block we may have to append some nops, - because the patcher stub calling code might be longer than the - actual instruction. So codepatching does not change the - following block unintentionally. */ - - if (cd->mcodeptr < cd->lastmcodeptr) { - while (cd->mcodeptr < cd->lastmcodeptr) { - M_NOP; - } - } - - } /* if (bptr -> flags >= BBREACHED) */ - } /* for basic block */ - - /* generate stubs */ - - emit_patcher_stubs(jd); - - /* everything's ok */ - - return true; } diff --git a/src/vm/jit/sparc64/codegen.h b/src/vm/jit/sparc64/codegen.h index b64cf4fc6..35759493a 100644 --- a/src/vm/jit/sparc64/codegen.h +++ b/src/vm/jit/sparc64/codegen.h @@ -92,31 +92,6 @@ s4 nat_argintregs[INT_NATARG_CNT]; slots++; -/* M_INTMOVE: - generates an integer-move from register rs to rd. - if rs and rd are the same int-register, no code will be generated. -*/ - -#define M_INTMOVE(rs,rd) if (rs != rd) { M_MOV(rs, rd); } - - -/* M_DBLMOVE: - generates a double floating-point-move from register (pair) rs to rd. - if rs and rd are the same double-register, no code will be generated -*/ - -#define M_DBLMOVE(rs, rd) if (rs != rd) { M_DMOV (rs, rd); } - - -/* M_FLTMOVE: - generates a double floating-point-move from pseudo register rs to rd. - (ie. lower register of double rs pair to lower register of double rd pair) - if rs and rd are the same double-register, no code will be generated -*/ -#define M_FLTMOVE(rs, rd) if (rs != rd) { M_FMOV (rs, rd); } - - - #define M_COPY(s,d) emit_copy(jd, iptr, (s), (d)) #define ICONST(d,c) emit_iconst(cd, (d), (c)) #define LCONST(d,c) emit_lconst(cd, (d), (c)) @@ -692,6 +667,8 @@ s4 get_lopart_disp(s4 disp); #define M_AADD_IMM(a,b,c) M_ADD_IMM(a,b,c) #define M_ASUB_IMM(a,b,c) M_SUB_IMM(a,b,c) #define M_ASLL_IMM(a,b,c) M_SLLX_IMM(a,b,c) - + +#define M_ACMP(a,b) M_CMP(a,b) +#define M_ICMP(a,b) M_CMP(a,b) #endif /* _CODEGEN_H */ diff --git a/src/vm/jit/sparc64/emit.c b/src/vm/jit/sparc64/emit.c index 0c71d11a7..e4d9a3fa6 100644 --- a/src/vm/jit/sparc64/emit.c +++ b/src/vm/jit/sparc64/emit.c @@ -239,6 +239,23 @@ void emit_lconst(codegendata *cd, s4 d, s8 value) } } + +/** + * Emits code updating the condition register by comparing one integer + * register to an immediate integer value. + */ +void emit_icmp_imm(codegendata* cd, int reg, int32_t value) +{ + if ((value >= -4096) && (value <= 4095)) { + M_CMP_IMM(reg, value); + } else { + assert(reg != REG_ITMP2); + ICONST(REG_ITMP2, value); + M_CMP(reg, REG_ITMP2); + } +} + + /* emit_branch ***************************************************************** Emits the code for conditional and unconditional branchs. @@ -583,6 +600,124 @@ uint32_t emit_trap(codegendata *cd) } +/** + * Emit code to recompute the procedure vector. + */ +void emit_recompute_pv(codegendata *cd) +{ + int32_t disp = (int32_t) (cd->mcodeptr - cd->mcodebase); + + /* REG_RA holds the value of the jmp instruction, therefore +8 */ + M_LDA(REG_ZERO, REG_RA_CALLER, -disp + 8); +} + + +/** + * Generates synchronization code to enter a monitor. + */ +#if defined(ENABLE_THREADS) +void emit_monitor_enter(jitdata* jd, int32_t syncslot_offset) +{ + int32_t i, slots; + int32_t disp; + + // Get required compiler data. + methodinfo* m = jd->m; + codegendata* cd = jd->cd; + +# if !defined(NDEBUG) + if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) { + /* save float argument registers */ + + /* XXX jit-c-call */ + slots = FLT_ARG_CNT; + ALIGN_STACK_SLOTS(slots); + + M_LDA(REG_SP, REG_SP, -(slots * 8)); + for (i = 0; i < FLT_ARG_CNT; i++) + M_DST(abi_registers_float_argument[i], REG_SP, CSTACK + i * 8); + + syncslot_offset += slots * 8; + } +# endif + + /* get correct lock object */ + + if (m->flags & ACC_STATIC) { + disp = dseg_add_address(cd, &m->clazz->object.header); + M_ALD(REG_OUT0, REG_PV, disp); + disp = dseg_add_functionptr(cd, LOCK_monitor_enter); + M_ALD(REG_ITMP3, REG_PV, disp); + } + else { + /* copy class pointer: $i0 -> $o0 */ + M_MOV(REG_RESULT_CALLEE, REG_OUT0); + M_BNEZ(REG_OUT0, 3); + disp = dseg_add_functionptr(cd, LOCK_monitor_enter); + M_ALD(REG_ITMP3, REG_PV, disp); /* branch delay */ + M_ALD_INTERN(REG_ZERO, REG_ZERO, TRAP_NullPointerException); + } + + M_JMP(REG_RA_CALLER, REG_ITMP3, REG_ZERO); + M_AST(REG_OUT0, REG_SP, CSTACK + syncslot_offset); /* branch delay */ + +# if !defined(NDEBUG) + if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) { + /* restore float argument registers */ + + for (i = 0; i < FLT_ARG_CNT; i++) + M_DLD(abi_registers_float_argument[i], REG_SP, CSTACK + i * 8); + + M_LDA(REG_SP, REG_SP, slots * 8); + } +# endif +} +#endif + + +/** + * Generates synchronization code to leave a monitor. + */ +#if defined(ENABLE_THREADS) +void emit_monitor_exit(jitdata* jd, int32_t syncslot_offset) +{ + int32_t disp; + + // Get required compiler data. + methodinfo* m = jd->m; + codegendata* cd = jd->cd; + + /* XXX jit-c-call */ + disp = dseg_add_functionptr(cd, LOCK_monitor_exit); + M_ALD(REG_ITMP3, REG_PV, disp); + + /* we need to save fp return value (int saved by window) */ + + methoddesc* md = m->parseddesc; + + switch (md->returntype.type) { + case TYPE_FLT: + case TYPE_DBL: + M_ALD(REG_OUT0, REG_SP, CSTACK + syncslot_offset); + M_JMP(REG_RA_CALLER, REG_ITMP3, REG_ZERO); + M_DST(REG_FRESULT, REG_SP, CSTACK + syncslot_offset); /* delay */ + + /* restore the fp return value */ + + M_DLD(REG_FRESULT, REG_SP, CSTACK + syncslot_offset); + break; + case TYPE_INT: + case TYPE_LNG: + case TYPE_DBL: + default: + M_JMP(REG_RA_CALLER, REG_ITMP3, REG_ZERO); + M_ALD(REG_OUT0, REG_SP, CSTACK + syncslot_offset); /* delay */ + break; + } +} +#endif + + /* emit_patcher_stubs ********************************************************** Generates the code for the patcher stubs. diff --git a/src/vm/jit/sparc64/md.h b/src/vm/jit/sparc64/md.h index f47f7750d..8f71e2fae 100644 --- a/src/vm/jit/sparc64/md.h +++ b/src/vm/jit/sparc64/md.h @@ -38,6 +38,22 @@ #include "vm/jit/codegen-common.hpp" +/** + * Returns the size (in bytes) of the current stackframe, specified by + * the passed codeinfo structure. + */ +inline static int32_t md_stacktrace_get_framesize(codeinfo* code) +{ + // Check for the asm_vm_call_method special case. + if (code == NULL) + return 0; + + // On SPARC we use 8-byte stackslots. +#error Verify the below line, then remove this error! + return code->stackframesize * 8; +} + + /* md_stacktrace_get_returnaddress ********************************************* Returns the return address of the current stackframe, specified by diff --git a/src/vm/jit/stacktrace.cpp b/src/vm/jit/stacktrace.cpp index b51154ed2..ad3b43825 100644 --- a/src/vm/jit/stacktrace.cpp +++ b/src/vm/jit/stacktrace.cpp @@ -33,6 +33,7 @@ #include "vm/types.h" +#include "arch.h" #include "md.h" #include "mm/gc.hpp" @@ -138,7 +139,7 @@ void stacktrace_stackframeinfo_add(stackframeinfo_t* sfi, void* pv, void* sp, vo /* On S390 we use REG_RA as REG_ITMP3, so we have always to get the RA from stack. */ - framesize = *((u4 *) (((uintptr_t) pv) + FrameSize)); + framesize = md_stacktrace_get_framesize(code); ra = md_stacktrace_get_returnaddress(sp, framesize); # else @@ -149,7 +150,7 @@ void stacktrace_stackframeinfo_add(stackframeinfo_t* sfi, void* pv, void* sp, vo the asm_vm_call_method special case. */ if ((code == NULL) || !code_is_leafmethod(code)) { - framesize = *((u4 *) (((uintptr_t) pv) + FrameSize)); + framesize = md_stacktrace_get_framesize(code); ra = md_stacktrace_get_returnaddress(sp, framesize); } @@ -306,7 +307,7 @@ static inline void stacktrace_stackframeinfo_next(stackframeinfo_t *tmpsfi) /* Get the current stack frame size. */ - framesize = *((uint32_t *) (((intptr_t) pv) + FrameSize)); + framesize = md_stacktrace_get_framesize(code); /* Get the RA of the current stack frame (RA to the parent Java method) if the current method is a non-leaf method. Otherwise @@ -357,7 +358,7 @@ static inline void stacktrace_stackframeinfo_next(stackframeinfo_t *tmpsfi) else #endif { -#if defined(__I386__) || defined (__X86_64__) || defined (__M68K__) +#if STACKFRMAE_RA_BETWEEN_FRAMES sp = (void *) (((intptr_t) sp) + framesize + SIZEOF_VOID_P); #elif defined(__SPARC_64__) /* already has the new sp */ diff --git a/src/vm/jit/x86_64/arch.h b/src/vm/jit/x86_64/arch.h index 7bd7d809d..787eba2d3 100644 --- a/src/vm/jit/x86_64/arch.h +++ b/src/vm/jit/x86_64/arch.h @@ -108,6 +108,14 @@ #define SUPPORT_HARDWARE_DIVIDE_BY_ZERO 1 +/* stackframe *****************************************************************/ + +#define STACKFRMAE_RA_BETWEEN_FRAMES 1 +#define STACKFRAME_RA_TOP_OF_FRAME 0 +#define STACKFRAME_LEAFMETHODS_RA_REGISTER 0 +#define STACKFRAME_SYNC_NEEDS_TWO_SLOTS 0 + + /* replacement ****************************************************************/ #define REPLACEMENT_PATCH_SIZE 2 /* bytes */ diff --git a/src/vm/jit/x86_64/codegen.c b/src/vm/jit/x86_64/codegen.c index 008172b19..61c86520a 100644 --- a/src/vm/jit/x86_64/codegen.c +++ b/src/vm/jit/x86_64/codegen.c @@ -67,112 +67,26 @@ #include "vm/jit/parse.hpp" #include "vm/jit/patcher-common.hpp" #include "vm/jit/reg.h" -#include "vm/jit/replace.hpp" #include "vm/jit/stacktrace.hpp" #include "vm/jit/trap.hpp" -#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 len, s1, s2, s3, d, disp; - u2 currentline; - ptrint a; - varinfo *var, *dst; - basicblock *bptr; - instruction *iptr; - constant_classref *cr; - unresolved_class *uc; - methodinfo *lm; /* local methodinfo for ICMD_INVOKE* */ - unresolved_method *um; - builtintable_entry *bte; - methoddesc *md; - fieldinfo *fi; - unresolved_field *uf; - s4 fieldtype; - s4 varindex; - - /* get required compiler data */ - - m = jd->m; - code = jd->code; - cd = jd->cd; - rd = jd->rd; - - /* prevent compiler warnings */ - - d = 0; - lm = NULL; - um = NULL; - bte = NULL; - - { - s4 i, p, t, l; - s4 savedregs_num; - - savedregs_num = 0; - - /* space to save used callee saved registers */ - - savedregs_num += (INT_SAV_CNT - rd->savintreguse); - savedregs_num += (FLT_SAV_CNT - rd->savfltreguse); - - cd->stackframesize = rd->memuse + savedregs_num; - -#if defined(ENABLE_THREADS) - /* space to save argument of monitor_enter */ - - if (checksync && code_is_synchronized(code)) - cd->stackframesize++; -#endif - - /* Keep stack of non-leaf functions 16-byte aligned for calls into - native code e.g. libc or jni (alignment problems with - movaps). */ - - if (!code_is_leafmethod(code) || opt_verbosecall) - cd->stackframesize |= 0x1; - - /* create method header */ - - (void) dseg_add_unique_address(cd, code); /* CodeinfoPointer */ - (void) dseg_add_unique_s4(cd, cd->stackframesize * 8); /* FrameSize */ - - code->synchronizedoffset = rd->memuse * 8; - - if (code_is_leafmethod(code)) - (void) dseg_add_unique_s4(cd, 1); /* IsLeaf */ - else - (void) dseg_add_unique_s4(cd, 0); /* 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 */ - -#if defined(ENABLE_PROFILING) - /* generate method profiling code */ - - if (JITDATA_HAS_FLAG_INSTRUMENT(jd)) { - /* count frequency */ - - M_MOV_IMM(code, REG_ITMP3); - M_IINC_MEMBASE(REG_ITMP3, OFFSET(codeinfo, frequency)); - - PROFILE_CYCLE_START; - } -#endif + varinfo* var; + methoddesc* md; + int32_t s1; + int32_t p, t, l; + int32_t varindex; + int i; + + // Get required compiler data. + methodinfo* m = jd->m; + codegendata* cd = jd->cd; + registerdata* rd = jd->rd; /* create stack frame (if necessary) */ @@ -227,7 +141,7 @@ bool codegen_emit(jitdata *jd) else { /* floating args */ if (!md->params[p].inmemory) { /* register arguments */ if (!IS_INMEMORY(var->flags)) - M_FLTMOVE(s1, var->vv.regoff); + emit_fmove(cd, s1, var->vv.regoff); else M_DST(s1, REG_SP, var->vv.regoff); } @@ -239,201 +153,64 @@ bool codegen_emit(jitdata *jd) } } } +} - /* save monitorenter argument */ - -#if defined(ENABLE_THREADS) - if (checksync && code_is_synchronized(code)) { - /* stack offset for monitor argument */ - - s1 = rd->memuse; - - if (opt_verbosecall) { - M_LSUB_IMM((INT_ARG_CNT + FLT_ARG_CNT) * 8, REG_SP); - - for (p = 0; p < INT_ARG_CNT; p++) - M_LST(abi_registers_integer_argument[p], REG_SP, p * 8); - - for (p = 0; p < FLT_ARG_CNT; p++) - M_DST(abi_registers_float_argument[p], REG_SP, (INT_ARG_CNT + p) * 8); - - s1 += INT_ARG_CNT + FLT_ARG_CNT; - } - - /* decide which monitor enter function to call */ - if (m->flags & ACC_STATIC) { - M_MOV_IMM(&m->clazz->object.header, REG_A0); - } - else { - M_TEST(REG_A0); - M_BNE(8); - M_ALD_MEM(REG_A0, TRAP_NullPointerException); - } +/** + * Generates machine code for the method epilog. + */ +void codegen_emit_epilog(jitdata* jd) +{ + int32_t p; + int i; - M_AST(REG_A0, REG_SP, s1 * 8); - M_MOV_IMM(LOCK_monitor_enter, REG_ITMP1); - M_CALL(REG_ITMP1); + // Get required compiler data. + codegendata* cd = jd->cd; + registerdata* rd = jd->rd; - if (opt_verbosecall) { - for (p = 0; p < INT_ARG_CNT; p++) - M_LLD(abi_registers_integer_argument[p], REG_SP, p * 8); + p = cd->stackframesize; - for (p = 0; p < FLT_ARG_CNT; p++) - M_DLD(abi_registers_float_argument[p], REG_SP, (INT_ARG_CNT + p) * 8); + /* restore saved registers */ - M_LADD_IMM((INT_ARG_CNT + FLT_ARG_CNT) * 8, REG_SP); - } + for (i = INT_SAV_CNT - 1; i >= rd->savintreguse; i--) { + p--; M_LLD(rd->savintregs[i], REG_SP, p * 8); } -#endif - -#if !defined(NDEBUG) - if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) - emit_verbosecall_enter(jd); -#endif /* !defined(NDEBUG) */ - + for (i = FLT_SAV_CNT - 1; i >= rd->savfltreguse; i--) { + p--; M_DLD(rd->savfltregs[i], REG_SP, p * 8); } - /* end of header generation */ - - /* create replacement points */ - - REPLACEMENT_POINTS_INIT(cd, jd); - - /* walk through all basic blocks */ - - for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) { - - bptr->mpc = (u4) ((u1 *) cd->mcodeptr - cd->mcodebase); - - if (bptr->flags >= BBREACHED) { - - /* branch resolving */ - - codegen_resolve_branchrefs(cd, bptr); - - /* handle replacement points */ - - REPLACEMENT_POINT_BLOCK_START(cd, bptr); - - /* copy interface registers to their destination */ - - len = bptr->indepth; - MCODECHECK(512); - -#if defined(ENABLE_PROFILING) - /* generate basicblock profiling code */ - - if (JITDATA_HAS_FLAG_INSTRUMENT(jd)) { - /* count frequency */ - - M_MOV_IMM(code->bbfrequency, REG_ITMP3); - M_IINC_MEMBASE(REG_ITMP3, bptr->nr * 4); - - /* if this is an exception handler, start profiling again */ - - if (bptr->type == BBTYPE_EXH) - PROFILE_CYCLE_START; - } -#endif - -#if defined(ENABLE_LSRA) - if (opt_lsra) { - while (len) { - len--; - src = bptr->invars[len]; - if ((len == bptr->indepth-1) && (bptr->type != BBTYPE_STD)) { - if (bptr->type == BBTYPE_EXH) { -/* d = reg_of_var(rd, src, REG_ITMP1); */ - if (!IS_INMEMORY(src->flags)) - d= src->vv.regoff; - else - d=REG_ITMP1; - M_INTMOVE(REG_ITMP1, d); - emit_store(jd, NULL, src, d); - } - } - } - - } else { -#endif - - while (len) { - len--; - var = VAR(bptr->invars[len]); - if ((len == bptr->indepth-1) && (bptr->type != BBTYPE_STD)) { - if (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 - /* walk through all instructions */ - - len = bptr->icount; - currentline = 0; - - for (iptr = bptr->iinstr; len > 0; len--, iptr++) { - if (iptr->line != currentline) { - linenumbertable_list_entry_add(cd, iptr->line); - currentline = iptr->line; - } - - MCODECHECK(1024); /* 1KB should be enough */ - - switch (iptr->opc) { - case ICMD_NOP: /* ... ==> ... */ - case ICMD_POP: /* ..., value ==> ... */ - case ICMD_POP2: /* ..., value, value ==> ... */ - break; - - case ICMD_INLINE_START: + /* deallocate stack */ - REPLACEMENT_POINT_INLINE_START(cd, iptr); - break; - - case ICMD_INLINE_BODY: - - REPLACEMENT_POINT_INLINE_BODY(cd, iptr); - linenumbertable_list_entry_add_inline_start(cd, iptr); - linenumbertable_list_entry_add(cd, iptr->line); - break; - - case ICMD_INLINE_END: + if (cd->stackframesize) + M_AADD_IMM(cd->stackframesize * 8, REG_SP); - linenumbertable_list_entry_add_inline_end(cd, iptr); - linenumbertable_list_entry_add(cd, iptr->line); - break; + M_RET; +} - case ICMD_CHECKNULL: /* ..., objectref ==> ..., objectref */ - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - emit_nullpointer_check(cd, iptr, s1); - break; +/** + * Generates machine code for one ICMD. + */ +void codegen_emit_instruction(jitdata* jd, instruction* iptr) +{ + varinfo* var; + varinfo* dst; + builtintable_entry* bte; + 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; + + 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_LCONST: /* ... ==> ..., constant */ - - d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); - LCONST(d, iptr->sx.val.l); - emit_store_dst(jd, iptr, d); - break; - case ICMD_FCONST: /* ... ==> ..., constant */ d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); @@ -455,7 +232,7 @@ bool codegen_emit(jitdata *jd) d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - cr = iptr->sx.val.c.ref; + constant_classref *cr = iptr->sx.val.c.ref; disp = dseg_add_unique_address(cd, cr); /* PROFILE_CYCLE_STOP; */ @@ -480,28 +257,6 @@ bool codegen_emit(jitdata *jd) break; - /* load/store/copy/move operations ************************************/ - - case ICMD_ILOAD: /* ... ==> ..., content of local variable */ - case ICMD_ALOAD: /* s1 = local variable */ - case ICMD_LLOAD: - case ICMD_FLOAD: - case ICMD_DLOAD: - case ICMD_ISTORE: /* ..., value ==> ... */ - case ICMD_LSTORE: - case ICMD_FSTORE: - 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_INEG: /* ..., value ==> ..., - value */ @@ -1170,7 +925,7 @@ bool codegen_emit(jitdata *jd) s1 = emit_load_s1(jd, iptr, REG_FTMP1); d = codegen_reg_of_dst(jd, iptr, REG_FTMP3); disp = dseg_add_s4(cd, 0x80000000); - M_FLTMOVE(s1, d); + emit_fmove(cd, s1, d); emit_movss_membase_reg(cd, RIP, -((cd->mcodeptr + 9) - cd->mcodebase) + disp, REG_FTMP2); emit_xorps_reg_reg(cd, REG_FTMP2, d); emit_store_dst(jd, iptr, d); @@ -1181,7 +936,7 @@ bool codegen_emit(jitdata *jd) s1 = emit_load_s1(jd, iptr, REG_FTMP1); d = codegen_reg_of_dst(jd, iptr, REG_FTMP3); disp = dseg_add_s8(cd, 0x8000000000000000); - M_FLTMOVE(s1, d); + emit_fmove(cd, s1, d); emit_movd_membase_reg(cd, RIP, -((cd->mcodeptr + 9) - cd->mcodebase) + disp, REG_FTMP2); emit_xorpd_reg_reg(cd, REG_FTMP2, d); emit_store_dst(jd, iptr, d); @@ -1195,7 +950,7 @@ bool codegen_emit(jitdata *jd) if (s2 == d) M_FADD(s1, d); else { - M_FLTMOVE(s1, d); + emit_fmove(cd, s1, d); M_FADD(s2, d); } emit_store_dst(jd, iptr, d); @@ -1209,7 +964,7 @@ bool codegen_emit(jitdata *jd) if (s2 == d) M_DADD(s1, d); else { - M_FLTMOVE(s1, d); + emit_fmove(cd, s1, d); M_DADD(s2, d); } emit_store_dst(jd, iptr, d); @@ -1221,10 +976,10 @@ bool codegen_emit(jitdata *jd) s2 = emit_load_s2(jd, iptr, REG_FTMP2); d = codegen_reg_of_dst(jd, iptr, REG_FTMP3); if (s2 == d) { - M_FLTMOVE(s2, REG_FTMP2); + emit_fmove(cd, s2, REG_FTMP2); s2 = REG_FTMP2; } - M_FLTMOVE(s1, d); + emit_fmove(cd, s1, d); M_FSUB(s2, d); emit_store_dst(jd, iptr, d); break; @@ -1235,10 +990,10 @@ bool codegen_emit(jitdata *jd) s2 = emit_load_s2(jd, iptr, REG_FTMP2); d = codegen_reg_of_dst(jd, iptr, REG_FTMP3); if (s2 == d) { - M_FLTMOVE(s2, REG_FTMP2); + emit_fmove(cd, s2, REG_FTMP2); s2 = REG_FTMP2; } - M_FLTMOVE(s1, d); + emit_fmove(cd, s1, d); M_DSUB(s2, d); emit_store_dst(jd, iptr, d); break; @@ -1251,7 +1006,7 @@ bool codegen_emit(jitdata *jd) if (s2 == d) M_FMUL(s1, d); else { - M_FLTMOVE(s1, d); + emit_fmove(cd, s1, d); M_FMUL(s2, d); } emit_store_dst(jd, iptr, d); @@ -1265,7 +1020,7 @@ bool codegen_emit(jitdata *jd) if (s2 == d) M_DMUL(s1, d); else { - M_FLTMOVE(s1, d); + emit_fmove(cd, s1, d); M_DMUL(s2, d); } emit_store_dst(jd, iptr, d); @@ -1277,10 +1032,10 @@ bool codegen_emit(jitdata *jd) s2 = emit_load_s2(jd, iptr, REG_FTMP2); d = codegen_reg_of_dst(jd, iptr, REG_FTMP3); if (s2 == d) { - M_FLTMOVE(s2, REG_FTMP2); + emit_fmove(cd, s2, REG_FTMP2); s2 = REG_FTMP2; } - M_FLTMOVE(s1, d); + emit_fmove(cd, s1, d); M_FDIV(s2, d); emit_store_dst(jd, iptr, d); break; @@ -1291,10 +1046,10 @@ bool codegen_emit(jitdata *jd) s2 = emit_load_s2(jd, iptr, REG_FTMP2); d = codegen_reg_of_dst(jd, iptr, REG_FTMP3); if (s2 == d) { - M_FLTMOVE(s2, REG_FTMP2); + emit_fmove(cd, s2, REG_FTMP2); s2 = REG_FTMP2; } - M_FLTMOVE(s1, d); + emit_fmove(cd, s1, d); M_DDIV(s2, d); emit_store_dst(jd, iptr, d); break; @@ -1340,7 +1095,7 @@ bool codegen_emit(jitdata *jd) disp = ((s1 == REG_FTMP1) ? 0 : 5) + 10 + 3 + ((REG_RESULT == d) ? 0 : 3); M_BNE(disp); - M_FLTMOVE(s1, REG_FTMP1); + emit_fmove(cd, s1, REG_FTMP1); M_MOV_IMM(asm_builtin_f2i, REG_ITMP2); M_CALL(REG_ITMP2); M_INTMOVE(REG_RESULT, d); @@ -1356,7 +1111,7 @@ bool codegen_emit(jitdata *jd) disp = ((s1 == REG_FTMP1) ? 0 : 5) + 10 + 3 + ((REG_RESULT == d) ? 0 : 3); M_BNE(disp); - M_FLTMOVE(s1, REG_FTMP1); + emit_fmove(cd, s1, REG_FTMP1); M_MOV_IMM(asm_builtin_d2i, REG_ITMP2); M_CALL(REG_ITMP2); M_INTMOVE(REG_RESULT, d); @@ -1373,7 +1128,7 @@ bool codegen_emit(jitdata *jd) disp = ((s1 == REG_FTMP1) ? 0 : 5) + 10 + 3 + ((REG_RESULT == d) ? 0 : 3); M_BNE(disp); - M_FLTMOVE(s1, REG_FTMP1); + emit_fmove(cd, s1, REG_FTMP1); M_MOV_IMM(asm_builtin_f2l, REG_ITMP2); M_CALL(REG_ITMP2); M_INTMOVE(REG_RESULT, d); @@ -1390,7 +1145,7 @@ bool codegen_emit(jitdata *jd) disp = ((s1 == REG_FTMP1) ? 0 : 5) + 10 + 3 + ((REG_RESULT == d) ? 0 : 3); M_BNE(disp); - M_FLTMOVE(s1, REG_FTMP1); + emit_fmove(cd, s1, REG_FTMP1); M_MOV_IMM(asm_builtin_d2l, REG_ITMP2); M_CALL(REG_ITMP2); M_INTMOVE(REG_RESULT, d); @@ -1480,15 +1235,6 @@ bool codegen_emit(jitdata *jd) /* memory operations **************************************************/ - case ICMD_ARRAYLENGTH: /* ..., arrayref ==> ..., (int) length */ - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - d = codegen_reg_of_dst(jd, iptr, REG_ITMP3); - /* implicit null-pointer check */ - M_ILD(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); @@ -1730,116 +1476,6 @@ bool codegen_emit(jitdata *jd) emit_mov_imm_memindex(cd, 0, OFFSET(java_objectarray_t, data[0]), s1, s2, 3); 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, uf); - -/* PROFILE_CYCLE_STOP; */ - - patcher_add_patch_ref(jd, PATCHER_get_putstatic, uf, disp); - -/* PROFILE_CYCLE_START; */ - } - 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)) { - PROFILE_CYCLE_STOP; - - patcher_add_patch_ref(jd, PATCHER_initialize_class, - fi->clazz, 0); - - PROFILE_CYCLE_START; - } - } - - /* This approach is much faster than moving the field - address inline into a register. */ - - M_ALD(REG_ITMP1, RIP, disp); - - switch (fieldtype) { - case TYPE_INT: - d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); - M_ILD(d, REG_ITMP1, 0); - break; - case TYPE_LNG: - case TYPE_ADR: - d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); - M_LLD(d, REG_ITMP1, 0); - break; - case TYPE_FLT: - d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); - M_FLD(d, REG_ITMP1, 0); - break; - case TYPE_DBL: - d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); - M_DLD(d, REG_ITMP1, 0); - break; - } - 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, uf); - -/* PROFILE_CYCLE_STOP; */ - - patcher_add_patch_ref(jd, PATCHER_get_putstatic, uf, disp); - -/* PROFILE_CYCLE_START; */ - } - 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)) { - PROFILE_CYCLE_STOP; - - patcher_add_patch_ref(jd, PATCHER_initialize_class, - fi->clazz, 0); - - PROFILE_CYCLE_START; - } - } - - /* This approach is much faster than moving the field - address inline into a register. */ - - M_ALD(REG_ITMP1, RIP, disp); - - switch (fieldtype) { - case TYPE_INT: - s1 = emit_load_s1(jd, iptr, REG_ITMP2); - M_IST(s1, REG_ITMP1, 0); - break; - case TYPE_LNG: - case TYPE_ADR: - s1 = emit_load_s1(jd, iptr, REG_ITMP2); - M_LST(s1, REG_ITMP1, 0); - break; - case TYPE_FLT: - s1 = emit_load_s1(jd, iptr, REG_FTMP1); - M_FST(s1, REG_ITMP1, 0); - break; - case TYPE_DBL: - s1 = emit_load_s1(jd, iptr, REG_FTMP1); - M_DST(s1, REG_ITMP1, 0); - break; - } - break; - case ICMD_PUTSTATICCONST: /* ... ==> ... */ /* val = value (in current instruction) */ /* following NOP) */ @@ -1861,12 +1497,12 @@ bool codegen_emit(jitdata *jd) disp = dseg_add_address(cd, fi->value); if (!CLASS_IS_OR_ALMOST_INITIALIZED(fi->clazz)) { - PROFILE_CYCLE_STOP; + //PROFILE_CYCLE_STOP; patcher_add_patch_ref(jd, PATCHER_initialize_class, fi->clazz, 0); - PROFILE_CYCLE_START; + //PROFILE_CYCLE_START; } } @@ -2024,19 +1660,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); - - PROFILE_CYCLE_STOP; - -#ifdef ENABLE_VERIFIER - if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - uc = iptr->sx.s23.s2.uc; - - patcher_add_patch_ref(jd, PATCHER_resolve_class, uc, 0); - } -#endif /* ENABLE_VERIFIER */ - M_CALL_IMM(0); /* passing exception pc */ M_POP(REG_ITMP2_XPC); @@ -2044,39 +1667,6 @@ bool codegen_emit(jitdata *jd) M_JMP(REG_ITMP3); break; - case ICMD_GOTO: /* ... ==> ... */ - case ICMD_RET: - - emit_br(cd, iptr->dst.block); - ALIGNCODENOP; - break; - - case ICMD_JSR: /* ... ==> ... */ - - emit_br(cd, iptr->sx.s23.s3.jsrtarget.block); - ALIGNCODENOP; - break; - - case ICMD_IFNULL: /* ..., value ==> ... */ - case ICMD_IFNONNULL: - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - M_TEST(s1); - emit_bcc(cd, iptr->dst.block, iptr->opc - ICMD_IFNULL, BRANCH_OPT_NONE); - break; - - case ICMD_IFEQ: /* ..., value ==> ... */ - case ICMD_IFLT: - case ICMD_IFLE: - case ICMD_IFNE: - case ICMD_IFGT: - case ICMD_IFGE: - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - M_ICMP_IMM(iptr->sx.val.i, s1); - emit_bcc(cd, iptr->dst.block, iptr->opc - ICMD_IFEQ, BRANCH_OPT_NONE); - break; - case ICMD_IF_LEQ: /* ..., value ==> ... */ case ICMD_IF_LNE: case ICMD_IF_LLT: @@ -2094,28 +1684,6 @@ bool codegen_emit(jitdata *jd) emit_bcc(cd, iptr->dst.block, iptr->opc - ICMD_IF_LEQ, BRANCH_OPT_NONE); break; - case ICMD_IF_ICMPEQ: /* ..., value, value ==> ... */ - case ICMD_IF_ICMPNE: - case ICMD_IF_ICMPLT: - case ICMD_IF_ICMPGE: - case ICMD_IF_ICMPGT: - case ICMD_IF_ICMPLE: - - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - s2 = emit_load_s2(jd, iptr, REG_ITMP2); - M_ICMP(s2, s1); - 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_LCMP(s2, s1); - emit_bcc(cd, iptr->dst.block, iptr->opc - ICMD_IF_ACMPEQ, BRANCH_OPT_NONE); - break; - case ICMD_IF_LCMPEQ: /* ..., value, value ==> ... */ case ICMD_IF_LCMPNE: case ICMD_IF_LCMPLT: @@ -2129,114 +1697,6 @@ bool codegen_emit(jitdata *jd) emit_bcc(cd, iptr->dst.block, iptr->opc - ICMD_IF_LCMPEQ, BRANCH_OPT_NONE); break; - case ICMD_IRETURN: /* ..., retvalue ==> ... */ - case ICMD_LRETURN: - - REPLACEMENT_POINT_RETURN(cd, iptr); - s1 = emit_load_s1(jd, iptr, REG_RESULT); - M_INTMOVE(s1, REG_RESULT); - goto nowperformreturn; - - case ICMD_ARETURN: /* ..., retvalue ==> ... */ - - REPLACEMENT_POINT_RETURN(cd, iptr); - s1 = emit_load_s1(jd, iptr, REG_RESULT); - M_INTMOVE(s1, REG_RESULT); - -#ifdef ENABLE_VERIFIER - if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - uc = iptr->sx.s23.s2.uc; - - PROFILE_CYCLE_STOP; - - patcher_add_patch_ref(jd, PATCHER_resolve_class, uc, 0); - - PROFILE_CYCLE_START; - } -#endif /* ENABLE_VERIFIER */ - goto nowperformreturn; - - case ICMD_FRETURN: /* ..., retvalue ==> ... */ - case ICMD_DRETURN: - - REPLACEMENT_POINT_RETURN(cd, iptr); - s1 = emit_load_s1(jd, iptr, REG_FRESULT); - M_FLTMOVE(s1, REG_FRESULT); - goto nowperformreturn; - - case ICMD_RETURN: /* ... ==> ... */ - - REPLACEMENT_POINT_RETURN(cd, iptr); - -nowperformreturn: - { - s4 i, p; - - p = cd->stackframesize; - -#if !defined(NDEBUG) - if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) - emit_verbosecall_exit(jd); -#endif /* !defined(NDEBUG) */ - -#if defined(ENABLE_THREADS) - if (checksync && code_is_synchronized(code)) { - M_ALD(REG_A0, REG_SP, rd->memuse * 8); - - /* we need to save the proper return value */ - switch (iptr->opc) { - case ICMD_IRETURN: - case ICMD_ARETURN: - case ICMD_LRETURN: - M_LST(REG_RESULT, REG_SP, rd->memuse * 8); - break; - case ICMD_FRETURN: - case ICMD_DRETURN: - M_DST(REG_FRESULT, REG_SP, rd->memuse * 8); - break; - } - - M_MOV_IMM(LOCK_monitor_exit, REG_ITMP1); - M_CALL(REG_ITMP1); - - /* and now restore the proper return value */ - switch (iptr->opc) { - case ICMD_IRETURN: - case ICMD_ARETURN: - case ICMD_LRETURN: - M_LLD(REG_RESULT, REG_SP, rd->memuse * 8); - break; - case ICMD_FRETURN: - case ICMD_DRETURN: - M_DLD(REG_FRESULT, REG_SP, rd->memuse * 8); - break; - } - } -#endif - - /* restore saved registers */ - - for (i = INT_SAV_CNT - 1; i >= rd->savintreguse; i--) { - p--; M_LLD(rd->savintregs[i], REG_SP, p * 8); - } - for (i = FLT_SAV_CNT - 1; i >= rd->savfltreguse; i--) { - p--; M_DLD(rd->savfltregs[i], REG_SP, p * 8); - } - - /* deallocate stack */ - - if (cd->stackframesize) - M_AADD_IMM(cd->stackframesize * 8, REG_SP); - - /* generate method profiling code */ - - PROFILE_CYCLE_STOP; - - M_RET; - } - break; - - case ICMD_TABLESWITCH: /* ..., index ==> ... */ { s4 i, l; @@ -2280,204 +1740,79 @@ nowperformreturn: } break; - - case ICMD_LOOKUPSWITCH: /* ..., key ==> ... */ - { - s4 i; - lookup_target_t *lookup; - - lookup = iptr->dst.lookup; - - i = iptr->sx.s23.s2.lookupcount; - - MCODECHECK(8 + ((7 + 6) * i) + 5); - s1 = emit_load_s1(jd, iptr, REG_ITMP1); - - while (--i >= 0) { - M_ICMP_IMM(lookup->value, s1); - emit_beq(cd, lookup->target.block); - lookup++; - } - - emit_br(cd, iptr->sx.s23.s3.lookupdefault.block); - ALIGNCODENOP; + case ICMD_BUILTIN: + bte = iptr->sx.s23.s3.bte; + if (bte->stub == NULL) { + M_MOV_IMM(bte->fp, REG_ITMP1); } + else { + M_MOV_IMM(bte->stub, REG_ITMP1); + } + M_CALL(REG_ITMP1); break; + case ICMD_INVOKESPECIAL: + emit_nullpointer_check(cd, iptr, REG_A0); + /* fall through */ - case ICMD_BUILTIN: /* ..., [arg1, [arg2 ...]] ==> ... */ - - REPLACEMENT_POINT_FORGC_BUILTIN(cd, iptr); - - bte = iptr->sx.s23.s3.bte; - md = bte->md; - goto gen_method; - - case ICMD_INVOKESTATIC: /* ..., [arg1, [arg2 ...]] ==> ... */ - - case ICMD_INVOKESPECIAL:/* ..., objectref, [arg1, [arg2 ...]] ==> ... */ - case ICMD_INVOKEVIRTUAL:/* op1 = arg count, val.a = method pointer */ - case ICMD_INVOKEINTERFACE: - - REPLACEMENT_POINT_INVOKE(cd, iptr); - + case ICMD_INVOKESTATIC: if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - lm = NULL; um = iptr->sx.s23.s3.um; - md = um->methodref->parseddesc.md; + disp = dseg_add_unique_address(cd, um); + + patcher_add_patch_ref(jd, PATCHER_invokestatic_special, + um, disp); } else { lm = iptr->sx.s23.s3.fmiref->p.method; - um = NULL; - md = lm->parseddesc; + disp = dseg_add_functionptr(cd, lm->stubroutine); } -gen_method: - s3 = md->paramcount; - - MCODECHECK((20 * s3) + 128); - - /* copy arguments to registers or stack location */ - - for (s3 = s3 - 1; s3 >= 0; s3--) { - var = VAR(iptr->sx.s23.s2.args[s3]); - d = md->params[s3].regoff; - - /* already preallocated (ARGVAR)? */ - - if (var->flags & PREALLOC) - continue; + M_ALD(REG_ITMP2, RIP, disp); + M_CALL(REG_ITMP2); + break; - if (IS_INT_LNG_TYPE(var->type)) { - if (!md->params[s3].inmemory) { - s1 = emit_load(jd, iptr, var, d); - M_INTMOVE(s1, d); - } - else { - s1 = emit_load(jd, iptr, var, REG_ITMP1); - M_LST(s1, REG_SP, d); - } - } - else { - if (!md->params[s3].inmemory) { - s1 = emit_load(jd, iptr, var, d); - M_FLTMOVE(s1, d); - } - else { - s1 = emit_load(jd, iptr, var, REG_FTMP1); + case ICMD_INVOKEVIRTUAL: + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + um = iptr->sx.s23.s3.um; + patcher_add_patch_ref(jd, PATCHER_invokevirtual, um, 0); - if (IS_2_WORD_TYPE(var->type)) - M_DST(s1, REG_SP, d); - else - M_FST(s1, REG_SP, d); - } - } + s1 = 0; } - - /* generate method profiling code */ - - PROFILE_CYCLE_STOP; - - switch (iptr->opc) { - case ICMD_BUILTIN: - if (bte->stub == NULL) { - M_MOV_IMM(bte->fp, REG_ITMP1); - } - else { - M_MOV_IMM(bte->stub, REG_ITMP1); - } - M_CALL(REG_ITMP1); - 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, um); - - patcher_add_patch_ref(jd, PATCHER_invokestatic_special, - um, disp); - } - else { - disp = dseg_add_functionptr(cd, lm->stubroutine); - } - - M_ALD(REG_ITMP2, RIP, disp); - M_CALL(REG_ITMP2); - 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_ALD(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl)); - M_ALD32(REG_ITMP3, REG_METHODPTR, s1); - M_CALL(REG_ITMP3); - break; - - case ICMD_INVOKEINTERFACE: - if (lm == NULL) { - patcher_add_patch_ref(jd, PATCHER_invokeinterface, um, 0); - - s1 = 0; - s2 = 0; - } - else { - s1 = OFFSET(vftbl_t, interfacetable[0]) - - sizeof(methodptr) * lm->clazz->index; - - s2 = sizeof(methodptr) * (lm - lm->clazz->methods); - } - - /* implicit null-pointer check */ - M_ALD(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl)); - M_ALD32(REG_METHODPTR, REG_METHODPTR, s1); - M_ALD32(REG_ITMP3, REG_METHODPTR, s2); - M_CALL(REG_ITMP3); - break; + else { + lm = iptr->sx.s23.s3.fmiref->p.method; + s1 = OFFSET(vftbl_t, table[0]) + + sizeof(methodptr) * lm->vftblindex; } - /* generate method profiling code */ - - PROFILE_CYCLE_START; - - /* store size of call code in replacement point */ + /* implicit null-pointer check */ + M_ALD(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl)); + M_ALD32(REG_ITMP3, REG_METHODPTR, s1); + M_CALL(REG_ITMP3); + break; - REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr); - REPLACEMENT_POINT_FORGC_BUILTIN_RETURN(cd, iptr); + case ICMD_INVOKEINTERFACE: + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + um = iptr->sx.s23.s3.um; + patcher_add_patch_ref(jd, PATCHER_invokeinterface, um, 0); - /* store return value */ + s1 = 0; + s2 = 0; + } + else { + lm = iptr->sx.s23.s3.fmiref->p.method; + s1 = OFFSET(vftbl_t, interfacetable[0]) - + sizeof(methodptr) * lm->clazz->index; - switch (md->returntype.type) { - case TYPE_INT: - case TYPE_LNG: - case TYPE_ADR: - s1 = codegen_reg_of_dst(jd, iptr, REG_RESULT); - M_INTMOVE(REG_RESULT, s1); - emit_store_dst(jd, iptr, s1); - break; - case TYPE_FLT: - case TYPE_DBL: - s1 = codegen_reg_of_dst(jd, iptr, REG_FRESULT); - M_FLTMOVE(REG_FRESULT, s1); - emit_store_dst(jd, iptr, s1); - break; - default: - /* TYPE_VOID */ - break; + s2 = sizeof(methodptr) * (lm - lm->clazz->methods); } - break; + /* implicit null-pointer check */ + M_ALD(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl)); + M_ALD32(REG_METHODPTR, REG_METHODPTR, s1); + M_ALD32(REG_ITMP3, REG_METHODPTR, s2); + M_CALL(REG_ITMP3); + break; case ICMD_CHECKCAST: /* ..., objectref ==> ..., objectref */ @@ -2551,7 +1886,7 @@ gen_method: if (super == NULL) { emit_label(cd, BRANCH_LABEL_2); - cr = iptr->sx.s23.s3.c.ref; + constant_classref *cr = iptr->sx.s23.s3.c.ref; disp = dseg_add_unique_address(cd, cr); patcher_add_patch_ref(jd, @@ -2622,7 +1957,7 @@ gen_method: M_INTMOVE(s1, REG_A0); if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - cr = iptr->sx.s23.s3.c.ref; + constant_classref *cr = iptr->sx.s23.s3.c.ref; disp = dseg_add_unique_address(cd, cr); patcher_add_patch_ref(jd, @@ -2707,7 +2042,7 @@ gen_method: REG_ITMP1, OFFSET(vftbl_t, interfacetablelength)); M_ICMP_IMM32(superindex, REG_ITMP3); - a = 3 + 4 /* mov_membase32_reg */ + 3 /* test */ + 4 /* setcc */; + int a = 3 + 4 /* mov_membase32_reg */ + 3 /* test */ + 4 /* setcc */; M_BLE(a); M_ALD32(REG_ITMP1, REG_ITMP1, @@ -2728,7 +2063,7 @@ gen_method: if (super == NULL) { emit_label(cd, BRANCH_LABEL_2); - cr = iptr->sx.s23.s3.c.ref; + constant_classref *cr = iptr->sx.s23.s3.c.ref; disp = dseg_add_unique_address(cd, cr); patcher_add_patch_ref(jd, @@ -2830,7 +2165,7 @@ gen_method: /* is a patcher function set? */ if (INSTRUCTION_IS_UNRESOLVED(iptr)) { - cr = iptr->sx.s23.s3.c.ref; + constant_classref *cr = iptr->sx.s23.s3.c.ref; disp = dseg_add_unique_address(cd, cr); patcher_add_patch_ref(jd, PATCHER_resolve_classref_to_classinfo, @@ -2861,36 +2196,8 @@ gen_method: break; default: - exceptions_throw_internalerror("Unknown ICMD %d during code generation", - iptr->opc); - return false; + vm_abort("Unknown ICMD %d during code generation", iptr->opc); } /* switch */ - - } /* for instruction */ - - MCODECHECK(512); /* XXX require a lower number? */ - - /* At the end of a basic block we may have to append some nops, - because the patcher stub calling code might be longer than the - actual instruction. So codepatching does not change the - following block unintentionally. */ - - if (cd->mcodeptr < cd->lastmcodeptr) { - while (cd->mcodeptr < cd->lastmcodeptr) { - M_NOP; - } - } - - } /* if (bptr -> flags >= BBREACHED) */ - } /* for basic block */ - - /* Generate patcher traps. */ - - emit_patcher_traps(jd); - - /* everything's ok */ - - return true; } diff --git a/src/vm/jit/x86_64/codegen.h b/src/vm/jit/x86_64/codegen.h index cb073729d..ce8576e3d 100644 --- a/src/vm/jit/x86_64/codegen.h +++ b/src/vm/jit/x86_64/codegen.h @@ -55,32 +55,6 @@ } while (0) -/* M_INTMOVE: - generates an integer-move from register a to b. - if a and b are the same int-register, no code will be generated. -*/ - -#define M_INTMOVE(reg,dreg) \ - do { \ - if ((reg) != (dreg)) { \ - M_MOV(reg, dreg); \ - } \ - } while (0) - - -/* M_FLTMOVE: - generates a floating-point-move from register a to b. - if a and b are the same float-register, no code will be generated -*/ - -#define M_FLTMOVE(reg,dreg) \ - do { \ - if ((reg) != (dreg)) { \ - M_FMOV(reg, dreg); \ - } \ - } while (0) - - #define ICONST(r,c) \ do { \ if ((c) == 0) \ @@ -152,6 +126,7 @@ #define M_IMOV_IMM(a,b) emit_movl_imm_reg(cd, (u4) (a), (b)) #define M_FMOV(a,b) emit_movq_reg_reg(cd, (a), (b)) +#define M_DMOV(a,b) M_FMOV(a,b) #define M_ILD(a,b,disp) emit_movl_membase_reg(cd, (b), (disp), (a)) #define M_LLD(a,b,disp) emit_mov_membase_reg(cd, (b), (disp), (a)) @@ -200,6 +175,7 @@ } while (0) #define M_ALD32(a,b,disp) M_LLD32(a,b,disp) +#define M_ALD_DSEG(a,disp) M_ALD(a,RIP,disp) #define M_ALD_MEM(a,disp) emit_mov_mem_reg(cd, (disp), (a)) @@ -277,6 +253,8 @@ #define M_ICMP_MEMBASE(a,b,c) emit_alul_membase_reg(cd, ALU_CMP, (a), (b), (c)) #define M_ICMP_MEMINDEX(a,b,c,d,e) emit_alu_memindex_reg(cd, ALU_CMP, (b), (a), (c), (d), (e)) +#define M_ACMP(a,b) M_LCMP(a,b) + #define M_BEQ(disp) emit_jcc(cd, CC_E, (disp)) #define M_BNE(disp) emit_jcc(cd, CC_NE, (disp)) #define M_BLT(disp) emit_jcc(cd, CC_L, (disp)) @@ -368,47 +346,6 @@ #define M_ISBB_MEMBASE(a,b,c) emit_alul_reg_membase(cd, ALU_SBB, (a), (b), (c)) -#if defined(ENABLE_PROFILING) - -#define PROFILE_CYCLE_START \ - do { \ - if (JITDATA_HAS_FLAG_INSTRUMENT(jd)) { \ - M_PUSH(RAX); \ - M_PUSH(RDX); \ - \ - M_MOV_IMM(code, REG_ITMP3); \ - M_RDTSC; \ - M_ISUB_MEMBASE(RAX, REG_ITMP3, OFFSET(codeinfo, cycles)); \ - M_ISBB_MEMBASE(RDX, REG_ITMP3, OFFSET(codeinfo, cycles) + 4); \ - \ - M_POP(RDX); \ - M_POP(RAX); \ - } \ - } while (0) - -#define PROFILE_CYCLE_STOP \ - do { \ - if (JITDATA_HAS_FLAG_INSTRUMENT(jd)) { \ - M_PUSH(RAX); \ - M_PUSH(RDX); \ - \ - M_MOV_IMM(code, REG_ITMP3); \ - M_RDTSC; \ - M_IADD_MEMBASE(RAX, REG_ITMP3, OFFSET(codeinfo, cycles)); \ - M_IADC_MEMBASE(RDX, REG_ITMP3, OFFSET(codeinfo, cycles) + 4); \ - \ - M_POP(RDX); \ - M_POP(RAX); \ - } \ - } while (0) - -#else - -#define PROFILE_CYCLE_START -#define PROFILE_CYCLE_STOP - -#endif - #endif /* _CODEGEN_H */ diff --git a/src/vm/jit/x86_64/emit.c b/src/vm/jit/x86_64/emit.c index 398d7d058..649270abe 100644 --- a/src/vm/jit/x86_64/emit.c +++ b/src/vm/jit/x86_64/emit.c @@ -233,6 +233,16 @@ void emit_cmovxx(codegendata *cd, instruction *iptr, s4 s, s4 d) } +/** + * Emits code updating the condition register by comparing one integer + * register to an immediate integer value. + */ +void emit_icmp_imm(codegendata* cd, int reg, int32_t value) +{ + M_ICMP_IMM(value, reg); +} + + /* emit_branch ***************************************************************** Emits the code for conditional and unconditional branchs. @@ -461,6 +471,135 @@ uint32_t emit_trap(codegendata *cd) } +/** + * Generates synchronization code to enter a monitor. + */ +#if defined(ENABLE_THREADS) +void emit_monitor_enter(jitdata* jd, int32_t syncslot_offset) +{ + int32_t p; + + // Get required compiler data. + methodinfo* m = jd->m; + codegendata* cd = jd->cd; + +# if !defined(NDEBUG) + if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) { + M_LSUB_IMM((INT_ARG_CNT + FLT_ARG_CNT) * 8, REG_SP); + + for (p = 0; p < INT_ARG_CNT; p++) + M_LST(abi_registers_integer_argument[p], REG_SP, p * 8); + + for (p = 0; p < FLT_ARG_CNT; p++) + M_DST(abi_registers_float_argument[p], REG_SP, (INT_ARG_CNT + p) * 8); + + syncslot_offset += (INT_ARG_CNT + FLT_ARG_CNT) * 8; + } +# endif + + /* decide which monitor enter function to call */ + + if (m->flags & ACC_STATIC) { + M_MOV_IMM(&m->clazz->object.header, REG_A0); + } + else { + M_TEST(REG_A0); + M_BNE(8); + M_ALD_MEM(REG_A0, TRAP_NullPointerException); + } + + M_AST(REG_A0, REG_SP, syncslot_offset); + M_MOV_IMM(LOCK_monitor_enter, REG_ITMP1); + M_CALL(REG_ITMP1); + +# if !defined(NDEBUG) + if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) { + + for (p = 0; p < INT_ARG_CNT; p++) + M_LLD(abi_registers_integer_argument[p], REG_SP, p * 8); + + for (p = 0; p < FLT_ARG_CNT; p++) + M_DLD(abi_registers_float_argument[p], REG_SP, (INT_ARG_CNT + p) * 8); + + M_LADD_IMM((INT_ARG_CNT + FLT_ARG_CNT) * 8, REG_SP); + } +# endif +} +#endif + + +/** + * Generates synchronization code to leave a monitor. + */ +#if defined(ENABLE_THREADS) +void emit_monitor_exit(jitdata* jd, int32_t syncslot_offset) +{ + // Get required compiler data. + methodinfo* m = jd->m; + codegendata* cd = jd->cd; + + M_ALD(REG_A0, REG_SP, syncslot_offset); + + /* we need to save the proper return value */ + + methoddesc* md = m->parseddesc; + + switch (md->returntype.type) { + case TYPE_INT: + case TYPE_ADR: + case TYPE_LNG: + M_LST(REG_RESULT, REG_SP, syncslot_offset); + break; + case TYPE_FLT: + case TYPE_DBL: + M_DST(REG_FRESULT, REG_SP, syncslot_offset); + break; + } + + M_MOV_IMM(LOCK_monitor_exit, REG_ITMP1); + M_CALL(REG_ITMP1); + + /* and now restore the proper return value */ + + switch (md->returntype.type) { + case TYPE_INT: + case TYPE_ADR: + case TYPE_LNG: + M_LLD(REG_RESULT, REG_SP, syncslot_offset); + break; + case TYPE_FLT: + case TYPE_DBL: + M_DLD(REG_FRESULT, REG_SP, syncslot_offset); + break; + } +} +#endif + + +/** + * Emit profiling code for method frequency counting. + */ +#if defined(ENABLE_PROFILING) +void emit_profile_method(codegendata* cd, codeinfo* code) +{ + M_MOV_IMM(code, REG_ITMP3); + M_IINC_MEMBASE(REG_ITMP3, OFFSET(codeinfo, frequency)); +} +#endif + + +/** + * Emit profiling code for basicblock frequency counting. + */ +#if defined(ENABLE_PROFILING) +void emit_profile_basicblock(codegendata* cd, codeinfo* code, basicblock* bptr) +{ + M_MOV_IMM(code->bbfrequency, REG_ITMP3); + M_IINC_MEMBASE(REG_ITMP3, bptr->nr * 4); +} +#endif + + /* emit_verbosecall_enter ****************************************************** Generates the code for the call trace. diff --git a/src/vm/jit/x86_64/emit.h b/src/vm/jit/x86_64/emit.h index 4a1cb4c98..790f659a9 100644 --- a/src/vm/jit/x86_64/emit.h +++ b/src/vm/jit/x86_64/emit.h @@ -180,6 +180,10 @@ typedef union { /* function prototypes ********************************************************/ +#ifdef __cplusplus +extern "C" { +#endif + void emit_cmovxx(codegendata *cd, instruction *iptr, s4 s, s4 d); @@ -363,6 +367,18 @@ void emit_xorpd_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 dreg); void emit_rdtsc(codegendata *cd); + +/** + * Emit code to recompute the procedure vector. This is a nop, + * because we do not use a procedure vector. + */ +static inline void emit_recompute_pv(codegendata* cd) {} + + +#ifdef __cplusplus +} +#endif + #endif /* _MD_EMIT_H */ diff --git a/src/vm/jit/x86_64/md.h b/src/vm/jit/x86_64/md.h index 6495479a8..9a65d6b65 100644 --- a/src/vm/jit/x86_64/md.h +++ b/src/vm/jit/x86_64/md.h @@ -37,6 +37,21 @@ /* inline functions ***********************************************************/ +/** + * Returns the size (in bytes) of the current stackframe, specified by + * the passed codeinfo structure. + */ +inline static int32_t md_stacktrace_get_framesize(codeinfo* code) +{ + // Check for the asm_vm_call_method special case. + if (code == NULL) + return 0; + + // On x86_64 we use 8-byte stackslots. + return code->stackframesize * 8; +} + + /* md_stacktrace_get_returnaddress ********************************************* Returns the return address of the current stackframe, specified by