/* src/vm/jit/arm/codegen.c - machine code generator for Arm
- 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
+ Copyright (C) 1996-2005, 2006, 2007, 2008
+ CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
This file is part of CACAO.
#include "vm/jit/arm/arch.h"
#include "vm/jit/arm/codegen.h"
-#include "mm/memory.h"
+#include "mm/memory.hpp"
-#include "native/localref.h"
-#include "native/native.h"
+#include "native/localref.hpp"
+#include "native/native.hpp"
-#include "threads/lock-common.h"
+#include "threads/lock.hpp"
-#include "vm/builtin.h"
-#include "vm/exceptions.h"
+#include "vm/jit/builtin.hpp"
+#include "vm/exceptions.hpp"
#include "vm/global.h"
-#include "vm/vm.h"
+#include "vm/loader.hpp"
+#include "vm/options.h"
+#include "vm/vm.hpp"
#include "vm/jit/abi.h"
#include "vm/jit/asmpart.h"
-#include "vm/jit/codegen-common.h"
+#include "vm/jit/codegen-common.hpp"
#include "vm/jit/dseg.h"
-#include "vm/jit/emit-common.h"
-#include "vm/jit/jit.h"
-#include "vm/jit/md.h"
+#include "vm/jit/emit-common.hpp"
+#include "vm/jit/jit.hpp"
+#include "vm/jit/linenumbertable.hpp"
#include "vm/jit/methodheader.h"
-#include "vm/jit/parse.h"
-#include "vm/jit/patcher-common.h"
+#include "vm/jit/parse.hpp"
+#include "vm/jit/patcher-common.hpp"
#include "vm/jit/reg.h"
#if defined(ENABLE_LSRA)
#include "vm/jit/allocator/lsra.h"
#endif
-#include "vmcore/loader.h"
-#include "vmcore/options.h"
-
/* codegen_emit ****************************************************************
(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);
-
/* save return address and used callee saved registers */
savedregs_bitmask = 0;
/* get the correct lock object */
if (m->flags & ACC_STATIC) {
- disp = dseg_add_address(cd, &m->class->object.header);
+ disp = dseg_add_address(cd, &m->clazz->object.header);
M_DSEG_LOAD(REG_A0, disp);
}
else {
/* add line number */
if (iptr->line != currentline) {
- dseg_addlinenumber(cd, iptr->line);
+ linenumbertable_list_entry_add(cd, iptr->line);
currentline = iptr->line;
}
MCODECHECK(64); /* an instruction usually needs < 64 words */
- /* the big switch */
- switch (iptr->opc) {
- case ICMD_NOP: /* ... ==> ... */
+ /* the big switch */
+ switch (iptr->opc) {
+
+ case ICMD_NOP: /* ... ==> ... */
+ case ICMD_POP: /* ..., value ==> ... */
+ case ICMD_POP2: /* ..., value, value ==> ... */
break;
- /* constant operations ************************************************/
+ /* constant operations ************************************************/
case ICMD_ICONST: /* ... ==> ..., constant */
break;
case ICMD_ASTORE:
+
if (!(iptr->flags.bits & INS_FLAG_RETADDR))
emit_copy(jd, iptr);
break;
- /* pop operations *****************************************************/
-
- /* attention: double and longs are only one entry in CACAO ICMDs */
-
- case ICMD_POP: /* ..., value ==> ... */
- case ICMD_POP2: /* ..., value, value ==> ... */
-
- break;
-
/* integer operations *************************************************/
s1 = emit_load_s1(jd, iptr, REG_ITMP1);
d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+#if defined(__VFP_FP__)
+ M_FMSR(s1, d);
+ M_CVTIF(d, d);
+#else
M_CVTIF(s1, d);
+#endif
emit_store_dst(jd, iptr, d);
break;
s1 = emit_load_s1(jd, iptr, REG_ITMP1);
d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
+#if defined(__VFP_FP__)
+ M_FMSR(s1, d);
+ M_CVTID(d, d);
+#else
M_CVTID(s1, d);
+#endif
emit_store_dst(jd, iptr, d);
break;
s1 = emit_load_s1(jd, iptr, REG_FTMP1);
d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+#if defined(__VFP_FP__)
+ M_CVTFI(s1, REG_FTMP2);
+ M_FMRS(REG_FTMP2, d);
+#else
/* this uses round towards zero, as Java likes it */
M_CVTFI(s1, d);
-#if !defined(__VFP_FP__)
/* this checks for NaN; to return zero as Java likes it */
M_FCMP(s1, 0x8);
M_MOVVS_IMM(0, d);
s1 = emit_load_s1(jd, iptr, REG_FTMP1);
d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
+#if defined(__VFP_FP__)
+ M_CVTDI(s1, REG_FTMP2);
+ M_FMRS(REG_FTMP2, d);
+#else
/* this uses round towards zero, as Java likes it */
M_CVTDI(s1, d);
-#if !defined(__VFP_FP__)
/* this checks for NaN; to return zero as Java likes it */
M_DCMP(s1, 0x8);
M_MOVVS_IMM(0, d);
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)) {
patcher_add_patch_ref(jd, PATCHER_initialize_class,
- fi->class, 0);
+ fi->clazz, 0);
}
}
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)) {
patcher_add_patch_ref(jd, PATCHER_initialize_class,
- fi->class, 0);
+ fi->clazz, 0);
}
}
case ICMD_INVOKEVIRTUAL:
if (lm == NULL) {
- patcher_add_patch_ref(jd, PATCHER_invokevirtual, um, 0);
+ int32_t disp = dseg_add_unique_s4(cd, 0);
+ patcher_add_patch_ref(jd, PATCHER_invokevirtual, um, disp);
- s1 = 0;
- }
- else
- s1 = OFFSET(vftbl_t, table[0]) +
- sizeof(methodptr) * lm->vftblindex;
+ // The following instruction MUST NOT change a0 because of the implicit NPE check.
+ M_LDR_INTERN(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl));
- /* implicit null-pointer check */
- M_LDR_INTERN(REG_METHODPTR, REG_A0,
- OFFSET(java_object_t, vftbl));
- M_LDR_INTERN(REG_PV, REG_METHODPTR, s1);
+ // Sanity check.
+ assert(REG_ITMP1 != REG_METHODPTR);
+ assert(REG_ITMP2 == REG_METHODPTR);
- /* generate the actual call */
+ M_DSEG_LOAD(REG_ITMP1, disp);
+ M_ADD(REG_METHODPTR, REG_METHODPTR, REG_ITMP1);
+
+ // This must be a load with displacement,
+ // otherwise the JIT method address patching does
+ // not work anymore (see md_jit_method_patch_address).
+ M_LDR_INTERN(REG_PV, REG_METHODPTR, 0);
+ }
+ else {
+ s1 = OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * lm->vftblindex;
+ // The following instruction MUST NOT change a0 because of the implicit NPE check.
+ M_LDR_INTERN(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl));
+ M_LDR(REG_PV, REG_METHODPTR, s1);
+ }
+
+ // Generate the actual call.
M_MOV(REG_LR, REG_PC);
M_MOV(REG_PC, REG_PV);
s1 = (s4) (cd->mcodeptr - cd->mcodebase);
case ICMD_INVOKEINTERFACE:
if (lm == NULL) {
- patcher_add_patch_ref(jd, PATCHER_invokeinterface, um, 0);
+ int32_t disp = dseg_add_unique_s4(cd, 0);
+ int32_t disp2 = dseg_add_unique_s4(cd, 0);
- s1 = 0;
- s2 = 0;
+ // XXX We need two displacements.
+ assert(disp2 == disp - 4);
+ patcher_add_patch_ref(jd, PATCHER_invokeinterface, um, disp);
+
+ // The following instruction MUST NOT change a0 because of the implicit NPE check.
+ M_LDR_INTERN(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl));
+
+ // Sanity check.
+ assert(REG_ITMP1 != REG_METHODPTR);
+ assert(REG_ITMP2 == REG_METHODPTR);
+ assert(REG_ITMP3 != REG_METHODPTR);
+
+ M_DSEG_LOAD(REG_ITMP1, disp);
+ M_LDR_REG(REG_METHODPTR, REG_METHODPTR, REG_ITMP1);
+
+ M_DSEG_LOAD(REG_ITMP3, disp2);
+ M_ADD(REG_METHODPTR, REG_METHODPTR, REG_ITMP3);
+
+ // This must be a load with displacement,
+ // otherwise the JIT method address patching does
+ // not work anymore (see md_jit_method_patch_address).
+ M_LDR_INTERN(REG_PV, REG_METHODPTR, 0);
}
else {
- s1 = OFFSET(vftbl_t, interfacetable[0]) -
- sizeof(methodptr*) * lm->class->index;
- s2 = sizeof(methodptr) * (lm - lm->class->methods);
- }
+ s1 = OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr*) * lm->clazz->index;
+ s2 = sizeof(methodptr) * (lm - lm->clazz->methods);
- /* implicit null-pointer check */
- M_LDR_INTERN(REG_METHODPTR, REG_A0,
- OFFSET(java_object_t, vftbl));
- M_LDR_INTERN(REG_METHODPTR, REG_METHODPTR, s1);
- M_LDR_INTERN(REG_PV, REG_METHODPTR, s2);
-
- /* generate the actual call */
+ // The following instruction MUST NOT change a0 because of the implicit NPE check.
+ M_LDR_INTERN(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl));
+ M_LDR(REG_METHODPTR, REG_METHODPTR, s1);
+ M_LDR(REG_PV, REG_METHODPTR, s2);
+ }
+ // Generate the actual call.
M_MOV(REG_LR, REG_PC);
M_MOV(REG_PC, REG_PV);
s1 = (s4) (cd->mcodeptr - cd->mcodebase);
our ENABLE_SOFTFLOAT define */
if (iptr->opc == ICMD_BUILTIN && d != TYPE_VOID && IS_FLT_DBL_TYPE(d)) {
#if 0 && !defined(NDEBUG)
- dolog("BUILTIN that returns float or double (%s.%s)", m->class->name->text, m->name->text);
+ dolog("BUILTIN that returns float or double (%s.%s)", m->clazz->name->text, m->name->text);
#endif
/* we cannot use this macro, since it is not defined
in ENABLE_SOFTFLOAT M_CAST_FLT_TO_INT_TYPED(d,
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_LDR_INTERN(REG_ITMP2, s1, OFFSET(java_object_t, vftbl));
M_DSEG_LOAD(REG_ITMP3, disp);
- CODEGEN_CRITICAL_SECTION_START;
-
M_LDR_INTERN(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, baseval));
M_LDR_INTERN(REG_ITMP3, REG_ITMP3, OFFSET(vftbl_t, baseval));
M_SUB(REG_ITMP2, REG_ITMP2, REG_ITMP3);
M_DSEG_LOAD(REG_ITMP3, disp);
M_LDR_INTERN(REG_ITMP3, REG_ITMP3, OFFSET(vftbl_t, diffval));
- CODEGEN_CRITICAL_SECTION_END;
-
M_CMP(REG_ITMP2, REG_ITMP3);
emit_classcast_check(cd, iptr, BRANCH_UGT, 0, s1);
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);
M_LDR_INTERN(REG_ITMP1, s1, OFFSET(java_object_t, vftbl));
M_DSEG_LOAD(REG_ITMP2, disp);
- CODEGEN_CRITICAL_SECTION_START;
-
M_LDR_INTERN(REG_ITMP1, REG_ITMP1, OFFSET(vftbl_t, baseval));
M_LDR_INTERN(REG_ITMP3, REG_ITMP2, OFFSET(vftbl_t, baseval));
M_LDR_INTERN(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, diffval));
- CODEGEN_CRITICAL_SECTION_END;
-
M_SUB(REG_ITMP1, REG_ITMP1, REG_ITMP3);
M_CMP(REG_ITMP1, REG_ITMP2);
/* If d == REG_ITMP2, then it's destroyed */
} /* for all basic blocks */
- dseg_createlinenumbertable(cd);
-
-
/* generate traps */
emit_patcher_traps(jd);
}
-/* codegen_emit_stub_compiler **************************************************
-
- Emits 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_LDR_INTERN(REG_ITMP1, REG_PC, -(2 * 4 + 2 * SIZEOF_VOID_P));
- M_LDR_INTERN(REG_PC, REG_PC, -(3 * 4 + 3 * SIZEOF_VOID_P));
-}
-
-
/* codegen_emit_stub_native ****************************************************
Emits a stub routine which calls a native method.
(void) dseg_add_unique_address(cd, code); /* CodeinfoPointer */
(void) dseg_add_unique_s4(cd, cd->stackframesize); /* 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 */
/* put env into first argument register */
- disp = dseg_add_address(cd, _Jv_env);
+ disp = dseg_add_address(cd, VM_get_jnienv());
M_DSEG_LOAD(REG_A0, disp);
}
/* this depends on gcc; it is independent from our ENABLE_SOFTFLOAT define */
if (md->returntype.type != TYPE_VOID && IS_FLT_DBL_TYPE(md->returntype.type)) {
#if 0 && !defined(NDEBUG)
- dolog("NATIVESTUB that returns float or double (%s.%s)", m->class->name->text, m->name->text);
+ dolog("NATIVESTUB that returns float or double (%s.%s)", m->clazz->name->text, m->name->text);
#endif
/* we cannot use this macro, since it is not defined in ENABLE_SOFTFLOAT */
/* M_CAST_FLT_TO_INT_TYPED(md->returntype.type, REG_FRESULT, REG_RESULT_TYPED(md->returntype.type)); */
disp = dseg_add_functionptr(cd, asm_handle_nat_exception);
M_DSEG_LOAD(REG_ITMP3, disp); /* load asm exception handler address */
M_MOV(REG_PC, REG_ITMP3); /* jump to asm exception handler */
-
- /* generate patcher stubs */
-
- emit_patcher_traps(jd);
}