/* src/vm/jit/mips/codegen.c - machine code generator for MIPS
- Copyright (C) 1996-2005 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 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
This file is part of CACAO.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA.
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
- Contact: cacao@complang.tuwien.ac.at
+ Contact: cacao@cacaojvm.org
Authors: Andreas Krall
Reinhard Grafl
This module generates MIPS machine code for a sequence of
intermediate code commands (ICMDs).
- $Id: codegen.c 4055 2006-01-02 12:59:54Z christian $
+ $Id: codegen.c 4654 2006-03-19 19:46:11Z edwin $
*/
#include "vm/jit/mips/arch.h"
#include "vm/jit/mips/codegen.h"
-#include "cacao/cacao.h"
#include "native/native.h"
#include "vm/builtin.h"
#include "vm/class.h"
#include "vm/exceptions.h"
#include "vm/options.h"
#include "vm/stringlocal.h"
+#include "vm/vm.h"
#include "vm/jit/asmpart.h"
#include "vm/jit/codegen-common.h"
#include "vm/jit/dseg.h"
#include "vm/jit/jit.h"
#include "vm/jit/patcher.h"
#include "vm/jit/reg.h"
+#include "vm/jit/replace.h"
#if defined(ENABLE_LSRA)
# include "vm/jit/allocator/lsra.h"
methodinfo *lm; /* local methodinfo for ICMD_INVOKE* */
builtintable_entry *bte;
methoddesc *md;
+ rplpoint *replacementpoint;
{
s4 i, p, t, l;
mcodeptr = (s4 *) cd->mcodeptr;
- MCODECHECK(128 + m->paramcount);
-
/* initialize the last patcher pointer */
cd->lastmcodeptr = (u1 *) mcodeptr;
s1 = rd->memuse;
- if (runverbose) {
+ if (opt_verbosecall) {
M_LDA(REG_SP, REG_SP, -(INT_ARG_CNT + FLT_ARG_CNT) * 8);
for (p = 0; p < INT_ARG_CNT; p++)
} else {
M_BEQZ(rd->argintregs[0], 0);
- codegen_addxnullrefs(cd, mcodeptr);
+ codegen_add_nullpointerexception_ref(cd, mcodeptr);
p = dseg_addaddress(cd, BUILTIN_monitorenter);
M_ALD(REG_ITMP3, REG_PV, p);
M_JSR(REG_RA, REG_ITMP3);
M_AST(rd->argintregs[0], REG_SP, s1 * 8); /* branch delay */
}
- if (runverbose) {
+ if (opt_verbosecall) {
for (p = 0; p < INT_ARG_CNT; p++)
M_LLD(rd->argintregs[p], REG_SP, p * 8);
/* copy argument registers to stack and call trace function */
- if (runverbose) {
+ if (opt_verbosecall) {
M_LDA(REG_SP, REG_SP, -(2 + INT_ARG_CNT + FLT_ARG_CNT + INT_TMP_CNT + FLT_TMP_CNT) * 8);
M_AST(REG_RA, REG_SP, 1 * 8);
/* end of header generation */
+ replacementpoint = cd->code->rplpoints;
+
/* walk through all basic blocks */
for (bptr = m->basicblocks; bptr != NULL; bptr = bptr->next) {
+ /* handle replacement points */
+
+ if (bptr->bitflags & BBFLAG_REPLACEMENT && bptr->flags >= BBREACHED) {
+
+ /* 8-byte align pc */
+ if ((ptrint)mcodeptr & 4) {
+ M_NOP;
+ }
+
+ replacementpoint->pc = (u1*)(ptrint)((u1*)mcodeptr - cd->mcodebase);
+ replacementpoint++;
+
+ assert(cd->lastmcodeptr <= (u1*)mcodeptr);
+ cd->lastmcodeptr = (u1*)cd->mcodeptr + 2*4; /* br + delay slot */
+ }
+
+ /* store relative start of block */
+
bptr->mpc = (s4) ((u1 *) mcodeptr - cd->mcodebase);
if (bptr->flags >= BBREACHED) {
var_to_reg_int(s1, src, REG_ITMP1);
M_BEQZ(s1, 0);
- codegen_addxnullrefs(cd, mcodeptr);
+ codegen_add_nullpointerexception_ref(cd, mcodeptr);
M_NOP;
break;
M_CVTLD(d, d);
store_reg_to_var_flt(iptr->dst, d);
break;
-
+
+#if 0
+ /* XXX these do not work correctly */
+
case ICMD_F2I: /* ..., (float) value ==> ..., (int) value */
var_to_reg_flt(s1, src, REG_FTMP1);
M_NOP;
store_reg_to_var_int(iptr->dst, d);
break;
+#endif
case ICMD_F2D: /* ..., value ==> ..., (double) value */
M_NOP;
M_BEQZ(REG_RESULT, 0);
- codegen_addxstorerefs(cd, mcodeptr);
+ codegen_add_arraystoreexception_ref(cd, mcodeptr);
M_NOP;
var_to_reg_int(s1, src->prev->prev, REG_ITMP1);
case ICMD_GETSTATIC: /* ... ==> ..., value */
/* op1 = type, val.a = field address */
- if (!iptr->val.a) {
+ if (iptr->val.a == NULL) {
disp = dseg_addaddress(cd, NULL);
codegen_addpatchref(cd, mcodeptr,
disp = dseg_addaddress(cd, &(fi->value));
- if (!(fi->class->state & CLASS_INITIALIZED)) {
+ if (!CLASS_IS_OR_ALMOST_INITIALIZED(fi->class)) {
codegen_addpatchref(cd, mcodeptr,
PATCHER_clinit, fi->class, 0);
case ICMD_PUTSTATIC: /* ..., value ==> ... */
/* op1 = type, val.a = field address */
- if (!iptr->val.a) {
+ if (iptr->val.a == NULL) {
disp = dseg_addaddress(cd, NULL);
codegen_addpatchref(cd, mcodeptr,
disp = dseg_addaddress(cd, &(fi->value));
- if (!(fi->class->state & CLASS_INITIALIZED)) {
+ if (!CLASS_IS_OR_ALMOST_INITIALIZED(fi->class)) {
codegen_addpatchref(cd, mcodeptr,
PATCHER_clinit, fi->class, 0);
/* op1 = type, val.a = field address (in */
/* following NOP) */
- if (!iptr[1].val.a) {
+ if (iptr[1].val.a == NULL) {
disp = dseg_addaddress(cd, NULL);
codegen_addpatchref(cd, mcodeptr,
disp = dseg_addaddress(cd, &(fi->value));
- if (!(fi->class->state & CLASS_INITIALIZED)) {
+ if (!CLASS_IS_OR_ALMOST_INITIALIZED(fi->class)) {
codegen_addpatchref(cd, mcodeptr,
PATCHER_clinit, fi->class, 0);
var_to_reg_int(s1, src, REG_ITMP1);
gen_nullptr_check(s1);
- if (!iptr->val.a) {
+ if (iptr->val.a == NULL) {
codegen_addpatchref(cd, mcodeptr,
PATCHER_get_putfield,
(unresolved_field *) iptr->target, 0);
var_to_reg_flt(s2, src, REG_FTMP2);
}
- if (!iptr->val.a) {
+ if (iptr->val.a == NULL) {
codegen_addpatchref(cd, mcodeptr,
PATCHER_get_putfield,
(unresolved_field *) iptr->target, 0);
var_to_reg_int(s1, src, REG_ITMP1);
gen_nullptr_check(s1);
- if (!iptr[1].val.a) {
+ if (iptr[1].val.a == NULL) {
codegen_addpatchref(cd, mcodeptr,
PATCHER_get_putfield,
(unresolved_field *) iptr[1].target, 0);
/* call trace function */
- if (runverbose) {
+ if (opt_verbosecall) {
M_LDA(REG_SP, REG_SP, -3 * 8);
M_LST(REG_RA, REG_SP, 0 * 8);
M_LST(REG_RESULT, REG_SP, 1 * 8);
if (iptr->op1 == true) {
M_BEQZ(REG_RESULT, 0);
- codegen_addxexceptionrefs(cd, mcodeptr);
+ codegen_add_fillinstacktrace_ref(cd, mcodeptr);
M_NOP;
}
break;
case ICMD_INVOKESPECIAL:
M_BEQZ(rd->argintregs[0], 0);
- codegen_addxnullrefs(cd, mcodeptr);
+ codegen_add_nullpointerexception_ref(cd, mcodeptr);
M_NOP;
/* fall through */
M_ILD(REG_ITMP3, REG_ITMP2, OFFSET(vftbl_t, interfacetablelength));
M_IADD_IMM(REG_ITMP3, -superindex, REG_ITMP3);
M_BLEZ(REG_ITMP3, 0);
- codegen_addxcastrefs(cd, mcodeptr);
+ codegen_add_classcastexception_ref(cd, mcodeptr);
M_NOP;
M_ALD(REG_ITMP3, REG_ITMP2,
OFFSET(vftbl_t, interfacetable[0]) -
superindex * sizeof(methodptr*));
M_BEQZ(REG_ITMP3, 0);
- codegen_addxcastrefs(cd, mcodeptr);
+ codegen_add_classcastexception_ref(cd, mcodeptr);
M_NOP;
if (!super) {
/* } */
M_CMPULT(REG_ITMP3, REG_ITMP2, REG_ITMP3);
M_BNEZ(REG_ITMP3, 0);
- codegen_addxcastrefs(cd, mcodeptr);
+ codegen_add_classcastexception_ref(cd, mcodeptr);
M_NOP;
}
d = reg_of_var(rd, iptr->dst, s1);
M_NOP;
M_BEQZ(REG_RESULT, 0);
- codegen_addxcastrefs(cd, mcodeptr);
+ codegen_add_classcastexception_ref(cd, mcodeptr);
M_NOP;
var_to_reg_int(s1, src, REG_ITMP1);
break;
case ICMD_MULTIANEWARRAY:/* ..., cnt1, [cnt2, ...] ==> ..., arrayref */
- /* op1 = dimension, val.a = array descriptor */
+ /* op1 = dimension, val.a = class */
/* check for negative sizes and copy sizes to stack if necessary */
/* is patcher function set? */
- if (iptr->target) {
+ if (iptr->val.a == NULL) {
disp = dseg_addaddress(cd, NULL);
codegen_addpatchref(cd, mcodeptr,
PATCHER_builtin_multianewarray,
- iptr->val.a, disp);
+ (constant_classref *) iptr->target,
+ disp);
if (opt_showdisassemble) {
M_NOP; M_NOP;
/* check for exception before result assignment */
M_BEQZ(REG_RESULT, 0);
- codegen_addxexceptionrefs(cd, mcodeptr);
+ codegen_add_fillinstacktrace_ref(cd, mcodeptr);
M_NOP;
d = reg_of_var(rd, iptr->dst, REG_RESULT);
dseg_createlinenumbertable(cd);
+#if 0
{
s4 *xcodeptr;
branchref *bref;
M_NOP;
}
}
+#endif
+
- /* generate patcher stub call code */
+ /* generate exception and patcher stubs */
{
- patchref *pref;
- u8 mcode;
- s4 *tmpmcodeptr;
+ exceptionref *eref;
+ patchref *pref;
+ u8 mcode;
+ s4 *savedmcodeptr;
+ s4 *tmpmcodeptr;
+
+ savedmcodeptr = NULL;
+
+ /* generate exception stubs */
+
+ for (eref = cd->exceptionrefs; eref != NULL; eref = eref->next) {
+ gen_resolvebranch((u1 *) cd->mcodebase + eref->branchpos,
+ eref->branchpos,
+ (u1 *) mcodeptr - cd->mcodebase);
+
+ MCODECHECK(100);
+
+ /* Check if the exception is an
+ ArrayIndexOutOfBoundsException. If so, move index register
+ into REG_ITMP1. */
+
+ if (eref->reg != -1)
+ M_MOV(eref->reg, REG_ITMP1);
+
+ /* calcuate exception address */
+
+ M_LDA(REG_ITMP2_XPC, REG_PV, eref->branchpos - 4);
+
+ /* move function to call into REG_ITMP3 */
+
+ disp = dseg_addaddress(cd, eref->function);
+ M_ALD(REG_ITMP3, REG_PV, disp);
+
+ if (savedmcodeptr != NULL) {
+ M_BR(savedmcodeptr - mcodeptr);
+ M_NOP;
+
+ } else {
+ savedmcodeptr = mcodeptr;
+
+ M_MOV(REG_PV, rd->argintregs[0]);
+ M_MOV(REG_SP, rd->argintregs[1]);
+
+ if (m->isleafmethod)
+ M_MOV(REG_RA, rd->argintregs[2]);
+ else
+ M_ALD(rd->argintregs[2],
+ REG_SP, parentargs_base * 8 - SIZEOF_VOID_P);
+
+ M_MOV(REG_ITMP2_XPC, rd->argintregs[3]);
+ M_MOV(REG_ITMP1, rd->argintregs[4]);
+
+ M_ASUB_IMM(REG_SP, 2 * 8, REG_SP);
+ M_AST(REG_ITMP2_XPC, REG_SP, 0 * 8);
+
+ if (m->isleafmethod)
+ M_AST(REG_RA, REG_SP, 1 * 8);
+
+ M_JSR(REG_RA, REG_ITMP3);
+ M_NOP;
+ M_MOV(REG_RESULT, REG_ITMP1_XPTR);
+
+ if (m->isleafmethod)
+ M_ALD(REG_RA, REG_SP, 1 * 8);
+
+ M_ALD(REG_ITMP2_XPC, REG_SP, 0 * 8);
+ M_AADD_IMM(REG_SP, 2 * 8, REG_SP);
+
+ a = dseg_addaddress(cd, asm_handle_exception);
+ M_ALD(REG_ITMP3, REG_PV, a);
+ M_JMP(REG_ITMP3);
+ M_NOP;
+ }
+ }
+
+
+ /* generate code patching stub call code */
for (pref = cd->patchrefs; pref != NULL; pref = pref->next) {
/* check code segment size */
MCODECHECK(100);
- /* Get machine code which is patched back in later. The call is */
- /* 2 instruction words long. */
+ /* Get machine code which is patched back in later. The
+ call is 2 instruction words long. */
- xcodeptr = (s4 *) (cd->mcodebase + pref->branchpos);
+ tmpmcodeptr = (s4 *) (cd->mcodebase + pref->branchpos);
- /* We need to split this, because an unaligned 8 byte read causes */
- /* a SIGSEGV. */
+ /* We need to split this, because an unaligned 8 byte read
+ causes a SIGSEGV. */
- mcode = ((u8) xcodeptr[1] << 32) + (u4) xcodeptr[0];
+ mcode = ((u8) tmpmcodeptr[1] << 32) + (u4) tmpmcodeptr[0];
- /* patch in the call to call the following code (done at compile */
- /* time) */
+ /* Patch in the call to call the following code (done at
+ compile time). */
- tmpmcodeptr = mcodeptr; /* save current mcodeptr */
- mcodeptr = xcodeptr; /* set mcodeptr to patch position */
+ savedmcodeptr = mcodeptr; /* save current mcodeptr */
+ mcodeptr = tmpmcodeptr; /* set mcodeptr to patch position */
- disp = (s4) (tmpmcodeptr - (xcodeptr + 1));
+ disp = (s4) (savedmcodeptr - (tmpmcodeptr + 1));
if ((disp < (s4) 0xffff8000) || (disp > (s4) 0x00007fff)) {
*exceptionptr =
M_BR(disp);
M_NOP;
- mcodeptr = tmpmcodeptr; /* restore the current mcodeptr */
+ mcodeptr = savedmcodeptr; /* restore the current mcodeptr */
/* create stack frame */
M_JMP(REG_ITMP3);
M_NOP;
}
- }
+
+ /* generate replacement-out stubs */
+
+ {
+ int i;
+
+ replacementpoint = cd->code->rplpoints;
+ for (i=0; i<cd->code->rplpointcount; ++i, ++replacementpoint) {
+ /* check code segment size */
+
+ MCODECHECK(100);
+
+ /* note start of stub code */
+
+ replacementpoint->outcode = (u1*) (ptrint)((u1*)mcodeptr - cd->mcodebase);
+
+ /* make machine code for patching */
+
+ tmpmcodeptr = mcodeptr;
+ mcodeptr = (s4*) &(replacementpoint->mcode);
+
+ disp = (ptrint)((s4*)replacementpoint->outcode - (s4*)replacementpoint->pc) - 1;
+ if ((disp < (s4) 0xffff8000) || (disp > (s4) 0x00007fff)) {
+ *exceptionptr =
+ new_internalerror("Jump offset is out of range: %d > +/-%d",
+ disp, 0x00007fff);
+ return false;
+ }
+ M_BR(disp);
+ M_NOP; /* delay slot */
+
+ mcodeptr = tmpmcodeptr;
+
+ /* create stack frame - 16-byte aligned */
+
+ M_ASUB_IMM(REG_SP, 2 * 8, REG_SP);
+
+ /* push address of `rplpoint` struct */
+
+ disp = dseg_addaddress(cd, replacementpoint);
+ M_ALD(REG_ITMP3, REG_PV, disp);
+ M_AST(REG_ITMP3, REG_SP, 0 * 8);
+
+ /* jump to replacement function */
+
+ disp = dseg_addaddress(cd, asm_replacement_out);
+ M_ALD(REG_ITMP3, REG_PV, disp);
+ M_JMP(REG_ITMP3);
+ M_NOP; /* delay slot */
+ }
+ }
}
codegen_finish(m, cd, (s4) ((u1 *) mcodeptr - cd->mcodebase));
- docacheflush((void *) m->entrypoint, ((u1 *) mcodeptr - cd->mcodebase));
+ docacheflush((void *) cd->code->entrypoint, ((u1 *) mcodeptr - cd->mcodebase));
/* everything's ok */
u1 *createcompilerstub(methodinfo *m)
{
- ptrint *s; /* memory to hold the stub */
+ u1 *s; /* memory to hold the stub */
+ ptrint *d;
s4 *mcodeptr; /* code generation pointer */
- s = (ptrint *) CNEW(u1, COMPILERSTUB_SIZE);
+ s = CNEW(u1, COMPILERSTUB_SIZE);
- s[0] = (ptrint) m;
- s[1] = (ptrint) asm_call_jit_compiler;
+ /* set data pointer and code pointer */
- mcodeptr = (s4 *) (s + 2);
+ d = (ptrint *) s;
+ s = s + COMPILERSTUB_DATASIZE;
- M_ALD(REG_ITMP1, REG_PV, -2 * SIZEOF_VOID_P); /* method pointer */
- M_ALD(REG_PV, REG_PV, -1 * SIZEOF_VOID_P); /* pointer to compiler */
+ mcodeptr = (s4 *) s;
+
+ /* Store the methodinfo* in the same place as in the methodheader
+ for compiled methods. */
+
+ d[0] = (ptrint) asm_call_jit_compiler;
+ d[1] = (ptrint) m;
+
+ M_ALD_INTERN(REG_ITMP1, REG_PV, -1 * SIZEOF_VOID_P); /* method pointer */
+ M_ALD_INTERN(REG_PV, REG_PV, -2 * SIZEOF_VOID_P); /* pointer to compiler */
M_JMP(REG_PV);
M_NOP;
count_cstub_len += COMPILERSTUB_SIZE;
#endif
- return (((u1 *) s) + COMPILERSTUB_DATASIZE);
+ return s;
}
/* call trace function */
- if (runverbose) {
+ if (opt_verbosecall) {
M_LDA(REG_SP, REG_SP, -(1 + INT_ARG_CNT + FLT_ARG_CNT) * 8);
/* save integer argument registers */
funcdisp = dseg_addaddress(cd, f);
-#if !defined(ENABLE_STATICVM)
+#if !defined(WITH_STATIC_CLASSPATH)
if (f == NULL) {
codegen_addpatchref(cd, mcodeptr, PATCHER_resolve_native, m, funcdisp);
/* put env into first argument register */
- disp = dseg_addaddress(cd, &env);
+ disp = dseg_addaddress(cd, _Jv_env);
M_ALD(rd->argintregs[0], REG_PV, disp);
/* do the native function call */
/* call finished trace function */
- if (runverbose) {
+ if (opt_verbosecall) {
if (IS_INT_LNG_TYPE(md->returntype.type))
M_LLD(REG_RESULT, REG_SP, 0 * 8);
else
{
patchref *pref;
- s4 *xcodeptr;
- s8 mcode;
+ u8 mcode;
+ s4 *savedmcodeptr;
s4 *tmpmcodeptr;
for (pref = cd->patchrefs; pref != NULL; pref = pref->next) {
- /* Get machine code which is patched back in later. The call is */
- /* 2 instruction words long. */
+ /* Get machine code which is patched back in later. The
+ call is 2 instruction words long. */
- xcodeptr = (s4 *) (cd->mcodebase + pref->branchpos);
+ tmpmcodeptr = (s4 *) (cd->mcodebase + pref->branchpos);
- /* We need to split this, because an unaligned 8 byte read causes */
- /* a SIGSEGV. */
+ /* We need to split this, because an unaligned 8 byte read
+ causes a SIGSEGV. */
- mcode = ((u8) xcodeptr[1] << 32) + (u4) xcodeptr[0];
+ mcode = ((u8) tmpmcodeptr[1] << 32) + (u4) tmpmcodeptr[0];
- /* patch in the call to call the following code (done at compile */
- /* time) */
+ /* Patch in the call to call the following code (done at
+ compile time). */
- tmpmcodeptr = mcodeptr; /* save current mcodeptr */
- mcodeptr = xcodeptr; /* set mcodeptr to patch position */
+ savedmcodeptr = mcodeptr; /* save current mcodeptr */
+ mcodeptr = tmpmcodeptr; /* set mcodeptr to patch position */
- M_BRS(tmpmcodeptr - (xcodeptr + 1));
+ M_BRS(savedmcodeptr - (tmpmcodeptr + 1));
M_NOP; /* branch delay slot */
- mcodeptr = tmpmcodeptr; /* restore the current mcodeptr */
+ mcodeptr = savedmcodeptr; /* restore the current mcodeptr */
/* create stack frame */
codegen_finish(m, cd, (s4) ((u1 *) mcodeptr - cd->mcodebase));
- docacheflush((void *) m->entrypoint, ((u1 *) mcodeptr - cd->mcodebase));
+ docacheflush((void *) cd->code->entrypoint, ((u1 *) mcodeptr - cd->mcodebase));
- return m->entrypoint;
+ return cd->code->entrypoint;
}
* c-basic-offset: 4
* tab-width: 4
* End:
+ * vim:noexpandtab:sw=4:ts=4:
*/