1 /* src/vm/jit/patcher-common.c - architecture independent code patching stuff
3 Copyright (C) 2007, 2008
4 CACAOVM - Verein zu Foerderung der freien virtuellen Machine 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/jit.h"
50 #include "vm/jit/patcher-common.h"
52 #include "vmcore/options.h"
55 /* patcher_function_list *******************************************************
57 This is a list which maps patcher function pointers to the according
58 names of the patcher functions. It is only usefull for debugging
61 *******************************************************************************/
64 typedef struct patcher_function_list_t {
67 } patcher_function_list_t;
69 static patcher_function_list_t patcher_function_list[] = {
70 { PATCHER_initialize_class, "initialize_class" },
71 { PATCHER_resolve_class, "resolve_class" },
72 { PATCHER_resolve_native_function, "resolve_native_function" },
73 { PATCHER_invokestatic_special, "invokestatic_special" },
74 { PATCHER_invokevirtual, "invokevirtual" },
75 { PATCHER_invokeinterface, "invokeinterface" },
76 { NULL, "-UNKNOWN PATCHER FUNCTION-" }
81 /* patcher_list_create *********************************************************
83 Creates an empty patcher list for the given codeinfo.
85 *******************************************************************************/
87 void patcher_list_create(codeinfo *code)
89 code->patchers = list_create(OFFSET(patchref_t, linkage));
93 /* patcher_list_reset **********************************************************
95 Resets the patcher list inside a codeinfo. This is usefull when
96 resetting a codeinfo for recompiling.
98 *******************************************************************************/
100 void patcher_list_reset(codeinfo *code)
104 /* free all elements of the list */
106 while((pr = list_first(code->patchers)) != NULL) {
107 list_remove(code->patchers, pr);
109 FREE(pr, patchref_t);
111 #if defined(ENABLE_STATISTICS)
113 size_patchref -= sizeof(patchref_t);
118 /* patcher_list_free ***********************************************************
120 Frees the patcher list and all its entries for the given codeinfo.
122 *******************************************************************************/
124 void patcher_list_free(codeinfo *code)
126 /* free all elements of the list */
128 patcher_list_reset(code);
130 /* free the list itself */
132 FREE(code->patchers, list_t);
136 /* patcher_list_find ***********************************************************
138 Find an entry inside the patcher list for the given codeinfo
139 by specifying the program counter of the patcher position.
141 NOTE: Caller should hold the patcher list lock or maintain
142 exclusive access otherwise.
144 *******************************************************************************/
146 static patchref_t *patcher_list_find(codeinfo *code, u1 *pc)
150 /* walk through all patcher references for the given codeinfo */
152 pr = list_first_unsynced(code->patchers);
155 /*#define TRACE_PATCHER_FIND*/
156 #ifdef TRACE_PATCHER_FIND
157 log_println("patcher_list_find: %p == %p", pr->mpc, pc);
160 if (pr->mpc == (ptrint) pc)
163 pr = list_next_unsynced(code->patchers, pr);
170 /* patcher_add_patch_ref *******************************************************
172 Appends a new patcher reference to the list of patching positions.
174 *******************************************************************************/
176 void patcher_add_patch_ref(jitdata *jd, functionptr patcher, voidptr ref,
186 patchmpc = cd->mcodeptr - cd->mcodebase;
189 if (patcher_list_find(code, (u1 *) (intptr_t) patchmpc) != NULL)
190 vm_abort("patcher_add_patch_ref: different patchers at same position.");
193 /* allocate patchref on heap (at least freed together with codeinfo) */
195 pr = NEW(patchref_t);
196 list_add_first_unsynced(code->patchers, pr);
198 #if defined(ENABLE_STATISTICS)
200 size_patchref += sizeof(patchref_t);
203 /* set patcher information (mpc is resolved later) */
207 pr->patcher = patcher;
212 /* Generate NOPs for opt_shownops. */
217 #if defined(ENABLE_JIT) && (defined(__I386__) || defined(__M68K__) || defined(__SPARC_64__) || defined(__X86_64__))
219 /* XXX We can remove that when we don't use UD2 anymore on i386
222 /* On some architectures the patcher stub call instruction might
223 be longer than the actual instruction generated. On this
224 architectures we store the last patcher call position and after
225 the basic block code generation is completed, we check the
226 range and maybe generate some nop's. */
227 /* The nops are generated in codegen_emit in each codegen */
229 cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE;
234 /* patcher_handler *************************************************************
236 Handles the request to patch JIT code at the given patching
237 position. This function is normally called by the signal
240 NOTE: The patcher list lock is used to maintain exclusive
241 access of the patched position (in fact of the whole code).
242 After patching has suceeded, the patcher reference should be
243 removed from the patcher list to avoid double patching.
245 *******************************************************************************/
248 /* XXX this indent is not thread safe! */
249 /* XXX if you want it thread safe, place patcher_depth in threadobject! */
250 static int patcher_depth = 0;
251 #define TRACE_PATCHER_INDENT for (i=0; i<patcher_depth; i++) printf("\t")
252 #endif /* !defined(NDEBUG) */
254 java_handle_t *patcher_handler(u1 *pc)
261 patcher_function_list_t *l;
265 /* define the patcher function */
267 bool (*patcher_function)(patchref_t *);
269 /* search the codeinfo for the given PC */
271 code = code_find_codeinfo_for_pc(pc);
274 /* enter a monitor on the patcher list */
276 LOCK_MONITOR_ENTER(code->patchers);
278 /* search the patcher information for the given PC */
280 pr = patcher_list_find(code, pc);
283 vm_abort("patcher_handler: Unable to find patcher reference.");
287 if (opt_DebugPatcher) {
288 log_println("patcher_handler: double-patching detected!");
291 LOCK_MONITOR_EXIT(code->patchers);
296 if (opt_DebugPatcher) {
297 for (l = patcher_function_list; l->patcher != NULL; l++)
298 if (l->patcher == pr->patcher)
301 TRACE_PATCHER_INDENT; printf("patching in "); method_print(code->m); printf(" at %p\n", (void *) pr->mpc);
302 TRACE_PATCHER_INDENT; printf("\tpatcher function = %s <%p>\n", l->name, (void *) (intptr_t) pr->patcher);
303 TRACE_PATCHER_INDENT; printf("\tmcodes before = "); for (i=0; i<5; i++) printf("0x%08x ", *((u4 *) pr->mpc + i)); printf("\n");
305 assert(patcher_depth > 0);
309 /* cast the passed function to a patcher function */
311 patcher_function = (bool (*)(patchref_t *)) (ptrint) pr->patcher;
313 /* call the proper patcher function */
315 result = (patcher_function)(pr);
318 if (opt_DebugPatcher) {
319 assert(patcher_depth > 0);
321 TRACE_PATCHER_INDENT; printf("\tmcodes after = "); for (i=0; i<5; i++) printf("0x%08x ", *((u4 *) pr->mpc + i)); printf("\n");
322 if (result == false) {
323 TRACE_PATCHER_INDENT; printf("\tPATCHER EXCEPTION!\n");
328 /* check for return value and exit accordingly */
330 if (result == false) {
331 e = exceptions_get_and_clear_exception();
333 LOCK_MONITOR_EXIT(code->patchers);
338 pr->done = true; /* XXX this is only preliminary to prevent double-patching */
340 LOCK_MONITOR_EXIT(code->patchers);
346 /* patcher_initialize_class ****************************************************
348 Initalizes a given classinfo pointer.
349 This function does not patch any data.
351 *******************************************************************************/
353 bool patcher_initialize_class(patchref_t *pr)
357 /* get stuff from the patcher reference */
359 c = (classinfo *) pr->ref;
361 /* check if the class is initialized */
363 if (!(c->state & CLASS_INITIALIZED))
364 if (!initialize_class(c))
367 /* patch back original code */
369 patcher_patch_code(pr);
375 /* patcher_resolve_class *******************************************************
377 Resolves a given unresolved class reference.
378 This function does not patch any data.
380 *******************************************************************************/
382 #ifdef ENABLE_VERIFIER
383 bool patcher_resolve_class(patchref_t *pr)
385 unresolved_class *uc;
387 /* get stuff from the patcher reference */
389 uc = (unresolved_class *) pr->ref;
391 /* resolve the class and check subtype constraints */
393 if (!resolve_class_eager_no_access_check(uc))
396 /* patch back original code */
398 patcher_patch_code(pr);
402 #endif /* ENABLE_VERIFIER */
405 /* patcher_resolve_native_function *********************************************
407 Resolves the native function for a given methodinfo.
408 This function patches one data segment word.
410 *******************************************************************************/
412 bool patcher_resolve_native_function(patchref_t *pr)
418 /* get stuff from the patcher reference */
420 m = (methodinfo *) pr->ref;
421 datap = (uint8_t *) pr->datap;
423 /* resolve native function */
425 if (!(f = native_method_resolve(m)))
428 /* patch native function pointer */
430 *((intptr_t *) datap) = (intptr_t) f;
432 /* synchronize data cache */
434 md_dcacheflush(datap, SIZEOF_VOID_P);
436 /* patch back original code */
438 patcher_patch_code(pr);
445 * These are local overrides for various environment variables in Emacs.
446 * Please do not remove this and leave it at the end of the file, where
447 * Emacs will automagically detect them.
448 * ---------------------------------------------------------------------
451 * indent-tabs-mode: t
455 * vim:noexpandtab:sw=4:ts=4: