/* 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"
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
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.
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;
+
+#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).
// 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;
}
codeinfo *code;
patchref_t *pr;
bool result;
- java_handle_t *e;
#if !defined(NDEBUG)
patcher_function_list_t *l;
int i;
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
- /* 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();
}
+/**
+ * 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;
+
+#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);
+
+ 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