1 /* src/vm/jit/patcher-common.c - architecture independent code patching stuff
3 Copyright (C) 2007, 2008
4 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
6 This file is part of CACAO.
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2, or (at
11 your option) any later version.
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
31 #include "codegen.h" /* for PATCHER_NOPS */
34 #include "mm/memory.h"
36 #include "native/native.h"
38 #include "threads/lock-common.h"
40 #include "toolbox/list.h"
41 #include "toolbox/logging.h" /* XXX remove me! */
43 #include "vm/exceptions.h"
44 #include "vm/initialize.h"
45 #include "vm/resolve.h"
46 #include "vm/vm.h" /* for vm_abort */
48 #include "vm/jit/code.h"
49 #include "vm/jit/disass.h"
50 #include "vm/jit/jit.h"
51 #include "vm/jit/patcher-common.h"
53 #include "vmcore/options.h"
56 /* patcher_function_list *******************************************************
58 This is a list which maps patcher function pointers to the according
59 names of the patcher functions. It is only usefull for debugging
62 *******************************************************************************/
65 typedef struct patcher_function_list_t {
68 } patcher_function_list_t;
70 static patcher_function_list_t patcher_function_list[] = {
71 { PATCHER_initialize_class, "initialize_class" },
72 { PATCHER_resolve_class, "resolve_class" },
73 { PATCHER_resolve_native_function, "resolve_native_function" },
74 { PATCHER_invokestatic_special, "invokestatic_special" },
75 { PATCHER_invokevirtual, "invokevirtual" },
76 { PATCHER_invokeinterface, "invokeinterface" },
77 { NULL, "-UNKNOWN PATCHER FUNCTION-" }
82 /* patcher_list_create *********************************************************
84 Creates an empty patcher list for the given codeinfo.
86 *******************************************************************************/
88 void patcher_list_create(codeinfo *code)
90 code->patchers = list_create(OFFSET(patchref_t, linkage));
94 /* patcher_list_reset **********************************************************
96 Resets the patcher list inside a codeinfo. This is usefull when
97 resetting a codeinfo for recompiling.
99 *******************************************************************************/
101 void patcher_list_reset(codeinfo *code)
105 /* free all elements of the list */
107 while((pr = list_first(code->patchers)) != NULL) {
108 list_remove(code->patchers, pr);
110 FREE(pr, patchref_t);
112 #if defined(ENABLE_STATISTICS)
114 size_patchref -= sizeof(patchref_t);
119 /* patcher_list_free ***********************************************************
121 Frees the patcher list and all its entries for the given codeinfo.
123 *******************************************************************************/
125 void patcher_list_free(codeinfo *code)
127 /* free all elements of the list */
129 patcher_list_reset(code);
131 /* free the list itself */
133 FREE(code->patchers, list_t);
137 /* patcher_list_find ***********************************************************
139 Find an entry inside the patcher list for the given codeinfo
140 by specifying the program counter of the patcher position.
142 NOTE: Caller should hold the patcher list lock or maintain
143 exclusive access otherwise.
145 *******************************************************************************/
147 static patchref_t *patcher_list_find(codeinfo *code, u1 *pc)
151 /* walk through all patcher references for the given codeinfo */
153 pr = list_first(code->patchers);
157 /*#define TRACE_PATCHER_FIND*/
158 #ifdef TRACE_PATCHER_FIND
159 log_println("patcher_list_find: %p == %p", pr->mpc, pc);
162 if (pr->mpc == (ptrint) pc)
165 pr = list_next(code->patchers, pr);
172 /* patcher_add_patch_ref *******************************************************
174 Appends a new patcher reference to the list of patching positions.
176 *******************************************************************************/
178 void patcher_add_patch_ref(jitdata *jd, functionptr patcher, voidptr ref,
188 patchmpc = cd->mcodeptr - cd->mcodebase;
191 if (patcher_list_find(code, (u1 *) (intptr_t) patchmpc) != NULL)
192 vm_abort("patcher_add_patch_ref: different patchers at same position.");
195 /* allocate patchref on heap (at least freed together with codeinfo) */
197 pr = NEW(patchref_t);
198 list_add_first(code->patchers, pr);
200 #if defined(ENABLE_STATISTICS)
202 size_patchref += sizeof(patchref_t);
205 /* set patcher information (mpc is resolved later) */
209 pr->patcher = patcher;
214 #if defined(ENABLE_JITCACHE)
215 pr->attached_ref = NULL;
218 /* Generate NOPs for opt_shownops. */
223 #if defined(ENABLE_JIT) && (defined(__I386__) || defined(__M68K__) || defined(__SPARC_64__) || defined(__X86_64__))
225 /* XXX We can remove that when we don't use UD2 anymore on i386
228 /* On some architectures the patcher stub call instruction might
229 be longer than the actual instruction generated. On this
230 architectures we store the last patcher call position and after
231 the basic block code generation is completed, we check the
232 range and maybe generate some nop's. */
233 /* The nops are generated in codegen_emit in each codegen */
235 cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE;
241 * Resolve all patchers in the current JIT run.
243 * @param jd JIT data-structure
245 void patcher_resolve(jitdata* jd)
250 /* Get required compiler data. */
254 for (pr = list_first(code->patchers); pr != NULL; pr = list_next(code->patchers, pr)) {
255 pr->mpc += (intptr_t) code->entrypoint;
256 pr->datap = (intptr_t) (pr->disp + code->entrypoint);
261 /* patcher_handler *************************************************************
263 Handles the request to patch JIT code at the given patching
264 position. This function is normally called by the signal
267 NOTE: The patcher list lock is used to maintain exclusive
268 access of the patched position (in fact of the whole code).
269 After patching has suceeded, the patcher reference should be
270 removed from the patcher list to avoid double patching.
272 *******************************************************************************/
275 /* XXX this indent is not thread safe! */
276 /* XXX if you want it thread safe, place patcher_depth in threadobject! */
277 static int patcher_depth = 0;
278 #define TRACE_PATCHER_INDENT for (i=0; i<patcher_depth; i++) printf("\t")
279 #endif /* !defined(NDEBUG) */
281 java_handle_t *patcher_handler(u1 *pc)
288 patcher_function_list_t *l;
292 /* define the patcher function */
294 bool (*patcher_function)(patchref_t *);
296 /* search the codeinfo for the given PC */
298 code = code_find_codeinfo_for_pc(pc);
301 /* enter a monitor on the patcher list */
303 LOCK_MONITOR_ENTER(code->patchers);
305 /* search the patcher information for the given PC */
307 pr = patcher_list_find(code, pc);
310 vm_abort("patcher_handler: Unable to find patcher reference.");
314 if (opt_DebugPatcher) {
315 log_println("patcher_handler: double-patching detected!");
318 LOCK_MONITOR_EXIT(code->patchers);
323 if (opt_DebugPatcher) {
324 for (l = patcher_function_list; l->patcher != NULL; l++)
325 if (l->patcher == pr->patcher)
328 TRACE_PATCHER_INDENT; printf("patching in "); method_print(code->m); printf(" at %p\n", (void *) pr->mpc);
329 TRACE_PATCHER_INDENT; printf("\tpatcher function = %s <%p>\n", l->name, (void *) (intptr_t) pr->patcher);
331 TRACE_PATCHER_INDENT;
332 printf("\tmachine code before = ");
334 # if defined(ENABLE_DISASSEMBLER)
335 disassinstr((void *) pr->mpc);
337 printf("disassembler disabled\n");
341 assert(patcher_depth > 0);
345 /* cast the passed function to a patcher function */
347 patcher_function = (bool (*)(patchref_t *)) (ptrint) pr->patcher;
349 /* call the proper patcher function */
351 result = (patcher_function)(pr);
354 if (opt_DebugPatcher) {
355 assert(patcher_depth > 0);
358 TRACE_PATCHER_INDENT;
359 printf("\tmachine code after = ");
361 # if defined(ENABLE_DISASSEMBLER)
362 disassinstr((void *) pr->mpc);
364 printf("disassembler disabled\n");
367 if (result == false) {
368 TRACE_PATCHER_INDENT; printf("\tPATCHER EXCEPTION!\n");
373 #if defined(ENABLE_JITCACHE)
374 /* Put cached reference into the code and remove it from the patcher */
375 if (pr->attached_ref)
377 jitcache_handle_cached_ref(pr->attached_ref, code);
378 pr->attached_ref = NULL;
382 /* check for return value and exit accordingly */
384 if (result == false) {
385 e = exceptions_get_and_clear_exception();
387 LOCK_MONITOR_EXIT(code->patchers);
392 pr->done = true; /* XXX this is only preliminary to prevent double-patching */
394 LOCK_MONITOR_EXIT(code->patchers);
400 /* patcher_initialize_class ****************************************************
402 Initalizes a given classinfo pointer.
403 This function does not patch any data.
405 *******************************************************************************/
407 bool patcher_initialize_class(patchref_t *pr)
411 /* get stuff from the patcher reference */
413 c = (classinfo *) pr->ref;
415 /* check if the class is initialized */
417 if (!(c->state & CLASS_INITIALIZED))
418 if (!initialize_class(c))
421 /* patch back original code */
423 patcher_patch_code(pr);
429 /* patcher_resolve_class *******************************************************
431 Resolves a given unresolved class reference.
432 This function does not patch any data.
434 *******************************************************************************/
436 #ifdef ENABLE_VERIFIER
437 bool patcher_resolve_class(patchref_t *pr)
439 unresolved_class *uc;
441 /* get stuff from the patcher reference */
443 uc = (unresolved_class *) pr->ref;
445 /* resolve the class and check subtype constraints */
447 if (!resolve_class_eager_no_access_check(uc))
450 /* patch back original code */
452 patcher_patch_code(pr);
456 #endif /* ENABLE_VERIFIER */
459 /* patcher_resolve_native_function *********************************************
461 Resolves the native function for a given methodinfo.
462 This function patches one data segment word.
464 *******************************************************************************/
466 bool patcher_resolve_native_function(patchref_t *pr)
472 /* get stuff from the patcher reference */
474 m = (methodinfo *) pr->ref;
475 datap = (uint8_t *) pr->datap;
477 /* resolve native function */
479 if (!(f = native_method_resolve(m)))
482 /* patch native function pointer */
484 *((intptr_t *) datap) = (intptr_t) f;
486 /* synchronize data cache */
488 md_dcacheflush(datap, SIZEOF_VOID_P);
490 /* patch back original code */
492 patcher_patch_code(pr);
497 /** Placeholder functions to calm down linker */
498 #if defined(__I386__)
499 bool patcher_resolve_classref_to_classinfo(patchref_t *pr)
504 bool patcher_resolve_classref_to_vftbl(patchref_t *pr)
509 bool patcher_resolve_classref_to_index(patchref_t *pr)
514 bool patcher_resolve_classref_to_flags(patchref_t *pr)
521 * These are local overrides for various environment variables in Emacs.
522 * Please do not remove this and leave it at the end of the file, where
523 * Emacs will automagically detect them.
524 * ---------------------------------------------------------------------
527 * indent-tabs-mode: t
531 * vim:noexpandtab:sw=4:ts=4: