/* src/vm/jit/x86_64/patcher.c - x86_64 code patching functions
- Copyright (C) 1996-2005, 2006, 2007, 2008
+ Copyright (C) 1996-2011
CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
This file is part of CACAO.
#include "vm/jit/x86_64/codegen.h"
#include "vm/jit/x86_64/md.h"
-#include "mm/memory.h"
+#include "mm/memory.hpp"
-#include "native/native.h"
+#include "native/native.hpp"
#include "vm/jit/builtin.hpp"
-#include "vm/class.h"
+#include "vm/class.hpp"
#include "vm/field.hpp"
-#include "vm/initialize.h"
+#include "vm/initialize.hpp"
#include "vm/options.h"
#include "vm/references.h"
-#include "vm/resolve.h"
+#include "vm/resolve.hpp"
-#include "vm/jit/patcher-common.h"
+#include "vm/jit/patcher-common.hpp"
/* patcher_patch_code **********************************************************
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.
+ *
+ * @param pc Program counter.
+ *
+ * @return true if valid, false otherwise.
+ */
+bool patcher_is_valid_trap_instruction_at(void* pc)
+{
+ uint16_t mcode = *((uint16_t*) pc);
+
+ // Check for the undefined instruction we use.
+ 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;
+ 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)); */
{
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;
- // 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;
- }
+ pc += PATCHER_CALL_SIZE;
+
+ 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);
if (fi == NULL)
return false;
- // 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;
- }
+ pc += PATCHER_CALL_SIZE;
+
+ 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);
if (m == NULL)
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);
if (m == NULL)
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);
if (c == NULL)
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);
if (c == NULL)
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);