/* src/vm/jit/i386/emit.c - i386 code emitter 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.
#include <assert.h>
#include "vm/types.h"
+#include "vm/os.hpp"
#include "vm/jit/i386/codegen.h"
#include "vm/jit/i386/emit.h"
#include "vm/jit/i386/md-abi.h"
-#include "mm/memory.h"
+#include "mm/memory.hpp"
-#include "threads/lock-common.h"
+#include "threads/lock.hpp"
#include "vm/options.h"
#include "vm/statistics.h"
#include "vm/jit/patcher-common.hpp"
#include "vm/jit/replace.hpp"
#include "vm/jit/trace.hpp"
-#include "vm/jit/trap.h"
+#include "vm/jit/trap.hpp"
/* emit_load ******************************************************************
}
+/**
+ * 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.
case BRANCH_LE:
M_BGT(6);
break;
+ case BRANCH_GE:
+ M_BLT(6);
+ break;
case BRANCH_EQ:
M_BNE(6);
break;
+ case BRANCH_NE:
+ M_BEQ(6);
+ break;
case BRANCH_ULE:
M_BBE(6);
break;
M_ALD_MEM(REG_METHODPTR, TRAP_COUNTDOWN);
}
+/* emit_patcher_alignment ******************************************************
+
+ Emit NOP to ensure placement at an even address.
+
+*******************************************************************************/
+
+void emit_patcher_alignment(codegendata *cd)
+{
+ if ((uintptr_t) cd->mcodeptr & 1)
+ M_NOP;
+}
+
+
/* 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)
+{
+ 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 profiling code to start CPU cycle counting.
+ */
+#if defined(ENABLE_PROFILING)
+void emit_profile_cycle_start(codegendata* cd, codeinfo* code)
+{
+ // XXX Not implemented yet!
+}
+#endif
+
+
+/**
+ * Emit profiling code to stop CPU cycle counting.
+ */
+#if defined(ENABLE_PROFILING)
+void emit_profile_cycle_stop(codegendata* cd, codeinfo* code)
+{
+ // XXX Not implemented yet!
+}
+#endif
+
+
/* emit_verbosecall_enter ******************************************************
Generates the code for the call trace.
emit_imm32((imm));
}
+/* 2-byte opcode for use with patchers */
+void emit_mov_imm2_reg(codegendata *cd, s4 imm, s4 reg)
+{
+ *(cd->mcodeptr++) = 0xc7;
+ emit_address_byte(3, 0, reg);
+ emit_imm32((imm));
+}
+
+
void emit_movb_imm_reg(codegendata *cd, s4 imm, s4 reg)
{
}
}
+void emit_alu_memindex_reg(codegendata *cd, s4 opc, s4 disp, s4 basereg, s4 indexreg, s4 scale, s4 reg)
+{
+ *(cd->mcodeptr++) = (((u1) (opc)) << 3) + 3;
+ emit_memindex(cd, (reg),(disp),(basereg),(indexreg),(scale));
+}
void emit_test_reg_reg(codegendata *cd, s4 reg, s4 dreg)
{
/*
* inc, dec operations
*/
+void emit_inc_reg(codegendata *cd, s4 reg)
+{
+ *(cd->mcodeptr++) = 0xff;
+ emit_reg(0,(reg));
+}
+
void emit_dec_mem(codegendata *cd, s4 mem)
{
*(cd->mcodeptr++) = 0xff;
*/
void emit_setcc_reg(codegendata *cd, s4 opc, s4 reg)
{
+ assert(reg < 4); /* Can only operate on al, bl, cl, dl. */
*(cd->mcodeptr++) = 0x0f;
*(cd->mcodeptr++) = 0x90 + (u1) (opc);
emit_reg(0,(reg));