- created jitcache-arm-x86 branch
[cacao.git] / src / vm / jit / patcher-common.c
index 0a85f3d848c9cf8335818200a3b2de2cf83511b6..dee3d3de592714dc863fe3a2d66db4a9dde01a56 100644 (file)
@@ -1,9 +1,7 @@
 /* src/vm/jit/patcher-common.c - architecture independent code patching stuff
 
-   Copyright (C) 2007 R. Grafl, A. Krall, C. Kruegel,
-   C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
-   E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
-   J. Wenninger, Institut f. Computersprachen - TU Wien
+   Copyright (C) 2007, 2008
+   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
 
    This file is part of CACAO.
 
@@ -31,6 +29,7 @@
 #include <stdint.h>
 
 #include "codegen.h"                   /* for PATCHER_NOPS */
+#include "md.h"
 
 #include "mm/memory.h"
 
 #include "vm/vm.h"                     /* for vm_abort */
 
 #include "vm/jit/code.h"
+#include "vm/jit/disass.h"
 #include "vm/jit/jit.h"
-#include "vm/jit/md.h"
 #include "vm/jit/patcher-common.h"
 
 #include "vmcore/options.h"
 
 
+/* patcher_function_list *******************************************************
+
+   This is a list which maps patcher function pointers to the according
+   names of the patcher functions. It is only usefull for debugging
+   purposes.
+
+*******************************************************************************/
+
+#if !defined(NDEBUG)
+typedef struct patcher_function_list_t {
+       functionptr  patcher;
+       char        *name;
+} patcher_function_list_t;
+
+static patcher_function_list_t patcher_function_list[] = {
+       { PATCHER_initialize_class,              "initialize_class" },
+       { PATCHER_resolve_class,                 "resolve_class" },
+       { PATCHER_resolve_native_function,       "resolve_native_function" },
+       { PATCHER_invokestatic_special,          "invokestatic_special" },
+       { PATCHER_invokevirtual,                 "invokevirtual" },
+       { PATCHER_invokeinterface,               "invokeinterface" },
+       { NULL,                                  "-UNKNOWN PATCHER FUNCTION-" }
+};
+#endif
+
+
 /* patcher_list_create *********************************************************
 
-   TODO
+   Creates an empty patcher list for the given codeinfo.
 
 *******************************************************************************/
 
@@ -68,7 +93,8 @@ void patcher_list_create(codeinfo *code)
 
 /* patcher_list_reset **********************************************************
 
-   TODO
+   Resets the patcher list inside a codeinfo. This is usefull when
+   resetting a codeinfo for recompiling.
 
 *******************************************************************************/
 
@@ -92,7 +118,7 @@ void patcher_list_reset(codeinfo *code)
 
 /* patcher_list_free ***********************************************************
 
-   TODO
+   Frees the patcher list and all its entries for the given codeinfo.
 
 *******************************************************************************/
 
@@ -110,7 +136,8 @@ void patcher_list_free(codeinfo *code)
 
 /* patcher_list_find ***********************************************************
 
-   TODO
+   Find an entry inside the patcher list for the given codeinfo
+   by specifying the program counter of the patcher position.
 
    NOTE: Caller should hold the patcher list lock or maintain
    exclusive access otherwise.
@@ -123,7 +150,8 @@ static patchref_t *patcher_list_find(codeinfo *code, u1 *pc)
 
        /* walk through all patcher references for the given codeinfo */
 
-       pr = list_first_unsynced(code->patchers);
+       pr = list_first(code->patchers);
+
        while (pr) {
 
 /*#define TRACE_PATCHER_FIND*/
@@ -134,7 +162,7 @@ static patchref_t *patcher_list_find(codeinfo *code, u1 *pc)
                if (pr->mpc == (ptrint) pc)
                        return pr;
 
-               pr = list_next_unsynced(code->patchers, pr);
+               pr = list_next(code->patchers, pr);
        }
 
        return NULL;
@@ -151,42 +179,46 @@ void patcher_add_patch_ref(jitdata *jd, functionptr patcher, voidptr ref,
                            s4 disp)
 {
        codegendata *cd;
-    codeinfo    *code;
-    patchref_t  *pr;
-    s4           patchmpc;
+       codeinfo    *code;
+       patchref_t  *pr;
+       s4           patchmpc;
 
        cd       = jd->cd;
-    code     = jd->code;
-    patchmpc = cd->mcodeptr - cd->mcodebase;
+       code     = jd->code;
+       patchmpc = cd->mcodeptr - cd->mcodebase;
 
 #if !defined(NDEBUG)
        if (patcher_list_find(code, (u1 *) (intptr_t) patchmpc) != NULL)
                vm_abort("patcher_add_patch_ref: different patchers at same position.");
 #endif
 
-    /* allocate patchref on heap (at least freed together with codeinfo) */
+       /* allocate patchref on heap (at least freed together with codeinfo) */
 
        pr = NEW(patchref_t);
-       list_add_first_unsynced(code->patchers, pr);
+       list_add_first(code->patchers, pr);
 
 #if defined(ENABLE_STATISTICS)
        if (opt_stat)
                size_patchref += sizeof(patchref_t);
 #endif
 
-    /* set patcher information (mpc is resolved later) */
+       /* set patcher information (mpc is resolved later) */
 
-    pr->mpc     = patchmpc;
-    pr->disp    = disp;
-    pr->patcher = patcher;
-    pr->ref     = ref;
+       pr->mpc     = patchmpc;
+       pr->disp    = disp;
+       pr->patcher = patcher;
+       pr->ref     = ref;
        pr->mcode   = 0;
        pr->done    = false;
 
-    /* Generate NOPs for opt_shownops. */
+#if defined(ENABLE_JITCACHE)
+       pr->attached_ref = NULL;
+#endif
 
-    if (opt_shownops)
-        PATCHER_NOPS;
+       /* Generate NOPs for opt_shownops. */
+
+       if (opt_shownops)
+               PATCHER_NOPS;
 
 #if defined(ENABLE_JIT) && (defined(__I386__) || defined(__M68K__) || defined(__SPARC_64__) || defined(__X86_64__))
 
@@ -205,35 +237,46 @@ void patcher_add_patch_ref(jitdata *jd, functionptr patcher, voidptr ref,
 }
 
 
+/**
+ * Resolve all patchers in the current JIT run.
+ *
+ * @param jd JIT data-structure
+ */
+void patcher_resolve(jitdata* jd)
+{
+       codeinfo*   code;
+       patchref_t* pr;
+
+       /* Get required compiler data. */
+
+       code = jd->code;
+
+       for (pr = list_first(code->patchers); pr != NULL; pr = list_next(code->patchers, pr)) {
+               pr->mpc   += (intptr_t) code->entrypoint;
+               pr->datap  = (intptr_t) (pr->disp + code->entrypoint);
+       }
+}
+
+
 /* patcher_handler *************************************************************
 
-   TODO
+   Handles the request to patch JIT code at the given patching
+   position. This function is normally called by the signal
+   handler.
 
-*******************************************************************************/
+   NOTE: The patcher list lock is used to maintain exclusive
+   access of the patched position (in fact of the whole code).
+   After patching has suceeded, the patcher reference should be
+   removed from the patcher list to avoid double patching.
 
-/*#define TRACE_PATCHER*/
+*******************************************************************************/
 
-#ifdef TRACE_PATCHER
+#if !defined(NDEBUG)
 /* XXX this indent is not thread safe! */
 /* XXX if you want it thread safe, place patcher_depth in threadobject! */
 static int patcher_depth = 0;
 #define TRACE_PATCHER_INDENT for (i=0; i<patcher_depth; i++) printf("\t")
-
-typedef struct patcher_function_list_t {
-       functionptr  patcher;
-       char        *name;
-} patcher_function_list_t;
-
-static patcher_function_list_t patcher_function_list[] = {
-       { PATCHER_initialize_class,              "initialize_class" },
-       { PATCHER_resolve_class,                 "resolve_class" },
-       { PATCHER_resolve_native_function,       "resolve_native_function" },
-       { PATCHER_invokestatic_special,          "invokestatic_special" },
-       { PATCHER_invokevirtual,                 "invokevirtual" },
-       { PATCHER_invokeinterface,               "invokeinterface" },
-       { NULL, "-UNKNOWN PATCHER FUNCTION-" }
-};
-#endif /* TRACE_PATCHER */
+#endif /* !defined(NDEBUG) */
 
 java_handle_t *patcher_handler(u1 *pc)
 {
@@ -241,7 +284,7 @@ java_handle_t *patcher_handler(u1 *pc)
        patchref_t    *pr;
        bool           result;
        java_handle_t *e;
-#ifdef TRACE_PATCHER
+#if !defined(NDEBUG)
        patcher_function_list_t *l;
        int                      i;
 #endif
@@ -267,22 +310,36 @@ java_handle_t *patcher_handler(u1 *pc)
                vm_abort("patcher_handler: Unable to find patcher reference.");
 
        if (pr->done) {
-               log_println("patcher_handler: double-patching detected!");
+#if !defined(NDEBUG)
+               if (opt_DebugPatcher) {
+                       log_println("patcher_handler: double-patching detected!");
+               }
+#endif
                LOCK_MONITOR_EXIT(code->patchers);
                return NULL;
        }
 
-#ifdef TRACE_PATCHER
-       for (l = patcher_function_list; l->patcher != NULL; l++)
-               if (l->patcher == pr->patcher)
-                       break;
-
-       TRACE_PATCHER_INDENT; printf("patching in "); method_print(code->m); printf("\n");
-       TRACE_PATCHER_INDENT; printf("\texception program counter = %p\n", (void *) pr->mpc);
-       TRACE_PATCHER_INDENT; printf("\tpatcher function = %s\n", l->name);
-       TRACE_PATCHER_INDENT; printf("\tmcodes before = "); for (i=0; i<5; i++) printf("0x%08x ", *((u4 *) pr->mpc + i)); printf("\n");
-       patcher_depth++;
-       assert(patcher_depth > 0);
+#if !defined(NDEBUG)
+       if (opt_DebugPatcher) {
+               for (l = patcher_function_list; l->patcher != NULL; l++)
+                       if (l->patcher == pr->patcher)
+                               break;
+
+               TRACE_PATCHER_INDENT; printf("patching in "); method_print(code->m); printf(" at %p\n", (void *) pr->mpc);
+               TRACE_PATCHER_INDENT; printf("\tpatcher function = %s <%p>\n", l->name, (void *) (intptr_t) pr->patcher);
+
+               TRACE_PATCHER_INDENT;
+               printf("\tmachine code before = ");
+
+# if defined(ENABLE_DISASSEMBLER)
+               disassinstr((void *) pr->mpc);
+# else
+               printf("disassembler disabled\n");
+# endif
+
+               patcher_depth++;
+               assert(patcher_depth > 0);
+       }
 #endif
 
        /* cast the passed function to a patcher function */
@@ -293,12 +350,32 @@ java_handle_t *patcher_handler(u1 *pc)
 
        result = (patcher_function)(pr);
 
-#ifdef TRACE_PATCHER
-       assert(patcher_depth > 0);
-       patcher_depth--;
-       TRACE_PATCHER_INDENT; printf("\tmcodes after  = "); for (i=0; i<5; i++) printf("0x%08x ", *((u4 *) pr->mpc + i)); printf("\n");
-       if (result == false) {
-               TRACE_PATCHER_INDENT; printf("\tPATCHER EXCEPTION!\n");
+#if !defined(NDEBUG)
+       if (opt_DebugPatcher) {
+               assert(patcher_depth > 0);
+               patcher_depth--;
+
+               TRACE_PATCHER_INDENT;
+               printf("\tmachine code after  = ");
+
+# if defined(ENABLE_DISASSEMBLER)
+               disassinstr((void *) pr->mpc);
+# else
+               printf("disassembler disabled\n");
+# endif
+
+               if (result == false) {
+                       TRACE_PATCHER_INDENT; printf("\tPATCHER EXCEPTION!\n");
+               }
+       }
+#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
 
@@ -399,7 +476,7 @@ bool patcher_resolve_native_function(patchref_t *pr)
 
        /* resolve native function */
 
-       if (!(f = native_resolve_function(m)))
+       if (!(f = native_method_resolve(m)))
                return false;
 
        /* patch native function pointer */
@@ -417,6 +494,28 @@ 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)
+{
+       return true;
+}
+
+bool patcher_resolve_classref_to_index(patchref_t *pr)
+{
+       return true;
+}
+
+bool patcher_resolve_classref_to_flags(patchref_t *pr)
+{
+       return true;
+}
+#endif
 
 /*
  * These are local overrides for various environment variables in Emacs.