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 */
304 /* patcher_resolve_classref_to_classinfo ***************************************
306 0x4028f2ca: 2479 0000 0000 moveal 0x00000000,%a2
307 *******************************************************************************/
308 bool patcher_resolve_classref_to_classinfo(patchref_t *pr)
310 constant_classref *cr;
315 /* get stuff from the stack */
316 cr = (constant_classref *) *((ptrint *) (sp + 1 * 4));
317 disp = *((s4 *) (sp + 6 * 4));
319 /* get the classinfo */
320 if (!(c = resolve_classref_eager(cr)))
323 /* patch back original code */
324 PATCH_BACK_ORIGINAL_MCODE;
326 /* patch the classinfo pointer */
327 if (opt_shownops) disp += PATCHER_CALL_SIZE;
328 *((ptrint *) (disp+2)) = (ptrint) c;
330 /* synchronize inst cache */
331 md_icacheflush(disp+2, SIZEOF_VOID_P);
337 /* patcher_get_putstatic *******************************************************
341 *******************************************************************************/
343 bool patcher_get_putstatic(patchref_t *pr)
345 unresolved_field *uf;
349 /* get stuff from the stack */
350 uf = (unresolved_field *) pr->ref;
353 /* get the fieldinfo */
354 if (!(fi = resolve_field_eager(uf)))
357 /* check if the field's class is initialized */
358 if (!(fi->class->state & CLASS_INITIALIZED))
359 if (!initialize_class(fi->class))
362 /* patch back original code */
363 PATCH_BACK_ORIGINAL_MCODE;
365 /* patch the field value's address */
366 if (opt_shownops) disp += PATCHER_CALL_SIZE;
367 assert(*((uint16_t*)(disp)) == 0x247c);
368 *((intptr_t *) (disp+2)) = (intptr_t) fi->value;
370 /* synchronize inst cache */
371 md_icacheflush((void*)(disp+2), SIZEOF_VOID_P);
376 /* patcher_get_putfield ********************************************************
380 <patched call position>
382 *******************************************************************************/
384 bool patcher_get_putfield(patchref_t *pr)
387 unresolved_field *uf;
391 uf = (unresolved_field *) pr->ref;
393 /* get the fieldinfo */
394 if (!(fi = resolve_field_eager(uf)))
397 /* patch back original code */
398 PATCH_BACK_ORIGINAL_MCODE;
400 /* if we show NOPs, we have to skip them */
401 if (opt_shownops) ra += PATCHER_CALL_SIZE;
403 /* patch the field's offset */
404 if (IS_LNG_TYPE(fi->type)) {
406 * 0x40d05bb2: 0x25440000 movel %d4,%a2@(0)
407 * 0x40d05bb6: 0x25430004 movel %d3,%a2@(4)
409 * both 0000 and 0004 have to be patched
412 assert( (fi->offset & 0x0000ffff) == fi->offset );
414 assert( (*((uint32_t*)ra) & 0xffff0000) == *((uint32_t*)ra) );
415 assert( (*((uint32_t*)(ra+4)) & 0xffff0004) == *((uint32_t*)(ra+4)) );
417 *((int16_t *) (ra + 2)) = (int16_t) ((fi->offset) & 0x0000ffff);
418 *((int16_t *) (ra + 6)) = (int16_t) ((fi->offset + 4) & 0x0000ffff);
420 md_icacheflush(ra, 2 * 4);
422 /* Multiple cases here, int, adr, flt and dbl. */
423 if ( (*((uint32_t*)ra) & 0xfff00000) == 0xf2200000 ) {
425 * 0x40d3ddc2: 0xf22944c0 0x0000xxxx fsmoves %a1@(0),%fp1
429 assert( (fi->offset & 0x0000ffff) == fi->offset );
430 assert( (*((uint32_t*)(ra+4)) & 0x0000ffff) == *((uint32_t*)(ra+4)) );
431 *((int16_t*)(ra+4)) = (int16_t)fi->offset;
433 md_icacheflush(ra+4, 1 * 4);
436 * 0x40adb3f6: 0x254d0000 movel %a5,%a2@(0)
440 assert( (*((uint32_t*)ra) & 0xffff0000) == *((uint32_t*)ra) );
441 assert( (fi->offset & 0x0000ffff) == fi->offset );
442 *((int16_t*)(ra+2)) = (int16_t)fi->offset;
444 /* synchronize instruction cache */
445 md_icacheflush(ra, 1 * 4);
451 /* patcher_resolve_classref_to_flags *******************************************
453 CHECKCAST/INSTANCEOF:
457 0x4029b056: 61ff 0000 013e bsrl 0x4029b196
458 0x4029b05c: 263c 0000 0000 movel #0,%d3 <-- patch this #0
459 0x4029b062: 0283 0000 0200 andil #512,%d3
462 0x402a4aa8: 61ff 0000 05c4 bsrl 0x402a506e
463 0x402a4aae: 283c 0000 0000 movel #0,%d4 <-- same here
464 0x402a4ab4: 0284 0000 0200 andil #512,%d4
467 *******************************************************************************/
469 bool patcher_resolve_classref_to_flags(patchref_t *pr)
471 constant_classref *cr;
475 /* get stuff from the stack */
476 cr = (constant_classref *) pr->ref;
479 /* get the fieldinfo */
480 if (!(c = resolve_classref_eager(cr)))
483 /* patch back original code */
484 PATCH_BACK_ORIGINAL_MCODE;
486 /* patch class flags */
487 if (opt_shownops) disp += PATCHER_CALL_SIZE;
488 assert( (*((u2*)(disp)) == 0x263c) || (*((u2*)(disp)) == 0x283c) );
489 *((s4 *) (disp + 2)) = (s4) c->flags;
491 /* synchronize insn cache */
492 md_icacheflush((void*)(disp + 2), SIZEOF_VOID_P);
497 /* patcher_resolve_classref_to_vftbl *******************************************
500 0x4029b094: 61ff 0000 00b4 bsrl 0x4029b14a
501 0x4029b09a: 287c 0000 0000 moveal #0,%a4 <-- patch this #0
502 0x4029b0a0: 2668 0000 moveal %a0@(0),%a3
505 0x402a9300: 61ff 0000 0574 bsrl 0x402a9876
506 0x402a9306: 267c 0000 0000 moveal #0,%a3
507 0x402a930c: 246a 0000 moveal %a2@(0),%a2
510 *******************************************************************************/
512 bool patcher_resolve_classref_to_vftbl(patchref_t *pr)
514 constant_classref *cr;
518 /* get stuff from the stack */
519 cr = (constant_classref *) pr->ref;
522 /* get the fieldinfo */
523 if (!(c = resolve_classref_eager(cr)))
526 /* patch back original code */
527 PATCH_BACK_ORIGINAL_MCODE;
529 /* patch super class' vftbl */
530 if (opt_shownops) disp += PATCHER_CALL_SIZE;
531 assert( (*((u2*)disp) == 0x287c) || (*((u2*)disp)== 0x267c) );
533 *((s4 *) (disp+2)) = (s4) c->vftbl;
535 /* synchronize insin cache */
536 md_icacheflush((void*)(disp+2), SIZEOF_VOID_P);
541 /* patcher_instanceof_interface ************************************************
545 0x402a92da: 61ff 0000 05c0 bsrl 0x402a989c
546 0x402a92e0: 246a 0000 moveal %a2@(0),%a2
547 0x402a92e4: 282a 0010 movel %a2@(16),%d4
548 0x402a92e8: d8bc 0000 0000 addl #0,%d4 <-- this const
549 0x402a92ee: 4a84 tstl %d4
550 0x402a92f0: 6e0a bles 0x402a92fc
551 0x402a92f2: 246a 0000 moveal %a2@(0),%a2 <-- this offset
553 *******************************************************************************/
555 bool patcher_instanceof_interface(patchref_t *pr)
558 constant_classref *cr;
562 /* get stuff from the stack */
565 cr = (constant_classref *) pr->ref;
567 /* get the fieldinfo */
568 if (!(c = resolve_classref_eager(cr)))
571 /* patch back original code */
572 PATCH_BACK_ORIGINAL_MCODE;
574 /* if we show NOPs, we have to skip them */
575 if (opt_shownops) ra += PATCHER_CALL_SIZE;
577 /* patch super class index */
579 assert( *((u2*)(ra + 8)) == 0xd8bc );
580 *((s4 *) (ra + 10 )) = disp;
582 disp = OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*);
584 assert( (s2)disp == disp);
585 assert ( *((s2*)(ra+18)) == 0x246a );
587 *((s2 *) (ra + 20)) = disp;
589 /* synchronize instruction cache */
590 md_icacheflush((void*)(ra + 10), 12);
595 /* patcher_checkcast_interface *************************************************
597 0x402a9400: 61ff 0000 03b6 bsrl 0x402a97b8
598 0x402a9406: 266a 0000 moveal %a2@(0),%a3
599 0x402a940a: 282b 0010 movel %a3@(16),%d4
600 0x402a940e: d8bc 0000 0000 addl #0,%d4 <-- this 0
601 0x402a9414: 4a84 tstl %d4
602 0x402a9416: 6e02 bgts 0x402a941a
604 0x402a9418: 4afc illegal
605 0x402a941a: 286b 0000 moveal %a3@(0),%a4 <-- and this 0 offset
607 *******************************************************************************/
609 bool patcher_checkcast_interface(patchref_t *pr)
612 constant_classref *cr;
616 /* get stuff from the stack */
618 cr = (constant_classref *) pr->ref;
620 /* get the fieldinfo */
621 if (!(c = resolve_classref_eager(cr)))
624 /* patch back original code */
625 PATCH_BACK_ORIGINAL_MCODE;
627 /* if we show NOPs, we have to skip them */
628 if (opt_shownops) ra += PATCHER_CALL_SIZE;
630 /* patch super class index */
632 assert ( *((u2 *)(ra + 8)) == 0xd8bc );
633 *((s4 *) (ra + 10)) = disp;
635 disp = OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*);
636 assert( *((u2 *)(ra + 22)) == 0x286b );
637 assert( (s2)disp == disp);
638 *((s2 *) (ra + 24)) = disp;
640 /* synchronize instruction cache */
641 md_icacheflush((void*)(ra + 10), 16);
647 /* patcher_resolve_native_function *********************************************
651 *******************************************************************************/
653 bool patcher_resolve_native_function(patchref_t *pr)
659 /* get stuff from the stack */
660 m = (methodinfo *) pr->ref;
663 /* resolve native function */
664 if (!(f = native_resolve_function(m)))
667 /* patch back original code */
668 PATCH_BACK_ORIGINAL_MCODE;
670 /* patch native function pointer */
671 if (opt_shownops) disp += PATCHER_CALL_SIZE;
672 *((ptrint *) (disp + 2)) = (ptrint) f;
674 /* synchronize data cache */
675 md_icacheflush((void*)(disp + 2), SIZEOF_VOID_P);
681 /* patcher_invokeinterface *****************************************************
684 0x40adb03e: moveal %a2@(0),%a3 0x266a0000 <-- no patching
685 0x40adb042: moveal %a3@(0),%a3 0x266b0000 <-- patch this 0000
686 0x40adb046: moveal %a3@(0),%a4 0xxxxx0000 <-- patch this 0000
687 0x40adb04a: jsr %a4@ 0xxxxx
690 *******************************************************************************/
692 bool patcher_invokeinterface(patchref_t *pr)
695 unresolved_method *um;
699 /* get stuff from the stack */
701 um = (unresolved_method *) pr->ref;
704 /* get the fieldinfo */
705 if (!(m = resolve_method_eager(um)))
708 /* patch back original code */
709 PATCH_BACK_ORIGINAL_MCODE;
711 /* if we show NOPs, we have to skip them */
712 if (opt_shownops) ra += PATCHER_CALL_SIZE;
713 assert( *((uint32_t*)ra) == 0x246f0000 );
715 /* patch interfacetable index (first #0) */
716 disp = OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr*) * m->class->index;
717 /* XXX this disp is negative, check!
718 * assert( (disp & 0x0000ffff) == disp);*/
719 *((uint16_t *) (ra + 5 * 2)) = disp;
721 /* patch method offset (second #0) */
722 disp = sizeof(methodptr) * (m - m->class->methods);
723 assert( (disp & 0x0000ffff) == disp);
724 *((uint16_t *) (ra + 7 * 2)) = disp;
726 /* synchronize instruction cache */
727 md_icacheflush((void*)(ra + 5 * 2), 2 * 2);
732 * These are local overrides for various environment variables in Emacs.
733 * Please do not remove this and leave it at the end of the file, where
734 * Emacs will automagically detect them.
735 * ---------------------------------------------------------------------
738 * indent-tabs-mode: t
742 * vim:noexpandtab:sw=4:ts=4: