#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 = jd->cd;
codeinfo *code = jd->code;
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);
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;
#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; \
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 ***************************************
// 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);
*((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));
*((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));