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 $
35 #include "mm/memory.h"
36 #include "native/native.h"
38 #include "vm/builtin.h"
39 #include "vm/exceptions.h"
40 #include "vm/initialize.h"
41 #include "vm/resolve.h"
43 #include "vm/jit/asmpart.h"
44 #include "vm/jit/patcher.h"
45 #include "vm/jit/md.h"
46 #include "vm/jit/methodheader.h"
47 #include "vm/jit/stacktrace.h"
49 #include "vmcore/class.h"
50 #include "vmcore/field.h"
51 #include "vmcore/options.h"
52 #include "vmcore/references.h"
56 /* patcher_wrapper *************************************************************
58 Wrapper for all patchers. It also creates the stackframe info
61 If the return value of the patcher function is false, it gets the
62 exception object, clears the exception pointer and returns the
65 *******************************************************************************/
67 java_objectheader *patcher_wrapper(u1 *sp, u1 *pv, u1 *ra)
76 /* define the patcher function */
78 bool (*patcher_function)(u1 *);
80 /* get stuff from the stack */
82 xpc = (u1 *) *((ptrint *) (sp + 6 * 4));
83 /* REG_ITMP3 sp + 5 * 4 */
84 o = (java_objectheader *) *((ptrint *) (sp + 4 * 4));
85 /*mcode = *((u4*) (sp + 3 * 4));*/
86 /*xmcode = *((u4*) (sp + 2 * 4));*/
87 /* unresolved file sp + 1 * 4 */
88 f = (functionptr) *((ptrint *) (sp + 0 * 4));
91 /* calculate and set the new return address */
92 xpc = xpc - PATCHER_CALL_SIZE;
93 *((ptrint *) (sp + 6 * 4)) = (ptrint) xpc;
96 /* cast the passed function to a patcher function */
97 patcher_function = (bool (*)(u1 *)) (ptrint) f;
99 /* enter a monitor on the patching position */
100 PATCHER_MONITORENTER;
102 /* create the stackframeinfo */
104 /* RA is passed as NULL, but the XPC is correct and can be used in
105 stacktrace_create_extern_stackframeinfo for
106 md_codegen_get_pv_from_pc. */
109 fprintf(stderr, "EXT STACKFRAME: sfi=%x pv=%x, sp=%x, xpc=%x\n", &sfi, pv, sp+7*4, xpc);
111 stacktrace_create_extern_stackframeinfo(&sfi, pv, sp + 7 * 4, xpc, xpc);
113 /* call the proper patcher function */
114 result = (patcher_function)(sp);
117 /* remove the stackframeinfo */
118 stacktrace_remove_stackframeinfo(&sfi);
120 /* check for return value and exit accordingly */
121 if (result == false) {
122 e = exceptions_get_and_clear_exception();
128 PATCHER_MARK_PATCHED_MONITOREXIT;
135 static void patcher_patch_back(u1 *sp)
137 u1* xpc = (u1 *) *((ptrint *) (sp + 6 * 4));
138 u4 mcode = *((u4*) (sp + 3 * 4));
139 u4 xmcode = *((u4*) (sp + 2 * 4));
141 *((u4*)(xpc)) = mcode;
142 *((u4*)(xpc+4)) = xmcode;
143 md_icacheflush(xpc, 8);
146 /* patcher_initialize_class ****************************************************
148 Initalizes a given classinfo pointer. This function does not patch
151 *******************************************************************************/
153 bool patcher_initialize_class(u1 *sp)
156 u4 xpc, mcode, xmcode;
158 /* get stuff from the stack */
159 c = (classinfo *) *((ptrint *) (sp + 1 * 4));
161 /* check if the class is initialized */
162 if (!(c->state & CLASS_INITIALIZED))
163 if (!initialize_class(c))
166 /* patch back original code */
167 patcher_patch_back(sp);
172 /* patcher_invokevirtual *******************************************************
175 0x4029bc46: 61ff 0000 00ba bsrl 0x4029bd02
176 0x4029bc4c: 246f 0000 moveal %sp@(0),%a2
177 0x4029bc50: 266a 0000 moveal %a2@(0),%a3
178 0x4029bc54: 246b 0000 moveal %a3@(0),%a2 <-- patch this (0) offset
179 0x4029bc58: 4e92 jsr %a2@
181 *******************************************************************************/
183 bool patcher_invokevirtual(u1 *sp)
186 unresolved_method *um;
190 /* get stuff from the stack */
191 ra = (u1 *) *((ptrint *) (sp + 6 * 4));
192 um = (unresolved_method *) *((ptrint *) (sp + 1 * 4));
194 /* get the fieldinfo */
195 if (!(m = resolve_method_eager(um)))
198 /* patch back original code */
199 patcher_patch_back(sp);
201 /* if we show NOPs, we have to skip them */
202 if (opt_shownops) ra += PATCHER_CALL_SIZE;
204 assert( *((u2*)(ra+8)) == 0x286b);
206 /* patch vftbl index */
207 disp = (OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * m->vftblindex);
208 *((s2 *) (ra + 10)) = disp;
210 /* synchronize instruction cache */
211 md_icacheflush(ra + 10, 2);
216 /* patcher_invokestatic_special ************************************************
221 0x402902bc: 61ff 0000 0076 bsrl 0x40290334
222 0x402902c2: 247c 0000 0000 moveal #0,%a2 <-- this #0
223 0x402902c8: 4e92 jsr %a2@
225 ******************************************************************************/
227 bool patcher_invokestatic_special(u1 *sp)
229 unresolved_method *um;
233 /* get stuff from the stack */
234 disp = *((s4 *) (sp + 6 * 4));
235 um = (unresolved_method *) *((ptrint *) (sp + 1 * 4));
237 /* get the fieldinfo */
238 if (!(m = resolve_method_eager(um)))
241 /* patch back original code */
242 patcher_patch_back(sp);
244 /* patch stubroutine */
245 if (opt_shownops) disp += PATCHER_CALL_SIZE;
247 *((ptrint *) (disp+2)) = (ptrint) m->stubroutine;
249 /* synchronize inst cache */
251 md_icacheflush(disp+2, SIZEOF_VOID_P);
257 /* patcher_resolve_class *******************************************************
259 Resolves a given unresolved_class pointer. This function does not
262 *******************************************************************************/
264 #ifdef ENABLE_VERIFIER
265 bool patcher_resolve_class(u1 *sp)
267 unresolved_class *uc;
271 /* get stuff from the stack */
272 uc = (unresolved_class *) *((ptrint *) (sp + 1 * 4));
273 disp = *((s4 *) (sp + 6 * 4));
275 /* resolve the class */
276 if (!resolve_class(uc, resolveEager, false, &c))
279 /* patch back original code */
280 patcher_patch_back(sp);
284 #endif /* ENABLE_VERIFIER */
286 /* patcher_resolve_classref_to_classinfo ***************************************
288 0x4028f2ca: 2479 0000 0000 moveal 0x00000000,%a2
289 *******************************************************************************/
290 bool patcher_resolve_classref_to_classinfo(u1 *sp)
292 constant_classref *cr;
297 /* get stuff from the stack */
298 cr = (constant_classref *) *((ptrint *) (sp + 1 * 4));
299 disp = *((s4 *) (sp + 6 * 4));
301 /* get the classinfo */
302 if (!(c = resolve_classref_eager(cr)))
305 /* patch back original code */
306 patcher_patch_back(sp);
308 /* patch the classinfo pointer */
309 if (opt_shownops) disp += PATCHER_CALL_SIZE;
310 *((ptrint *) (disp+2)) = (ptrint) c;
312 /* synchronize inst cache */
313 md_icacheflush(disp+2, SIZEOF_VOID_P);
318 /* patcher_get_putstatic *******************************************************
322 *******************************************************************************/
324 bool patcher_get_putstatic(u1 *sp)
327 unresolved_field *uf;
332 /* get stuff from the stack */
333 uf = (unresolved_field *) *((ptrint *) (sp + 1 * 4));
334 disp = *((s4 *) (sp + 6 * 4));
336 /* get the fieldinfo */
337 if (!(fi = resolve_field_eager(uf)))
340 /* check if the field's class is initialized */
341 if (!(fi->class->state & CLASS_INITIALIZED))
342 if (!initialize_class(fi->class))
345 /* patch back original code */
346 patcher_patch_back(sp);
348 /* patch the field value's address */
349 if (opt_shownops) disp += PATCHER_CALL_SIZE;
350 assert(*((uint16_t*)(disp)) == 0x247c);
351 *((ptrint *) (disp+2)) = (ptrint) &(fi->value);
353 /* synchronize inst cache */
354 md_icacheflush(disp+2, SIZEOF_VOID_P);
359 /* patcher_get_putfield ********************************************************
363 <patched call position>
365 *******************************************************************************/
367 bool patcher_get_putfield(u1 *sp)
370 unresolved_field *uf;
374 ra = (u1 *) *((ptrint *) (sp + 6 * 4));
375 uf = (unresolved_field *) *((ptrint *) (sp + 1 * 4));
377 /* get the fieldinfo */
378 if (!(fi = resolve_field_eager(uf)))
381 /* patch back original code */
382 patcher_patch_back(sp);
384 /* if we show NOPs, we have to skip them */
385 if (opt_shownops) ra += PATCHER_CALL_SIZE;
387 /* patch the field's offset */
388 if (IS_LNG_TYPE(fi->type)) {
390 * 0x40d05bb2: 0x25440000 movel %d4,%a2@(0)
391 * 0x40d05bb6: 0x25430004 movel %d3,%a2@(4)
393 * both 0000 and 0004 have to be patched
396 assert( (fi->offset & 0x0000ffff) == fi->offset );
398 assert( (*((uint32_t*)ra) & 0xffff0000) == *((uint32_t*)ra) );
399 assert( (*((uint32_t*)(ra+4)) & 0xffff0004) == *((uint32_t*)(ra+4)) );
401 *((int16_t *) (ra + 2)) = (int16_t) ((fi->offset) & 0x0000ffff);
402 *((int16_t *) (ra + 6)) = (int16_t) ((fi->offset + 4) & 0x0000ffff);
404 md_icacheflush(ra, 2 * 4);
406 /* Multiple cases here, int, adr, flt and dbl. */
407 if ( (*((uint32_t*)ra) & 0xfff00000) == 0xf2200000 ) {
409 * 0x40d3ddc2: 0xf22944c0 0x0000xxxx fsmoves %a1@(0),%fp1
413 assert( (fi->offset & 0x0000ffff) == fi->offset );
414 assert( (*((uint32_t*)(ra+4)) & 0x0000ffff) == *((uint32_t*)(ra+4)) );
415 *((int16_t*)(ra+4)) = (int16_t)fi->offset;
417 md_icacheflush(ra+4, 1 * 4);
420 * 0x40adb3f6: 0x254d0000 movel %a5,%a2@(0)
424 assert( (*((uint32_t*)ra) & 0xffff0000) == *((uint32_t*)ra) );
425 assert( (fi->offset & 0x0000ffff) == fi->offset );
426 *((int16_t*)(ra+2)) = (int16_t)fi->offset;
428 /* synchronize instruction cache */
429 md_icacheflush(ra, 1 * 4);
435 /* patcher_resolve_classref_to_flags *******************************************
437 CHECKCAST/INSTANCEOF:
441 0x4029b056: 61ff 0000 013e bsrl 0x4029b196
442 0x4029b05c: 263c 0000 0000 movel #0,%d3 <-- patch this #0
443 0x4029b062: 0283 0000 0200 andil #512,%d3
446 0x402a4aa8: 61ff 0000 05c4 bsrl 0x402a506e
447 0x402a4aae: 283c 0000 0000 movel #0,%d4 <-- same here
448 0x402a4ab4: 0284 0000 0200 andil #512,%d4
451 *******************************************************************************/
453 bool patcher_resolve_classref_to_flags(u1 *sp)
455 constant_classref *cr;
459 /* get stuff from the stack */
460 cr = (constant_classref *) *((ptrint *) (sp + 1 * 4));
461 disp = *((s4 *) (sp + 6 * 4));
463 /* get the fieldinfo */
464 if (!(c = resolve_classref_eager(cr)))
467 /* patch back original code */
468 patcher_patch_back(sp);
470 /* patch class flags */
471 if (opt_shownops) disp += PATCHER_CALL_SIZE;
472 assert( (*((u2*)(disp)) == 0x263c) || (*((u2*)(disp)) == 0x283c) );
473 *((s4 *) (disp + 2)) = (s4) c->flags;
475 /* synchronize insn cache */
476 md_icacheflush(disp + 2, SIZEOF_VOID_P);
481 /* patcher_resolve_classref_to_vftbl *******************************************
484 0x4029b094: 61ff 0000 00b4 bsrl 0x4029b14a
485 0x4029b09a: 287c 0000 0000 moveal #0,%a4 <-- patch this #0
486 0x4029b0a0: 2668 0000 moveal %a0@(0),%a3
489 0x402a9300: 61ff 0000 0574 bsrl 0x402a9876
490 0x402a9306: 267c 0000 0000 moveal #0,%a3
491 0x402a930c: 246a 0000 moveal %a2@(0),%a2
494 *******************************************************************************/
496 bool patcher_resolve_classref_to_vftbl(u1 *sp)
498 constant_classref *cr;
502 /* get stuff from the stack */
503 cr = (constant_classref *) *((ptrint *) (sp + 1 * 4));
504 disp = *((s4 *) (sp + 6 * 4));
506 /* get the fieldinfo */
507 if (!(c = resolve_classref_eager(cr)))
510 /* patch back original code */
511 patcher_patch_back(sp);
513 /* patch super class' vftbl */
514 if (opt_shownops) disp += PATCHER_CALL_SIZE;
515 assert( (*((u2*)disp) == 0x287c) || (*((u2*)disp)== 0x267c) );
517 *((s4 *) (disp+2)) = (s4) c->vftbl;
519 /* synchronize insin cache */
520 md_icacheflush(disp+2, SIZEOF_VOID_P);
525 /* patcher_instanceof_interface ************************************************
529 0x402a92da: 61ff 0000 05c0 bsrl 0x402a989c
530 0x402a92e0: 246a 0000 moveal %a2@(0),%a2
531 0x402a92e4: 282a 0010 movel %a2@(16),%d4
532 0x402a92e8: d8bc 0000 0000 addl #0,%d4 <-- this const
533 0x402a92ee: 4a84 tstl %d4
534 0x402a92f0: 6e0a bles 0x402a92fc
535 0x402a92f2: 246a 0000 moveal %a2@(0),%a2 <-- this offset
537 *******************************************************************************/
539 bool patcher_instanceof_interface(u1 *sp)
542 constant_classref *cr;
546 /* get stuff from the stack */
548 ra = (u1 *) *((ptrint *) (sp + 6 * 4));
549 cr = (constant_classref *) *((ptrint *) (sp + 1 * 4));
551 /* get the fieldinfo */
552 if (!(c = resolve_classref_eager(cr)))
555 /* patch back original code */
556 patcher_patch_back(sp);
558 /* if we show NOPs, we have to skip them */
559 if (opt_shownops) ra += PATCHER_CALL_SIZE;
561 /* patch super class index */
563 assert( *((u2*)(ra + 8)) == 0xd8bc );
564 *((s4 *) (ra + 10 )) = disp;
566 disp = OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*);
568 assert( (s2)disp == disp);
569 assert ( *((s2*)(ra+18)) == 0x246a );
571 *((s2 *) (ra + 20)) = disp;
573 /* synchronize instruction cache */
574 md_icacheflush(ra + 10, 12);
579 /* patcher_checkcast_interface *************************************************
581 0x402a9400: 61ff 0000 03b6 bsrl 0x402a97b8
582 0x402a9406: 266a 0000 moveal %a2@(0),%a3
583 0x402a940a: 282b 0010 movel %a3@(16),%d4
584 0x402a940e: d8bc 0000 0000 addl #0,%d4 <-- this 0
585 0x402a9414: 4a84 tstl %d4
586 0x402a9416: 6e02 bgts 0x402a941a
588 0x402a9418: 4afc illegal
589 0x402a941a: 286b 0000 moveal %a3@(0),%a4 <-- and this 0 offset
591 *******************************************************************************/
593 bool patcher_checkcast_interface(u1 *sp)
596 constant_classref *cr;
600 /* get stuff from the stack */
601 ra = (u1 *) *((ptrint *) (sp + 6 * 4));
602 cr = (constant_classref *) *((ptrint *) (sp + 1 * 4));
604 /* get the fieldinfo */
605 if (!(c = resolve_classref_eager(cr)))
608 /* patch back original code */
609 patcher_patch_back(sp);
611 /* if we show NOPs, we have to skip them */
612 if (opt_shownops) ra += PATCHER_CALL_SIZE;
614 /* patch super class index */
616 assert ( *((u2 *)(ra + 8)) == 0xd8bc );
617 *((s4 *) (ra + 10)) = disp;
619 disp = OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*);
620 assert( *((u2 *)(ra + 22)) == 0x286b );
621 assert( (s2)disp == disp);
622 *((s2 *) (ra + 24)) = disp;
624 /* synchronize instruction cache */
625 md_icacheflush(ra + 10, 16);
630 /* patcher_resolve_native_function *********************************************
634 *******************************************************************************/
636 #if !defined(WITH_STATIC_CLASSPATH)
637 bool patcher_resolve_native_function(u1 *sp)
643 /* get stuff from the stack */
644 m = (methodinfo *) *((ptrint *) (sp + 1 * 4));
645 disp = *((s4 *) (sp + 6 * 4));
647 /* resolve native function */
648 if (!(f = native_resolve_function(m)))
651 /* patch back original code */
652 patcher_patch_back(sp);
654 /* patch native function pointer */
655 if (opt_shownops) disp += PATCHER_CALL_SIZE;
656 *((ptrint *) (disp + 2)) = (ptrint) f;
658 /* synchronize data cache */
659 md_icacheflush(disp + 2, SIZEOF_VOID_P);
663 #endif /* !defined(WITH_STATIC_CLASSPATH) */
666 /* patcher_invokeinterface *****************************************************
669 0x40adb03e: moveal %a2@(0),%a3 0x266a0000 <-- no patching
670 0x40adb042: moveal %a3@(0),%a3 0x266b0000 <-- patch this 0000
671 0x40adb046: moveal %a3@(0),%a4 0xxxxx0000 <-- patch this 0000
672 0x40adb04a: jsr %a4@ 0xxxxx
675 *******************************************************************************/
677 bool patcher_invokeinterface(u1 *sp)
680 unresolved_method *um;
684 /* get stuff from the stack */
685 ra = (u1 *) *((ptrint *) (sp + 6 * 4));
686 um = (unresolved_method *) *((ptrint *) (sp + 1 * 4));
689 /* get the fieldinfo */
690 if (!(m = resolve_method_eager(um)))
693 /* patch back original code */
694 patcher_patch_back(sp);
696 /* if we show NOPs, we have to skip them */
697 if (opt_shownops) ra += PATCHER_CALL_SIZE;
698 assert( *((uint32_t*)ra) == 0x246f0000 );
700 /* patch interfacetable index (first #0) */
701 disp = OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr*) * m->class->index;
702 /* XXX this disp is negative, check!
703 * assert( (disp & 0x0000ffff) == disp);*/
704 *((uint16_t *) (ra + 5 * 2)) = disp;
706 /* patch method offset (second #0) */
707 disp = sizeof(methodptr) * (m - m->class->methods);
708 assert( (disp & 0x0000ffff) == disp);
709 *((uint16_t *) (ra + 7 * 2)) = disp;
711 /* synchronize instruction cache */
712 md_icacheflush(ra + 5 * 2, 2 * 2);
717 * These are local overrides for various environment variables in Emacs.
718 * Please do not remove this and leave it at the end of the file, where
719 * Emacs will automagically detect them.
720 * ---------------------------------------------------------------------
723 * indent-tabs-mode: t
727 * vim:noexpandtab:sw=4:ts=4: