1 /* src/vm/jit/m68k/patcher.c - m68k patcher functions
3 Copyright (C) 1996-2005, 2006, 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
34 #include "mm/memory.h"
35 #include "native/native.h"
37 #include "vm/builtin.h"
38 #include "vm/exceptions.h"
39 #include "vm/initialize.h"
40 #include "vm/resolve.h"
42 #include "vm/jit/asmpart.h"
43 #include "vm/jit/patcher-common.h"
44 #include "vm/jit/md.h"
45 #include "vm/jit/stacktrace.h"
47 #include "vmcore/class.h"
48 #include "vmcore/field.h"
49 #include "vmcore/options.h"
50 #include "vmcore/references.h"
54 /* patcher_wrapper *************************************************************
56 Wrapper for all patchers. It also creates the stackframe info
59 If the return value of the patcher function is false, it gets the
60 exception object, clears the exception pointer and returns the
63 *******************************************************************************/
66 java_objectheader *patcher_wrapper(u1 *sp, u1 *pv, u1 *ra)
75 /* define the patcher function */
77 bool (*patcher_function)(u1 *);
79 /* get stuff from the stack */
81 xpc = (u1 *) *((ptrint *) (sp + 6 * 4));
82 /* REG_ITMP3 sp + 5 * 4 */
83 o = (java_objectheader *) *((ptrint *) (sp + 4 * 4));
84 /*mcode = *((u4*) (sp + 3 * 4));*/
85 /*xmcode = *((u4*) (sp + 2 * 4));*/
86 /* unresolved file sp + 1 * 4 */
87 f = (functionptr) *((ptrint *) (sp + 0 * 4));
90 /* calculate and set the new return address */
91 xpc = xpc - PATCHER_CALL_SIZE;
92 *((ptrint *) (sp + 6 * 4)) = (ptrint) xpc;
95 /* cast the passed function to a patcher function */
96 patcher_function = (bool (*)(u1 *)) (ptrint) f;
98 /* enter a monitor on the patching position */
101 /* create the stackframeinfo */
103 /* RA is passed as NULL, but the XPC is correct and can be used in
104 stacktrace_stackframeinfo_add for md_codegen_get_pv_from_pc. */
107 fprintf(stderr, "EXT STACKFRAME: sfi=%x pv=%x, sp=%x, xpc=%x\n", &sfi, pv, sp+7*4, xpc);
109 stacktrace_stackframeinfo_add(&sfi, pv, sp + 7 * 4, xpc, xpc);
111 /* call the proper patcher function */
112 result = (patcher_function)(sp);
115 /* remove the stackframeinfo */
116 stacktrace_stackframeinfo_remove(&sfi);
118 /* check for return value and exit accordingly */
119 if (result == false) {
120 e = exceptions_get_and_clear_exception();
126 PATCHER_MARK_PATCHED_MONITOREXIT;
133 #define PATCH_BACK_ORIGINAL_MCODE *((u8*)(pr->mpc)) = pr->mcode
135 /* patcher_initialize_class ****************************************************
137 just patch back original code
139 *******************************************************************************/
142 void patcher_patch_code(patchref_t *pr)
145 u1* xpc = (u1 *) *((ptrint *) (sp + 6 * 4));
146 u4 mcode = *((u4*) (sp + 3 * 4));
147 u4 xmcode = *((u4*) (sp + 2 * 4));
149 *((u4*)(xpc)) = mcode;
150 *((u4*)(xpc+4)) = xmcode;
153 PATCH_BACK_ORIGINAL_MCODE;
154 md_icacheflush((void*)pr->mpc, 8);
160 /* patcher_initialize_class ****************************************************
162 Initalizes a given classinfo pointer. This function does not patch
165 *******************************************************************************/
167 bool patcher_initialize_class(patchref_t *pr)
170 u4 xpc, mcode, xmcode;
172 /* get stuff from the stack */
173 c = (classinfo *) *((ptrint *) (sp + 1 * 4));
175 /* check if the class is initialized */
176 if (!(c->state & CLASS_INITIALIZED))
177 if (!initialize_class(c))
180 /* patch back original code */
181 patcher_patch_back(sp);
187 /* patcher_invokevirtual *******************************************************
190 0x4029bc46: 61ff 0000 00ba bsrl 0x4029bd02
191 0x4029bc4c: 246f 0000 moveal %sp@(0),%a2
192 0x4029bc50: 266a 0000 moveal %a2@(0),%a3
193 0x4029bc54: 246b 0000 moveal %a3@(0),%a2 <-- patch this (0) offset
194 0x4029bc58: 4e92 jsr %a2@
196 *******************************************************************************/
198 bool patcher_invokevirtual(patchref_t *pr)
201 unresolved_method *um;
205 /* get stuff from the stack */
207 um = (unresolved_method *) pr->ref;
209 /* get the fieldinfo */
210 if (!(m = resolve_method_eager(um)))
213 /* patch back original code */
214 PATCH_BACK_ORIGINAL_MCODE;
216 /* if we show NOPs, we have to skip them */
217 if (opt_shownops) ra += PATCHER_CALL_SIZE;
219 assert( *((u2*)(ra+8)) == 0x286b);
221 /* patch vftbl index */
222 disp = (OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * m->vftblindex);
223 *((s2 *) (ra + 10)) = disp;
225 /* synchronize instruction cache */
226 md_icacheflush(ra + 10, 2);
231 /* patcher_invokestatic_special ************************************************
236 0x402902bc: 61ff 0000 0076 bsrl 0x40290334
237 0x402902c2: 247c 0000 0000 moveal #0,%a2 <-- this #0
238 0x402902c8: 4e92 jsr %a2@
240 ******************************************************************************/
242 bool patcher_invokestatic_special(patchref_t *pr)
244 unresolved_method *um;
248 /* get stuff from the stack */
250 um = (unresolved_method *) pr->ref;
252 /* get the fieldinfo */
253 if (!(m = resolve_method_eager(um)))
256 /* patch back original code */
257 PATCH_BACK_ORIGINAL_MCODE;
259 /* patch stubroutine */
260 if (opt_shownops) disp += PATCHER_CALL_SIZE;
262 *((ptrint *) (disp+2)) = (ptrint) m->stubroutine;
264 /* synchronize inst cache */
266 md_icacheflush((void*)(disp+2), SIZEOF_VOID_P);
273 /* patcher_resolve_class *******************************************************
275 Resolves a given unresolved_class pointer. This function does not
278 *******************************************************************************/
280 #ifdef ENABLE_VERIFIER
281 bool patcher_resolve_class(patchref_t *pr)
283 unresolved_class *uc;
287 /* get stuff from the stack */
288 uc = (unresolved_class *) *((ptrint *) (sp + 1 * 4));
289 disp = *((s4 *) (sp + 6 * 4));
291 /* resolve the class */
292 if (!resolve_class(uc, resolveEager, false, &c))
295 /* patch back original code */
296 PATCH_BACK_ORIGINAL_MCODE;
300 #endif /* ENABLE_VERIFIER */
303 /* patcher_resolve_classref_to_classinfo ***************************************
305 0x4028f2ca: 2479 0000 0000 moveal 0x00000000,%a2
306 *******************************************************************************/
307 bool patcher_resolve_classref_to_classinfo(patchref_t *pr)
309 constant_classref *cr;
314 /* get stuff from the stack */
315 cr = (constant_classref *) pr->ref;
318 /* get the classinfo */
319 if (!(c = resolve_classref_eager(cr)))
322 /* patch back original code */
323 PATCH_BACK_ORIGINAL_MCODE;
325 /* patch the classinfo pointer */
326 if (opt_shownops) disp += PATCHER_CALL_SIZE;
327 *((ptrint *) (disp+2)) = (ptrint) c;
329 /* synchronize inst cache */
330 md_icacheflush(disp+2, SIZEOF_VOID_P);
335 /* patcher_get_putstatic *******************************************************
339 *******************************************************************************/
341 bool patcher_get_putstatic(patchref_t *pr)
343 unresolved_field *uf;
347 /* get stuff from the stack */
348 uf = (unresolved_field *) pr->ref;
351 /* get the fieldinfo */
352 if (!(fi = resolve_field_eager(uf)))
355 /* check if the field's class is initialized */
356 if (!(fi->class->state & CLASS_INITIALIZED))
357 if (!initialize_class(fi->class))
360 /* patch back original code */
361 PATCH_BACK_ORIGINAL_MCODE;
363 /* patch the field value's address */
364 if (opt_shownops) disp += PATCHER_CALL_SIZE;
365 assert(*((uint16_t*)(disp)) == 0x247c);
366 *((intptr_t *) (disp+2)) = (intptr_t) fi->value;
368 /* synchronize inst cache */
369 md_icacheflush((void*)(disp+2), SIZEOF_VOID_P);
374 /* patcher_get_putfield ********************************************************
378 <patched call position>
380 *******************************************************************************/
382 bool patcher_get_putfield(patchref_t *pr)
385 unresolved_field *uf;
389 uf = (unresolved_field *) pr->ref;
391 /* get the fieldinfo */
392 if (!(fi = resolve_field_eager(uf)))
395 /* patch back original code */
396 PATCH_BACK_ORIGINAL_MCODE;
398 /* if we show NOPs, we have to skip them */
399 if (opt_shownops) ra += PATCHER_CALL_SIZE;
401 /* patch the field's offset */
402 if (IS_LNG_TYPE(fi->type)) {
404 * 0x40d05bb2: 0x25440000 movel %d4,%a2@(0)
405 * 0x40d05bb6: 0x25430004 movel %d3,%a2@(4)
407 * both 0000 and 0004 have to be patched
410 assert( (fi->offset & 0x0000ffff) == fi->offset );
412 assert( (*((uint32_t*)ra) & 0xffff0000) == *((uint32_t*)ra) );
413 assert( (*((uint32_t*)(ra+4)) & 0xffff0004) == *((uint32_t*)(ra+4)) );
415 *((int16_t *) (ra + 2)) = (int16_t) ((fi->offset) & 0x0000ffff);
416 *((int16_t *) (ra + 6)) = (int16_t) ((fi->offset + 4) & 0x0000ffff);
418 md_icacheflush(ra, 2 * 4);
420 /* Multiple cases here, int, adr, flt and dbl. */
421 if ( (*((uint32_t*)ra) & 0xfff00000) == 0xf2200000 ) {
423 * 0x40d3ddc2: 0xf22944c0 0x0000xxxx fsmoves %a1@(0),%fp1
427 assert( (fi->offset & 0x0000ffff) == fi->offset );
428 assert( (*((uint32_t*)(ra+4)) & 0x0000ffff) == *((uint32_t*)(ra+4)) );
429 *((int16_t*)(ra+4)) = (int16_t)fi->offset;
431 md_icacheflush(ra+4, 1 * 4);
434 * 0x40adb3f6: 0x254d0000 movel %a5,%a2@(0)
438 assert( (*((uint32_t*)ra) & 0xffff0000) == *((uint32_t*)ra) );
439 assert( (fi->offset & 0x0000ffff) == fi->offset );
440 *((int16_t*)(ra+2)) = (int16_t)fi->offset;
442 /* synchronize instruction cache */
443 md_icacheflush(ra, 1 * 4);
449 /* patcher_resolve_classref_to_flags *******************************************
451 CHECKCAST/INSTANCEOF:
455 0x4029b056: 61ff 0000 013e bsrl 0x4029b196
456 0x4029b05c: 263c 0000 0000 movel #0,%d3 <-- patch this #0
457 0x4029b062: 0283 0000 0200 andil #512,%d3
460 0x402a4aa8: 61ff 0000 05c4 bsrl 0x402a506e
461 0x402a4aae: 283c 0000 0000 movel #0,%d4 <-- same here
462 0x402a4ab4: 0284 0000 0200 andil #512,%d4
465 *******************************************************************************/
467 bool patcher_resolve_classref_to_flags(patchref_t *pr)
469 constant_classref *cr;
473 /* get stuff from the stack */
474 cr = (constant_classref *) pr->ref;
477 /* get the fieldinfo */
478 if (!(c = resolve_classref_eager(cr)))
481 /* patch back original code */
482 PATCH_BACK_ORIGINAL_MCODE;
484 /* patch class flags */
485 if (opt_shownops) disp += PATCHER_CALL_SIZE;
486 assert( (*((u2*)(disp)) == 0x263c) || (*((u2*)(disp)) == 0x283c) );
487 *((s4 *) (disp + 2)) = (s4) c->flags;
489 /* synchronize insn cache */
490 md_icacheflush((void*)(disp + 2), SIZEOF_VOID_P);
495 /* patcher_resolve_classref_to_vftbl *******************************************
498 0x4029b094: 61ff 0000 00b4 bsrl 0x4029b14a
499 0x4029b09a: 287c 0000 0000 moveal #0,%a4 <-- patch this #0
500 0x4029b0a0: 2668 0000 moveal %a0@(0),%a3
503 0x402a9300: 61ff 0000 0574 bsrl 0x402a9876
504 0x402a9306: 267c 0000 0000 moveal #0,%a3
505 0x402a930c: 246a 0000 moveal %a2@(0),%a2
508 *******************************************************************************/
510 bool patcher_resolve_classref_to_vftbl(patchref_t *pr)
512 constant_classref *cr;
516 /* get stuff from the stack */
517 cr = (constant_classref *) pr->ref;
520 /* get the fieldinfo */
521 if (!(c = resolve_classref_eager(cr)))
524 /* patch back original code */
525 PATCH_BACK_ORIGINAL_MCODE;
527 /* patch super class' vftbl */
528 if (opt_shownops) disp += PATCHER_CALL_SIZE;
529 assert( (*((u2*)disp) == 0x287c) || (*((u2*)disp)== 0x267c) );
531 *((s4 *) (disp+2)) = (s4) c->vftbl;
533 /* synchronize insin cache */
534 md_icacheflush((void*)(disp+2), SIZEOF_VOID_P);
539 /* patcher_instanceof_interface ************************************************
543 0x402a92da: 61ff 0000 05c0 bsrl 0x402a989c
544 0x402a92e0: 246a 0000 moveal %a2@(0),%a2
545 0x402a92e4: 282a 0010 movel %a2@(16),%d4
546 0x402a92e8: d8bc 0000 0000 addl #0,%d4 <-- this const
547 0x402a92ee: 4a84 tstl %d4
548 0x402a92f0: 6e0a bles 0x402a92fc
549 0x402a92f2: 246a 0000 moveal %a2@(0),%a2 <-- this offset
551 *******************************************************************************/
553 bool patcher_instanceof_interface(patchref_t *pr)
556 constant_classref *cr;
560 /* get stuff from the stack */
563 cr = (constant_classref *) pr->ref;
565 /* get the fieldinfo */
566 if (!(c = resolve_classref_eager(cr)))
569 /* patch back original code */
570 PATCH_BACK_ORIGINAL_MCODE;
572 /* if we show NOPs, we have to skip them */
573 if (opt_shownops) ra += PATCHER_CALL_SIZE;
575 /* patch super class index */
577 assert( *((u2*)(ra + 8)) == 0xd8bc );
578 *((s4 *) (ra + 10 )) = disp;
580 disp = OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*);
582 assert( (s2)disp == disp);
583 assert ( *((s2*)(ra+18)) == 0x246a );
585 *((s2 *) (ra + 20)) = disp;
587 /* synchronize instruction cache */
588 md_icacheflush((void*)(ra + 10), 12);
593 /* patcher_checkcast_interface *************************************************
595 0x402a9400: 61ff 0000 03b6 bsrl 0x402a97b8
596 0x402a9406: 266a 0000 moveal %a2@(0),%a3
597 0x402a940a: 282b 0010 movel %a3@(16),%d4
598 0x402a940e: d8bc 0000 0000 addl #0,%d4 <-- this 0
599 0x402a9414: 4a84 tstl %d4
600 0x402a9416: 6e02 bgts 0x402a941a
602 0x402a9418: 4afc illegal
603 0x402a941a: 286b 0000 moveal %a3@(0),%a4 <-- and this 0 offset
605 *******************************************************************************/
607 bool patcher_checkcast_interface(patchref_t *pr)
610 constant_classref *cr;
614 /* get stuff from the stack */
616 cr = (constant_classref *) pr->ref;
618 /* get the fieldinfo */
619 if (!(c = resolve_classref_eager(cr)))
622 /* patch back original code */
623 PATCH_BACK_ORIGINAL_MCODE;
625 /* if we show NOPs, we have to skip them */
626 if (opt_shownops) ra += PATCHER_CALL_SIZE;
628 /* patch super class index */
630 assert ( *((u2 *)(ra + 8)) == 0xd8bc );
631 *((s4 *) (ra + 10)) = disp;
633 disp = OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*);
634 assert( *((u2 *)(ra + 22)) == 0x286b );
635 assert( (s2)disp == disp);
636 *((s2 *) (ra + 24)) = disp;
638 /* synchronize instruction cache */
639 md_icacheflush((void*)(ra + 10), 16);
645 /* patcher_resolve_native_function *********************************************
649 *******************************************************************************/
651 bool patcher_resolve_native_function(patchref_t *pr)
657 /* get stuff from the stack */
658 m = (methodinfo *) pr->ref;
661 /* resolve native function */
662 if (!(f = native_resolve_function(m)))
665 /* patch back original code */
666 PATCH_BACK_ORIGINAL_MCODE;
668 /* patch native function pointer */
669 if (opt_shownops) disp += PATCHER_CALL_SIZE;
670 *((ptrint *) (disp + 2)) = (ptrint) f;
672 /* synchronize data cache */
673 md_icacheflush((void*)(disp + 2), SIZEOF_VOID_P);
679 /* patcher_invokeinterface *****************************************************
682 0x40adb03e: moveal %a2@(0),%a3 0x266a0000 <-- no patching
683 0x40adb042: moveal %a3@(0),%a3 0x266b0000 <-- patch this 0000
684 0x40adb046: moveal %a3@(0),%a4 0xxxxx0000 <-- patch this 0000
685 0x40adb04a: jsr %a4@ 0xxxxx
688 *******************************************************************************/
690 bool patcher_invokeinterface(patchref_t *pr)
693 unresolved_method *um;
697 /* get stuff from the stack */
699 um = (unresolved_method *) pr->ref;
702 /* get the fieldinfo */
703 if (!(m = resolve_method_eager(um)))
706 /* patch back original code */
707 PATCH_BACK_ORIGINAL_MCODE;
709 /* if we show NOPs, we have to skip them */
710 if (opt_shownops) ra += PATCHER_CALL_SIZE;
711 assert( *((uint32_t*)ra) == 0x246f0000 );
713 /* patch interfacetable index (first #0) */
714 disp = OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr*) * m->class->index;
715 /* XXX this disp is negative, check!
716 * assert( (disp & 0x0000ffff) == disp);*/
717 *((uint16_t *) (ra + 5 * 2)) = disp;
719 /* patch method offset (second #0) */
720 disp = sizeof(methodptr) * (m - m->class->methods);
721 assert( (disp & 0x0000ffff) == disp);
722 *((uint16_t *) (ra + 7 * 2)) = disp;
724 /* synchronize instruction cache */
725 md_icacheflush((void*)(ra + 5 * 2), 2 * 2);
730 * These are local overrides for various environment variables in Emacs.
731 * Please do not remove this and leave it at the end of the file, where
732 * Emacs will automagically detect them.
733 * ---------------------------------------------------------------------
736 * indent-tabs-mode: t
740 * vim:noexpandtab:sw=4:ts=4: