merged volatile memory barriers
[cacao.git] / src / vm / jit / patcher-common.cpp
index f443af0ade3b42fd2ca31e533437441b26d24b80..6acd9687c493440c8548b4509a9c584a8642b4d6 100644 (file)
@@ -1,6 +1,6 @@
 /* src/vm/jit/patcher-common.cpp - architecture independent code patching stuff
 
-   Copyright (C) 2007, 2008
+   Copyright (C) 2007, 2008, 2009
    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
    Copyright (C) 2008 Theobroma Systems Ltd.
 
 
 #include "codegen.h"                   /* for PATCHER_NOPS */
 #include "md.h"
+#include "trap.hpp"
 
-#include "mm/memory.h"
+#include "mm/memory.hpp"
 
 #include "native/native.hpp"
 
 #include "toolbox/list.hpp"
 #include "toolbox/logging.hpp"           /* XXX remove me! */
 
+#include "vm/breakpoint.hpp"
 #include "vm/exceptions.hpp"
+#include "vm/hook.hpp"
 #include "vm/initialize.hpp"
 #include "vm/options.h"
+#include "vm/os.hpp"
 #include "vm/resolve.hpp"
-#include "vm/vm.hpp"                     /* for vm_abort */
 
 #include "vm/jit/code.hpp"
 #include "vm/jit/disass.h"
@@ -70,11 +73,14 @@ typedef struct patcher_function_list_t {
 
 static patcher_function_list_t patcher_function_list[] = {
        { PATCHER_initialize_class,              "initialize_class" },
+#ifdef ENABLE_VERIFIER
        { PATCHER_resolve_class,                 "resolve_class" },
+#endif /* ENABLE_VERIFIER */
        { PATCHER_resolve_native_function,       "resolve_native_function" },
        { PATCHER_invokestatic_special,          "invokestatic_special" },
        { PATCHER_invokevirtual,                 "invokevirtual" },
        { PATCHER_invokeinterface,               "invokeinterface" },
+       { PATCHER_breakpoint,                    "breakpoint" },
        { NULL,                                  "-UNKNOWN PATCHER FUNCTION-" }
 };
 #endif
@@ -88,7 +94,7 @@ static patcher_function_list_t patcher_function_list[] = {
 
 void patcher_list_create(codeinfo *code)
 {
-       code->patchers = new List<patchref_t>();
+       code->patchers = new LockedList<patchref_t>();
 }
 
 
@@ -157,25 +163,75 @@ static patchref_t* patcher_list_find(codeinfo* code, void* pc)
 }
 
 
+/**
+ * Show the content of the whole patcher reference list for
+ * debugging purposes.
+ *
+ * @param code The codeinfo containing the patcher list.
+ */
+#if !defined(NDEBUG)
+void patcher_list_show(codeinfo *code)
+{
+       for (List<patchref_t>::iterator it = code->patchers->begin(); it != code->patchers->end(); it++) {
+               patchref_t& pr = *it;
+
+               // Lookup name in patcher function list.
+               patcher_function_list_t* l;
+               for (l = patcher_function_list; l->patcher != NULL; l++)
+                       if (l->patcher == pr.patcher)
+                               break;
+
+               // Display information about patcher.
+               printf("\tpatcher pc:"PRINTF_FORMAT_INTPTR_T, pr.mpc);
+               printf(" datap:"PRINTF_FORMAT_INTPTR_T, pr.datap);
+               printf(" ref:"PRINTF_FORMAT_INTPTR_T, (intptr_t) pr.ref);
+#if PATCHER_CALL_SIZE == 4
+               printf(" mcode:%08x", (uint32_t) pr.mcode);
+#elif PATCHER_CALL_SIZE == 2
+               printf(" mcode:%04x", (uint16_t) pr.mcode);
+#else
+# error Unknown PATCHER_CALL_SIZE
+#endif
+               printf(" type:%s\n", l->name);
+
+               // Display machine code of patched position.
+#if 0 && defined(ENABLE_DISASSEMBLER)
+               printf("\t\tcurrent -> ");
+               disassinstr((uint8_t*) pr.mpc);
+               printf("\t\tapplied -> ");
+               disassinstr((uint8_t*) &(pr.mcode));
+#endif
+       }
+}
+#endif
+
+
 /* patcher_add_patch_ref *******************************************************
 
    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;
+       codegendata *cd   = jd->cd;
+       codeinfo    *code = jd->code;
+
+#if defined(ALIGN_PATCHER_TRAP)
+       emit_patcher_alignment(cd);
+#endif
 
-       cd       = jd->cd;
-       code     = jd->code;
-       patchmpc = cd->mcodeptr - cd->mcodebase;
+       int32_t patchmpc = cd->mcodeptr - cd->mcodebase;
 
 #if !defined(NDEBUG)
        if (patcher_list_find(code, (void*) (intptr_t) patchmpc) != NULL)
-               vm_abort("patcher_add_patch_ref: different patchers at same position.");
+               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).
@@ -184,6 +240,7 @@ void patcher_add_patch_ref(jitdata *jd, functionptr patcher, void* ref, s4 disp)
        pr.mpc     = patchmpc;
        pr.datap   = 0;
        pr.disp    = disp;
+       pr.disp_mb = 0;
        pr.patcher = patcher;
        pr.ref     = ref;
        pr.mcode   = 0;
@@ -211,6 +268,8 @@ void patcher_add_patch_ref(jitdata *jd, functionptr patcher, void* ref, s4 disp)
 
        cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE;
 #endif
+
+       return &code->patchers->back();
 }
 
 
@@ -247,7 +306,13 @@ bool patcher_is_patched(patchref_t* pr)
        // instruction as the patcher structure contains.
        uint32_t mcode = *((uint32_t*) pr->mpc);
 
+#if PATCHER_CALL_SIZE == 4
        if (mcode != pr->mcode) {
+#elif PATCHER_CALL_SIZE == 2
+       if ((uint16_t) mcode != (uint16_t) pr->mcode) {
+#else
+#error Unknown PATCHER_CALL_SIZE
+#endif
                // The code differs.
                return false;
        }
@@ -296,12 +361,11 @@ static int patcher_depth = 0;
 #define TRACE_PATCHER_INDENT for (i=0; i<patcher_depth; i++) printf("\t")
 #endif /* !defined(NDEBUG) */
 
-java_handle_t *patcher_handler(u1 *pc)
+bool patcher_handler(u1 *pc)
 {
        codeinfo      *code;
        patchref_t    *pr;
        bool           result;
-       java_handle_t *e;
 #if !defined(NDEBUG)
        patcher_function_list_t *l;
        int                      i;
@@ -324,7 +388,7 @@ java_handle_t *patcher_handler(u1 *pc)
        pr = patcher_list_find(code, pc);
 
        if (pr == NULL)
-               vm_abort("patcher_handler: Unable to find patcher reference.");
+               os::abort("patcher_handler: Unable to find patcher reference.");
 
        if (pr->done) {
 #if !defined(NDEBUG)
@@ -333,7 +397,7 @@ java_handle_t *patcher_handler(u1 *pc)
                }
 #endif
                code->patchers->unlock();
-               return NULL;
+               return true;
        }
 
 #if !defined(NDEBUG)
@@ -387,21 +451,17 @@ java_handle_t *patcher_handler(u1 *pc)
        }
 #endif
 
-       /* check for return value and exit accordingly */
-
-       if (result == false) {
-               e = exceptions_get_and_clear_exception();
+       // Check return value and mangle the pending exception.
+       if (result == false)
+               resolve_handle_pending_exception(true);
 
-               code->patchers->unlock();
-
-               return e;
-       }
-
-       pr->done = true; /* XXX this is only preliminary to prevent double-patching */
+       // XXX This is only preliminary to prevent double-patching.
+       else
+               pr->done = true;
 
        code->patchers->unlock();
 
-       return NULL;
+       return result;
 }
 
 
@@ -505,6 +565,31 @@ bool patcher_resolve_native_function(patchref_t *pr)
 }
 
 
+/**
+ * Deals with breakpoint instructions (ICMD_BREAKPOINT) compiled
+ * into a JIT method. This patcher might never patch back the
+ * original machine code because breakpoints are kept active.
+ */
+bool patcher_breakpoint(patchref_t *pr)
+{
+       // Get stuff from the patcher reference.
+       Breakpoint* breakp = (Breakpoint*) pr->ref;
+
+       // Hook point when a breakpoint was triggered.
+       Hook::breakpoint(breakp);
+
+       // In case the breakpoint wants to be kept active, we simply
+       // fail to "patch" at this point.
+       if (!breakp->is_oneshot)
+               return false;
+
+       // Patch back original code.
+       patcher_patch_code(pr);
+
+       return true;
+}
+
+
 /*
  * These are local overrides for various environment variables in Emacs.
  * Please do not remove this and leave it at the end of the file, where