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
25 $Id: arch.h 5330 2006-09-05 18:43:12Z edwin $
36 #include "mm/memory.h"
37 #include "native/native.h"
39 #include "vm/builtin.h"
40 #include "vm/exceptions.h"
41 #include "vm/initialize.h"
42 #include "vm/resolve.h"
44 #include "vm/jit/asmpart.h"
45 #include "vm/jit/patcher.h"
46 #include "vm/jit/md.h"
47 #include "vm/jit/methodheader.h"
48 #include "vm/jit/stacktrace.h"
50 #include "vmcore/class.h"
51 #include "vmcore/field.h"
52 #include "vmcore/options.h"
53 #include "vmcore/references.h"
57 /* patcher_wrapper *************************************************************
59 Wrapper for all patchers. It also creates the stackframe info
62 If the return value of the patcher function is false, it gets the
63 exception object, clears the exception pointer and returns the
66 *******************************************************************************/
68 java_objectheader *patcher_wrapper(u1 *sp, u1 *pv, u1 *ra)
77 /* define the patcher function */
79 bool (*patcher_function)(u1 *);
81 /* get stuff from the stack */
83 xpc = (u1 *) *((ptrint *) (sp + 6 * 4));
84 /* REG_ITMP3 sp + 5 * 4 */
85 o = (java_objectheader *) *((ptrint *) (sp + 4 * 4));
86 /*mcode = *((u4*) (sp + 3 * 4));*/
87 /*xmcode = *((u4*) (sp + 2 * 4));*/
88 /* unresolved file sp + 1 * 4 */
89 f = (functionptr) *((ptrint *) (sp + 0 * 4));
92 /* calculate and set the new return address */
93 xpc = xpc - PATCHER_CALL_SIZE;
94 *((ptrint *) (sp + 6 * 4)) = (ptrint) xpc;
97 /* cast the passed function to a patcher function */
98 patcher_function = (bool (*)(u1 *)) (ptrint) f;
100 /* enter a monitor on the patching position */
101 PATCHER_MONITORENTER;
103 /* create the stackframeinfo */
105 /* RA is passed as NULL, but the XPC is correct and can be used in
106 stacktrace_create_extern_stackframeinfo for
107 md_codegen_get_pv_from_pc. */
110 fprintf(stderr, "EXT STACKFRAME: sfi=%x pv=%x, sp=%x, xpc=%x\n", &sfi, pv, sp+7*4, xpc);
112 stacktrace_create_extern_stackframeinfo(&sfi, pv, sp + 7 * 4, xpc, xpc);
114 /* call the proper patcher function */
115 result = (patcher_function)(sp);
118 /* remove the stackframeinfo */
119 stacktrace_remove_stackframeinfo(&sfi);
121 /* check for return value and exit accordingly */
122 if (result == false) {
123 e = exceptions_get_and_clear_exception();
129 PATCHER_MARK_PATCHED_MONITOREXIT;
136 static void patcher_patch_back(u1 *sp)
138 u1* xpc = (u1 *) *((ptrint *) (sp + 6 * 4));
139 u4 mcode = *((u4*) (sp + 3 * 4));
140 u4 xmcode = *((u4*) (sp + 2 * 4));
142 *((u4*)(xpc)) = mcode;
143 *((u4*)(xpc+4)) = xmcode;
144 md_icacheflush(xpc, 8);
147 /* patcher_initialize_class ****************************************************
149 Initalizes a given classinfo pointer. This function does not patch
152 *******************************************************************************/
154 bool patcher_initialize_class(u1 *sp)
157 u4 xpc, mcode, xmcode;
159 /* get stuff from the stack */
160 c = (classinfo *) *((ptrint *) (sp + 1 * 4));
162 /* check if the class is initialized */
163 if (!(c->state & CLASS_INITIALIZED))
164 if (!initialize_class(c))
167 /* patch back original code */
168 patcher_patch_back(sp);
173 /* patcher_invokevirtual *******************************************************
176 0x4029bc46: 61ff 0000 00ba bsrl 0x4029bd02
177 0x4029bc4c: 246f 0000 moveal %sp@(0),%a2
178 0x4029bc50: 266a 0000 moveal %a2@(0),%a3
179 0x4029bc54: 246b 0000 moveal %a3@(0),%a2 <-- patch this (0) offset
180 0x4029bc58: 4e92 jsr %a2@
182 *******************************************************************************/
184 bool patcher_invokevirtual(u1 *sp)
187 unresolved_method *um;
191 /* get stuff from the stack */
192 ra = (u1 *) *((ptrint *) (sp + 6 * 4));
193 um = (unresolved_method *) *((ptrint *) (sp + 1 * 4));
195 /* get the fieldinfo */
196 if (!(m = resolve_method_eager(um)))
199 /* patch back original code */
200 patcher_patch_back(sp);
202 /* if we show NOPs, we have to skip them */
203 if (opt_shownops) ra += PATCHER_CALL_SIZE;
205 assert( *((u2*)(ra+8)) == 0x286b);
207 /* patch vftbl index */
208 disp = (OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * m->vftblindex);
209 *((s2 *) (ra + 10)) = disp;
211 /* synchronize instruction cache */
212 md_icacheflush(ra + 10, 2);
217 /* patcher_invokestatic_special ************************************************
222 0x402902bc: 61ff 0000 0076 bsrl 0x40290334
223 0x402902c2: 247c 0000 0000 moveal #0,%a2 <-- this #0
224 0x402902c8: 4e92 jsr %a2@
226 ******************************************************************************/
228 bool patcher_invokestatic_special(u1 *sp)
230 unresolved_method *um;
234 /* get stuff from the stack */
235 disp = *((s4 *) (sp + 6 * 4));
236 um = (unresolved_method *) *((ptrint *) (sp + 1 * 4));
238 /* get the fieldinfo */
239 if (!(m = resolve_method_eager(um)))
242 /* patch back original code */
243 patcher_patch_back(sp);
245 /* patch stubroutine */
246 if (opt_shownops) disp += PATCHER_CALL_SIZE;
248 *((ptrint *) (disp+2)) = (ptrint) m->stubroutine;
250 /* synchronize inst cache */
252 md_icacheflush(disp+2, SIZEOF_VOID_P);
258 /* patcher_resolve_class *******************************************************
260 Resolves a given unresolved_class pointer. This function does not
263 *******************************************************************************/
265 #ifdef ENABLE_VERIFIER
266 bool patcher_resolve_class(u1 *sp)
268 unresolved_class *uc;
272 /* get stuff from the stack */
273 uc = (unresolved_class *) *((ptrint *) (sp + 1 * 4));
274 disp = *((s4 *) (sp + 6 * 4));
276 /* resolve the class */
277 if (!resolve_class(uc, resolveEager, false, &c))
280 /* patch back original code */
281 patcher_patch_back(sp);
285 #endif /* ENABLE_VERIFIER */
287 /* patcher_resolve_classref_to_classinfo ***************************************
289 0x4028f2ca: 2479 0000 0000 moveal 0x00000000,%a2
290 *******************************************************************************/
291 bool patcher_resolve_classref_to_classinfo(u1 *sp)
293 constant_classref *cr;
298 /* get stuff from the stack */
299 cr = (constant_classref *) *((ptrint *) (sp + 1 * 4));
300 disp = *((s4 *) (sp + 6 * 4));
302 /* get the classinfo */
303 if (!(c = resolve_classref_eager(cr)))
306 /* patch back original code */
307 patcher_patch_back(sp);
309 /* patch the classinfo pointer */
310 if (opt_shownops) disp += PATCHER_CALL_SIZE;
311 *((ptrint *) (disp+2)) = (ptrint) c;
313 /* synchronize inst cache */
314 md_icacheflush(disp+2, SIZEOF_VOID_P);
319 /* patcher_get_putstatic *******************************************************
323 *******************************************************************************/
325 bool patcher_get_putstatic(u1 *sp)
328 unresolved_field *uf;
333 /* get stuff from the stack */
334 uf = (unresolved_field *) *((ptrint *) (sp + 1 * 4));
335 disp = *((s4 *) (sp + 6 * 4));
337 /* get the fieldinfo */
338 if (!(fi = resolve_field_eager(uf)))
341 /* check if the field's class is initialized */
342 if (!(fi->class->state & CLASS_INITIALIZED))
343 if (!initialize_class(fi->class))
346 /* patch back original code */
347 patcher_patch_back(sp);
349 /* patch the field value's address */
350 if (opt_shownops) disp += PATCHER_CALL_SIZE;
351 assert(*((uint16_t*)(disp)) == 0x247c);
352 *((intptr_t *) (disp+2)) = (intptr_t) fi->value;
354 /* synchronize inst cache */
355 md_icacheflush(disp+2, SIZEOF_VOID_P);
360 /* patcher_get_putfield ********************************************************
364 <patched call position>
366 *******************************************************************************/
368 bool patcher_get_putfield(u1 *sp)
371 unresolved_field *uf;
375 ra = (u1 *) *((ptrint *) (sp + 6 * 4));
376 uf = (unresolved_field *) *((ptrint *) (sp + 1 * 4));
378 /* get the fieldinfo */
379 if (!(fi = resolve_field_eager(uf)))
382 /* patch back original code */
383 patcher_patch_back(sp);
385 /* if we show NOPs, we have to skip them */
386 if (opt_shownops) ra += PATCHER_CALL_SIZE;
388 /* patch the field's offset */
389 if (IS_LNG_TYPE(fi->type)) {
391 * 0x40d05bb2: 0x25440000 movel %d4,%a2@(0)
392 * 0x40d05bb6: 0x25430004 movel %d3,%a2@(4)
394 * both 0000 and 0004 have to be patched
397 assert( (fi->offset & 0x0000ffff) == fi->offset );
399 assert( (*((uint32_t*)ra) & 0xffff0000) == *((uint32_t*)ra) );
400 assert( (*((uint32_t*)(ra+4)) & 0xffff0004) == *((uint32_t*)(ra+4)) );
402 *((int16_t *) (ra + 2)) = (int16_t) ((fi->offset) & 0x0000ffff);
403 *((int16_t *) (ra + 6)) = (int16_t) ((fi->offset + 4) & 0x0000ffff);
405 md_icacheflush(ra, 2 * 4);
407 /* Multiple cases here, int, adr, flt and dbl. */
408 if ( (*((uint32_t*)ra) & 0xfff00000) == 0xf2200000 ) {
410 * 0x40d3ddc2: 0xf22944c0 0x0000xxxx fsmoves %a1@(0),%fp1
414 assert( (fi->offset & 0x0000ffff) == fi->offset );
415 assert( (*((uint32_t*)(ra+4)) & 0x0000ffff) == *((uint32_t*)(ra+4)) );
416 *((int16_t*)(ra+4)) = (int16_t)fi->offset;
418 md_icacheflush(ra+4, 1 * 4);
421 * 0x40adb3f6: 0x254d0000 movel %a5,%a2@(0)
425 assert( (*((uint32_t*)ra) & 0xffff0000) == *((uint32_t*)ra) );
426 assert( (fi->offset & 0x0000ffff) == fi->offset );
427 *((int16_t*)(ra+2)) = (int16_t)fi->offset;
429 /* synchronize instruction cache */
430 md_icacheflush(ra, 1 * 4);
436 /* patcher_resolve_classref_to_flags *******************************************
438 CHECKCAST/INSTANCEOF:
442 0x4029b056: 61ff 0000 013e bsrl 0x4029b196
443 0x4029b05c: 263c 0000 0000 movel #0,%d3 <-- patch this #0
444 0x4029b062: 0283 0000 0200 andil #512,%d3
447 0x402a4aa8: 61ff 0000 05c4 bsrl 0x402a506e
448 0x402a4aae: 283c 0000 0000 movel #0,%d4 <-- same here
449 0x402a4ab4: 0284 0000 0200 andil #512,%d4
452 *******************************************************************************/
454 bool patcher_resolve_classref_to_flags(u1 *sp)
456 constant_classref *cr;
460 /* get stuff from the stack */
461 cr = (constant_classref *) *((ptrint *) (sp + 1 * 4));
462 disp = *((s4 *) (sp + 6 * 4));
464 /* get the fieldinfo */
465 if (!(c = resolve_classref_eager(cr)))
468 /* patch back original code */
469 patcher_patch_back(sp);
471 /* patch class flags */
472 if (opt_shownops) disp += PATCHER_CALL_SIZE;
473 assert( (*((u2*)(disp)) == 0x263c) || (*((u2*)(disp)) == 0x283c) );
474 *((s4 *) (disp + 2)) = (s4) c->flags;
476 /* synchronize insn cache */
477 md_icacheflush(disp + 2, SIZEOF_VOID_P);
482 /* patcher_resolve_classref_to_vftbl *******************************************
485 0x4029b094: 61ff 0000 00b4 bsrl 0x4029b14a
486 0x4029b09a: 287c 0000 0000 moveal #0,%a4 <-- patch this #0
487 0x4029b0a0: 2668 0000 moveal %a0@(0),%a3
490 0x402a9300: 61ff 0000 0574 bsrl 0x402a9876
491 0x402a9306: 267c 0000 0000 moveal #0,%a3
492 0x402a930c: 246a 0000 moveal %a2@(0),%a2
495 *******************************************************************************/
497 bool patcher_resolve_classref_to_vftbl(u1 *sp)
499 constant_classref *cr;
503 /* get stuff from the stack */
504 cr = (constant_classref *) *((ptrint *) (sp + 1 * 4));
505 disp = *((s4 *) (sp + 6 * 4));
507 /* get the fieldinfo */
508 if (!(c = resolve_classref_eager(cr)))
511 /* patch back original code */
512 patcher_patch_back(sp);
514 /* patch super class' vftbl */
515 if (opt_shownops) disp += PATCHER_CALL_SIZE;
516 assert( (*((u2*)disp) == 0x287c) || (*((u2*)disp)== 0x267c) );
518 *((s4 *) (disp+2)) = (s4) c->vftbl;
520 /* synchronize insin cache */
521 md_icacheflush(disp+2, SIZEOF_VOID_P);
526 /* patcher_instanceof_interface ************************************************
530 0x402a92da: 61ff 0000 05c0 bsrl 0x402a989c
531 0x402a92e0: 246a 0000 moveal %a2@(0),%a2
532 0x402a92e4: 282a 0010 movel %a2@(16),%d4
533 0x402a92e8: d8bc 0000 0000 addl #0,%d4 <-- this const
534 0x402a92ee: 4a84 tstl %d4
535 0x402a92f0: 6e0a bles 0x402a92fc
536 0x402a92f2: 246a 0000 moveal %a2@(0),%a2 <-- this offset
538 *******************************************************************************/
540 bool patcher_instanceof_interface(u1 *sp)
543 constant_classref *cr;
547 /* get stuff from the stack */
549 ra = (u1 *) *((ptrint *) (sp + 6 * 4));
550 cr = (constant_classref *) *((ptrint *) (sp + 1 * 4));
552 /* get the fieldinfo */
553 if (!(c = resolve_classref_eager(cr)))
556 /* patch back original code */
557 patcher_patch_back(sp);
559 /* if we show NOPs, we have to skip them */
560 if (opt_shownops) ra += PATCHER_CALL_SIZE;
562 /* patch super class index */
564 assert( *((u2*)(ra + 8)) == 0xd8bc );
565 *((s4 *) (ra + 10 )) = disp;
567 disp = OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*);
569 assert( (s2)disp == disp);
570 assert ( *((s2*)(ra+18)) == 0x246a );
572 *((s2 *) (ra + 20)) = disp;
574 /* synchronize instruction cache */
575 md_icacheflush(ra + 10, 12);
580 /* patcher_checkcast_interface *************************************************
582 0x402a9400: 61ff 0000 03b6 bsrl 0x402a97b8
583 0x402a9406: 266a 0000 moveal %a2@(0),%a3
584 0x402a940a: 282b 0010 movel %a3@(16),%d4
585 0x402a940e: d8bc 0000 0000 addl #0,%d4 <-- this 0
586 0x402a9414: 4a84 tstl %d4
587 0x402a9416: 6e02 bgts 0x402a941a
589 0x402a9418: 4afc illegal
590 0x402a941a: 286b 0000 moveal %a3@(0),%a4 <-- and this 0 offset
592 *******************************************************************************/
594 bool patcher_checkcast_interface(u1 *sp)
597 constant_classref *cr;
601 /* get stuff from the stack */
602 ra = (u1 *) *((ptrint *) (sp + 6 * 4));
603 cr = (constant_classref *) *((ptrint *) (sp + 1 * 4));
605 /* get the fieldinfo */
606 if (!(c = resolve_classref_eager(cr)))
609 /* patch back original code */
610 patcher_patch_back(sp);
612 /* if we show NOPs, we have to skip them */
613 if (opt_shownops) ra += PATCHER_CALL_SIZE;
615 /* patch super class index */
617 assert ( *((u2 *)(ra + 8)) == 0xd8bc );
618 *((s4 *) (ra + 10)) = disp;
620 disp = OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*);
621 assert( *((u2 *)(ra + 22)) == 0x286b );
622 assert( (s2)disp == disp);
623 *((s2 *) (ra + 24)) = disp;
625 /* synchronize instruction cache */
626 md_icacheflush(ra + 10, 16);
631 /* patcher_resolve_native_function *********************************************
635 *******************************************************************************/
637 #if !defined(WITH_STATIC_CLASSPATH)
638 bool patcher_resolve_native_function(u1 *sp)
644 /* get stuff from the stack */
645 m = (methodinfo *) *((ptrint *) (sp + 1 * 4));
646 disp = *((s4 *) (sp + 6 * 4));
648 /* resolve native function */
649 if (!(f = native_resolve_function(m)))
652 /* patch back original code */
653 patcher_patch_back(sp);
655 /* patch native function pointer */
656 if (opt_shownops) disp += PATCHER_CALL_SIZE;
657 *((ptrint *) (disp + 2)) = (ptrint) f;
659 /* synchronize data cache */
660 md_icacheflush(disp + 2, SIZEOF_VOID_P);
664 #endif /* !defined(WITH_STATIC_CLASSPATH) */
667 /* patcher_invokeinterface *****************************************************
670 0x40adb03e: moveal %a2@(0),%a3 0x266a0000 <-- no patching
671 0x40adb042: moveal %a3@(0),%a3 0x266b0000 <-- patch this 0000
672 0x40adb046: moveal %a3@(0),%a4 0xxxxx0000 <-- patch this 0000
673 0x40adb04a: jsr %a4@ 0xxxxx
676 *******************************************************************************/
678 bool patcher_invokeinterface(u1 *sp)
681 unresolved_method *um;
685 /* get stuff from the stack */
686 ra = (u1 *) *((ptrint *) (sp + 6 * 4));
687 um = (unresolved_method *) *((ptrint *) (sp + 1 * 4));
690 /* get the fieldinfo */
691 if (!(m = resolve_method_eager(um)))
694 /* patch back original code */
695 patcher_patch_back(sp);
697 /* if we show NOPs, we have to skip them */
698 if (opt_shownops) ra += PATCHER_CALL_SIZE;
699 assert( *((uint32_t*)ra) == 0x246f0000 );
701 /* patch interfacetable index (first #0) */
702 disp = OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr*) * m->class->index;
703 /* XXX this disp is negative, check!
704 * assert( (disp & 0x0000ffff) == disp);*/
705 *((uint16_t *) (ra + 5 * 2)) = disp;
707 /* patch method offset (second #0) */
708 disp = sizeof(methodptr) * (m - m->class->methods);
709 assert( (disp & 0x0000ffff) == disp);
710 *((uint16_t *) (ra + 7 * 2)) = disp;
712 /* synchronize instruction cache */
713 md_icacheflush(ra + 5 * 2, 2 * 2);
718 * These are local overrides for various environment variables in Emacs.
719 * Please do not remove this and leave it at the end of the file, where
720 * Emacs will automagically detect them.
721 * ---------------------------------------------------------------------
724 * indent-tabs-mode: t
728 * vim:noexpandtab:sw=4:ts=4: