* src/threads/posix/thread-posix.cpp: Eliminated some easy-to-fix or pointless compil...
[cacao.git] / src / vm / jit / x86_64 / patcher.c
index 8439237050a3943424dd0adb7233d430ecb7cd7d..2d394fff212ef8392a6c6dd7c30878fab9f9af03 100644 (file)
@@ -1,6 +1,6 @@
 /* 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, 2010
    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/builtin.h"
-#include "vm/class.h"
-#include "vm/field.h"
-#include "vm/initialize.h"
+#include "vm/jit/builtin.hpp"
+#include "vm/class.hpp"
+#include "vm/field.hpp"
+#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 **********************************************************
@@ -59,6 +59,40 @@ void patcher_patch_code(patchref_t *pr)
        md_icacheflush((void*) pr->mpc, PATCHER_CALL_SIZE);
 }
 
+/**
+ * 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 ***************************************
 
@@ -99,7 +133,7 @@ bool patcher_resolve_classref_to_classinfo(patchref_t *pr)
        *datap = (uintptr_t) c;
 
        // Synchronize data cache.
-       md_dcacheflush(pr->datap, SIZEOF_VOID_P);
+       md_dcacheflush((void*) pr->datap, SIZEOF_VOID_P);
 
        // Patch back the original code.
        patcher_patch_code(pr);
@@ -132,7 +166,7 @@ bool patcher_resolve_classref_to_vftbl(patchref_t *pr)
        *datap = (uintptr_t) c->vftbl;
 
        // Synchronize data cache.
-       md_dcacheflush(pr->datap, SIZEOF_VOID_P);
+       md_dcacheflush((void*) pr->datap, SIZEOF_VOID_P);
 
        // Patch back the original code.
        patcher_patch_code(pr);
@@ -161,6 +195,8 @@ bool patcher_resolve_classref_to_flags(patchref_t *pr)
        if (c == NULL)
                return false;
 
+       ra += PATCHER_CALL_SIZE;
+
        // Patch class flags.
 /*     *datap = c->flags; */
        *((int32_t*) (ra + 2)) = c->flags;
@@ -190,6 +226,7 @@ bool patcher_get_putstatic(patchref_t *pr)
 {
        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);
@@ -197,6 +234,8 @@ bool patcher_get_putstatic(patchref_t *pr)
        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))
@@ -205,8 +244,11 @@ bool patcher_get_putstatic(patchref_t *pr)
        // 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(pr->datap, SIZEOF_VOID_P);
+       md_dcacheflush((void*) pr->datap, SIZEOF_VOID_P);
 
        // Patch back the original code.
        patcher_patch_code(pr);
@@ -235,6 +277,8 @@ bool patcher_get_putfield(patchref_t *pr)
        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)) {
@@ -252,6 +296,9 @@ bool patcher_get_putfield(patchref_t *pr)
                        *((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));
 
@@ -282,6 +329,8 @@ bool patcher_putfieldconst(patchref_t *pr)
        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.
@@ -298,6 +347,9 @@ bool patcher_putfieldconst(patchref_t *pr)
                        *((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));
 
@@ -333,7 +385,7 @@ bool patcher_invokestatic_special(patchref_t *pr)
        *datap = (uintptr_t) m->stubroutine;
 
        // Synchronize data cache.
-       md_dcacheflush(pr->datap, SIZEOF_VOID_P);
+       md_dcacheflush((void*) pr->datap, SIZEOF_VOID_P);
 
        // Patch back the original code.
        patcher_patch_code(pr);
@@ -364,6 +416,8 @@ bool patcher_invokevirtual(patchref_t *pr)
        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);
 
@@ -400,6 +454,8 @@ bool patcher_invokeinterface(patchref_t *pr)
        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);
 
@@ -440,6 +496,8 @@ bool patcher_checkcast_interface(patchref_t *pr)
        if (c == NULL)
                return false;
 
+       pc += PATCHER_CALL_SIZE;
+
        // Patch super class index.
        *((int32_t*) (pc + 7 + 3)) = c->index;
 
@@ -478,6 +536,8 @@ bool patcher_instanceof_interface(patchref_t *pr)
        if (c == NULL)
                return false;
 
+       pc += PATCHER_CALL_SIZE;
+
        // Patch super class index.
        *((int32_t*) (pc + 7 + 3)) = c->index;