1 /* src/vm/jit/patcher-common.c - architecture independent code patching stuff
3 Copyright (C) 2007 R. Grafl, A. Krall, C. Kruegel,
4 C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5 E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6 J. Wenninger, Institut f. Computersprachen - TU Wien
8 This file is part of CACAO.
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2, or (at
13 your option) any later version.
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
33 #include "codegen.h" /* for PATCHER_NOPS */
35 #include "mm/memory.h"
37 #include "native/native.h"
39 #include "threads/lock-common.h"
41 #include "toolbox/list.h"
42 #include "toolbox/logging.h" /* XXX remove me! */
44 #include "vm/exceptions.h"
45 #include "vm/initialize.h"
46 #include "vm/resolve.h"
47 #include "vm/vm.h" /* for vm_abort */
49 #include "vm/jit/code.h"
50 #include "vm/jit/jit.h"
51 #include "vm/jit/md.h"
52 #include "vm/jit/patcher-common.h"
54 #include "vmcore/options.h"
57 /* patcher_list_create *********************************************************
61 *******************************************************************************/
63 void patcher_list_create(codeinfo *code)
65 code->patchers = list_create(OFFSET(patchref_t, linkage));
69 /* patcher_list_reset **********************************************************
73 *******************************************************************************/
75 void patcher_list_reset(codeinfo *code)
79 /* free all elements of the list */
81 while((pr = list_first(code->patchers)) != NULL) {
82 list_remove(code->patchers, pr);
86 #if defined(ENABLE_STATISTICS)
88 size_patchref -= sizeof(patchref_t);
93 /* patcher_list_free ***********************************************************
97 *******************************************************************************/
99 void patcher_list_free(codeinfo *code)
101 /* free all elements of the list */
103 patcher_list_reset(code);
105 /* free the list itself */
107 FREE(code->patchers, list_t);
111 /* patcher_list_find ***********************************************************
115 NOTE: Caller should hold the patcher list lock or maintain
116 exclusive access otherwise.
118 *******************************************************************************/
120 static patchref_t *patcher_list_find(codeinfo *code, u1 *pc)
124 /* walk through all patcher references for the given codeinfo */
126 pr = list_first_unsynced(code->patchers);
129 /*#define TRACE_PATCHER_FIND*/
130 #ifdef TRACE_PATCHER_FIND
131 log_println("patcher_list_find: %p == %p", pr->mpc, pc);
134 if (pr->mpc == (ptrint) pc)
137 pr = list_next_unsynced(code->patchers, pr);
144 /* patcher_add_patch_ref *******************************************************
146 Appends a new patcher reference to the list of patching positions.
148 *******************************************************************************/
150 void patcher_add_patch_ref(jitdata *jd, functionptr patcher, voidptr ref,
160 patchmpc = cd->mcodeptr - cd->mcodebase;
163 if (patcher_list_find(code, (u1 *) (intptr_t) patchmpc) != NULL)
164 vm_abort("patcher_add_patch_ref: different patchers at same position.");
167 /* allocate patchref on heap (at least freed together with codeinfo) */
169 pr = NEW(patchref_t);
170 list_add_first_unsynced(code->patchers, pr);
172 #if defined(ENABLE_STATISTICS)
174 size_patchref += sizeof(patchref_t);
177 /* set patcher information (mpc is resolved later) */
181 pr->patcher = patcher;
186 /* Generate NOPs for opt_shownops. */
193 /* patcher_handler *************************************************************
197 *******************************************************************************/
199 /*#define TRACE_PATCHER*/
202 /* XXX this indent is not thread safe! */
203 /* XXX if you want it thread safe, place patcher_depth in threadobject! */
204 static int patcher_depth = 0;
205 #define TRACE_PATCHER_INDENT for (i=0; i<patcher_depth; i++) printf("\t")
207 typedef struct patcher_function_list_t {
210 } patcher_function_list_t;
212 static patcher_function_list_t patcher_function_list[] = {
213 { PATCHER_initialize_class, "initialize_class" },
214 { PATCHER_resolve_class, "resolve_class" },
215 { PATCHER_resolve_native_function, "resolve_native_function" },
216 { PATCHER_invokestatic_special, "invokestatic_special" },
217 { PATCHER_invokevirtual, "invokevirtual" },
218 { PATCHER_invokeinterface, "invokeinterface" },
219 { NULL, "-UNKNOWN PATCHER FUNCTION-" }
221 #endif /* TRACE_PATCHER */
223 java_handle_t *patcher_handler(u1 *pc)
230 patcher_function_list_t *l;
234 /* define the patcher function */
236 bool (*patcher_function)(patchref_t *);
238 /* search the codeinfo for the given PC */
240 code = code_find_codeinfo_for_pc(pc);
243 /* enter a monitor on the patcher list */
245 LOCK_MONITOR_ENTER(code->patchers);
247 /* search the patcher information for the given PC */
249 pr = patcher_list_find(code, pc);
252 vm_abort("patcher_handler: Unable to find patcher reference.");
255 log_println("patcher_handler: double-patching detected!");
256 LOCK_MONITOR_EXIT(code->patchers);
261 for (l = patcher_function_list; l->patcher != NULL; l++)
262 if (l->patcher == pr->patcher)
265 TRACE_PATCHER_INDENT; printf("patching in "); method_print(code->m); printf("\n");
266 TRACE_PATCHER_INDENT; printf("\texception program counter = %p\n", (void *) pr->mpc);
267 TRACE_PATCHER_INDENT; printf("\tpatcher function = %s\n", l->name);
268 TRACE_PATCHER_INDENT; printf("\tmcodes before = "); for (i=0; i<5; i++) printf("0x%08x ", *((u4 *) pr->mpc + i)); printf("\n");
270 assert(patcher_depth > 0);
273 /* cast the passed function to a patcher function */
275 patcher_function = (bool (*)(patchref_t *)) (ptrint) pr->patcher;
277 /* call the proper patcher function */
279 result = (patcher_function)(pr);
282 assert(patcher_depth > 0);
284 TRACE_PATCHER_INDENT; printf("\tmcodes after = "); for (i=0; i<5; i++) printf("0x%08x ", *((u4 *) pr->mpc + i)); printf("\n");
285 if (result == false) {
286 TRACE_PATCHER_INDENT; printf("\tPATCHER EXCEPTION!\n");
290 /* check for return value and exit accordingly */
292 if (result == false) {
293 e = exceptions_get_and_clear_exception();
295 LOCK_MONITOR_EXIT(code->patchers);
300 pr->done = true; /* XXX this is only preliminary to prevent double-patching */
302 LOCK_MONITOR_EXIT(code->patchers);
308 /* patcher_initialize_class ****************************************************
310 Initalizes a given classinfo pointer.
311 This function does not patch any data.
313 *******************************************************************************/
315 bool patcher_initialize_class(patchref_t *pr)
319 /* get stuff from the patcher reference */
321 c = (classinfo *) pr->ref;
323 /* check if the class is initialized */
325 if (!(c->state & CLASS_INITIALIZED))
326 if (!initialize_class(c))
329 /* patch back original code */
331 patcher_patch_code(pr);
337 /* patcher_resolve_class *******************************************************
339 Resolves a given unresolved class reference.
340 This function does not patch any data.
342 *******************************************************************************/
344 #ifdef ENABLE_VERIFIER
345 bool patcher_resolve_class(patchref_t *pr)
347 unresolved_class *uc;
349 /* get stuff from the patcher reference */
351 uc = (unresolved_class *) pr->ref;
353 /* resolve the class and check subtype constraints */
355 if (!resolve_class_eager_no_access_check(uc))
358 /* patch back original code */
360 patcher_patch_code(pr);
364 #endif /* ENABLE_VERIFIER */
367 /* patcher_resolve_native_function *********************************************
369 Resolves the native function for a given methodinfo.
370 This function patches one data segment word.
372 *******************************************************************************/
374 bool patcher_resolve_native_function(patchref_t *pr)
380 /* get stuff from the patcher reference */
382 m = (methodinfo *) pr->ref;
383 datap = (uint8_t *) pr->datap;
385 /* resolve native function */
387 if (!(f = native_resolve_function(m)))
390 /* patch native function pointer */
392 *((intptr_t *) datap) = (intptr_t) f;
394 /* synchronize data cache */
396 md_dcacheflush(datap, SIZEOF_VOID_P);
398 /* patch back original code */
400 patcher_patch_code(pr);
407 * These are local overrides for various environment variables in Emacs.
408 * Please do not remove this and leave it at the end of the file, where
409 * Emacs will automagically detect them.
410 * ---------------------------------------------------------------------
413 * indent-tabs-mode: t
417 * vim:noexpandtab:sw=4:ts=4: