#include <assert.h>
#include <stdint.h>
+#include <algorithm>
+#include <functional>
+
#include "codegen.h" /* for PATCHER_NOPS */
#include "md.h"
#include "mm/memory.h"
-#include "native/native.h"
+#include "native/native.hpp"
-#include "toolbox/list.h"
+#include "toolbox/list.hpp"
#include "toolbox/logging.h" /* XXX remove me! */
#include "vm/exceptions.hpp"
void patcher_list_create(codeinfo *code)
{
- code->patchers = list_create(OFFSET(patchref_t, linkage));
+ code->patchers = new List<patchref_t>();
}
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 ***********************************************************
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<patchref_t, void*, bool> {
+ 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;
-
- /* walk through all patcher references for the given codeinfo */
+ // Search for a patcher with the given PC.
+ List<patchref_t>::iterator it = std::find_if(code->patchers->begin(), code->patchers->end(), std::bind2nd(foo(), pc));
- pr = (patchref_t*) list_first(code->patchers);
-
- while (pr) {
-
-/*#define TRACE_PATCHER_FIND*/
-#ifdef TRACE_PATCHER_FIND
- log_println("patcher_list_find: %p == %p", pr->mpc, pc);
-#endif
-
- if (pr->mpc == (ptrint) pc)
- return pr;
-
- pr = (patchref_t*) list_next(code->patchers, pr);
- }
+ if (it == code->patchers->end())
+ return NULL;
- return NULL;
+ return &(*it);
}
{
codegendata *cd;
codeinfo *code;
- patchref_t *pr;
s4 patchmpc;
cd = jd->cd;
vm_abort("patcher_add_patch_ref: different patchers at same position.");
#endif
- /* allocate patchref on heap (at least freed together with codeinfo) */
+ // Set patcher information (mpc is resolved later).
+ patchref_t pr;
+
+ pr.mpc = patchmpc;
+ pr.datap = 0;
+ pr.disp = disp;
+ pr.patcher = patcher;
+ pr.ref = ref;
+ pr.mcode = 0;
+ pr.done = false;
+
+#if defined(ENABLE_JITCACHE)
+ pr.attached_ref = NULL;
+#endif
- pr = NEW(patchref_t);
- list_add_first(code->patchers, pr);
+ // 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
*/
void patcher_resolve(jitdata* jd)
{
- codeinfo* code;
- patchref_t* pr;
-
- /* Get required compiler data. */
+ // Get required compiler data.
+ codeinfo* code = jd->code;
- code = jd->code;
+ for (List<patchref_t>::iterator it = code->patchers->begin(); it != code->patchers->end(); it++) {
+ patchref_t& pr = *it;
- 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);
}
}
code = code_find_codeinfo_for_pc(pc);
assert(code);
- /* enter a monitor on the patcher list */
-
- list_lock(code->patchers);
+ // Enter a mutex on the patcher list.
+ code->patchers->lock();
/* search the patcher information for the given PC */
log_println("patcher_handler: double-patching detected!");
}
#endif
- list_unlock(code->patchers);
+ code->patchers->unlock();
return NULL;
}
}
#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 */
if (result == false) {
e = exceptions_get_and_clear_exception();
- list_unlock(code->patchers);
+ code->patchers->unlock();
return e;
}
pr->done = true; /* XXX this is only preliminary to prevent double-patching */
- list_unlock(code->patchers);
+ code->patchers->unlock();
return NULL;
}
{
methodinfo *m;
uint8_t *datap;
- functionptr f;
/* get stuff from the patcher reference */
/* 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 */
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.