#include <assert.h>
#include <stdio.h>
+#include <stdint.h>
#include "vm/types.h"
#include "vm/builtin.h"
#include "vm/exceptions.h"
#include "vm/global.h"
+#include "vm/primitive.h"
#include "vm/stringlocal.h"
#include "vm/vm.h"
#include "vm/jit/abi.h"
#include "vm/jit/asmpart.h"
+#include "vm/jit/code.h"
#include "vm/jit/codegen-common.h"
#include "vm/jit/dseg.h"
#include "vm/jit/emit-common.h"
#include "vm/jit/jit.h"
+#include "vm/jit/linenumbertable.h"
#include "vm/jit/methodheader.h"
#include "vm/jit/parse.h"
#include "vm/jit/patcher-common.h"
#include "vm/jit/reg.h"
#include "vm/jit/replace.h"
#include "vm/jit/stacktrace.h"
+#include "vm/jit/trap.h"
#if defined(ENABLE_LSRA)
# include "vm/jit/allocator/lsra.h"
varinfo *var, *dst;
basicblock *bptr;
instruction *iptr;
- exception_entry *ex;
constant_classref *cr;
unresolved_class *uc;
methodinfo *lm; /* local methodinfo for ICMD_INVOKE* */
#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
native code e.g. libc or jni (alignment problems with
movaps). */
- if (!jd->isleafmethod || opt_verbosecall)
+ 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 */
-#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.
- */
-
- if (checksync && (m->flags & ACC_SYNCHRONIZED))
- (void) dseg_add_unique_s4(cd, (rd->memuse + 1) * 8); /* IsSync */
+ code->synchronizedoffset = rd->memuse * 8;
+
+ if (code_is_leafmethod(code))
+ (void) dseg_add_unique_s4(cd, 1); /* IsLeaf */
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); /* 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 */
- (void) 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);
- }
-
#if defined(ENABLE_PROFILING)
/* generate method profiling code */
/* save monitorenter argument */
#if defined(ENABLE_THREADS)
- if (checksync && (m->flags & ACC_SYNCHRONIZED)) {
+ if (checksync && code_is_synchronized(code)) {
/* stack offset for monitor argument */
s1 = rd->memuse;
/* decide which monitor enter function to call */
if (m->flags & ACC_STATIC) {
- M_MOV_IMM(&m->class->object.header, REG_A0);
+ M_MOV_IMM(&m->clazz->object.header, REG_A0);
}
else {
M_TEST(REG_A0);
M_BNE(8);
- M_ALD_MEM(REG_A0, EXCEPTION_HARDWARE_NULLPOINTER);
+ M_ALD_MEM(REG_A0, TRAP_NullPointerException);
}
M_AST(REG_A0, REG_SP, s1 * 8);
for (iptr = bptr->iinstr; len > 0; len--, iptr++) {
if (iptr->line != currentline) {
- dseg_addlinenumber(cd, iptr->line);
+ linenumbertable_list_entry_add(cd, iptr->line);
currentline = iptr->line;
}
case ICMD_INLINE_BODY:
REPLACEMENT_POINT_INLINE_BODY(cd, iptr);
- dseg_addlinenumber_inline_start(cd, iptr);
- dseg_addlinenumber(cd, iptr->line);
+ linenumbertable_list_entry_add_inline_start(cd, iptr);
+ linenumbertable_list_entry_add(cd, iptr->line);
break;
case ICMD_INLINE_END:
- dseg_addlinenumber_inline_end(cd, iptr);
- dseg_addlinenumber(cd, iptr->line);
+ linenumbertable_list_entry_add_inline_end(cd, iptr);
+ linenumbertable_list_entry_add(cd, iptr->line);
break;
case ICMD_CHECKNULL: /* ..., objectref ==> ..., objectref */
fieldtype = fi->type;
disp = dseg_add_address(cd, fi->value);
- if (!CLASS_IS_OR_ALMOST_INITIALIZED(fi->class)) {
+ if (!CLASS_IS_OR_ALMOST_INITIALIZED(fi->clazz)) {
PROFILE_CYCLE_STOP;
patcher_add_patch_ref(jd, PATCHER_initialize_class,
- fi->class, 0);
+ fi->clazz, 0);
PROFILE_CYCLE_START;
}
fieldtype = fi->type;
disp = dseg_add_address(cd, fi->value);
- if (!CLASS_IS_OR_ALMOST_INITIALIZED(fi->class)) {
+ if (!CLASS_IS_OR_ALMOST_INITIALIZED(fi->clazz)) {
PROFILE_CYCLE_STOP;
patcher_add_patch_ref(jd, PATCHER_initialize_class,
- fi->class, 0);
+ fi->clazz, 0);
PROFILE_CYCLE_START;
}
fieldtype = fi->type;
disp = dseg_add_address(cd, fi->value);
- if (!CLASS_IS_OR_ALMOST_INITIALIZED(fi->class)) {
+ if (!CLASS_IS_OR_ALMOST_INITIALIZED(fi->clazz)) {
PROFILE_CYCLE_STOP;
patcher_add_patch_ref(jd, PATCHER_initialize_class,
- fi->class, 0);
+ fi->clazz, 0);
PROFILE_CYCLE_START;
}
#endif /* !defined(NDEBUG) */
#if defined(ENABLE_THREADS)
- if (checksync && (m->flags & ACC_SYNCHRONIZED)) {
+ if (checksync && code_is_synchronized(code)) {
M_ALD(REG_A0, REG_SP, rd->memuse * 8);
/* we need to save the proper return value */
}
else {
s1 = OFFSET(vftbl_t, interfacetable[0]) -
- sizeof(methodptr) * lm->class->index;
+ sizeof(methodptr) * lm->clazz->index;
- s2 = sizeof(methodptr) * (lm - lm->class->methods);
+ s2 = sizeof(methodptr) * (lm - lm->clazz->methods);
}
/* implicit null-pointer check */
classinfo *super;
s4 superindex;
+ s4 looptarget;
+
if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
super = NULL;
superindex = 0;
superindex = super->index;
}
- if ((super == NULL) || !(super->flags & ACC_INTERFACE))
- CODEGEN_CRITICAL_SECTION_NEW;
-
s1 = emit_load_s1(jd, iptr, REG_ITMP1);
/* if class is not resolved, check which code to call */
M_ALD(REG_ITMP2, s1, OFFSET(java_object_t, vftbl));
M_ALD(REG_ITMP3, RIP, disp);
- CODEGEN_CRITICAL_SECTION_START;
+ if (super == NULL || super->vftbl->subtype_depth >= DISPLAY_SIZE) {
+ M_AADD_IMM(-32, REG_SP); /* need some stack */
+ if (s1 == REG_ITMP1)
+ M_AST(REG_ITMP1, REG_SP, -8 + 32);
- M_ILD(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, baseval));
+ M_ALD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_offset));
- /* if (s1 != REG_ITMP1) { */
- /* emit_movl_membase_reg(cd, REG_ITMP3, */
- /* OFFSET(vftbl_t, baseval), */
- /* REG_ITMP1); */
- /* emit_movl_membase_reg(cd, REG_ITMP3, */
- /* OFFSET(vftbl_t, diffval), */
- /* REG_ITMP3); */
- /* #if defined(ENABLE_THREADS) */
- /* codegen_threadcritstop(cd, cd->mcodeptr - cd->mcodebase); */
- /* #endif */
- /* emit_alu_reg_reg(cd, ALU_SUB, REG_ITMP1, REG_ITMP2); */
+ *(cd->mcodeptr++) = 0x4d;
+ *(cd->mcodeptr++) = 0x3b;
+ *(cd->mcodeptr++) = 0x1c;
+ *(cd->mcodeptr++) = 0x02;
+ /* cmp (ITMP2, ITMP1, 1), ITMP3 */
- /* } else { */
+ emit_label_beq(cd, BRANCH_LABEL_6); /* good */
- M_ILD(REG_ITMP3, REG_ITMP3, OFFSET(vftbl_t, baseval));
- M_ISUB(REG_ITMP3, REG_ITMP2);
- M_ALD(REG_ITMP3, RIP, disp);
- M_ILD(REG_ITMP3, REG_ITMP3, OFFSET(vftbl_t, diffval));
- /* } */
+ M_LCMP_IMM(OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE]), REG_ITMP1);
+ emit_classcast_check(cd, iptr, BRANCH_NE, REG_ITMP3, s1);
+
+ M_AST(REG_ITMP3, REG_SP, -16 + 32);
+ M_AST_IMM32(0, REG_SP, -24 + 32);
+ M_ALD(REG_ITMP1, REG_ITMP2, OFFSET(vftbl_t, subtype_overflow));
+ looptarget = cd->mcodeptr - cd->mcodebase;
+
+ M_ALD(REG_ITMP3, REG_SP, -24 + 32);
+ M_ICMP_MEMBASE(REG_ITMP2, OFFSET(vftbl_t, subtype_overflow_length), REG_ITMP3);
+ emit_label_bge(cd, BRANCH_LABEL_9); /* throw */
+
+ *(cd->mcodeptr++) = 0x4e;
+ *(cd->mcodeptr++) = 0x8b;
+ *(cd->mcodeptr++) = 0x1c;
+ *(cd->mcodeptr++) = 0xd8;
+ /* movq (ITMP1, ITMP3, 8), ITMP3 */
+
+ M_LCMP_MEMBASE(REG_SP, -16 + 32, REG_ITMP3);
+ emit_label_beq(cd, BRANCH_LABEL_7); /* good */
+
+ M_LINC_MEMBASE(REG_SP, -24 + 32);
+ M_JMP_IMM2(looptarget - (cd->mcodeptr - cd->mcodebase) - 2); /* 1 byte displacement */
- CODEGEN_CRITICAL_SECTION_END;
+ emit_label(cd, BRANCH_LABEL_9);
+ M_AADD_IMM(32, REG_SP); /* restore stack frame */
+ M_ALD_MEM(REG_ITMP3, TRAP_ClassCastException);
- M_ICMP(REG_ITMP3, REG_ITMP2);
- emit_classcast_check(cd, iptr, BRANCH_UGT, REG_ITMP3, s1);
+ emit_label(cd, BRANCH_LABEL_7);
+
+ emit_label(cd, BRANCH_LABEL_6);
+
+ if (s1 == REG_ITMP1)
+ M_ALD(REG_ITMP1, REG_SP, -8 + 32);
+ M_AADD_IMM(32, REG_SP);
+ }
+ else {
+ assert(super->vftbl->subtype_offset < 0x80);
+ *(cd->mcodeptr++) = 0x4d;
+ *(cd->mcodeptr++) = 0x3b;
+ *(cd->mcodeptr++) = 0x5a;
+ *(cd->mcodeptr++) = super->vftbl->subtype_offset;
+ /* cmp off(ITMP1), ITMP2 */
+
+ emit_classcast_check(cd, iptr, BRANCH_NE, REG_ITMP3, s1);
+ }
if (super != NULL)
emit_label(cd, BRANCH_LABEL_5);
classinfo *super;
s4 superindex;
+ s4 looptarget;
+
if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
super = NULL;
superindex = 0;
superindex = super->index;
}
- 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);
disp = dseg_add_address(cd, super->vftbl);
}
- M_ALD(REG_ITMP1, s1, OFFSET(java_object_t, vftbl));
- M_ALD(REG_ITMP2, RIP, disp);
-
- CODEGEN_CRITICAL_SECTION_START;
-
- M_ILD(REG_ITMP1, REG_ITMP1, OFFSET(vftbl_t, baseval));
- M_ILD(REG_ITMP3, REG_ITMP2, OFFSET(vftbl_t, diffval));
- M_ILD(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, baseval));
-
- CODEGEN_CRITICAL_SECTION_END;
+ M_ALD(REG_ITMP2, s1, OFFSET(java_object_t, vftbl));
+ M_ALD(REG_ITMP3, RIP, disp);
+
+ if (super == NULL || super->vftbl->subtype_depth >= DISPLAY_SIZE) {
+ M_AADD_IMM(-32, REG_SP); /* need some stack */
+ M_ALD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_offset));
+
+ *(cd->mcodeptr++) = 0x4d;
+ *(cd->mcodeptr++) = 0x3b;
+ *(cd->mcodeptr++) = 0x1c;
+ *(cd->mcodeptr++) = 0x02;
+ /* cmp (ITMP2, ITMP1, 1), ITMP3 */
+
+ emit_label_bne(cd, BRANCH_LABEL_6);
+ if (d == REG_ITMP2) {
+ M_SETE(d);
+ M_BSEXT(d, d);
+ } else
+ M_LINC(d);
+ emit_label_br(cd, BRANCH_LABEL_7); /* done, true */
+
+ emit_label(cd, BRANCH_LABEL_6);
+
+ M_LCMP_IMM(OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE]), REG_ITMP1);
+ emit_label_bne(cd, BRANCH_LABEL_6); /* done, false */
+
+ M_AST(REG_ITMP3, REG_SP, -16 + 32);
+ M_AST_IMM32(0, REG_SP, -24 + 32);
+ M_ALD(REG_ITMP1, REG_ITMP2, OFFSET(vftbl_t, subtype_overflow));
+ looptarget = cd->mcodeptr - cd->mcodebase;
+
+ M_ALD(REG_ITMP3, REG_SP, -24 + 32);
+ M_ICMP_MEMBASE(REG_ITMP2, OFFSET(vftbl_t, subtype_overflow_length), REG_ITMP3);
+ emit_label_bge(cd, BRANCH_LABEL_8); /* done, false */
+
+ *(cd->mcodeptr++) = 0x4e;
+ *(cd->mcodeptr++) = 0x8b;
+ *(cd->mcodeptr++) = 0x1c;
+ *(cd->mcodeptr++) = 0xd8;
+ /* movq (ITMP1, ITMP3, 8), ITMP3 */
+
+ M_LCMP_MEMBASE(REG_SP, -16 + 32, REG_ITMP3);
+ emit_label_bne(cd, BRANCH_LABEL_9);
+ if (d == REG_ITMP2) {
+ M_SETE(d);
+ M_BSEXT(d, d);
+ } else
+ M_LINC(d);
+ emit_label_br(cd, BRANCH_LABEL_10); /* done, true */
+ emit_label(cd, BRANCH_LABEL_9);
+
+ M_LINC_MEMBASE(REG_SP, -24 + 32);
+ M_JMP_IMM2(looptarget - (cd->mcodeptr - cd->mcodebase) - 2); /* 1 byte displacement */
+
+ emit_label(cd, BRANCH_LABEL_8);
+ emit_label(cd, BRANCH_LABEL_6);
+
+ if (d == REG_ITMP2)
+ M_CLR(d);
- M_ISUB(REG_ITMP2, REG_ITMP1);
- M_CLR(d); /* may be REG_ITMP2 */
- M_ICMP(REG_ITMP3, REG_ITMP1);
- M_SETULE(d);
+ emit_label(cd, BRANCH_LABEL_10);
+ emit_label(cd, BRANCH_LABEL_7);
+ M_AADD_IMM(32, REG_SP);
+ }
+ else {
+ assert(super->vftbl->subtype_offset < 0x80);
+ *(cd->mcodeptr++) = 0x4d;
+ *(cd->mcodeptr++) = 0x3b;
+ *(cd->mcodeptr++) = 0x5a;
+ *(cd->mcodeptr++) = super->vftbl->subtype_offset;
+ /* cmp off(ITMP1), ITMP2 */
+
+ M_SETE(d);
+ if (d == REG_ITMP2)
+ M_BSEXT(d, d);
+ }
if (super != NULL)
emit_label(cd, BRANCH_LABEL_5);
} /* if (bptr -> flags >= BBREACHED) */
} /* for basic block */
- dseg_createlinenumbertable(cd);
-
/* Generate patcher traps. */
emit_patcher_traps(jd);
}
-/* codegen_emit_stub_compiler **************************************************
-
- Emit a stub routine which calls the compiler.
-
-*******************************************************************************/
-
-void codegen_emit_stub_compiler(jitdata *jd)
-{
- methodinfo *m;
- codegendata *cd;
-
- /* get required compiler data */
-
- m = jd->m;
- cd = jd->cd;
-
- /* code for the stub */
-
- M_LLD(REG_ITMP1, RIP, -(7 * 1 + 2 * SIZEOF_VOID_P)); /* methodinfo */
-/* M_ALD(REG_ITMP1, RIP, -(2 * SIZEOF_VOID_P)); /\* methodinfo *\/ */
- M_LLD(REG_ITMP3, RIP, -(7 * 2 + 3 * SIZEOF_VOID_P)); /* compiler pointer */
-/* M_ALD(REG_ITMP3, RIP, -(3 * SIZEOF_VOID_P)); /\* compiler pointer *\/ */
- M_JMP(REG_ITMP3);
-}
-
-
/* codegen_emit_stub_native ****************************************************
Emits a stub routine which calls a native method.
methoddesc *md;
int i, j;
int s1, s2;
- int funcdisp;
-#if defined(ENABLE_GC_CACAO)
int disp;
-#endif
- /* get required compiler data */
+ /* Sanity check. */
+
+ assert(f != NULL);
+
+ /* Get required compiler data. */
m = jd->m;
code = jd->code;
/* calculate stack frame size */
cd->stackframesize =
- sizeof(stackframeinfo) / SIZEOF_VOID_P +
+ sizeof(stackframeinfo_t) / SIZEOF_VOID_P +
sizeof(localref_table) / SIZEOF_VOID_P +
md->paramcount +
+ (md->returntype.type == TYPE_VOID ? 0 : 1) +
nmd->memuse;
ALIGN_ODD(cd->stackframesize); /* keep stack 16-byte aligned */
(void) dseg_add_unique_address(cd, code); /* CodeinfoPointer */
(void) dseg_add_unique_s4(cd, cd->stackframesize * 8); /* 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 */
#if defined(ENABLE_PROFILING)
/* generate native method profiling code */
M_ASUB_IMM(cd->stackframesize * 8, REG_SP);
- /* get function address (this must happen before the stackframeinfo) */
-
- funcdisp = dseg_add_functionptr(cd, f);
-
- if (f == NULL)
- patcher_add_patch_ref(jd, PATCHER_resolve_native_function, m, funcdisp);
-
#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) +
- OFFSET(stackframeinfo, intregs);
+ disp = cd->stackframesize * 8 - sizeof(stackframeinfo_t) +
+ OFFSET(stackframeinfo_t, intregs);
for (i = 0; i < INT_SAV_CNT; i++)
M_AST(abi_registers_integer_saved[i], REG_SP, disp + i * 8);
M_MOV_IMM(_Jv_env, REG_A0);
}
- /* do the native function call */
+ /* Call the native function. */
- M_ALD(REG_ITMP1, RIP, funcdisp);
+ disp = dseg_add_functionptr(cd, f);
+ M_ALD(REG_ITMP1, RIP, disp);
M_CALL(REG_ITMP1);
/* save return value */
case TYPE_INT:
case TYPE_LNG:
case TYPE_ADR:
+ switch (md->returntype.decltype) {
+ case PRIMITIVETYPE_BOOLEAN:
+ M_BZEXT(REG_RESULT, REG_RESULT);
+ break;
+ case PRIMITIVETYPE_BYTE:
+ M_BSEXT(REG_RESULT, REG_RESULT);
+ break;
+ case PRIMITIVETYPE_CHAR:
+ M_CZEXT(REG_RESULT, REG_RESULT);
+ break;
+ case PRIMITIVETYPE_SHORT:
+ M_SSEXT(REG_RESULT, REG_RESULT);
+ break;
+ }
M_LST(REG_RESULT, REG_SP, 0 * 8);
break;
case TYPE_FLT:
/* Restore callee saved integer registers from stackframeinfo (GC
might have modified them during a collection). */
- disp = cd->stackframesize * 8 - sizeof(stackframeinfo) +
- OFFSET(stackframeinfo, intregs);
+ disp = cd->stackframesize * 8 - sizeof(stackframeinfo_t) +
+ OFFSET(stackframeinfo_t, intregs);
for (i = 0; i < INT_SAV_CNT; i++)
M_ALD(abi_registers_integer_saved[i], REG_SP, disp + i * 8);
M_MOV_IMM(asm_handle_nat_exception, REG_ITMP3);
M_JMP(REG_ITMP3);
-
- /* Generate patcher traps. */
-
- emit_patcher_traps(jd);
}