Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
- $Id: codegen.c 4644 2006-03-16 18:44:46Z edwin $
-
*/
#include "config.h"
#include <assert.h>
+#include <stdint.h>
#include <stdio.h>
#include "vm/types.h"
#include "mm/memory.h"
#include "native/jni.h"
+#include "native/localref.h"
#include "native/native.h"
#include "vm/builtin.h"
#include "vm/exceptions.h"
#include "vmcore/loader.h"
#include "vmcore/options.h"
+#include "vm/jit/sparc64/solaris/macro_rename.h"
#define BUILTIN_FLOAT_ARGS 1
return lodisp;
}
+
+#ifndef NDEBUG
+bool check_13bit_imm(s8 imm)
+{
+ s4 sign = (imm >> 12) & 0x1;
+
+ if (sign == 0) {
+ if ((imm & ~0xfff) == 0) return true; /* pos imm. */
+ }
+ else
+ if ((imm & ~0xfff) + 0xfff == -1) return true; /* neg imm. */
+
+ printf("immediate out-of-bounds: %ld\n", imm);
+ return false;
+}
+#endif
/* codegen_emit ****************************************************************
varinfo *var;
basicblock *bptr;
instruction *iptr;
- exception_entry *ex;
u2 currentline;
constant_classref *cr;
methodinfo *lm; /* local methodinfo for ICMD_INVOKE* */
{
s4 i, p, t, l;
- s4 savedregs_num, localbase;
+ s4 savedregs_num;
+ s4 framesize_disp;
#if 0 /* no leaf optimization yet */
- savedregs_num = (jd->isleafmethod) ? 0 : 1; /* space to save the RA */
+ savedregs_num = (code_is_leafmethod(code)) ? 0 : 1; /* space to save the RA */
#endif
savedregs_num = WINSAVE_CNT + ABIPARAMS_CNT; /* register-window save area */
cd->stackframesize = rd->memuse + savedregs_num;
#if defined(ENABLE_THREADS) /* space to save argument of monitor_enter */
- if (checksync && (m->flags & ACC_SYNCHRONIZED))
+ if (checksync && code_is_synchronized(code))
cd->stackframesize++;
#endif
/* create method header */
(void) dseg_add_unique_address(cd, code); /* CodeinfoPointer */
- (void) dseg_add_unique_s4(cd, cd->stackframesize * 8); /* FrameSize */
+ framesize_disp = dseg_add_unique_s4(cd, cd->stackframesize * 8); /* FrameSize */
-#if defined(ENABLE_THREADS)
- /* IsSync contains the offset relative to the stack pointer for the
- argument of monitor_exit used in the exception handler. Since the
- offset could be zero and give a wrong meaning of the flag it is
- offset by one.
- */
+ code->synchronizedoffset = JITSTACK + rd->memuse * 8;
+
+ /* REMOVEME: We still need it for exception handling in assembler. */
- if (checksync && (m->flags & ACC_SYNCHRONIZED))
- (void) dseg_add_unique_s4(cd, (rd->memuse + 1) * 8); /* IsSync */
+ if (code_is_leafmethod(code))
+ (void) dseg_add_unique_s4(cd, 1);
else
-#endif
- (void) dseg_add_unique_s4(cd, 0); /* IsSync */
-
- (void) dseg_add_unique_s4(cd, jd->isleafmethod); /* IsLeaf */
+ (void) dseg_add_unique_s4(cd, 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 */
- dseg_addlinenumbertablesize(cd);
- (void) dseg_add_unique_s4(cd, jd->exceptiontablelength); /* ExTableSize */
- /* create exception table */
-
- for (ex = jd->exceptiontable; ex != NULL; ex = ex->down) {
- dseg_add_target(cd, ex->start);
- dseg_add_target(cd, ex->end);
- dseg_add_target(cd, ex->handler);
- (void) dseg_add_unique_address(cd, ex->catchtype.any);
- }
+ dseg_addlinenumbertablesize(cd);
/* save register window and create stack frame (if necessary) */
- if (cd->stackframesize)
- M_SAVE(REG_SP, -cd->stackframesize * 8, REG_SP);
-
+ if (cd->stackframesize) {
+ if (cd->stackframesize <= 4095)
+ M_SAVE(REG_SP, -cd->stackframesize * 8, REG_SP);
+ else {
+ M_ILD_INTERN(REG_ITMP3, REG_PV_CALLER, framesize_disp);
+ M_SUB(REG_ZERO, REG_ITMP3, REG_ITMP3);
+ M_SAVE_REG(REG_SP, REG_ITMP3, REG_SP);
+ }
+ }
/* save callee saved float registers (none right now) */
#if 0
/* call monitorenter function */
#if defined(ENABLE_THREADS)
- if (checksync && (m->flags & ACC_SYNCHRONIZED)) {
+ if (checksync && code_is_synchronized(code)) {
/* stack offset for monitor argument */
s1 = rd->memuse;
md = m->parseddesc;
- /* when storing locals, use this as base */
- localbase = JITSTACK;
-
- /* since the register allocator does not know about the shifting window
- * arg regs need to be copied via the stack
- */
- if (md->argintreguse > 0) {
- /* allocate scratch space for copying in to save(i&l) regs */
- M_SUB_IMM(REG_SP, INT_ARG_CNT * 8, REG_SP);
-
- localbase += INT_ARG_CNT * 8;
-
- /* XXX could use the param slots on the stack for this! */
- for (p = 0; p < INT_ARG_CNT; p++)
- M_STX(REG_WINDOW_TRANSPOSE(abi_registers_integer_argument[p]), REG_SP, JITSTACK + (p * 8));
- }
-
-
for (p = 0, l = 0; p < md->paramcount; p++) {
t = md->paramtypes[p].type;
s1 = md->params[p].regoff;
if (IS_INT_LNG_TYPE(t)) { /* integer args */
+
+ s2 = var->vv.regoff;
if (!md->params[p].inmemory) { /* register arguments */
- /*s2 = rd->argintregs[s1];*/
- /*s2 = REG_WINDOW_TRANSPOSE(s2);*/
-
- /* need the argument index (p) here, not the register number */
+ s1 = REG_WINDOW_TRANSPOSE(s1);
if (!(var->flags & INMEMORY)) { /* reg arg -> register */
- /*M_INTMOVE(s2, var->vv.regoff);*/
- M_LDX(var->vv.regoff, REG_SP, JITSTACK + (p * 8));
- } else { /* reg arg -> spilled */
- /*M_STX(s2, REG_SP, (WINSAVE_CNT + var->vv.regoff) * 8);*/
-
- M_LDX(REG_ITMP1, REG_SP, JITSTACK + (p * 8));
- M_STX(REG_ITMP1, REG_SP, localbase + (var->vv.regoff * 8));
+ /* the register allocator does not know about the window. */
+ /* avoid copying the locals from save to save regs by */
+ /* swapping variables. */
+
+ {
+ int old_dest = var->vv.regoff;
+ int new_dest = p + 24;
+
+ /* run through all variables */
+
+ for (i = 0; i < jd->varcount; i++) {
+ varinfo* uvar = VAR(i);
+
+ if (IS_FLT_DBL_TYPE(uvar->type) || IS_INMEMORY(uvar->flags))
+ continue;
+
+ s2 = uvar->vv.regoff;
+
+ /* free the in reg by moving all other references */
+
+ if (s2 == new_dest) {
+ uvar->vv.regoff = old_dest;
+ /*printf("p%d-var[%d]: moved %d -> %d (to free save reg)\n", p, i, s2, old_dest);*/
+ }
+
+ /* move all variables to the in reg */
+
+ if (s2 == old_dest) {
+ uvar->vv.regoff = new_dest;
+ /*printf("p%d-var[%d]: moved %d -> %d (to avoid copy)\n", p, i, s2, new_dest);*/
+ }
+ }
+ }
+
+
+
+ }
+ else { /* reg arg -> spilled */
+ M_STX(s1, REG_SP, JITSTACK + var->vv.regoff);
}
} else { /* stack arguments */
if (!(var->flags & INMEMORY)) { /* stack arg -> register */
- M_LDX(var->vv.regoff, REG_FP, JITSTACK + (s1 * 8));
+ M_LDX(var->vv.regoff, REG_FP, JITSTACK + s1);
} else { /* stack arg -> spilled */
/* add the callers window save registers */
- var->vv.regoff = cd->stackframesize + s1;
+ var->vv.regoff = cd->stackframesize * 8 + s1;
}
}
M_FLTMOVE(s1, var->vv.regoff);
} else { /* reg arg -> spilled */
- M_DST(s1, REG_SP, localbase + (var->vv.regoff) * 8);
+ M_DST(s1, REG_SP, JITSTACK + var->vv.regoff);
}
} else { /* stack arguments */
if (!(var->flags & INMEMORY)) { /* stack-arg -> register */
- M_DLD(var->vv.regoff, REG_FP, JITSTACK + (s1 * 8));
+ M_DLD(var->vv.regoff, REG_FP, JITSTACK + s1);
} else { /* stack-arg -> spilled */
- var->vv.regoff = cd->stackframesize + s1;
+ var->vv.regoff = cd->stackframesize * 8 + s1;
}
}
}
} /* end for */
- if (md->argintreguse > 0) {
- /* release scratch space */
- M_ADD_IMM(REG_SP, INT_ARG_CNT * 8, REG_SP);
- }
-
-
-
}
/* handle replacement points */
-#if 0
- if (bptr->bitflags & BBFLAG_REPLACEMENT) {
- replacementpoint->pc = (u1*)(ptrint)bptr->mpc; /* will be resolved later */
-
- replacementpoint++;
- }
-#endif
+ REPLACEMENT_POINT_BLOCK_START(cd, bptr);
+
/* copy interface registers to their destination */
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_arrayheader, size));
+ M_ILD(d, s1, OFFSET(java_array_t, size));
emit_store_dst(jd, iptr, d);
break;
/* implicit null-pointer check */
emit_arrayindexoutofbounds_check(cd, iptr, s1, s2);
M_AADD(s2, s1, REG_ITMP3);
- M_BLDS(d, REG_ITMP3, OFFSET(java_bytearray, data[0]));
+ M_BLDS(d, REG_ITMP3, OFFSET(java_bytearray_t, data[0]));
emit_store_dst(jd, iptr, d);
break;
emit_arrayindexoutofbounds_check(cd, iptr, s1, s2);
M_AADD(s2, s1, REG_ITMP3);
M_AADD(s2, REG_ITMP3, REG_ITMP3);
- M_SLDU(d, REG_ITMP3, OFFSET(java_chararray, data[0]));
+ M_SLDU(d, REG_ITMP3, OFFSET(java_chararray_t, data[0]));
emit_store_dst(jd, iptr, d);
break;
emit_arrayindexoutofbounds_check(cd, iptr, s1, s2);
M_AADD(s2, s1, REG_ITMP3);
M_AADD(s2, REG_ITMP3, REG_ITMP3);
- M_SLDS(d, REG_ITMP3, OFFSET(java_shortarray, data[0]));
+ M_SLDS(d, REG_ITMP3, OFFSET(java_shortarray_t, data[0]));
emit_store_dst(jd, iptr, d);
break;
emit_arrayindexoutofbounds_check(cd, iptr, s1, s2);
M_ASLL_IMM(s2, 2, REG_ITMP3);
M_AADD(REG_ITMP3, s1, REG_ITMP3);
- M_ILD(d, REG_ITMP3, OFFSET(java_intarray, data[0]));
+ M_ILD(d, REG_ITMP3, OFFSET(java_intarray_t, data[0]));
emit_store_dst(jd, iptr, d);
break;
emit_arrayindexoutofbounds_check(cd, iptr, s1, s2);
M_ASLL_IMM(s2, 3, REG_ITMP3);
M_AADD(REG_ITMP3, s1, REG_ITMP3);
- M_LDX(d, REG_ITMP3, OFFSET(java_longarray, data[0]));
+ M_LDX(d, REG_ITMP3, OFFSET(java_longarray_t, data[0]));
emit_store_dst(jd, iptr, d);
break;
emit_arrayindexoutofbounds_check(cd, iptr, s1, s2);
M_ASLL_IMM(s2, 2, REG_ITMP3);
M_AADD(REG_ITMP3, s1, REG_ITMP3);
- M_FLD(d, REG_ITMP3, OFFSET(java_floatarray, data[0]));
+ M_FLD(d, REG_ITMP3, OFFSET(java_floatarray_t, data[0]));
emit_store_dst(jd, iptr, d);
break;
emit_arrayindexoutofbounds_check(cd, iptr, s1, s2);
M_ASLL_IMM(s2, 3, REG_ITMP3);
M_AADD(REG_ITMP3, s1, REG_ITMP3);
- M_DLD(d, REG_ITMP3, OFFSET(java_doublearray, data[0]));
+ M_DLD(d, REG_ITMP3, OFFSET(java_doublearray_t, data[0]));
emit_store_dst(jd, iptr, d);
break;
emit_arrayindexoutofbounds_check(cd, iptr, s1, s2);
M_ASLL_IMM(s2, POINTERSHIFT, REG_ITMP3);
M_AADD(REG_ITMP3, s1, REG_ITMP3);
- M_ALD(d, REG_ITMP3, OFFSET(java_objectarray, data[0]));
+ M_ALD(d, REG_ITMP3, OFFSET(java_objectarray_t, data[0]));
emit_store_dst(jd, iptr, d);
break;
emit_arrayindexoutofbounds_check(cd, iptr, s1, s2);
M_AADD(s2, s1, REG_ITMP1);
s3 = emit_load_s3(jd, iptr, REG_ITMP3);
- M_BST(s3, REG_ITMP1, OFFSET(java_bytearray, data[0]));
+ M_BST(s3, REG_ITMP1, OFFSET(java_bytearray_t, data[0]));
break;
case ICMD_CASTORE: /* ..., arrayref, index, value ==> ... */
M_AADD(s2, s1, REG_ITMP1);
M_AADD(s2, REG_ITMP1, REG_ITMP1);
s3 = emit_load_s3(jd, iptr, REG_ITMP3);
- M_SST(s3, REG_ITMP1, OFFSET(java_chararray, data[0]));
+ M_SST(s3, REG_ITMP1, OFFSET(java_chararray_t, data[0]));
break;
case ICMD_IASTORE: /* ..., arrayref, index, value ==> ... */
M_ASLL_IMM(s2, 2, REG_ITMP2);
M_AADD(REG_ITMP2, s1, REG_ITMP1);
s3 = emit_load_s3(jd, iptr, REG_ITMP3);
- M_IST_INTERN(s3, REG_ITMP1, OFFSET(java_intarray, data[0]));
+ M_IST_INTERN(s3, REG_ITMP1, OFFSET(java_intarray_t, data[0]));
break;
case ICMD_LASTORE: /* ..., arrayref, index, value ==> ... */
M_ASLL_IMM(s2, 3, REG_ITMP2);
M_AADD(REG_ITMP2, s1, REG_ITMP1);
s3 = emit_load_s3(jd, iptr, REG_ITMP3);
- M_STX_INTERN(s3, REG_ITMP1, OFFSET(java_longarray, data[0]));
+ M_STX_INTERN(s3, REG_ITMP1, OFFSET(java_longarray_t, data[0]));
break;
case ICMD_FASTORE: /* ..., arrayref, index, value ==> ... */
M_ASLL_IMM(s2, 2, REG_ITMP2);
M_AADD(REG_ITMP2, s1, REG_ITMP1);
s3 = emit_load_s3(jd, iptr, REG_FTMP1);
- M_FST_INTERN(s3, REG_ITMP1, OFFSET(java_floatarray, data[0]));
+ M_FST_INTERN(s3, REG_ITMP1, OFFSET(java_floatarray_t, data[0]));
break;
case ICMD_DASTORE: /* ..., arrayref, index, value ==> ... */
M_ASLL_IMM(s2, 3, REG_ITMP2);
M_AADD(REG_ITMP2, s1, REG_ITMP1);
s3 = emit_load_s3(jd, iptr, REG_FTMP1);
- M_DST_INTERN(s3, REG_ITMP1, OFFSET(java_doublearray, data[0]));
+ M_DST_INTERN(s3, REG_ITMP1, OFFSET(java_doublearray_t, data[0]));
break;
M_MOV(s1, REG_OUT0);
M_MOV(s3, REG_OUT1);
- disp = dseg_add_functionptr(cd, BUILTIN_canstore);
+ disp = dseg_add_functionptr(cd, BUILTIN_FAST_canstore);
M_ALD(REG_ITMP3, REG_PV, disp);
M_JMP(REG_RA_CALLER, REG_ITMP3, REG_ZERO);
M_NOP;
- emit_exception_check(cd, iptr);
+ emit_arraystore_check(cd, iptr);
s1 = emit_load_s1(jd, iptr, REG_ITMP1);
s2 = emit_load_s2(jd, iptr, REG_ITMP2);
M_AADD(REG_ITMP2, s1, REG_ITMP1);
s3 = emit_load_s3(jd, iptr, REG_ITMP3);
/* implicit null-pointer check */
- M_AST_INTERN(s3, REG_ITMP1, OFFSET(java_objectarray, data[0]));
+ M_AST_INTERN(s3, REG_ITMP1, OFFSET(java_objectarray_t, data[0]));
break;
/* implicit null-pointer check */
emit_arrayindexoutofbounds_check(cd, iptr, s1, s2);
M_AADD(s2, s1, REG_ITMP1);
- M_BST(REG_ZERO, REG_ITMP1, OFFSET(java_bytearray, data[0]));
+ M_BST(REG_ZERO, REG_ITMP1, OFFSET(java_bytearray_t, data[0]));
break;
case ICMD_CASTORECONST: /* ..., arrayref, index ==> ... */
emit_arrayindexoutofbounds_check(cd, iptr, s1, s2);
M_AADD(s2, s1, REG_ITMP1);
M_AADD(s2, REG_ITMP1, REG_ITMP1);
- M_SST(REG_ZERO, REG_ITMP1, OFFSET(java_chararray, data[0]));
+ M_SST(REG_ZERO, REG_ITMP1, OFFSET(java_chararray_t, data[0]));
break;
case ICMD_IASTORECONST: /* ..., arrayref, index ==> ... */
emit_arrayindexoutofbounds_check(cd, iptr, s1, s2);
M_ASLL_IMM(s2, 2, REG_ITMP2);
M_AADD(REG_ITMP2, s1, REG_ITMP1);
- M_IST_INTERN(REG_ZERO, REG_ITMP1, OFFSET(java_intarray, data[0]));
+ M_IST_INTERN(REG_ZERO, REG_ITMP1, OFFSET(java_intarray_t, data[0]));
break;
case ICMD_LASTORECONST: /* ..., arrayref, index ==> ... */
emit_arrayindexoutofbounds_check(cd, iptr, s1, s2);
M_ASLL_IMM(s2, 3, REG_ITMP2);
M_AADD(REG_ITMP2, s1, REG_ITMP1);
- M_STX_INTERN(REG_ZERO, REG_ITMP1, OFFSET(java_longarray, data[0]));
+ M_STX_INTERN(REG_ZERO, REG_ITMP1, OFFSET(java_longarray_t, data[0]));
break;
case ICMD_AASTORECONST: /* ..., arrayref, index ==> ... */
emit_arrayindexoutofbounds_check(cd, iptr, s1, s2);
M_ASLL_IMM(s2, POINTERSHIFT, REG_ITMP2);
M_AADD(REG_ITMP2, s1, REG_ITMP1);
- M_AST_INTERN(REG_ZERO, REG_ITMP1, OFFSET(java_objectarray, data[0]));
+ M_AST_INTERN(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;
+ uf = iptr->sx.s23.s3.uf;
fieldtype = uf->fieldref->parseddesc.fd->type;
disp = dseg_add_unique_address(cd, uf);
codegen_add_patch_ref(cd, PATCHER_get_putstatic, uf, disp);
}
else {
- fi = iptr->sx.s23.s3.fmiref->p.field;
+ fi = iptr->sx.s23.s3.fmiref->p.field;
fieldtype = fi->type;
- disp = dseg_add_address(cd, &(fi->value));
+ disp = dseg_add_address(cd, fi->value);
if (!CLASS_IS_OR_ALMOST_INITIALIZED(fi->class))
codegen_add_patch_ref(cd, PATCHER_clinit, fi->class, disp);
case ICMD_PUTSTATIC: /* ..., value ==> ... */
if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
- uf = iptr->sx.s23.s3.uf;
+ uf = iptr->sx.s23.s3.uf;
fieldtype = uf->fieldref->parseddesc.fd->type;
disp = dseg_add_unique_address(cd, uf);
codegen_add_patch_ref(cd, PATCHER_get_putstatic, uf, disp);
}
else {
- fi = iptr->sx.s23.s3.fmiref->p.field;
+ fi = iptr->sx.s23.s3.fmiref->p.field;
fieldtype = fi->type;
- disp = dseg_add_address(cd, &(fi->value));
+ disp = dseg_add_address(cd, fi->value);
if (!CLASS_IS_OR_ALMOST_INITIALIZED(fi->class))
codegen_add_patch_ref(cd, PATCHER_clinit, fi->class, disp);
if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
uf = iptr->sx.s23.s3.uf;
fieldtype = uf->fieldref->parseddesc.fd->type;
- disp = dseg_add_unique_address(cd, uf);
+ disp = dseg_add_unique_address(cd, uf);
codegen_add_patch_ref(cd, PATCHER_get_putstatic, uf, disp);
}
else {
fi = iptr->sx.s23.s3.fmiref->p.field;
fieldtype = fi->type;
- disp = dseg_add_address(cd, &(fi->value));
+ disp = dseg_add_address(cd, fi->value);
if (!CLASS_IS_OR_ALMOST_INITIALIZED(fi->class))
codegen_add_patch_ref(cd, PATCHER_clinit, fi->class, disp);
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);
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:
{
#endif
#if defined(ENABLE_THREADS)
- if (checksync && (m->flags & ACC_SYNCHRONIZED)) {
+ 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);
if (l == 0) {
M_INTMOVE(s1, REG_ITMP1);
}
- else if (l <= 4095) {
+ else if (-l >= 4096 && -l <= 4095) {
M_ADD_IMM(s1, -l, REG_ITMP1);
}
else {
ICONST(REG_ITMP2, l);
- /* XXX: do I need to truncate s1 to 32-bit ? */
M_SUB(s1, REG_ITMP2, REG_ITMP1);
}
- i = i - l + 1;
+
+ i = i - l + 1; /* number of targets (>0) */
/* range check */
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_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;
}
else {
s1 = emit_load(jd, iptr, var, REG_ITMP1);
- M_STX(s1, REG_SP, JITSTACK + d * 8);
+ M_STX(s1, REG_SP, JITSTACK + d);
}
}
else {
}
else {
s1 = emit_load(jd, iptr, var, REG_FTMP1);
- M_DST(s1, REG_SP, JITSTACK + d * 8);
+ M_DST(s1, REG_SP, JITSTACK + d);
}
}
}
switch (iptr->opc) {
case ICMD_BUILTIN:
- disp = dseg_add_functionptr(cd, bte->fp);
+ 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_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);
- emit_exception_check(cd, iptr);
if (md->returntype.type == TYPE_FLT) {
/* special handling for float return value in %f0 */
M_FMOV_INTERN(0,1);
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);
sizeof(methodptr) * lm->vftblindex;
/* implicit null-pointer check */
- M_ALD(REG_METHODPTR, REG_OUT0,OFFSET(java_objectheader, vftbl));
+ 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);
}
/* implicit null-pointer check */
- M_ALD(REG_METHODPTR, REG_OUT0, OFFSET(java_objectheader, vftbl));
+ 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);
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);
superindex = super->index;
}
-#if defined(ENABLE_THREADS)
- codegen_threadcritrestart(cd, cd->mcodeptr - cd->mcodebase);
-#endif
+ if ((super == NULL) || !(super->flags & ACC_INTERFACE))
+ CODEGEN_CRITICAL_SECTION_NEW;
s1 = emit_load_s1(jd, iptr, REG_ITMP1);
emit_label_beqz(cd, BRANCH_LABEL_3, s1);
}
- M_ALD(REG_ITMP2, s1, OFFSET(java_objectheader, vftbl));
+ M_ALD(REG_ITMP2, s1, OFFSET(java_object_t, vftbl));
M_ILD(REG_ITMP3, REG_ITMP2,
OFFSET(vftbl_t, interfacetablelength));
M_ADD_IMM(REG_ITMP3, -superindex, REG_ITMP3);
emit_label_beqz(cd, BRANCH_LABEL_5, s1);
}
- M_ALD(REG_ITMP2, s1, OFFSET(java_objectheader, vftbl));
+ M_ALD(REG_ITMP2, s1, OFFSET(java_object_t, vftbl));
M_ALD(REG_ITMP3, REG_PV, disp);
-#if defined(ENABLE_THREADS)
- codegen_threadcritstart(cd, cd->mcodeptr - cd->mcodebase);
-#endif
+
+ CODEGEN_CRITICAL_SECTION_START;
+
M_ILD(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, baseval));
M_ILD(REG_ITMP3, REG_ITMP3, OFFSET(vftbl_t, baseval));
M_SUB(REG_ITMP2, REG_ITMP3, REG_ITMP2);
M_ALD(REG_ITMP3, REG_PV, disp);
M_ILD(REG_ITMP3, REG_ITMP3, OFFSET(vftbl_t, diffval));
-#if defined(ENABLE_THREADS)
- codegen_threadcritstop(cd, cd->mcodeptr - cd->mcodebase);
-#endif
+
+ CODEGEN_CRITICAL_SECTION_END;
+
/* } */
M_CMP(REG_ITMP3, REG_ITMP2);
emit_classcast_check(cd, iptr, BRANCH_ULT, REG_ITMP3, s1);
supervftbl = super->vftbl;
}
-#if defined(ENABLE_THREADS)
- codegen_threadcritrestart(cd, cd->mcodeptr - cd->mcodebase);
-#endif
+ if ((super == NULL) || !(super->flags & ACC_INTERFACE))
+ CODEGEN_CRITICAL_SECTION_NEW;
+
s1 = emit_load_s1(jd, iptr, REG_ITMP1);
d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
if (s1 == d) {
emit_label_beqz(cd, BRANCH_LABEL_3, s1);
}
- M_ALD(REG_ITMP1, s1, OFFSET(java_objectheader, vftbl));
+ M_ALD(REG_ITMP1, s1, OFFSET(java_object_t, vftbl));
M_ILD(REG_ITMP3, REG_ITMP1, OFFSET(vftbl_t, interfacetablelength));
M_CMP_IMM(REG_ITMP3, superindex);
M_BLE(4);
emit_label_beqz(cd, BRANCH_LABEL_5, s1);
}
- M_ALD(REG_ITMP1, s1, OFFSET(java_objectheader, vftbl));
+ M_ALD(REG_ITMP1, s1, OFFSET(java_object_t, vftbl));
M_ALD(REG_ITMP2, REG_PV, disp);
-#if defined(ENABLE_THREADS)
- codegen_threadcritstart(cd, cd->mcodeptr - cd->mcodebase);
-#endif
+
+ CODEGEN_CRITICAL_SECTION_START;
+
M_ILD(REG_ITMP1, REG_ITMP1, OFFSET(vftbl_t, baseval));
M_ILD(REG_ITMP3, REG_ITMP2, OFFSET(vftbl_t, baseval));
M_ILD(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, diffval));
-#if defined(ENABLE_THREADS)
- codegen_threadcritstop(cd, cd->mcodeptr - cd->mcodebase);
-#endif
+
+ CODEGEN_CRITICAL_SECTION_END;
+
M_SUB(REG_ITMP1, REG_ITMP3, REG_ITMP1);
M_CMP(REG_ITMP1, REG_ITMP2);
M_XCMOVULE_IMM(1, d);
} /* 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);
- REPLACEMENT_EMIT_STUBS(jd);
/* everything's ok */
}
+/* codegen_emit_stub_builtin ***************************************************
+
+ Creates a stub routine which calls a builtin function.
+
+*******************************************************************************/
+
+void codegen_emit_stub_builtin(jitdata *jd, builtintable_entry *bte)
+{
+ codeinfo *code;
+ codegendata *cd;
+ methoddesc *md;
+ s4 i;
+ s4 disp;
+ s4 s1, s2;
+
+ /* get required compiler data */
+ code = jd->code;
+ cd = jd->cd;
+
+ /* set some variables */
+ md = bte->md;
+
+ /* calculate stack frame size */
+ cd->stackframesize =
+ WINSAVE_CNT +
+ ABIPARAMS_CNT +
+ FLT_ARG_CNT +
+ sizeof(stackframeinfo_t) / SIZEOF_VOID_P +
+ 4; /* 4 arguments or return value */
+
+
+ /* keep stack 16-byte aligned (ABI requirement) */
+
+ 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 * 4); /* FrameSize */
+ (void) dseg_add_unique_s4(cd, 0); /* IsSync */
+ (void) dseg_add_unique_s4(cd, 0); /* IsLeaf */
+ (void) dseg_add_unique_s4(cd, 0); /* IntSave */
+ (void) dseg_add_unique_s4(cd, 0); /* FltSave */
+ (void) dseg_addlinenumbertablesize(cd);
+ (void) dseg_add_unique_s4(cd, 0); /* ExTableSize */
+
+
+ /* generate stub code */
+ M_SAVE(REG_SP, -cd->stackframesize * 8, REG_SP); /* build up stackframe */
+
+#if defined(ENABLE_GC_CACAO)
+ /* Save callee saved integer registers in stackframeinfo (GC may
+ need to recover them during a collection). */
+
+ disp = cd->stackframesize * 8 - sizeof(stackframeinfo_t) +
+ OFFSET(stackframeinfo_t, intregs) + BIAS;
+
+ for (i = 0; i < INT_SAV_CNT; i++)
+ M_AST(abi_registers_integer_saved[i], REG_SP, disp + i * 8);
+#endif
+
+ for (i = 0; i < md->paramcount; i++) {
+ s1 = md->params[i].regoff;
+
+ switch (md->paramtypes[i].type) {
+ case TYPE_INT:
+ case TYPE_LNG:
+ case TYPE_ADR:
+ break;
+ case TYPE_FLT:
+ case TYPE_DBL:
+ M_DST(s1, REG_SP, JITSTACK + i * 8);
+ break;
+ }
+ }
+
+ /* create dynamic stack info */
+
+ M_AADD_IMM(REG_SP, BIAS + cd->stackframesize * 8, REG_OUT0); /* data sp*/
+ M_MOV(REG_PV_CALLEE, REG_OUT1); /* PV */
+ M_MOV(REG_FP, REG_OUT2); /* java sp */
+ M_MOV(REG_RA_CALLEE, REG_OUT3); /* ra */
+
+ disp = dseg_add_functionptr(cd, codegen_stub_builtin_enter);
+ M_ALD(REG_ITMP3, REG_PV_CALLEE, disp);
+ M_JMP(REG_RA_CALLER, REG_ITMP3, REG_ZERO);
+ M_NOP; /* XXX fill me! */
+
+
+ /* builtins are allowed to have 5 arguments max */
+
+ assert(md->paramcount <= 5);
+
+ /* copy arguments into position */
+
+ for (i = 0; i < md->paramcount; i++) {
+ assert(!md->params[i].inmemory);
+
+ s1 = md->params[i].regoff;
+
+ switch (md->paramtypes[i].type) {
+ case TYPE_INT:
+ case TYPE_LNG:
+ case TYPE_ADR:
+ M_MOV(REG_WINDOW_TRANSPOSE(abi_registers_integer_argument[i]), s1);
+ break;
+ case TYPE_FLT:
+ case TYPE_DBL:
+ M_DLD(s1, REG_SP, JITSTACK + i * 8);
+ break;
+ }
+
+ }
+
+ /* call the builtin function */
+
+ disp = dseg_add_functionptr(cd, bte->fp);
+ M_ALD(REG_ITMP3, REG_PV_CALLEE, disp); /* load adress of builtin */
+ M_JMP(REG_RA_CALLER, REG_ITMP3, REG_ZERO); /* call builtin */
+ M_NOP; /* delay slot */
+
+
+ /* save return value */
+
+ if (md->returntype.type != TYPE_VOID) {
+ if (IS_INT_LNG_TYPE(md->returntype.type))
+ M_MOV(REG_RESULT_CALLER, REG_RESULT_CALLEE);
+ else
+ M_DST(REG_FRESULT, REG_SP, CSTACK);
+ }
+
+
+ /* remove native stackframe info */
+
+ M_ADD_IMM(REG_FP, BIAS, REG_OUT0); /* datasp, like above */
+ disp = dseg_add_functionptr(cd, codegen_stub_builtin_exit);
+ M_ALD(REG_ITMP3, REG_PV_CALLEE, disp);
+ M_JMP(REG_RA_CALLER, REG_ITMP3, REG_ZERO);
+ M_NOP;
+
+ /* restore float return value, int return value already in our return reg */
+
+ if (md->returntype.type != TYPE_VOID) {
+ if (IS_FLT_DBL_TYPE(md->returntype.type)) {
+ if (IS_2_WORD_TYPE(md->returntype.type))
+ M_DLD(REG_FRESULT, REG_SP, CSTACK);
+ else
+ M_FLD(REG_FRESULT, REG_SP, CSTACK);
+ }
+ }
+
+
+#if defined(ENABLE_GC_CACAO)
+ /* Restore callee saved integer registers from stackframeinfo (GC
+ might have modified them during a collection). */
+
+ disp = cd->stackframesize * 8 - sizeof(stackframeinfo_t) +
+ OFFSET(stackframeinfo_t, intregs) + BIAS;
+
+ for (i = 0; i < INT_SAV_CNT; i++)
+ M_ALD(abi_registers_integer_saved[i], REG_SP, disp + i * 8);
+#endif
+
+ /* return */
+ M_RETURN(REG_RA_CALLEE, 8); /* implicit window restore */
+ M_NOP;
+
+ /* assert(0); */
+}
+
+
/* codegen_emit_stub_native ****************************************************
Emits a stub routine which calls a native method.
sizeof(stackframeinfo) / SIZEOF_VOID_P +
sizeof(localref_table) / SIZEOF_VOID_P +
md->paramcount + /* for saving arguments over calls */
- nmd->memuse + /* nmd knows about the native stackframe layout */
+ nmd->memuse + /* nmd->memuse includes the (6) abi params */
WINSAVE_CNT;
funcdisp = dseg_add_functionptr(cd, f);
-#if !defined(WITH_STATIC_CLASSPATH)
- if (f == NULL) {
+ if (f == NULL)
codegen_add_patch_ref(cd, PATCHER_resolve_native, m, funcdisp);
- }
-#endif
- /* save float argument registers (into abi parameter slots) */
+ /* save float argument registers */
assert(ABIPARAMS_CNT >= FLT_ARG_CNT);
for (i = 0, j = 0; i < md->paramcount && i < FLT_ARG_CNT; i++) {
if (IS_FLT_DBL_TYPE(md->paramtypes[i].type)) {
- s1 = WINSAVE_CNT + (j * 8);
- M_DST(abi_registers_float_argument[i], REG_SP, BIAS + s1);
+ s1 = WINSAVE_CNT + nmd->memuse + j;
+ M_DST(abi_registers_float_argument[i], REG_SP, BIAS + (s1*8));
fltregarg_offset[i] = s1; /* remember stack offset */
j++;
}
/* prepare data structures for native function call */
- M_ADD_IMM(REG_FP, BIAS, REG_OUT0); /* datasp == top of the stack frame (absolute == +BIAS) */
+ M_ADD_IMM(REG_FP, BIAS, REG_OUT0); /* datasp == top of the stack frame (absolute, ie. + BIAS) */
M_MOV(REG_PV_CALLEE, REG_OUT1);
M_MOV(REG_FP, REG_OUT2); /* java sp */
M_MOV(REG_RA_CALLEE, REG_OUT3);
M_JMP(REG_RA_CALLER, REG_ITMP3, REG_ZERO);
M_NOP; /* XXX fill me! */
+ /* remember class argument */
+
+ if (m->flags & ACC_STATIC)
+ M_MOV(REG_RESULT_CALLER, REG_ITMP3);
+
/* keep float arguments on stack */
#if 0
for (i = 0, j = 0; i < md->paramcount && i < FLT_ARG_CNT; i++) {
s1 = REG_WINDOW_TRANSPOSE(s1);
if (!nmd->params[j].inmemory) {
- s2 = nat_argintregs[nmd->params[j].regoff];
+ s2 = nmd->params[j].regoff;
M_INTMOVE(s1, s2);
} else {
- s2 = nmd->params[j].regoff - 6;
- M_AST(s1, REG_SP, CSTACK + s2 * 8);
+ /* nmd's regoff is relative to the start of the param array */
+ s2 = BIAS + WINSAVE_CNT * 8 + nmd->params[j].regoff;
+ M_AST(s1, REG_SP, s2);
}
} else {
assert(false); /* path never taken */
}
- s1 = md->params[i].regoff + cd->stackframesize;
- s2 = nmd->params[j].regoff - 6;
- M_ALD(REG_ITMP1, REG_SP, CSTACK + s1 * 8);
- M_AST(REG_ITMP1, REG_SP, CSTACK + s2 * 8);
+ s1 = md->params[i].regoff + cd->stackframesize * 8;
+ s2 = BIAS + WINSAVE_CNT * 8 + nmd->params[j].regoff;
+ M_ALD(REG_ITMP1, REG_SP, CSTACK + s1);
+ M_AST(REG_ITMP1, REG_SP, s2);
}
} else {
s2 = nmd->params[j].regoff;
/* JIT float regs are still on the stack */
- M_DLD(s2, REG_SP, BIAS + fltregarg_offset[i]);
+ M_DLD(s2, REG_SP, BIAS + (fltregarg_offset[i] * 8));
}
else {
/* not supposed to happen with 16 NAT flt args */
}
else {
- s1 = md->params[i].regoff + cd->stackframesize;
+ s1 = md->params[i].regoff;
if (!nmd->params[j].inmemory) {
/* JIT stack -> NAT reg */
- s2 = nmd->params[j].regoff;
- M_DLD(s2, REG_SP, CSTACK + s1 * 8);
+ s2 = nmd->params[j].regoff;
+ M_DLD(s2, REG_FP, JITSTACK + s1);
}
else {
/* JIT stack -> NAT stack */
- s2 = nmd->params[j].regoff - 6;
+ s2 = WINSAVE_CNT * 8 + nmd->params[j].regoff;
/* The FTMP register may already be loaded with args */
/* we know $f0 is unused because of the env pointer */
- M_DLD(REG_F0, REG_SP, CSTACK + s1 * 8);
- M_DST(REG_F0, REG_SP, CSTACK + s2 * 8);
+ M_DLD(REG_F0, REG_FP, JITSTACK + s1);
+ M_DST(REG_F0, REG_SP, BIAS + s2);
}
}
}
/* put class into second argument register */
- if (m->flags & ACC_STATIC) {
- disp = dseg_add_address(cd, m->class);
- M_ALD(REG_OUT1, REG_PV_CALLEE, disp);
- }
+ if (m->flags & ACC_STATIC)
+ M_MOV(REG_ITMP3, REG_OUT1);
/* put env into first argument register */