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 "threads/lock-common.h"
39 #include "toolbox/list.h"
40 #include "toolbox/logging.h" /* XXX remove me! */
42 #include "vm/exceptions.h"
43 #include "vm/vm.h" /* for vm_abort */
45 #include "vm/jit/code.h"
46 #include "vm/jit/jit.h"
47 #include "vm/jit/patcher-common.h"
49 #include "vmcore/options.h"
52 /* patcher_list_create *********************************************************
56 *******************************************************************************/
58 void patcher_list_create(codeinfo *code)
60 code->patchers = list_create(OFFSET(patchref_t, linkage));
64 /* patcher_list_reset **********************************************************
68 *******************************************************************************/
70 void patcher_list_reset(codeinfo *code)
74 /* free all elements of the list */
76 while((pr = list_first(code->patchers)) != NULL) {
77 list_remove(code->patchers, pr);
81 #if defined(ENABLE_STATISTICS)
83 size_patchref -= sizeof(patchref_t);
88 /* patcher_list_free ***********************************************************
92 *******************************************************************************/
94 void patcher_list_free(codeinfo *code)
96 /* free all elements of the list */
98 patcher_list_reset(code);
100 /* free the list itself */
102 FREE(code->patchers, list_t);
106 /* patcher_list_find ***********************************************************
110 NOTE: Caller should hold the patcher list lock or maintain
111 exclusive access otherwise.
113 *******************************************************************************/
115 static patchref_t *patcher_list_find(codeinfo *code, u1 *pc)
119 /* walk through all patcher references for the given codeinfo */
121 pr = list_first_unsynced(code->patchers);
124 if (pr->mpc == (ptrint) pc)
127 pr = list_next_unsynced(code->patchers, pr);
134 /* patcher_add_patch_ref *******************************************************
136 Appends a new patcher reference to the list of patching positions.
138 *******************************************************************************/
140 void patcher_add_patch_ref(jitdata *jd, functionptr patcher, voidptr ref,
150 patchmpc = cd->mcodeptr - cd->mcodebase;
153 if (patcher_list_find(code, (u1 *) (intptr_t) patchmpc) != NULL)
154 vm_abort("patcher_add_patch_ref: different patchers at same position.");
157 /* allocate patchref on heap (at least freed together with codeinfo) */
159 pr = NEW(patchref_t);
160 list_add_first_unsynced(code->patchers, pr);
162 #if defined(ENABLE_STATISTICS)
164 size_patchref += sizeof(patchref_t);
167 /* set patcher information (mpc is resolved later) */
171 pr->patcher = patcher;
176 /* Generate NOPs for opt_shownops. */
183 /* patcher_handler *************************************************************
187 *******************************************************************************/
189 /*#define TRACE_PATCHER*/
192 /* XXX this indent is not thread safe! */
193 /* XXX if you want it thread safe, place patcher_depth in threadobject! */
194 static int patcher_depth = 0;
195 # define TRACE_PATCHER_INDENT for (i=0; i<patcher_depth; i++) printf("\t")
198 java_handle_t *patcher_handler(u1 *pc)
208 /* define the patcher function */
210 bool (*patcher_function)(patchref_t *);
212 /* search the codeinfo for the given PC */
214 code = code_find_codeinfo_for_pc(pc);
217 /* enter a monitor on the patcher list */
219 LOCK_MONITOR_ENTER(code->patchers);
221 /* search the patcher information for the given PC */
223 pr = patcher_list_find(code, pc);
226 vm_abort("patcher_handler: Unable to find patcher reference.");
229 log_println("patcher_handler: double-patching detected!");
230 LOCK_MONITOR_EXIT(code->patchers);
235 TRACE_PATCHER_INDENT; printf("patching in "); method_print(code->m); printf("\n");
236 TRACE_PATCHER_INDENT; printf("\texception program counter = %p\n", (void *) pr->mpc);
237 TRACE_PATCHER_INDENT; printf("\tmcodes before = "); for (i=0; i<5; i++) printf("0x%08x ", *((u4 *) pr->mpc + i)); printf("\n");
239 assert(patcher_depth > 0);
242 /* cast the passed function to a patcher function */
244 patcher_function = (bool (*)(patchref_t *)) (ptrint) pr->patcher;
246 /* call the proper patcher function */
248 result = (patcher_function)(pr);
251 assert(patcher_depth > 0);
253 TRACE_PATCHER_INDENT; printf("\tmcodes after = "); for (i=0; i<5; i++) printf("0x%08x ", *((u4 *) pr->mpc + i)); printf("\n");
254 if (result == false) {
255 TRACE_PATCHER_INDENT; printf("\tPATCHER EXCEPTION!\n");
259 /* check for return value and exit accordingly */
261 if (result == false) {
262 e = exceptions_get_and_clear_exception();
264 LOCK_MONITOR_EXIT(code->patchers);
269 pr->done = true; /* XXX this is only preliminary to prevent double-patching */
271 LOCK_MONITOR_EXIT(code->patchers);
278 * These are local overrides for various environment variables in Emacs.
279 * Please do not remove this and leave it at the end of the file, where
280 * Emacs will automagically detect them.
281 * ---------------------------------------------------------------------
284 * indent-tabs-mode: t
288 * vim:noexpandtab:sw=4:ts=4: