/* 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.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"
{ PATCHER_invokestatic_special, "invokestatic_special" },
{ PATCHER_invokevirtual, "invokevirtual" },
{ PATCHER_invokeinterface, "invokeinterface" },
+ { PATCHER_breakpoint, "breakpoint" },
{ NULL, "-UNKNOWN PATCHER FUNCTION-" }
};
#endif
void patcher_list_create(codeinfo *code)
{
- code->patchers = new List<patchref_t>();
+ code->patchers = new LockedList<patchref_t>();
}
}
+/**
+ * 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).
pr.mpc = patchmpc;
pr.datap = 0;
pr.disp = disp;
+ pr.disp_mb = 0;
pr.patcher = patcher;
pr.ref = ref;
pr.mcode = 0;
cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE;
#endif
+
+ return &code->patchers->back();
}
#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;
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)
}
#endif
code->patchers->unlock();
- return NULL;
+ return true;
}
#if !defined(NDEBUG)
}
#endif
- // Check for return value and exit accordingly.
- if (result == false) {
- // Mangle the pending exception.
+ // Check return value and mangle the pending exception.
+ if (result == false)
resolve_handle_pending_exception(true);
- // Get the exception and return it.
- java_handle_t* e = exceptions_get_and_clear_exception();
-
- 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;
}
}
+/**
+ * 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