#define SET_FIELD(o,type,f,value) \
*((type *) (((intptr_t) (o)) + ((intptr_t) ((fieldinfo *) (f))->offset))) = (type) (value)
+#define GET_FIELDINFO(f) ((fieldinfo*) (f))
+
#define JNI_SET_FIELD(name, type, intern) \
void _Jv_JNI_Set##name##Field(JNIEnv *env, jobject obj, jfieldID fieldID, \
type value) \
\
SET_FIELD(LLNI_DIRECT((java_handle_t *) obj), intern, fieldID, value); \
\
- LLNI_CRITICAL_START; \
+ LLNI_CRITICAL_END; \
+ \
+ if (GET_FIELDINFO(fieldID)->flags & ACC_VOLATILE) \
+ Atomic::memory_barrier(); \
}
JNI_SET_FIELD(Boolean, jboolean, s4)
SET_FIELD(obj, java_handle_t*, fieldID, LLNI_UNWRAP((java_handle_t*) value));
LLNI_CRITICAL_END;
+
+ if (GET_FIELDINFO(fieldID)->flags & ACC_VOLATILE)
+ Atomic::memory_barrier();
}
return; \
\
f->value->field = value; \
+ \
+ if (f->flags & ACC_VOLATILE) \
+ Atomic::memory_barrier(); \
}
JNI_SET_STATIC_FIELD(Boolean, jboolean, i)
return;
f->value->a = LLNI_UNWRAP((java_handle_t *) value);
+
+ if (f->flags & ACC_VOLATILE)
+ Atomic::memory_barrier();
}
#if defined(__I386__)
// Generate architecture specific instructions.
codegen_emit_instruction(jd, iptr);
+ break;
#else
+ {
+ fieldinfo* fi;
+ patchref_t* pr;
if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
unresolved_field* uf = iptr->sx.s23.s3.uf;
fieldtype = uf->fieldref->parseddesc.fd->type;
disp = dseg_add_unique_address(cd, 0);
- patcher_add_patch_ref(jd, PATCHER_get_putstatic, uf, disp);
+ pr = patcher_add_patch_ref(jd, PATCHER_get_putstatic, uf, disp);
}
else {
- fieldinfo* fi = iptr->sx.s23.s3.fmiref->p.field;
+ fi = iptr->sx.s23.s3.fmiref->p.field;
fieldtype = fi->type;
disp = dseg_add_address(cd, fi->value);
}
}
+#if defined(USES_PATCHABLE_MEMORY_BARRIER)
+ codegen_emit_patchable_barrier(iptr, cd, pr, fi);
+#endif
+
// XXX X86_64: Here We had this:
/* This approach is much faster than moving the field
address inline into a register. */
break;
}
emit_store_dst(jd, iptr, d);
-#endif
break;
+ }
+#endif
case ICMD_PUTSTATIC: /* ..., value ==> ... */
#if defined(__I386__)
// Generate architecture specific instructions.
codegen_emit_instruction(jd, iptr);
+ break;
#else
+ {
+ fieldinfo* fi;
+ patchref_t* pr;
+
if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
unresolved_field* uf = iptr->sx.s23.s3.uf;
fieldtype = uf->fieldref->parseddesc.fd->type;
disp = dseg_add_unique_address(cd, 0);
- patcher_add_patch_ref(jd, PATCHER_get_putstatic, uf, disp);
+ pr = patcher_add_patch_ref(jd, PATCHER_get_putstatic, uf, disp);
}
else {
- fieldinfo* fi = iptr->sx.s23.s3.fmiref->p.field;
+ fi = iptr->sx.s23.s3.fmiref->p.field;
fieldtype = fi->type;
disp = dseg_add_address(cd, fi->value);
M_DST(s1, REG_ITMP1, 0);
break;
}
+#if defined(USES_PATCHABLE_MEMORY_BARRIER)
+ codegen_emit_patchable_barrier(iptr, cd, pr, fi);
#endif
break;
+ }
+#endif
/* branch operations **********************************************/
/* src/vm/jit/codegen-common.hpp - architecture independent code generator stuff
- 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.
typedef struct jumpref jumpref;
typedef struct dataref dataref;
+struct patchref_t;
#include "config.h"
#include "vm/types.h"
void codegen_emit_epilog(jitdata* jd);
void codegen_emit_instruction(jitdata* jd, instruction* iptr);
+#if defined(USES_PATCHABLE_MEMORY_BARRIER)
+void codegen_emit_patchable_barrier(instruction *iptr, codegendata *cd, struct patchref_t *pr, fieldinfo *fi);
+#endif
+
#if defined(ENABLE_INTRP)
bool intrp_codegen(jitdata *jd);
#endif
Appends a new patcher reference to the list of patching positions.
+ Returns a pointer to the newly created patchref_t.
+
*******************************************************************************/
-void patcher_add_patch_ref(jitdata *jd, functionptr patcher, void* ref, s4 disp)
+patchref_t *patcher_add_patch_ref(jitdata *jd, functionptr patcher, void* ref, s4 disp)
{
- codegendata *cd;
- codeinfo *code;
- s4 patchmpc;
-
- cd = jd->cd;
- code = jd->code;
- patchmpc = cd->mcodeptr - cd->mcodebase;
+ codegendata *cd = jd->cd;
+ codeinfo *code = jd->code;
#if defined(ALIGN_PATCHER_TRAP)
emit_patcher_alignment(cd);
- patchmpc = cd->mcodeptr - cd->mcodebase;
#endif
+ int32_t patchmpc = cd->mcodeptr - cd->mcodebase;
+
#if !defined(NDEBUG)
if (patcher_list_find(code, (void*) (intptr_t) patchmpc) != NULL)
os::abort("patcher_add_patch_ref: different patchers at same position.");
#endif
+#if defined(USES_PATCHABLE_MEMORY_BARRIER)
+ PATCHER_NOPS;
+#endif
+
// 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;
cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE;
#endif
+
+ return &code->patchers->back();
}
*******************************************************************************/
struct patchref_t {
- ptrint mpc; /* absolute position in code segment */
- ptrint datap; /* absolute position in data segment */
- s4 disp; /* displacement of ref in the data segment */
+ 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) */
functionptr patcher; /* patcher function to call */
void* ref; /* reference passed */
uint32_t mcode; /* machine code to be patched back in */
void patcher_list_show(codeinfo *code);
#endif
-void patcher_add_patch_ref(jitdata *jd, functionptr patcher, void* ref, s4 disp);
+patchref_t *patcher_add_patch_ref(jitdata *jd, functionptr patcher, void* ref, s4 disp);
void patcher_resolve(jitdata* jd);
#define CAS_PROVIDES_FULL_BARRIER 1
+#define USES_PATCHABLE_MEMORY_BARRIER 1
+
#endif /* _ARCH_H */
* c-basic-offset: 4
* tab-width: 4
* End:
+ * vim:noexpandtab:sw=4:ts=4:
*/
M_RET;
}
+/**
+ * Generates a memory barrier to be used after volatile writes. It can be
+ * patched out later if the field turns out not to be volatile.
+ */
+void codegen_emit_patchable_barrier(instruction *iptr, codegendata *cd, patchref_t *pr, fieldinfo *fi)
+{
+ if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
+ /* Align on word boundary */
+ if ((((intptr_t) cd->mcodeptr) & 3) >= 2)
+ emit_nop(cd, 4 - (((intptr_t) cd->mcodeptr) & 3));
+ /* Displacement for patching out MFENCE */
+ pr->disp_mb = (cd->mcodeptr - cd->mcodebase - pr->mpc);
+ }
+ if (INSTRUCTION_IS_UNRESOLVED(iptr) || fi->flags & ACC_VOLATILE)
+ M_MFENCE;
+}
/**
* Generates machine code for one ICMD.
unresolved_method* um;
fieldinfo* fi;
unresolved_field* uf;
+ patchref_t* pr;
int32_t fieldtype;
int32_t s1, s2, s3, d;
int32_t disp;
/* PROFILE_CYCLE_STOP; */
- patcher_add_patch_ref(jd, PATCHER_get_putstatic, uf, disp);
+ pr = patcher_add_patch_ref(jd, PATCHER_get_putstatic, uf, disp);
/* PROFILE_CYCLE_START; */
}
}
break;
}
+ codegen_emit_patchable_barrier(iptr, cd, pr, fi);
break;
case ICMD_GETFIELD: /* ... ==> ..., value */
/* PROFILE_CYCLE_STOP; */
- patcher_add_patch_ref(jd, PATCHER_get_putfield, uf, 0);
+ pr = patcher_add_patch_ref(jd, PATCHER_get_putfield, uf, 0);
/* PROFILE_CYCLE_START; */
}
M_DST32(s2, s1, disp);
break;
}
+ codegen_emit_patchable_barrier(iptr, cd, pr, fi);
break;
case ICMD_PUTFIELDCONST: /* ..., objectref, value ==> ... */
/* PROFILE_CYCLE_STOP; */
- patcher_add_patch_ref(jd, PATCHER_putfieldconst, uf, 0);
+ pr = patcher_add_patch_ref(jd, PATCHER_putfieldconst, uf, 0);
/* PROFILE_CYCLE_START; */
}
M_LST32(REG_ITMP2, s1, disp);
break;
}
+ codegen_emit_patchable_barrier(iptr, cd, pr, fi);
break;
/* src/vm/jit/x86_64/codegen.h - code generation macros for x86_64
- 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.
#define ALIGNCODENOP \
do { \
- for (s1 = 0; s1 < (s4) (((ptrint) cd->mcodeptr) & 7); s1++) \
- M_NOP; \
+ int len = (-(ptrint) cd->mcodeptr) & 7; \
+ if (len) \
+ emit_nop(cd, len); \
} while (0)
#define BRANCH_UNCONDITIONAL_SIZE 5 /* size in bytes of a branch */
#define BRANCH_CONDITIONAL_SIZE 6 /* size in bytes of a branch */
+/* These NOPs are never executed; they are only used as placeholders during
+ * code generation.
+ */
#define BRANCH_NOPS \
do { \
M_NOP; \
#define PATCHER_NOPS \
do { \
- M_NOP; \
- M_NOP; \
+ emit_nop(cd, 2); \
} while (0)
/* system instructions ********************************************************/
+#define M_MFENCE emit_mfence(cd)
#define M_RDTSC emit_rdtsc(cd)
#define M_IINC_MEMBASE(a,b) emit_incl_membase(cd, (a), (b))
* c-basic-offset: 4
* tab-width: 4
* End:
+ * vim:noexpandtab:sw=4:ts=4:
*/
/* low-level code emitter functions *******************************************/
+void emit_nop(codegendata *cd, int length)
+{
+ assert(length >= 1 && length <= 9);
+ switch (length) {
+ case 1:
+ *(cd->mcodeptr++) = 0x90;
+ break;
+ case 2:
+ *(cd->mcodeptr++) = 0x66;
+ *(cd->mcodeptr++) = 0x90;
+ break;
+ case 3:
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x1f;
+ *(cd->mcodeptr++) = 0x00;
+ break;
+ case 4:
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x1f;
+ *(cd->mcodeptr++) = 0x40;
+ *(cd->mcodeptr++) = 0x00;
+ break;
+ case 5:
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x1f;
+ *(cd->mcodeptr++) = 0x44;
+ *(cd->mcodeptr++) = 0x00;
+ *(cd->mcodeptr++) = 0x00;
+ break;
+ case 6:
+ *(cd->mcodeptr++) = 0x66;
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x1f;
+ *(cd->mcodeptr++) = 0x44;
+ *(cd->mcodeptr++) = 0x00;
+ *(cd->mcodeptr++) = 0x00;
+ break;
+ case 7:
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x1f;
+ *(cd->mcodeptr++) = 0x80;
+ *(cd->mcodeptr++) = 0x00;
+ *(cd->mcodeptr++) = 0x00;
+ *(cd->mcodeptr++) = 0x00;
+ *(cd->mcodeptr++) = 0x00;
+ break;
+ case 8:
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x1f;
+ *(cd->mcodeptr++) = 0x84;
+ *(cd->mcodeptr++) = 0x00;
+ *(cd->mcodeptr++) = 0x00;
+ *(cd->mcodeptr++) = 0x00;
+ *(cd->mcodeptr++) = 0x00;
+ *(cd->mcodeptr++) = 0x00;
+ break;
+ case 9:
+ *(cd->mcodeptr++) = 0x66;
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0x1f;
+ *(cd->mcodeptr++) = 0x84;
+ *(cd->mcodeptr++) = 0x00;
+ *(cd->mcodeptr++) = 0x00;
+ *(cd->mcodeptr++) = 0x00;
+ *(cd->mcodeptr++) = 0x00;
+ *(cd->mcodeptr++) = 0x00;
+ break;
+ }
+}
+
void emit_mov_reg_reg(codegendata *cd, s8 reg, s8 dreg)
{
emit_rex(1,(reg),0,(dreg));
*(cd->mcodeptr++) = 0x31;
}
+void emit_mfence(codegendata *cd)
+{
+ *(cd->mcodeptr++) = 0x0f;
+ *(cd->mcodeptr++) = 0xae;
+ *(cd->mcodeptr++) = 0xf0;
+}
+
/*
* These are local overrides for various environment variables in Emacs.
* c-basic-offset: 4
* tab-width: 4
* End:
+ * vim:noexpandtab:sw=4:ts=4:
*/
/* src/vm/jit/x86_64/emit.h - machine dependent emit function prototypes
- 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, 2009
+ CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
This file is part of CACAO.
/* integer instructions */
+void emit_nop(codegendata *cd, int length);
void emit_mov_reg_reg(codegendata *cd, s8 reg, s8 dreg);
void emit_mov_imm_reg(codegendata *cd, s8 imm, s8 reg);
void emit_movl_reg_reg(codegendata *cd, s8 reg, s8 dreg);
/* system instructions ********************************************************/
void emit_rdtsc(codegendata *cd);
+void emit_mfence(codegendata *cd);
/**
* c-basic-offset: 4
* tab-width: 4
* End:
+ * vim:noexpandtab:sw=4:ts=4:
*/
/* src/vm/jit/x86_64/patcher.c - x86_64 code patching 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.
return (mcode == 0x0b0f);
}
+/**
+ * Overwrites the MFENCE instruction at the indicated address with a 3-byte
+ * NOP. The MFENCE instruction is not allowed to cross a (4-byte) word
+ * boundary.
+ *
+ * @param pc Program counter.
+ */
+static void patch_out_mfence(void *pc)
+{
+ uint32_t *p = (uint32_t*) (((uintptr_t) pc) & ~3);
+
+ assert((((uintptr_t) pc) & 3) < 2);
+ if (((uintptr_t) pc) & 1)
+ *p = *p & 0x000000ff | 0x001f0f00;
+ else
+ *p = *p & 0xff000000 | 0x00001f0f;
+
+ md_icacheflush(p, 4);
+}
/* patcher_resolve_classref_to_classinfo ***************************************
if (c == NULL)
return false;
+ ra += PATCHER_CALL_SIZE;
+
// Patch class flags.
/* *datap = c->flags; */
*((int32_t*) (ra + 2)) = c->flags;
{
unresolved_field* uf = (unresolved_field*) pr->ref;
uintptr_t* datap = (uintptr_t*) pr->datap;
+ uint8_t* ra = (uint8_t*) pr->mpc;
// Resolve the field.
fieldinfo* fi = resolve_field_eager(uf);
if (fi == NULL)
return false;
+ ra += PATCHER_CALL_SIZE;
+
// Check if the field's class is initialized/
if (!(fi->clazz->state & CLASS_INITIALIZED))
if (!initialize_class(fi->clazz))
// Patch the field value's address.
*datap = (uintptr_t) fi->value;
+ if (pr->disp_mb && !(fi->flags & ACC_VOLATILE))
+ patch_out_mfence(ra + pr->disp_mb - 2);
+
// Synchronize data cache.
md_dcacheflush((void*) pr->datap, SIZEOF_VOID_P);
if (fi == NULL)
return false;
+ 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)) {
*((int32_t*) (pc + 5)) = 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));
if (fi == NULL)
return false;
+ 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.
*((uint32_t*) (pc + 3)) = 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));
if (m == NULL)
return false;
+ pc += PATCHER_CALL_SIZE;
+
// Patch vftbl index.
*((int32_t*) (pc + 3 + 3)) = (int32_t) (OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * m->vftblindex);
if (m == NULL)
return false;
+ pc += PATCHER_CALL_SIZE;
+
// Patch interfacetable index.
*((int32_t*) (pc + 3 + 3)) = (int32_t) (OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr) * m->clazz->index);
if (c == NULL)
return false;
+ pc += PATCHER_CALL_SIZE;
+
// Patch super class index.
*((int32_t*) (pc + 7 + 3)) = c->index;
if (c == NULL)
return false;
+ pc += PATCHER_CALL_SIZE;
+
// Patch super class index.
*((int32_t*) (pc + 7 + 3)) = c->index;