* src/vm/jit/patcher-common.cpp: Conditionally restored NOP-insertion at
[cacao.git] / src / vm / jit / patcher-common.cpp
index 2bcf973ba8b43bbcd714f433e3bae8dc1c90c977..57c6fdb39005537ba738f0c2e160324d418083d1 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.h"           /* XXX remove me! */
+#include "toolbox/logging.hpp"           /* XXX remove me! */
 
+#include "vm/breakpoint.hpp"
 #include "vm/exceptions.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 +72,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 +93,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,6 +162,49 @@ 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.
@@ -165,17 +213,22 @@ static patchref_t* patcher_list_find(codeinfo* code, void* pc)
 
 void 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;
 
-       cd       = jd->cd;
-       code     = jd->code;
-       patchmpc = cd->mcodeptr - cd->mcodebase;
+#if defined(ALIGN_PATCHER_TRAP)
+       emit_patcher_alignment(cd);
+#endif
+
+       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).
@@ -189,10 +242,6 @@ void patcher_add_patch_ref(jitdata *jd, functionptr patcher, void* ref, s4 disp)
        pr.mcode   = 0;
        pr.done    = false;
 
-#if defined(ENABLE_JITCACHE)
-       pr.attached_ref = NULL;
-#endif
-
        // Store patcher in the list (NOTE: structure is copied).
        code->patchers->push_back(pr);
 
@@ -251,7 +300,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;
        }
@@ -305,7 +360,6 @@ java_handle_t *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;
@@ -328,7 +382,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)
@@ -391,19 +445,13 @@ java_handle_t *patcher_handler(u1 *pc)
        }
 #endif
 
-#if defined(ENABLE_JITCACHE)
-       /* Put cached reference into the code and remove it from the patcher */
-       if (pr->attached_ref)
-       {
-               jitcache_handle_cached_ref(pr->attached_ref, code);
-               pr->attached_ref = NULL;
-       }
-#endif
-
-       /* check for return value and exit accordingly */
-
+       // Check for return value and exit accordingly.
        if (result == false) {
-               e = exceptions_get_and_clear_exception();
+               // Mangle the pending exception.
+               resolve_handle_pending_exception(true);
+
+               // Get the exception and return it.
+               java_handle_t* e = exceptions_get_and_clear_exception();
 
                code->patchers->unlock();
 
@@ -517,28 +565,36 @@ bool patcher_resolve_native_function(patchref_t *pr)
        return true;
 }
 
-/** Placeholder functions to calm down linker */
-#if defined(__I386__)
-bool patcher_resolve_classref_to_classinfo(patchref_t *pr)
-{
-       return true;
-}
 
-bool patcher_resolve_classref_to_vftbl(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)
 {
-       return true;
-}
+       // Get stuff from the patcher reference.
+       Breakpoint* breakp = (Breakpoint*) pr->ref;
 
-bool patcher_resolve_classref_to_index(patchref_t *pr)
-{
-       return true;
-}
+#if defined(ENABLE_JVMTI)
+       methodinfo* m = breakp->method;
+       int32_t     l = breakp->location;
+
+       log_message_method("JVMTI: Reached breakpoint in method ", m);
+       log_println("JVMTI: Reached breakpoint at location %d", l);
+#endif
+
+       // 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);
 
-bool patcher_resolve_classref_to_flags(patchref_t *pr)
-{
        return true;
 }
-#endif
+
 
 /*
  * These are local overrides for various environment variables in Emacs.