1 /* src/vm/jit/patcher-common.cpp - architecture independent code patching stuff
3 Copyright (C) 2007, 2008
4 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5 Copyright (C) 2008 Theobroma Systems Ltd.
7 This file is part of CACAO.
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation; either version 2, or (at
12 your option) any later version.
14 This program is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
35 #include "codegen.h" /* for PATCHER_NOPS */
38 #include "mm/memory.hpp"
40 #include "native/native.hpp"
42 #include "toolbox/list.hpp"
43 #include "toolbox/logging.hpp" /* XXX remove me! */
45 #include "vm/exceptions.hpp"
46 #include "vm/initialize.hpp"
47 #include "vm/options.h"
48 #include "vm/resolve.hpp"
49 #include "vm/vm.hpp" /* for vm_abort */
51 #include "vm/jit/code.hpp"
52 #include "vm/jit/disass.h"
53 #include "vm/jit/jit.hpp"
54 #include "vm/jit/patcher-common.hpp"
57 /* patcher_function_list *******************************************************
59 This is a list which maps patcher function pointers to the according
60 names of the patcher functions. It is only usefull for debugging
63 *******************************************************************************/
66 typedef struct patcher_function_list_t {
69 } patcher_function_list_t;
71 static patcher_function_list_t patcher_function_list[] = {
72 { PATCHER_initialize_class, "initialize_class" },
73 #ifdef ENABLE_VERIFIER
74 { PATCHER_resolve_class, "resolve_class" },
75 #endif /* ENABLE_VERIFIER */
76 { PATCHER_resolve_native_function, "resolve_native_function" },
77 { PATCHER_invokestatic_special, "invokestatic_special" },
78 { PATCHER_invokevirtual, "invokevirtual" },
79 { PATCHER_invokeinterface, "invokeinterface" },
80 { NULL, "-UNKNOWN PATCHER FUNCTION-" }
85 /* patcher_list_create *********************************************************
87 Creates an empty patcher list for the given codeinfo.
89 *******************************************************************************/
91 void patcher_list_create(codeinfo *code)
93 code->patchers = new List<patchref_t>();
97 /* patcher_list_reset **********************************************************
99 Resets the patcher list inside a codeinfo. This is usefull when
100 resetting a codeinfo for recompiling.
102 *******************************************************************************/
104 void patcher_list_reset(codeinfo *code)
106 #if defined(ENABLE_STATISTICS)
108 size_patchref -= sizeof(patchref_t) * code->patchers->size();
111 // Free all elements of the list.
112 code->patchers->clear();
115 /* patcher_list_free ***********************************************************
117 Frees the patcher list and all its entries for the given codeinfo.
119 *******************************************************************************/
121 void patcher_list_free(codeinfo *code)
123 // Free all elements of the list.
124 patcher_list_reset(code);
126 // Free the list itself.
127 delete code->patchers;
132 * Find an entry inside the patcher list for the given codeinfo by
133 * specifying the program counter of the patcher position.
135 * NOTE: Caller should hold the patcher list lock or maintain
136 * exclusive access otherwise.
138 * @param pc Program counter to find.
140 * @return Pointer to patcher.
143 struct foo : public std::binary_function<patchref_t, void*, bool> {
144 bool operator() (const patchref_t& pr, const void* pc) const
146 return (pr.mpc == (uintptr_t) pc);
150 static patchref_t* patcher_list_find(codeinfo* code, void* pc)
152 // Search for a patcher with the given PC.
153 List<patchref_t>::iterator it = std::find_if(code->patchers->begin(), code->patchers->end(), std::bind2nd(foo(), pc));
155 if (it == code->patchers->end())
162 /* patcher_add_patch_ref *******************************************************
164 Appends a new patcher reference to the list of patching positions.
166 *******************************************************************************/
168 void patcher_add_patch_ref(jitdata *jd, functionptr patcher, void* ref, s4 disp)
176 patchmpc = cd->mcodeptr - cd->mcodebase;
179 if (patcher_list_find(code, (void*) (intptr_t) patchmpc) != NULL)
180 vm_abort("patcher_add_patch_ref: different patchers at same position.");
183 // Set patcher information (mpc is resolved later).
189 pr.patcher = patcher;
194 // Store patcher in the list (NOTE: structure is copied).
195 code->patchers->push_back(pr);
197 #if defined(ENABLE_STATISTICS)
199 size_patchref += sizeof(patchref_t);
202 #if defined(ENABLE_JIT) && (defined(__I386__) || defined(__M68K__) || defined(__SPARC_64__) || defined(__X86_64__))
204 /* XXX We can remove that when we don't use UD2 anymore on i386
207 /* On some architectures the patcher stub call instruction might
208 be longer than the actual instruction generated. On this
209 architectures we store the last patcher call position and after
210 the basic block code generation is completed, we check the
211 range and maybe generate some nop's. */
212 /* The nops are generated in codegen_emit in each codegen */
214 cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE;
220 * Resolve all patchers in the current JIT run.
222 * @param jd JIT data-structure
224 void patcher_resolve(jitdata* jd)
226 // Get required compiler data.
227 codeinfo* code = jd->code;
229 for (List<patchref_t>::iterator it = code->patchers->begin(); it != code->patchers->end(); it++) {
230 patchref_t& pr = *it;
232 pr.mpc += (intptr_t) code->entrypoint;
233 pr.datap = (intptr_t) (pr.disp + code->entrypoint);
239 * Check if the patcher is already patched. This is done by comparing
240 * the machine instruction.
242 * @param pr Patcher structure.
244 * @return true if patched, false otherwise.
246 bool patcher_is_patched(patchref_t* pr)
248 // Validate the instruction at the patching position is the same
249 // instruction as the patcher structure contains.
250 uint32_t mcode = *((uint32_t*) pr->mpc);
252 #if PATCHER_CALL_SIZE == 4
253 if (mcode != pr->mcode) {
254 #elif PATCHER_CALL_SIZE == 2
255 if ((uint16_t) mcode != (uint16_t) pr->mcode) {
257 #error Unknown PATCHER_CALL_SIZE
270 bool patcher_is_patched_at(void* pc)
272 codeinfo* code = code_find_codeinfo_for_pc(pc);
274 // Get the patcher for the given PC.
275 patchref_t* pr = patcher_list_find(code, pc);
278 // The given PC is not a patcher position.
282 // Validate the instruction.
283 return patcher_is_patched(pr);
287 /* patcher_handler *************************************************************
289 Handles the request to patch JIT code at the given patching
290 position. This function is normally called by the signal
293 NOTE: The patcher list lock is used to maintain exclusive
294 access of the patched position (in fact of the whole code).
295 After patching has suceeded, the patcher reference should be
296 removed from the patcher list to avoid double patching.
298 *******************************************************************************/
301 /* XXX this indent is not thread safe! */
302 /* XXX if you want it thread safe, place patcher_depth in threadobject! */
303 static int patcher_depth = 0;
304 #define TRACE_PATCHER_INDENT for (i=0; i<patcher_depth; i++) printf("\t")
305 #endif /* !defined(NDEBUG) */
307 java_handle_t *patcher_handler(u1 *pc)
313 patcher_function_list_t *l;
317 /* define the patcher function */
319 bool (*patcher_function)(patchref_t *);
321 /* search the codeinfo for the given PC */
323 code = code_find_codeinfo_for_pc(pc);
326 // Enter a mutex on the patcher list.
327 code->patchers->lock();
329 /* search the patcher information for the given PC */
331 pr = patcher_list_find(code, pc);
334 vm_abort("patcher_handler: Unable to find patcher reference.");
338 if (opt_DebugPatcher) {
339 log_println("patcher_handler: double-patching detected!");
342 code->patchers->unlock();
347 if (opt_DebugPatcher) {
348 for (l = patcher_function_list; l->patcher != NULL; l++)
349 if (l->patcher == pr->patcher)
352 TRACE_PATCHER_INDENT; printf("patching in "); method_print(code->m); printf(" at %p\n", (void *) pr->mpc);
353 TRACE_PATCHER_INDENT; printf("\tpatcher function = %s <%p>\n", l->name, (void *) (intptr_t) pr->patcher);
355 TRACE_PATCHER_INDENT;
356 printf("\tmachine code before = ");
358 # if defined(ENABLE_DISASSEMBLER)
359 disassinstr((u1*) (void*) pr->mpc);
361 printf("%x at %p (disassembler disabled)\n", *((uint32_t*) pr->mpc), (void*) pr->mpc);
365 assert(patcher_depth > 0);
369 /* cast the passed function to a patcher function */
371 patcher_function = (bool (*)(patchref_t *)) (ptrint) pr->patcher;
373 /* call the proper patcher function */
375 result = (patcher_function)(pr);
378 if (opt_DebugPatcher) {
379 assert(patcher_depth > 0);
382 TRACE_PATCHER_INDENT;
383 printf("\tmachine code after = ");
385 # if defined(ENABLE_DISASSEMBLER)
386 disassinstr((u1*) (void*) pr->mpc);
388 printf("%x at %p (disassembler disabled)\n", *((uint32_t*) pr->mpc), (void*) pr->mpc);
391 if (result == false) {
392 TRACE_PATCHER_INDENT; printf("\tPATCHER EXCEPTION!\n");
397 // Check for return value and exit accordingly.
398 if (result == false) {
399 // Mangle the pending exception.
400 resolve_handle_pending_exception(true);
402 // Get the exception and return it.
403 java_handle_t* e = exceptions_get_and_clear_exception();
405 code->patchers->unlock();
410 pr->done = true; /* XXX this is only preliminary to prevent double-patching */
412 code->patchers->unlock();
418 /* patcher_initialize_class ****************************************************
420 Initalizes a given classinfo pointer.
421 This function does not patch any data.
423 *******************************************************************************/
425 bool patcher_initialize_class(patchref_t *pr)
429 /* get stuff from the patcher reference */
431 c = (classinfo *) pr->ref;
433 /* check if the class is initialized */
435 if (!(c->state & CLASS_INITIALIZED))
436 if (!initialize_class(c))
439 /* patch back original code */
441 patcher_patch_code(pr);
447 /* patcher_resolve_class *******************************************************
449 Resolves a given unresolved class reference.
450 This function does not patch any data.
452 *******************************************************************************/
454 #ifdef ENABLE_VERIFIER
455 bool patcher_resolve_class(patchref_t *pr)
457 unresolved_class *uc;
459 /* get stuff from the patcher reference */
461 uc = (unresolved_class *) pr->ref;
463 /* resolve the class and check subtype constraints */
465 if (!resolve_class_eager_no_access_check(uc))
468 /* patch back original code */
470 patcher_patch_code(pr);
474 #endif /* ENABLE_VERIFIER */
477 /* patcher_resolve_native_function *********************************************
479 Resolves the native function for a given methodinfo.
480 This function patches one data segment word.
482 *******************************************************************************/
484 bool patcher_resolve_native_function(patchref_t *pr)
489 /* get stuff from the patcher reference */
491 m = (methodinfo *) pr->ref;
492 datap = (uint8_t *) pr->datap;
494 /* resolve native function */
496 NativeMethods& nm = VM::get_current()->get_nativemethods();
497 void* f = nm.resolve_method(m);
502 /* patch native function pointer */
504 *((intptr_t*) datap) = (intptr_t) f;
506 /* synchronize data cache */
508 md_dcacheflush(datap, SIZEOF_VOID_P);
510 /* patch back original code */
512 patcher_patch_code(pr);
519 * These are local overrides for various environment variables in Emacs.
520 * Please do not remove this and leave it at the end of the file, where
521 * Emacs will automagically detect them.
522 * ---------------------------------------------------------------------
525 * indent-tabs-mode: t
529 * vim:noexpandtab:sw=4:ts=4: