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
#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 */
/* 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.
#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) */
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);
}
}
}
}
+}
- /* 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);
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 */
/* 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);
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) */
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 ==> ... */
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);
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);
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;
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)) {
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;
}
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);
}
-/* 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))
#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 */
#define M_FCMPLTS(a,b,c) M_FOP3 (0x16, 0x5a6, a,b,c) /* c = a<b */
#define M_FMOV(fa,fb) M_FOP3 (0x17, 0x020, fa,fa,fb) /* b = a */
+#define M_DMOV(fa,fb) M_FMOV (fa,fb)
#define M_FMOVN(fa,fb) M_FOP3 (0x17, 0x021, fa,fa,fb) /* b = -a */
#define M_FNOP M_FMOV (31,31)
}
+/**
+ * Emits code comparing one integer register to an immediate value.
+ */
+void emit_icmpeq_imm(codegendata* cd, int reg, int32_t value, int d)
+{
+ int32_t disp;
+
+ if ((value >= 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.
}
+/**
+ * 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.
/* 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
#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 */
/* 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.
#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<<REG_LR);
+ }
- for (i = INT_SAV_CNT - 1; i >= 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 */
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)
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<<REG_LR);
}
-#endif
-
-#if !defined(NDEBUG)
- /* call trace function */
-
- if (JITDATA_HAS_FLAG_VERBOSECALL(jd))
- emit_verbosecall_enter(jd);
-#endif
-
- /* end of header generation */
- /* create replacement points */
- REPLACEMENT_POINTS_INIT(cd, jd);
-
- /* SECTION: ICMD Code Generation */
- /* for all basic blocks */
-
- for (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);
+ 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<<REG_LR);
+ savedregs_bitmask |= (1<<REG_PC);
}
- } 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
-
- /* 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);
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)
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 */
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);
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);
/* 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);
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);
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)
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);
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);
/* 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);
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);
}
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);
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);
}
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);
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);
}
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);
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);
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);
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);
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);
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 */
/* 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 */
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<<REG_LR);
- savedregs_bitmask |= (1<<REG_PC);
- }
- M_LDMFD(savedregs_bitmask, REG_SP);
- }
-
- /* if LR was not on stack, we need to return manually */
-
- if (code_is_leafmethod(code))
- M_MOV(REG_PC, REG_LR);
break;
- case ICMD_BUILTIN: /* ..., arg1, arg2, arg3 ==> ... */
-
- 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 */
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);
/* recompute pv */
- s1 = (s4) (cd->mcodeptr - cd->mcodebase);
- M_RECOMPUTE_PV(s1);
+ emit_recompute_pv(cd);
/* check for exception before result assignment */
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 */
}
/* recompute pv */
- s1 = (s4) (cd->mcodeptr - cd->mcodebase);
- M_RECOMPUTE_PV(s1);
+ emit_recompute_pv(cd);
/* remember class argument */
/* 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! */
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);
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 *************************************************************/
#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
#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)
#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)
}
+/**
+ * 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.
}
+/**
+ * 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.
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 */
#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
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;
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 */
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
/* 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.
#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"
#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"
#include <vmlog_cacao.h>
#endif
-#include "show.hpp"
-
/* codegen_init ****************************************************************
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)
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 */
}
#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);
{
stackframeinfo_t *sfi;
localref_table *lrt;
+ codeinfo *code;
methodinfo *m;
int32_t framesize;
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__)
#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 */
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 */
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 */
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)
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)
}
+/**
+ * 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.
#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 **********************************************************/
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
/* 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.
*/
-#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"
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);
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);
}
#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 */
/*
#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 */
#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 */
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)
}
}
}
+}
- /* 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);
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 */
emit_arithmetic_check(cd, iptr, REG_ITMP3);
bte = iptr->sx.s23.s3.bte;
- md = bte->md;
M_LST(s2, REG_SP, 2 * 4);
/* 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);
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);
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);
}
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);
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;
}
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 */
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;
}
/* 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 */
} 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 { \
#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))
}
+/**
+ * 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.
}
+/**
+ * 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.
-/* 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.
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"
#define emit_reg(reg,rm) emit_address_byte(3,(reg),(rm))
+#ifdef __cplusplus
+extern "C" {
+#endif
/* integer instructions */
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 */
/*
/* 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.
/* 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
#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
-/* 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.
#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 */
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;
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;
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;
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;
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;
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;
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;
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;
#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);
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 */
}
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);
/* 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 */
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:
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 */
}
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 */
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.
#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 { \
} 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 */
cd->mcodeptr += 2; \
} while(0);
+#define M_TEST(a) M_ATST(a)
+
#if !defined(ENABLE_SOFTFLOAT)
}
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.
}
+/**
+ * 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.
#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
#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 */
#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)
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 */
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) */
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))
}
}
}
+}
- /* 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
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,
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 */
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);
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 ==> ... */
#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
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
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;
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))
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,
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);
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,
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,
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,
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);
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,
/* 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,
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;
}
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))
}
+/**
+ * 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.
#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
// Lock the thread lists.
ThreadList_lock();
+#if 0
/* iterate over all started threads */
for (t = ThreadList_first(); t != NULL; t = ThreadList_next(t)) {
}
}
}
+#endif
// Unlock the thread lists.
ThreadList_unlock();
frequency = 0;
cycles = 0;
+#if 0
/* create new method list */
// TODO Use a sorted container.
List* l = List_new();
j, code->bbfrequency[j]);
}
}
+#endif
printf("----------- -------------- \n");
printf("%10d %12ld\n", frequency, (long) cycles);
#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);
#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 */
/* 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.
#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) */
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);
}
}
}
}
+}
-#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);
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 */
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;
/* 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);
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 */
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);
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 ==> ... */
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);
}
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);
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;
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)) {
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;
}
} 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)) { \
#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 ************************************************/
}
+/**
+ * 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.
}
+/**
+ * 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.
#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
#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
/* 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.
#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);
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);
}
}
}
}
+}
- /* 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;
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 */
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;
/* 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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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;
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 */
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;
}
} 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))
#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 */
#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 */
}
+/**
+ * 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.
}
+/**
+ * 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
#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
/*** 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
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);
void md_pop_stackframe(executionstate_t *es)
{
u1 *ra;
- s4 ra_align_off;
+ s4 framesize;
s4 reg;
s4 i;
stackslot_t *basesp;
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 */
/* 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 */
/* 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 */
/* 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;
/* 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 */
/* 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);
/* 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 */
#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 */
/* 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.
#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"
#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"
/* #define SUPPORT_HERCULES 1 */
-/* codegen *********************************************************************
-
- Generates machine code.
-
-*******************************************************************************/
-
/*
Layout of stackframe:
*/
-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);
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;
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))
}
}
} /* 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);
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; */
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 */
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);
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);
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;
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;
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);
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);
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;
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;
/* 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);
*/
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);
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);
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:
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 ==> ... */
}
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;
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 */
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.
#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)
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)) { \
}
}
+
+/**
+ * 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.
}
+/**
+ * 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.
}
}
-void emit_restore_pv(codegendata *cd) {
+void emit_recompute_pv(codegendata *cd) {
s4 offset, offset_imm;
/*
#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
#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 */
#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"
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;
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++;
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) */
}
#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;
} 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);
}
}
} /* 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);
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);
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 */
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);
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 */
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 ==> ... */
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 ==> ... */
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 ==> ... */
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 ==> ... */
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 ==> ... */
{
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;
#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);
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 */
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,
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);
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,
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,
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,
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);
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,
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;
}
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))
#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 */
}
}
+
+/**
+ * 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.
}
+/**
+ * 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.
#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
#include "vm/types.h"
+#include "arch.h"
#include "md.h"
#include "mm/gc.hpp"
/* 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
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);
}
/* 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
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 */
#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 */
#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) */
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);
}
}
}
}
+}
- /* 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);
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; */
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 */
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);
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);
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);
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);
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;
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;
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);
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);
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;
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;
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);
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);
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);
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);
/* 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);
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) */
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;
}
}
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);
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:
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:
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;
}
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 */
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,
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,
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,
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,
/* 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,
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;
}
} 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) \
#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))
} 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))
#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))
#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 */
}
+/**
+ * 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.
}
+/**
+ * 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.
/* function prototypes ********************************************************/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
void emit_cmovxx(codegendata *cd, instruction *iptr, s4 s, s4 d);
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 */
/* 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