/* src/vm/jit/i386/emit.c - i386 code emitter functions
- Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
+ Copyright (C) 1996-2005, 2006, 2007 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
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
- Contact: cacao@cacaojvm.org
-
- Authors: Christian Thalinger
-
- $Id: emit.c 6056 2006-11-27 14:48:33Z edwin $
+ $Id: emit.c 8318 2007-08-16 10:05:34Z michi $
*/
#include "vm/jit/i386/emit.h"
#include "vm/jit/i386/md-abi.h"
-#if defined(ENABLE_THREADS)
-# include "threads/native/lock.h"
-#endif
+#include "mm/memory.h"
+
+#include "threads/lock-common.h"
#include "vm/builtin.h"
-#include "vm/statistics.h"
+#include "vm/exceptions.h"
+
+#include "vm/jit/abi.h"
#include "vm/jit/asmpart.h"
#include "vm/jit/dseg.h"
#include "vm/jit/emit-common.h"
#include "vm/jit/jit.h"
#include "vm/jit/replace.h"
+#include "vmcore/options.h"
+#include "vmcore/statistics.h"
+
/* emit_load ******************************************************************
if (IS_INMEMORY(src->flags)) {
COUNT_SPILLS;
- disp = src->vv.regoff * 4;
-
- if (IS_FLT_DBL_TYPE(src->type)) {
- if (IS_2_WORD_TYPE(src->type))
- M_DLD(tempreg, REG_SP, disp);
- else
- M_FLD(tempreg, REG_SP, disp);
- }
- else {
- if (IS_2_WORD_TYPE(src->type))
- M_LLD(tempreg, REG_SP, disp);
- else
- M_ILD(tempreg, REG_SP, disp);
+ disp = src->vv.regoff;
+
+ switch (src->type) {
+ case TYPE_INT:
+ case TYPE_ADR:
+ M_ILD(tempreg, REG_SP, disp);
+ break;
+ case TYPE_LNG:
+ M_LLD(tempreg, REG_SP, disp);
+ break;
+ case TYPE_FLT:
+ M_FLD(tempreg, REG_SP, disp);
+ break;
+ case TYPE_DBL:
+ M_DLD(tempreg, REG_SP, disp);
+ break;
+ default:
+ vm_abort("emit_load: unknown type %d", src->type);
}
reg = tempreg;
if (IS_INMEMORY(src->flags)) {
COUNT_SPILLS;
- disp = src->vv.regoff * 4;
+ disp = src->vv.regoff;
M_ILD(tempreg, REG_SP, disp);
if (IS_INMEMORY(src->flags)) {
COUNT_SPILLS;
- disp = src->vv.regoff * 4;
+ disp = src->vv.regoff;
M_ILD(tempreg, REG_SP, disp + 4);
inline void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
{
codegendata *cd;
+ s4 disp;
/* get required compiler data */
if (IS_INMEMORY(dst->flags)) {
COUNT_SPILLS;
- if (IS_FLT_DBL_TYPE(dst->type)) {
- if (IS_2_WORD_TYPE(dst->type))
- M_DST(d, REG_SP, dst->vv.regoff * 4);
- else
- M_FST(d, REG_SP, dst->vv.regoff * 4);
- }
- else {
- if (IS_2_WORD_TYPE(dst->type))
- M_LST(d, REG_SP, dst->vv.regoff * 4);
- else
- M_IST(d, REG_SP, dst->vv.regoff * 4);
+ disp = dst->vv.regoff;
+
+ switch (dst->type) {
+ case TYPE_INT:
+ case TYPE_ADR:
+ M_IST(d, REG_SP, disp);
+ break;
+ case TYPE_LNG:
+ M_LST(d, REG_SP, disp);
+ break;
+ case TYPE_FLT:
+ M_FST(d, REG_SP, disp);
+ break;
+ case TYPE_DBL:
+ M_DST(d, REG_SP, disp);
+ break;
+ default:
+ vm_abort("emit_store: unknown type %d", dst->type);
}
}
}
if (IS_INMEMORY(dst->flags)) {
COUNT_SPILLS;
- M_IST(GET_LOW_REG(d), REG_SP, dst->vv.regoff * 4);
+ M_IST(GET_LOW_REG(d), REG_SP, dst->vv.regoff);
}
}
if (IS_INMEMORY(dst->flags)) {
COUNT_SPILLS;
- M_IST(GET_HIGH_REG(d), REG_SP, dst->vv.regoff * 4 + 4);
+ M_IST(GET_HIGH_REG(d), REG_SP, dst->vv.regoff + 4);
}
}
*******************************************************************************/
-void emit_copy(jitdata *jd, instruction *iptr, varinfo *src, varinfo *dst)
+void emit_copy(jitdata *jd, instruction *iptr)
{
- codegendata *cd;
- s4 s1, d;
+ codegendata *cd;
+ varinfo *src;
+ varinfo *dst;
+ s4 s1, d;
/* get required compiler data */
cd = jd->cd;
+ /* get source and destination variables */
+
+ src = VAROP(iptr->s1);
+ dst = VAROP(iptr->dst);
+
if ((src->vv.regoff != dst->vv.regoff) ||
((src->flags ^ dst->flags) & INMEMORY)) {
+ if ((src->type == TYPE_RET) || (dst->type == TYPE_RET)) {
+ /* emit nothing, as the value won't be used anyway */
+ return;
+ }
+
/* If one of the variables resides in memory, we can eliminate
the register move from/to the temporary register with the
order of getting the destination register and the load. */
}
if (s1 != d) {
- if (IS_FLT_DBL_TYPE(src->type)) {
+ switch (src->type) {
+ case TYPE_INT:
+ case TYPE_ADR:
+ M_MOV(s1, d);
+ break;
+ case TYPE_LNG:
+ M_LNGMOVE(s1, d);
+ break;
+ case TYPE_FLT:
+ case TYPE_DBL:
/* M_FMOV(s1, d); */
- } else {
- if (IS_2_WORD_TYPE(src->type))
- M_LNGMOVE(s1, d);
- else
- M_MOV(s1, d);
+ break;
+ default:
+ vm_abort("emit_copy: unknown type %d", src->type);
}
}
}
-/* emit_exception_stubs ********************************************************
+/* emit_branch *****************************************************************
- Generates the code for the exception stubs.
+ Emits the code for conditional and unconditional branchs.
*******************************************************************************/
-void emit_exception_stubs(jitdata *jd)
+void emit_branch(codegendata *cd, s4 disp, s4 condition, s4 reg, u4 options)
{
- codegendata *cd;
- registerdata *rd;
- exceptionref *er;
- s4 branchmpc;
- s4 targetmpc;
- s4 targetdisp;
+ s4 branchdisp;
- /* get required compiler data */
+ /* ATTENTION: a displacement overflow cannot happen */
- cd = jd->cd;
- rd = jd->rd;
+ /* check which branch to generate */
- /* generate exception stubs */
-
- targetdisp = 0;
+ if (condition == BRANCH_UNCONDITIONAL) {
- for (er = cd->exceptionrefs; er != NULL; er = er->next) {
- /* back-patch the branch to this exception code */
+ /* calculate the different displacements */
- branchmpc = er->branchpos;
- targetmpc = cd->mcodeptr - cd->mcodebase;
+ branchdisp = disp - BRANCH_UNCONDITIONAL_SIZE;
- md_codegen_patch_branch(cd, branchmpc, targetmpc);
+ M_JMP_IMM(branchdisp);
+ }
+ else {
+ /* calculate the different displacements */
+
+ branchdisp = disp - BRANCH_CONDITIONAL_SIZE;
+
+ switch (condition) {
+ case BRANCH_EQ:
+ M_BEQ(branchdisp);
+ break;
+ case BRANCH_NE:
+ M_BNE(branchdisp);
+ break;
+ case BRANCH_LT:
+ M_BLT(branchdisp);
+ break;
+ case BRANCH_GE:
+ M_BGE(branchdisp);
+ break;
+ case BRANCH_GT:
+ M_BGT(branchdisp);
+ break;
+ case BRANCH_LE:
+ M_BLE(branchdisp);
+ break;
+ case BRANCH_ULT:
+ M_BB(branchdisp);
+ break;
+ case BRANCH_ULE:
+ M_BBE(branchdisp);
+ break;
+ case BRANCH_UGE:
+ M_BAE(branchdisp);
+ break;
+ case BRANCH_UGT:
+ M_BA(branchdisp);
+ break;
+ default:
+ vm_abort("emit_branch: unknown condition %d", condition);
+ }
+ }
+}
- MCODECHECK(512);
- /* Check if the exception is an
- ArrayIndexOutOfBoundsException. If so, move index register
- into REG_ITMP1. */
+/* emit_arithmetic_check *******************************************************
- if (er->reg != -1)
- M_INTMOVE(er->reg, REG_ITMP1);
+ Emit an ArithmeticException check.
- /* calcuate exception address */
+*******************************************************************************/
- M_MOV_IMM(0, REG_ITMP2_XPC);
- dseg_adddata(cd);
- M_AADD_IMM32(er->branchpos - 6, REG_ITMP2_XPC);
+void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg)
+{
+ if (INSTRUCTION_MUST_CHECK(iptr)) {
+ M_TEST(reg);
+ M_BNE(6);
+ M_ALD_MEM(reg, EXCEPTION_HARDWARE_ARITHMETIC);
+ }
+}
- /* move function to call into REG_ITMP3 */
- M_MOV_IMM(er->function, REG_ITMP3);
+/* emit_arrayindexoutofbounds_check ********************************************
- if (targetdisp == 0) {
- targetdisp = cd->mcodeptr - cd->mcodebase;
+ Emit a ArrayIndexOutOfBoundsException check.
- M_ASUB_IMM(5 * 4, REG_SP);
+*******************************************************************************/
- /* first store REG_ITMP1 so we can use it */
+void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, s4 s2)
+{
+ if (INSTRUCTION_MUST_CHECK(iptr)) {
+ M_ILD(REG_ITMP3, s1, OFFSET(java_array_t, size));
+ M_CMP(REG_ITMP3, s2);
+ M_BB(6);
+ M_ALD_MEM(s2, EXCEPTION_HARDWARE_ARRAYINDEXOUTOFBOUNDS);
+ }
+}
- M_AST(REG_ITMP1, REG_SP, 4 * 4); /* for AIOOBE */
- M_AST_IMM(0, REG_SP, 0 * 4);
- dseg_adddata(cd);
- M_MOV(REG_SP, REG_ITMP1);
- M_AADD_IMM(5 * 4, REG_ITMP1);
- M_AST(REG_ITMP1, REG_SP, 1 * 4);
- M_ALD(REG_ITMP1, REG_SP, (5 + cd->stackframesize) * 4);
- M_AST(REG_ITMP1, REG_SP, 2 * 4);
- M_AST(REG_ITMP2_XPC, REG_SP, 3 * 4);
+/* emit_classcast_check ********************************************************
- M_CALL(REG_ITMP3);
+ Emit a ClassCastException check.
- M_ALD(REG_ITMP2_XPC, REG_SP, 3 * 4);
- M_AADD_IMM(5 * 4, REG_SP);
+*******************************************************************************/
- M_MOV_IMM(asm_handle_exception, REG_ITMP3);
- M_JMP(REG_ITMP3);
- }
- else {
- M_JMP_IMM((cd->mcodebase + targetdisp) -
- (cd->mcodeptr + PATCHER_CALL_SIZE));
+void emit_classcast_check(codegendata *cd, instruction *iptr, s4 condition, s4 reg, s4 s1)
+{
+ if (INSTRUCTION_MUST_CHECK(iptr)) {
+ switch (condition) {
+ case BRANCH_LE:
+ M_BGT(6);
+ break;
+ case BRANCH_EQ:
+ M_BNE(6);
+ break;
+ case BRANCH_ULE:
+ M_BBE(6);
+ break;
+ default:
+ vm_abort("emit_classcast_check: unknown condition %d", condition);
}
+ M_ALD_MEM(s1, EXCEPTION_HARDWARE_CLASSCAST);
+ }
+}
+
+
+/* emit_nullpointer_check ******************************************************
+
+ Emit a NullPointerException check.
+
+*******************************************************************************/
+
+void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg)
+{
+ if (INSTRUCTION_MUST_CHECK(iptr)) {
+ M_TEST(reg);
+ M_BNE(6);
+ M_ALD_MEM(reg, EXCEPTION_HARDWARE_NULLPOINTER);
+ }
+}
+
+
+/* emit_exception_check ********************************************************
+
+ Emit an Exception check.
+
+*******************************************************************************/
+
+void emit_exception_check(codegendata *cd, instruction *iptr)
+{
+ if (INSTRUCTION_MUST_CHECK(iptr)) {
+ M_TEST(REG_RESULT);
+ M_BNE(6);
+ M_ALD_MEM(REG_RESULT, EXCEPTION_HARDWARE_EXCEPTION);
}
}
}
-/* emit_replacement_stubs ******************************************************
+/* emit_trap *******************************************************************
- Generates the code for the replacement stubs.
+ Emit a trap instruction and return the original machine code.
*******************************************************************************/
-void emit_replacement_stubs(jitdata *jd)
+uint32_t emit_trap(codegendata *cd)
{
- codegendata *cd;
- codeinfo *code;
- rplpoint *rplp;
- s4 disp;
- s4 i;
-
- /* get required compiler data */
-
- cd = jd->cd;
- code = jd->code;
+ uint32_t mcode;
- rplp = code->rplpoints;
+ /* Get machine code which is patched back in later. The
+ trap is 1 instruction word long. */
- for (i = 0; i < code->rplpointcount; ++i, ++rplp) {
- /* check code segment size */
+ mcode = *((uint32_t *) cd->mcodeptr);
- MCODECHECK(512);
-
- /* note start of stub code */
-
- rplp->outcode = (u1 *) (ptrint) (cd->mcodeptr - cd->mcodebase);
-
- /* make machine code for patching */
-
- disp = (ptrint) (rplp->outcode - rplp->pc) - 5;
-
- rplp->mcode = 0xe9 | ((u8) disp << 8);
-
- /* push address of `rplpoint` struct */
-
- M_PUSH_IMM(rplp);
-
- /* jump to replacement function */
+ M_NOP;
- M_PUSH_IMM(asm_replacement_out);
- M_RET;
- }
+ return mcode;
}
-
+
/* emit_verbosecall_enter ******************************************************
codegendata *cd;
registerdata *rd;
methoddesc *md;
- s4 disp;
- s4 i, t;
+ int32_t disp;
+ int i;
+ int d;
+
+ if (!JITDATA_HAS_FLAG_VERBOSECALL(jd))
+ return;
/* get required compiler data */
/* methodinfo* + arguments + return address */
- disp = TRACE_ARGS_NUM * 8 + 4 + INT_TMP_CNT * 4 +
- cd->stackframesize * 4 + 4;
+ disp = (TRACE_ARGS_NUM + 1 + TMP_CNT) * 8 + cd->stackframesize * 8 + 4;
- M_ASUB_IMM(TRACE_ARGS_NUM * 8 + 4 + INT_TMP_CNT * 4, REG_SP);
+ M_ASUB_IMM((TRACE_ARGS_NUM + 1 + TMP_CNT) * 8, REG_SP);
/* save temporary registers for leaf methods */
for (i = 0; i < INT_TMP_CNT; i++)
- M_IST(rd->tmpintregs[i], REG_SP, TRACE_ARGS_NUM * 8 + 4 + i * 4);
-
- for (i = 0; i < md->paramcount && i < TRACE_ARGS_NUM; i++) {
- t = md->paramtypes[i].type;
-
- if (IS_INT_LNG_TYPE(t)) {
- if (IS_2_WORD_TYPE(t)) {
- M_LLD(REG_ITMP12_PACKED, REG_SP, disp);
- M_LST(REG_ITMP12_PACKED, REG_SP, i * 8);
- }
- else if (IS_ADR_TYPE(t)) {
- M_ALD(REG_ITMP1, REG_SP, disp);
- M_AST(REG_ITMP1, REG_SP, i * 8);
- M_IST_IMM(0, REG_SP, i * 8 + 4);
- }
- else {
- M_ILD(EAX, REG_SP, disp);
- emit_cltd(cd);
- M_LST(EAX_EDX_PACKED, REG_SP, i * 8);
- }
- }
- else {
- if (IS_2_WORD_TYPE(t)) {
- M_DLD(REG_NULL, REG_SP, disp);
- M_DST(REG_NULL, REG_SP, i * 8);
- }
- else {
- M_FLD(REG_NULL, REG_SP, disp);
- M_FST(REG_NULL, REG_SP, i * 8);
- M_IST_IMM(0, REG_SP, i * 8 + 4);
- }
+ M_IST(rd->tmpintregs[i], REG_SP, (TRACE_ARGS_NUM + 1 + i) * 8);
+
+ /* save argument registers */
+
+ for (i = 0; i < md->paramcount; i++) {
+ d = i * 8;
+
+ switch (md->paramtypes[i].type) {
+ case TYPE_INT:
+ M_ILD(EAX, REG_SP, disp);
+ emit_cltd(cd);
+ M_LST(EAX_EDX_PACKED, REG_SP, d);
+ break;
+ case TYPE_LNG:
+ M_LLD(REG_ITMP12_PACKED, REG_SP, disp);
+ M_LST(REG_ITMP12_PACKED, REG_SP, d);
+ break;
+ case TYPE_ADR:
+ M_ALD(REG_ITMP1, REG_SP, disp);
+ M_AST(REG_ITMP1, REG_SP, d);
+ M_IST_IMM(0, REG_SP, d + 4); /* high-bits are zero */
+ break;
+ case TYPE_FLT:
+ M_FLD(REG_NULL, REG_SP, disp);
+ M_FST(REG_NULL, REG_SP, d);
+ M_IST_IMM(0, REG_SP, d + 4); /* high-bits are zero */
+ break;
+ case TYPE_DBL:
+ M_DLD(REG_NULL, REG_SP, disp);
+ M_DST(REG_NULL, REG_SP, d);
+ break;
}
- disp += (IS_2_WORD_TYPE(t)) ? 8 : 4;
+ disp += 8;
}
-
+
M_AST_IMM(m, REG_SP, TRACE_ARGS_NUM * 8);
- M_MOV_IMM(builtin_trace_args, REG_ITMP1);
+ M_MOV_IMM(builtin_verbosecall_enter, REG_ITMP1);
M_CALL(REG_ITMP1);
/* restore temporary registers for leaf methods */
for (i = 0; i < INT_TMP_CNT; i++)
- M_ILD(rd->tmpintregs[i], REG_SP, TRACE_ARGS_NUM * 8 + 4 + i * 4);
+ M_ILD(rd->tmpintregs[i], REG_SP, (TRACE_ARGS_NUM + 1 + i) * 8);
- M_AADD_IMM(TRACE_ARGS_NUM * 8 + 4 + INT_TMP_CNT * 4, REG_SP);
+ M_AADD_IMM((TRACE_ARGS_NUM + 1 + TMP_CNT) * 8, REG_SP);
/* mark trace code */
Generates the code for the call trace.
+ void builtin_verbosecall_exit(s8 l, double d, float f, methodinfo *m);
+
*******************************************************************************/
#if !defined(NDEBUG)
codegendata *cd;
registerdata *rd;
+ if (!JITDATA_HAS_FLAG_VERBOSECALL(jd))
+ return;
+
/* get required compiler data */
m = jd->m;
M_NOP;
- M_ASUB_IMM(4 + 8 + 8 + 4 + 8, REG_SP); /* +8: keep stack 16-byte aligned */
+ M_ASUB_IMM(8 + 8 + 4 + 4 + 8, REG_SP); /* +8: keep stack 16-byte aligned */
- M_AST_IMM(m, REG_SP, 0 * 4);
+ M_LST(REG_RESULT_PACKED, REG_SP, 0 * 8);
- M_LST(REG_RESULT_PACKED, REG_SP, 1 * 4);
+ M_DSTNP(REG_NULL, REG_SP, 1 * 8);
+ M_FSTNP(REG_NULL, REG_SP, 2 * 8);
- M_DSTNP(REG_NULL, REG_SP, 1 * 4 + 1 * 8);
- M_FSTNP(REG_NULL, REG_SP, 1 * 4 + 2 * 8);
+ M_AST_IMM(m, REG_SP, 2 * 8 + 1 * 4);
- M_MOV_IMM(builtin_displaymethodstop, REG_ITMP1);
+ M_MOV_IMM(builtin_verbosecall_exit, REG_ITMP1);
M_CALL(REG_ITMP1);
- M_LLD(REG_RESULT_PACKED, REG_SP, 1 * 4);
+ M_LLD(REG_RESULT_PACKED, REG_SP, 0 * 4);
- M_AADD_IMM(4 + 8 + 8 + 4 + 8, REG_SP);
+ M_AADD_IMM(8 + 8 + 4 + 4 + 8, REG_SP);
/* mark trace code */