X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Fjit%2Fpatcher-common.cpp;h=2963cf62b28f47fb8ff0a4e58602dda4ed45664b;hb=c414f560a7e0b7636a780e6b933e91e441f80503;hp=a33aba7893d350bfda472c2d7669d7935c0bc709;hpb=7933b38c4e2dd2621f00fb02bf50f4a400bc31c2;p=cacao.git diff --git a/src/vm/jit/patcher-common.cpp b/src/vm/jit/patcher-common.cpp index a33aba789..2963cf62b 100644 --- a/src/vm/jit/patcher-common.cpp +++ b/src/vm/jit/patcher-common.cpp @@ -1,6 +1,6 @@ /* src/vm/jit/patcher-common.cpp - architecture independent code patching stuff - Copyright (C) 2007, 2008 + Copyright (C) 1996-2011 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO Copyright (C) 2008 Theobroma Systems Ltd. @@ -29,21 +29,27 @@ #include #include +#include +#include + #include "codegen.h" /* for PATCHER_NOPS */ #include "md.h" +#include "trap.hpp" -#include "mm/memory.h" +#include "mm/memory.hpp" -#include "native/native.h" +#include "native/native.hpp" -#include "toolbox/list.h" -#include "toolbox/logging.h" /* XXX remove me! */ +#include "toolbox/list.hpp" +#include "toolbox/logging.hpp" /* XXX remove me! */ +#include "vm/breakpoint.hpp" #include "vm/exceptions.hpp" -#include "vm/initialize.h" +#include "vm/hook.hpp" +#include "vm/initialize.hpp" #include "vm/options.h" -#include "vm/resolve.h" -#include "vm/vm.hpp" /* for vm_abort */ +#include "vm/os.hpp" +#include "vm/resolve.hpp" #include "vm/jit/code.hpp" #include "vm/jit/disass.h" @@ -67,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 @@ -85,7 +94,7 @@ static patcher_function_list_t patcher_function_list[] = { void patcher_list_create(codeinfo *code) { - code->patchers = list_create(OFFSET(patchref_t, linkage)); + code->patchers = new LockedList(); } @@ -98,20 +107,13 @@ void patcher_list_create(codeinfo *code) void patcher_list_reset(codeinfo *code) { - patchref_t *pr; - - /* free all elements of the list */ - - while((pr = (patchref_t*) list_first(code->patchers)) != NULL) { - list_remove(code->patchers, pr); - - FREE(pr, patchref_t); - #if defined(ENABLE_STATISTICS) - if (opt_stat) - size_patchref -= sizeof(patchref_t); + if (opt_stat) + size_patchref -= sizeof(patchref_t) * code->patchers->size(); #endif - } + + // Free all elements of the list. + code->patchers->clear(); } /* patcher_list_free *********************************************************** @@ -122,92 +124,137 @@ void patcher_list_reset(codeinfo *code) void patcher_list_free(codeinfo *code) { - /* free all elements of the list */ - + // Free all elements of the list. patcher_list_reset(code); - /* free the list itself */ - - list_free(code->patchers); + // Free the list itself. + delete code->patchers; } -/* patcher_list_find *********************************************************** - - 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. +/** + * 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. + * + * @param pc Program counter to find. + * + * @return Pointer to patcher. + */ -*******************************************************************************/ +struct foo : public std::binary_function { + bool operator() (const patchref_t& pr, const void* pc) const + { + return (pr.mpc == (uintptr_t) pc); + } +}; -static patchref_t *patcher_list_find(codeinfo *code, void *pc) +static patchref_t* patcher_list_find(codeinfo* code, void* pc) { - patchref_t *pr; + // Search for a patcher with the given PC. + List::iterator it = std::find_if(code->patchers->begin(), code->patchers->end(), std::bind2nd(foo(), pc)); - /* walk through all patcher references for the given codeinfo */ + if (it == code->patchers->end()) + return NULL; - pr = (patchref_t*) list_first(code->patchers); + return &(*it); +} - while (pr) { -/*#define TRACE_PATCHER_FIND*/ -#ifdef TRACE_PATCHER_FIND - log_println("patcher_list_find: %p == %p", pr->mpc, pc); -#endif +/** + * 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::iterator it = code->patchers->begin(); it != code->patchers->end(); it++) { + patchref_t& pr = *it; - if (pr->mpc == (ptrint) pc) - return pr; + // 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; - pr = (patchref_t*) list_next(code->patchers, pr); + // 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 } - - return NULL; } +#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; - patchref_t *pr; - 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 - /* allocate patchref on heap (at least freed together with codeinfo) */ +#if defined(USES_PATCHABLE_MEMORY_BARRIER) + PATCHER_NOPS; +#endif + + // Set patcher information (mpc is resolved later). + patchref_t pr; - pr = NEW(patchref_t); - list_add_first(code->patchers, pr); + pr.mpc = patchmpc; + pr.datap = 0; + pr.disp = disp; + pr.disp_mb = 0; + pr.patch_align = 0; + pr.patcher = patcher; + pr.ref = ref; + pr.mcode = 0; + pr.done = false; + + // Store patcher in the list (NOTE: structure is copied). + code->patchers->push_back(pr); #if defined(ENABLE_STATISTICS) if (opt_stat) size_patchref += sizeof(patchref_t); #endif - /* set patcher information (mpc is resolved later) */ - - pr->mpc = patchmpc; - pr->disp = disp; - pr->patcher = patcher; - pr->ref = ref; - pr->mcode = 0; - pr->done = false; - #if defined(ENABLE_JIT) && (defined(__I386__) || defined(__M68K__) || defined(__SPARC_64__) || defined(__X86_64__)) /* XXX We can remove that when we don't use UD2 anymore on i386 @@ -222,6 +269,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(); } @@ -232,16 +281,14 @@ void patcher_add_patch_ref(jitdata *jd, functionptr patcher, void* ref, s4 disp) */ void patcher_resolve(jitdata* jd) { - codeinfo* code; - patchref_t* pr; + // Get required compiler data. + codeinfo* code = jd->code; - /* Get required compiler data. */ + for (List::iterator it = code->patchers->begin(); it != code->patchers->end(); it++) { + patchref_t& pr = *it; - code = jd->code; - - for (pr = (patchref_t*) list_first(code->patchers); pr != NULL; pr = (patchref_t*) list_next(code->patchers, pr)) { - pr->mpc += (intptr_t) code->entrypoint; - pr->datap = (intptr_t) (pr->disp + code->entrypoint); + pr.mpc += (intptr_t) code->entrypoint; + pr.datap = (intptr_t) (pr.disp + code->entrypoint); } } @@ -260,7 +307,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; } @@ -309,12 +362,11 @@ static int patcher_depth = 0; #define TRACE_PATCHER_INDENT for (i=0; ipatchers); + // Enter a mutex on the patcher list. + code->patchers->lock(); /* search the patcher information for the given 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) @@ -346,8 +397,8 @@ java_handle_t *patcher_handler(u1 *pc) log_println("patcher_handler: double-patching detected!"); } #endif - list_unlock(code->patchers); - return NULL; + code->patchers->unlock(); + return true; } #if !defined(NDEBUG) @@ -401,21 +452,17 @@ java_handle_t *patcher_handler(u1 *pc) } #endif - /* check for return value and exit accordingly */ + // Check return value and mangle the pending exception. + if (result == false) + resolve_handle_pending_exception(true); - if (result == false) { - e = exceptions_get_and_clear_exception(); + // XXX This is only preliminary to prevent double-patching. + else + pr->done = true; - list_unlock(code->patchers); - - return e; - } + code->patchers->unlock(); - pr->done = true; /* XXX this is only preliminary to prevent double-patching */ - - list_unlock(code->patchers); - - return NULL; + return result; } @@ -489,7 +536,6 @@ bool patcher_resolve_native_function(patchref_t *pr) { methodinfo *m; uint8_t *datap; - functionptr f; /* get stuff from the patcher reference */ @@ -498,12 +544,15 @@ bool patcher_resolve_native_function(patchref_t *pr) /* resolve native function */ - if (!(f = native_method_resolve(m))) + NativeMethods& nm = VM::get_current()->get_nativemethods(); + void* f = nm.resolve_method(m); + + if (f == NULL) return false; /* patch native function pointer */ - *((intptr_t *) datap) = (intptr_t) f; + *((intptr_t*) datap) = (intptr_t) f; /* synchronize data cache */ @@ -517,6 +566,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