/* src/vm/jit/patcher-common.cpp - architecture independent code patching stuff
- Copyright (C) 2007, 2008, 2009
+ Copyright (C) 1996-2011
CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
Copyright (C) 2008 Theobroma Systems Ltd.
// Set patcher information (mpc is resolved later).
patchref_t pr;
- pr.mpc = patchmpc;
- pr.datap = 0;
- pr.disp = disp;
- pr.disp_mb = 0;
- pr.patcher = patcher;
- pr.ref = ref;
- pr.mcode = 0;
- pr.done = false;
+ pr.mpc = patchmpc;
+ pr.datap = 0;
+ pr.disp = disp;
+ pr.disp_mb = 0;
+ pr.patch_align = 0;
+ pr.patcher = patcher;
+ pr.ref = ref;
+ pr.mcode = 0;
+ pr.done = false;
// Store patcher in the list (NOTE: structure is copied).
code->patchers->push_back(pr);
/* src/vm/jit/patcher-common.hpp - architecture independent code patching stuff
- Copyright (C) 2007, 2008, 2009
+ Copyright (C) 1996-2011
CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
This file is part of CACAO.
uintptr_t mpc; /* absolute position in code segment */
uintptr_t datap; /* absolute position in data segment */
int32_t disp; /* displacement of ref in the data segment */
- int32_t disp_mb; /* auxiliary code displacement (for membar) */
+ int16_t disp_mb; /* auxiliary code displacement (for membar) */
+ int16_t patch_align; /* auxiliary displacement for alignment */
functionptr patcher; /* patcher function to call */
void* ref; /* reference passed */
uint32_t mcode; /* machine code to be patched back in */
/* src/vm/jit/x86_64/codegen.c - machine code generator for x86_64
- Copyright (C) 1996-2005, 2006, 2007, 2008, 2009, 2010
+ Copyright (C) 1996-2011
CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
This file is part of CACAO.
M_MFENCE;
}
+/**
+ * Ensures that the patched location (an int32_t) is aligned.
+ */
+static void codegen_fixup_alignment(codegendata *cd, patchref_t *pr, u1 *mcodeptr_save)
+{
+ u1 *codeptr = cd->mcodeptr;
+ int disp = PATCH_ALIGNMENT((uintptr_t) cd->mcodeptr, 0, sizeof(int32_t));
+ memmove(mcodeptr_save + disp, mcodeptr_save, cd->mcodeptr - mcodeptr_save);
+ pr->patch_align += cd->mcodeptr - mcodeptr_save + disp;
+
+ cd->mcodeptr = mcodeptr_save;
+ emit_arbitrary_nop(cd, disp);
+ cd->mcodeptr = codeptr + disp;
+}
+
/**
* Generates machine code for one ICMD.
*/
int32_t fieldtype;
int32_t s1, s2, s3, d;
int32_t disp;
+ u1* mcodeptr_save;
// Get required compiler data.
codegendata* cd = jd->cd;
/* PROFILE_CYCLE_STOP; */
- patcher_add_patch_ref(jd, PATCHER_get_putfield, uf, 0);
+ pr = patcher_add_patch_ref(jd, PATCHER_get_putfield, uf, 0);
+ mcodeptr_save = cd->mcodeptr;
/* PROFILE_CYCLE_START; */
fi = iptr->sx.s23.s3.fmiref->p.field;
fieldtype = fi->type;
disp = fi->offset;
+
+ pr = 0;
}
/* implicit null-pointer check */
// Silence compiler warning.
d = 0;
}
+ if (pr)
+ codegen_fixup_alignment(cd, pr, mcodeptr_save);
emit_store_dst(jd, iptr, d);
break;
/* PROFILE_CYCLE_STOP; */
pr = patcher_add_patch_ref(jd, PATCHER_get_putfield, uf, 0);
+ mcodeptr_save = cd->mcodeptr;
/* PROFILE_CYCLE_START; */
M_DST32(s2, s1, disp);
break;
}
+ if (pr)
+ codegen_fixup_alignment(cd, pr, mcodeptr_save);
codegen_emit_patchable_barrier(iptr, cd, pr, fi);
break;
/* PROFILE_CYCLE_STOP; */
pr = patcher_add_patch_ref(jd, PATCHER_putfieldconst, uf, 0);
+ mcodeptr_save = cd->mcodeptr;
/* PROFILE_CYCLE_START; */
M_MOV_IMM(iptr->sx.s23.s2.constval, REG_ITMP2);
if (disp) /* resolved, disp can never be 0 */
M_LST(REG_ITMP2, s1, disp);
- else /* unresolved */
+ else { /* unresolved */
M_LST32(REG_ITMP2, s1, disp);
+ pr->patch_align = 4;
+ }
break;
}
+ if (pr)
+ codegen_fixup_alignment(cd, pr, mcodeptr_save);
codegen_emit_patchable_barrier(iptr, cd, pr, fi);
break;
if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
um = iptr->sx.s23.s3.um;
patcher_add_patch_ref(jd, PATCHER_invokevirtual, um, 0);
+ emit_arbitrary_nop(cd, PATCH_ALIGNMENT((uintptr_t) cd->mcodeptr, 6, sizeof(int32_t)));
s1 = 0;
}
if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
um = iptr->sx.s23.s3.um;
patcher_add_patch_ref(jd, PATCHER_invokeinterface, um, 0);
+ emit_arbitrary_nop(cd, PATCH_ALIGNMENT((uintptr_t) cd->mcodeptr, 6, sizeof(int32_t)));
s1 = 0;
s2 = 0;
/* implicit null-pointer check */
M_ALD(REG_METHODPTR, REG_A0, OFFSET(java_object_t, vftbl));
M_ALD32(REG_METHODPTR, REG_METHODPTR, s1);
+ if (INSTRUCTION_IS_UNRESOLVED(iptr))
+ emit_arbitrary_nop(cd, PATCH_ALIGNMENT((uintptr_t) cd->mcodeptr, 3, sizeof(int32_t)));
M_ALD32(REG_ITMP3, REG_METHODPTR, s2);
M_CALL(REG_ITMP3);
break;
patcher_add_patch_ref(jd, PATCHER_resolve_classref_to_flags,
iptr->sx.s23.s3.c.ref, 0);
+ emit_arbitrary_nop(cd, PATCH_ALIGNMENT((uintptr_t) cd->mcodeptr, 2, sizeof(int32_t)));
+
M_IMOV_IMM(0, REG_ITMP2); /* super->flags */
M_IAND_IMM(ACC_INTERFACE, REG_ITMP2);
emit_label_beq(cd, BRANCH_LABEL_2);
patcher_add_patch_ref(jd, PATCHER_checkcast_interface,
iptr->sx.s23.s3.c.ref,
0);
+ emit_arbitrary_nop(cd, PATCH_ALIGNMENT((uintptr_t) cd->mcodeptr, 10, sizeof(int32_t)));
}
M_ILD32(REG_ITMP3,
M_ICMP_IMM32(superindex, REG_ITMP3);
emit_classcast_check(cd, iptr, BRANCH_LE, REG_ITMP3, s1);
+ if (super == NULL)
+ emit_arbitrary_nop(cd, PATCH_ALIGNMENT((uintptr_t) cd->mcodeptr, 3, sizeof(int32_t)));
M_ALD32(REG_ITMP3, REG_ITMP2,
OFFSET(vftbl_t, interfacetable[0]) -
superindex * sizeof(methodptr*));
patcher_add_patch_ref(jd, PATCHER_resolve_classref_to_flags,
iptr->sx.s23.s3.c.ref, 0);
+ emit_arbitrary_nop(cd, PATCH_ALIGNMENT((uintptr_t) cd->mcodeptr, 2, sizeof(int32_t)));
+
M_IMOV_IMM(0, REG_ITMP3); /* super->flags */
M_IAND_IMM(ACC_INTERFACE, REG_ITMP3);
emit_label_beq(cd, BRANCH_LABEL_2);
/* interface instanceof code */
if ((super == NULL) || (super->flags & ACC_INTERFACE)) {
+ int nops;
if (super != NULL) {
M_TEST(s1);
emit_label_beq(cd, BRANCH_LABEL_3);
if (super == NULL) {
patcher_add_patch_ref(jd, PATCHER_instanceof_interface,
iptr->sx.s23.s3.c.ref, 0);
+ emit_arbitrary_nop(cd, PATCH_ALIGNMENT((uintptr_t) cd->mcodeptr, 10, sizeof(int32_t)));
}
M_ILD32(REG_ITMP3,
REG_ITMP1, OFFSET(vftbl_t, interfacetablelength));
M_ICMP_IMM32(superindex, REG_ITMP3);
- int a = 3 + 4 /* mov_membase32_reg */ + 3 /* test */ + 4 /* setcc */;
+ nops = super == NULL ? PATCH_ALIGNMENT((uintptr_t) (cd->mcodeptr + 6), 3, sizeof(int32_t)) : 0;
+
+ int a = 3 + 4 /* mov_membase32_reg */ + 3 /* test */ + 4 /* setcc */ + nops;
M_BLE(a);
+ emit_arbitrary_nop(cd, nops);
M_ALD32(REG_ITMP1, REG_ITMP1,
OFFSET(vftbl_t, interfacetable[0]) -
superindex * sizeof(methodptr*));
/* src/vm/jit/x86_64/codegen.h - code generation macros for x86_64
- Copyright (C) 1996-2005, 2006, 2007, 2008, 2009
+ Copyright (C) 1996-2011
CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
This file is part of CACAO.
} while (0)
+#define PATCH_ALIGNMENT(addr, offset, size) \
+ ((((addr)+(offset)+(size)-1) & ~((size)-1)) - ((addr)+(offset)))
+
+
#define ICONST(r,c) \
do { \
if ((c) == 0) \
/* src/vm/jit/x86_64/emit.c - x86_64 code emitter functions
- Copyright (C) 1996-2005, 2006, 2007, 2008, 2009
+ Copyright (C) 1996-2011
CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
This file is part of CACAO.
break;
}
}
+
+void emit_arbitrary_nop(codegendata *cd, int disp)
+{
+ while (disp) {
+ int x = disp < 9 ? disp : 9;
+ emit_nop(cd, x);
+ disp -= x;
+ }
+}
void emit_mov_reg_reg(codegendata *cd, s8 reg, s8 dreg)
{
/* src/vm/jit/x86_64/emit.h - machine dependent emit function prototypes
- Copyright (C) 1996-2005, 2006, 2007, 2008, 2009
+ Copyright (C) 1996-2011
CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
This file is part of CACAO.
*/
static inline void emit_recompute_pv(codegendata* cd) {}
+void emit_arbitrary_nop(codegendata *cd, int disp);
#ifdef __cplusplus
}
/* src/vm/jit/x86_64/patcher.c - x86_64 code patching functions
- Copyright (C) 1996-2005, 2006, 2007, 2008, 2009, 2010
+ Copyright (C) 1996-2011
CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
This file is part of CACAO.
md_icacheflush((void*) pr->mpc, PATCHER_CALL_SIZE);
}
+static int32_t *patch_checked_location(int32_t *p, int32_t val)
+{
+ assert(*p == 0);
+ // verify that it's aligned
+ assert((((uintptr_t) p) & (4-1)) == 0);
+ *p = val;
+ return p;
+}
+
+static void checked_icache_flush(int32_t *addr, int nbytes, int32_t *check_loc)
+{
+ assert((int8_t*) addr + nbytes - sizeof(int32_t) >= (int8_t*) check_loc);
+ md_icacheflush(addr, nbytes);
+}
+
/**
* Check if the trap instruction at the given PC is valid.
*
return false;
ra += PATCHER_CALL_SIZE;
+ ra += PATCH_ALIGNMENT((uintptr_t) ra, 2, sizeof(int32_t));
// Patch class flags.
/* *datap = c->flags; */
- *((int32_t*) (ra + 2)) = c->flags;
+ patch_checked_location((int32_t*) (ra + 2), c->flags);
// Synchronize data cache.
/* md_dcacheflush(datap, sizeof(int32_t)); */
pc += PATCHER_CALL_SIZE;
- // Patch the field's offset: we check for the field type, because
- // the instructions have different lengths.
- if (IS_INT_LNG_TYPE(fi->type)) {
- // Check for special case: %rsp or %r12 as base register.
- if (pc[3] == 0x24)
- *((int32_t*) (pc + 4)) = fi->offset;
- else
- *((int32_t*) (pc + 3)) = fi->offset;
- }
- else {
- // Check for special case: %rsp or %r12 as base register.
- if (pc[5] == 0x24)
- *((int32_t*) (pc + 6)) = fi->offset;
- else
- *((int32_t*) (pc + 5)) = fi->offset;
- }
+ int disp = -sizeof(int32_t) + pr->patch_align;
+ patch_checked_location((int32_t*) (pc + disp), fi->offset);
if (pr->disp_mb && !(fi->flags & ACC_VOLATILE))
patch_out_mfence(pc + pr->disp_mb - 2);
// Synchronize instruction cache.
- md_icacheflush(pc, 6 + sizeof(int32_t));
+ md_icacheflush(pc, disp + sizeof(int32_t));
// Patch back the original code.
patcher_patch_code(pr);
pc += PATCHER_CALL_SIZE;
- // Patch the field's offset.
- if (IS_2_WORD_TYPE(fi->type) || IS_ADR_TYPE(fi->type)) {
- // Handle special case when the base register is %r12.
- if (pc[12] == 0x94)
- *((uint32_t*) (pc + 14)) = fi->offset;
- else
- *((uint32_t*) (pc + 13)) = fi->offset;
- }
- else {
- // Handle special case when the base register is %r12.
- if (pc[2] == 0x84)
- *((uint32_t*) (pc + 4)) = fi->offset;
- else
- *((uint32_t*) (pc + 3)) = fi->offset;
- }
+ int disp = -2*sizeof(int32_t) + pr->patch_align;
+ patch_checked_location((int32_t*) (pc + disp), fi->offset);
if (pr->disp_mb && !(fi->flags & ACC_VOLATILE))
patch_out_mfence(pc + pr->disp_mb - 2);
// Synchronize instruction cache.
- md_icacheflush(pc, 14 + sizeof(int32_t));
+ md_icacheflush(pc, disp + sizeof(int32_t));
// Patch back the original code.
patcher_patch_code(pr);
return false;
pc += PATCHER_CALL_SIZE;
+ pc += PATCH_ALIGNMENT((uintptr_t) pc, 6, sizeof(int32_t));
// Patch vftbl index.
- *((int32_t*) (pc + 3 + 3)) = (int32_t) (OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * m->vftblindex);
+ patch_checked_location((int32_t*) (pc + 6), (int32_t) (OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * m->vftblindex));
// Synchronize instruction cache.
md_icacheflush(pc + 3 + 3, SIZEOF_VOID_P);
return false;
pc += PATCHER_CALL_SIZE;
+ pc += PATCH_ALIGNMENT((uintptr_t) pc, 6, sizeof(int32_t));
// Patch interfacetable index.
- *((int32_t*) (pc + 3 + 3)) = (int32_t) (OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr) * m->clazz->index);
+ patch_checked_location((int32_t*) (pc + 6), (int32_t) (OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr) * m->clazz->index));
+ int disp = PATCH_ALIGNMENT((uintptr_t) (pc + 3 + 7), 3, sizeof(int32_t));
+ pc += disp;
// Patch method offset.
- *((int32_t*) (pc + 3 + 7 + 3)) = (int32_t) (sizeof(methodptr) * (m - m->clazz->methods));
+ int32_t *loc = patch_checked_location((int32_t*) (pc + 3 + 7 + 3), (int32_t) (sizeof(methodptr) * (m - m->clazz->methods)));
// Synchronize instruction cache.
- md_icacheflush(pc + 3 + 3, SIZEOF_VOID_P + 3 + SIZEOF_VOID_P);
+ checked_icache_flush(pc + 6, SIZEOF_VOID_P + 3 + SIZEOF_VOID_P + disp, loc);
// Patch back the original code.
patcher_patch_code(pr);
return false;
pc += PATCHER_CALL_SIZE;
+ pc += PATCH_ALIGNMENT((uintptr_t) pc, 10, sizeof(int32_t));
// Patch super class index.
- *((int32_t*) (pc + 7 + 3)) = c->index;
+ patch_checked_location((int32_t*) (pc + 10), c->index);
- *((int32_t*) (pc + 7 + 7 + 6 + 8 + 3)) = (int32_t) (OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*));
+ int disp = PATCH_ALIGNMENT((uintptr_t) (pc + 7 + 7 + 6 + 8), 3, sizeof(int32_t));
+ pc += disp;
+ int32_t *loc = patch_checked_location((int32_t*) (pc + 7 + 7 + 6 + 8 + 3), (int32_t) (OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*)));
// Synchronize instruction cache.
- md_icacheflush(pc + 7 + 3, sizeof(int32_t) + 6 + 8 + 3 + sizeof(int32_t));
+ checked_icache_flush(pc + 10, sizeof(int32_t) + 6 + 8 + 3 + sizeof(int32_t) + disp, loc);
// Patch back the original code.
patcher_patch_code(pr);
return false;
pc += PATCHER_CALL_SIZE;
+ pc += PATCH_ALIGNMENT((uintptr_t) pc, 10, sizeof(int32_t));
// Patch super class index.
- *((int32_t*) (pc + 7 + 3)) = c->index;
+ patch_checked_location((int32_t*) (pc + 10), c->index);
- *((int32_t*) (pc + 7 + 7 + 6 + 3)) = (int32_t) (OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*));
+ int disp = PATCH_ALIGNMENT((uintptr_t) (pc + 7 + 7 + 6), 3, sizeof(int32_t));
+ pc += disp;
+ int32_t *loc = patch_checked_location((int32_t*) (pc + 7 + 7 + 6 + 3), (int32_t) (OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*)));
// Synchronize instruction cache.
- md_icacheflush(pc + 7 + 3, sizeof(int32_t) + 6 + 3 + sizeof(int32_t));
+ checked_icache_flush(pc + 10, sizeof(int32_t) + 6 + 3 + sizeof(int32_t) + disp, loc);
// Patch back the original code.
patcher_patch_code(pr);
/* tests/regression/bugzilla/All.java - runs all CACAO regression unit tests
- Copyright (C) 2008, 2009
+ Copyright (C) 1996-2011
CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
This file is part of CACAO.
PR119.class,
PR125.class,
PR131.class,
+PR144.class,
PR148.class
})
--- /dev/null
+/* tests/regression/bugzilla/PR144.java
+
+ Copyright (C) 1996-2011
+ CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+
+ This file is part of CACAO.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+*/
+
+
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+interface test_summable {
+ long sum();
+}
+
+class y implements test_summable {
+ public long l;
+ public int i;
+ public long sum() {
+ return l+i;
+ }
+}
+
+public class PR144 {
+ static long do_test(Object o, int val) {
+ y vy = (y) o;
+ test_summable sm = null;
+ if (o instanceof test_summable)
+ sm = (test_summable) o;
+ vy.l = 0x123456789L;
+ vy.i = 0x98765;
+ long r = sm.sum();
+ vy.l = val;
+ vy.i = val;
+ return r + sm.sum();
+ }
+
+ @Test
+ public void test() {
+ try {
+ do_test(null, 0);
+ } catch (NullPointerException e) {
+ }
+ assertEquals(4887631770L, do_test(new y(), 0x23456));
+ }
+}
+
+
+
+