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.h"
44 #include "vm/jit/md.h"
45 #include "vm/jit/methodheader.h"
46 #include "vm/jit/stacktrace.h"
48 #include "vmcore/class.h"
49 #include "vmcore/field.h"
50 #include "vmcore/options.h"
51 #include "vmcore/references.h"
55 /* patcher_wrapper *************************************************************
57 Wrapper for all patchers. It also creates the stackframe info
60 If the return value of the patcher function is false, it gets the
61 exception object, clears the exception pointer and returns the
64 *******************************************************************************/
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 static void patcher_patch_back(u1 *sp)
135 u1* xpc = (u1 *) *((ptrint *) (sp + 6 * 4));
136 u4 mcode = *((u4*) (sp + 3 * 4));
137 u4 xmcode = *((u4*) (sp + 2 * 4));
139 *((u4*)(xpc)) = mcode;
140 *((u4*)(xpc+4)) = xmcode;
141 md_icacheflush(xpc, 8);
144 /* patcher_initialize_class ****************************************************
146 Initalizes a given classinfo pointer. This function does not patch
149 *******************************************************************************/
151 bool patcher_initialize_class(u1 *sp)
154 u4 xpc, mcode, xmcode;
156 /* get stuff from the stack */
157 c = (classinfo *) *((ptrint *) (sp + 1 * 4));
159 /* check if the class is initialized */
160 if (!(c->state & CLASS_INITIALIZED))
161 if (!initialize_class(c))
164 /* patch back original code */
165 patcher_patch_back(sp);
170 /* patcher_invokevirtual *******************************************************
173 0x4029bc46: 61ff 0000 00ba bsrl 0x4029bd02
174 0x4029bc4c: 246f 0000 moveal %sp@(0),%a2
175 0x4029bc50: 266a 0000 moveal %a2@(0),%a3
176 0x4029bc54: 246b 0000 moveal %a3@(0),%a2 <-- patch this (0) offset
177 0x4029bc58: 4e92 jsr %a2@
179 *******************************************************************************/
181 bool patcher_invokevirtual(u1 *sp)
184 unresolved_method *um;
188 /* get stuff from the stack */
189 ra = (u1 *) *((ptrint *) (sp + 6 * 4));
190 um = (unresolved_method *) *((ptrint *) (sp + 1 * 4));
192 /* get the fieldinfo */
193 if (!(m = resolve_method_eager(um)))
196 /* patch back original code */
197 patcher_patch_back(sp);
199 /* if we show NOPs, we have to skip them */
200 if (opt_shownops) ra += PATCHER_CALL_SIZE;
202 assert( *((u2*)(ra+8)) == 0x286b);
204 /* patch vftbl index */
205 disp = (OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * m->vftblindex);
206 *((s2 *) (ra + 10)) = disp;
208 /* synchronize instruction cache */
209 md_icacheflush(ra + 10, 2);
214 /* patcher_invokestatic_special ************************************************
219 0x402902bc: 61ff 0000 0076 bsrl 0x40290334
220 0x402902c2: 247c 0000 0000 moveal #0,%a2 <-- this #0
221 0x402902c8: 4e92 jsr %a2@
223 ******************************************************************************/
225 bool patcher_invokestatic_special(u1 *sp)
227 unresolved_method *um;
231 /* get stuff from the stack */
232 disp = *((s4 *) (sp + 6 * 4));
233 um = (unresolved_method *) *((ptrint *) (sp + 1 * 4));
235 /* get the fieldinfo */
236 if (!(m = resolve_method_eager(um)))
239 /* patch back original code */
240 patcher_patch_back(sp);
242 /* patch stubroutine */
243 if (opt_shownops) disp += PATCHER_CALL_SIZE;
245 *((ptrint *) (disp+2)) = (ptrint) m->stubroutine;
247 /* synchronize inst cache */
249 md_icacheflush(disp+2, SIZEOF_VOID_P);
255 /* patcher_resolve_class *******************************************************
257 Resolves a given unresolved_class pointer. This function does not
260 *******************************************************************************/
262 #ifdef ENABLE_VERIFIER
263 bool patcher_resolve_class(u1 *sp)
265 unresolved_class *uc;
269 /* get stuff from the stack */
270 uc = (unresolved_class *) *((ptrint *) (sp + 1 * 4));
271 disp = *((s4 *) (sp + 6 * 4));
273 /* resolve the class */
274 if (!resolve_class(uc, resolveEager, false, &c))
277 /* patch back original code */
278 patcher_patch_back(sp);
282 #endif /* ENABLE_VERIFIER */
284 /* patcher_resolve_classref_to_classinfo ***************************************
286 0x4028f2ca: 2479 0000 0000 moveal 0x00000000,%a2
287 *******************************************************************************/
288 bool patcher_resolve_classref_to_classinfo(u1 *sp)
290 constant_classref *cr;
295 /* get stuff from the stack */
296 cr = (constant_classref *) *((ptrint *) (sp + 1 * 4));
297 disp = *((s4 *) (sp + 6 * 4));
299 /* get the classinfo */
300 if (!(c = resolve_classref_eager(cr)))
303 /* patch back original code */
304 patcher_patch_back(sp);
306 /* patch the classinfo pointer */
307 if (opt_shownops) disp += PATCHER_CALL_SIZE;
308 *((ptrint *) (disp+2)) = (ptrint) c;
310 /* synchronize inst cache */
311 md_icacheflush(disp+2, SIZEOF_VOID_P);
316 /* patcher_get_putstatic *******************************************************
320 *******************************************************************************/
322 bool patcher_get_putstatic(u1 *sp)
325 unresolved_field *uf;
330 /* get stuff from the stack */
331 uf = (unresolved_field *) *((ptrint *) (sp + 1 * 4));
332 disp = *((s4 *) (sp + 6 * 4));
334 /* get the fieldinfo */
335 if (!(fi = resolve_field_eager(uf)))
338 /* check if the field's class is initialized */
339 if (!(fi->class->state & CLASS_INITIALIZED))
340 if (!initialize_class(fi->class))
343 /* patch back original code */
344 patcher_patch_back(sp);
346 /* patch the field value's address */
347 if (opt_shownops) disp += PATCHER_CALL_SIZE;
348 assert(*((uint16_t*)(disp)) == 0x247c);
349 *((intptr_t *) (disp+2)) = (intptr_t) fi->value;
351 /* synchronize inst cache */
352 md_icacheflush(disp+2, SIZEOF_VOID_P);
357 /* patcher_get_putfield ********************************************************
361 <patched call position>
363 *******************************************************************************/
365 bool patcher_get_putfield(u1 *sp)
368 unresolved_field *uf;
372 ra = (u1 *) *((ptrint *) (sp + 6 * 4));
373 uf = (unresolved_field *) *((ptrint *) (sp + 1 * 4));
375 /* get the fieldinfo */
376 if (!(fi = resolve_field_eager(uf)))
379 /* patch back original code */
380 patcher_patch_back(sp);
382 /* if we show NOPs, we have to skip them */
383 if (opt_shownops) ra += PATCHER_CALL_SIZE;
385 /* patch the field's offset */
386 if (IS_LNG_TYPE(fi->type)) {
388 * 0x40d05bb2: 0x25440000 movel %d4,%a2@(0)
389 * 0x40d05bb6: 0x25430004 movel %d3,%a2@(4)
391 * both 0000 and 0004 have to be patched
394 assert( (fi->offset & 0x0000ffff) == fi->offset );
396 assert( (*((uint32_t*)ra) & 0xffff0000) == *((uint32_t*)ra) );
397 assert( (*((uint32_t*)(ra+4)) & 0xffff0004) == *((uint32_t*)(ra+4)) );
399 *((int16_t *) (ra + 2)) = (int16_t) ((fi->offset) & 0x0000ffff);
400 *((int16_t *) (ra + 6)) = (int16_t) ((fi->offset + 4) & 0x0000ffff);
402 md_icacheflush(ra, 2 * 4);
404 /* Multiple cases here, int, adr, flt and dbl. */
405 if ( (*((uint32_t*)ra) & 0xfff00000) == 0xf2200000 ) {
407 * 0x40d3ddc2: 0xf22944c0 0x0000xxxx fsmoves %a1@(0),%fp1
411 assert( (fi->offset & 0x0000ffff) == fi->offset );
412 assert( (*((uint32_t*)(ra+4)) & 0x0000ffff) == *((uint32_t*)(ra+4)) );
413 *((int16_t*)(ra+4)) = (int16_t)fi->offset;
415 md_icacheflush(ra+4, 1 * 4);
418 * 0x40adb3f6: 0x254d0000 movel %a5,%a2@(0)
422 assert( (*((uint32_t*)ra) & 0xffff0000) == *((uint32_t*)ra) );
423 assert( (fi->offset & 0x0000ffff) == fi->offset );
424 *((int16_t*)(ra+2)) = (int16_t)fi->offset;
426 /* synchronize instruction cache */
427 md_icacheflush(ra, 1 * 4);
433 /* patcher_resolve_classref_to_flags *******************************************
435 CHECKCAST/INSTANCEOF:
439 0x4029b056: 61ff 0000 013e bsrl 0x4029b196
440 0x4029b05c: 263c 0000 0000 movel #0,%d3 <-- patch this #0
441 0x4029b062: 0283 0000 0200 andil #512,%d3
444 0x402a4aa8: 61ff 0000 05c4 bsrl 0x402a506e
445 0x402a4aae: 283c 0000 0000 movel #0,%d4 <-- same here
446 0x402a4ab4: 0284 0000 0200 andil #512,%d4
449 *******************************************************************************/
451 bool patcher_resolve_classref_to_flags(u1 *sp)
453 constant_classref *cr;
457 /* get stuff from the stack */
458 cr = (constant_classref *) *((ptrint *) (sp + 1 * 4));
459 disp = *((s4 *) (sp + 6 * 4));
461 /* get the fieldinfo */
462 if (!(c = resolve_classref_eager(cr)))
465 /* patch back original code */
466 patcher_patch_back(sp);
468 /* patch class flags */
469 if (opt_shownops) disp += PATCHER_CALL_SIZE;
470 assert( (*((u2*)(disp)) == 0x263c) || (*((u2*)(disp)) == 0x283c) );
471 *((s4 *) (disp + 2)) = (s4) c->flags;
473 /* synchronize insn cache */
474 md_icacheflush(disp + 2, SIZEOF_VOID_P);
479 /* patcher_resolve_classref_to_vftbl *******************************************
482 0x4029b094: 61ff 0000 00b4 bsrl 0x4029b14a
483 0x4029b09a: 287c 0000 0000 moveal #0,%a4 <-- patch this #0
484 0x4029b0a0: 2668 0000 moveal %a0@(0),%a3
487 0x402a9300: 61ff 0000 0574 bsrl 0x402a9876
488 0x402a9306: 267c 0000 0000 moveal #0,%a3
489 0x402a930c: 246a 0000 moveal %a2@(0),%a2
492 *******************************************************************************/
494 bool patcher_resolve_classref_to_vftbl(u1 *sp)
496 constant_classref *cr;
500 /* get stuff from the stack */
501 cr = (constant_classref *) *((ptrint *) (sp + 1 * 4));
502 disp = *((s4 *) (sp + 6 * 4));
504 /* get the fieldinfo */
505 if (!(c = resolve_classref_eager(cr)))
508 /* patch back original code */
509 patcher_patch_back(sp);
511 /* patch super class' vftbl */
512 if (opt_shownops) disp += PATCHER_CALL_SIZE;
513 assert( (*((u2*)disp) == 0x287c) || (*((u2*)disp)== 0x267c) );
515 *((s4 *) (disp+2)) = (s4) c->vftbl;
517 /* synchronize insin cache */
518 md_icacheflush(disp+2, SIZEOF_VOID_P);
523 /* patcher_instanceof_interface ************************************************
527 0x402a92da: 61ff 0000 05c0 bsrl 0x402a989c
528 0x402a92e0: 246a 0000 moveal %a2@(0),%a2
529 0x402a92e4: 282a 0010 movel %a2@(16),%d4
530 0x402a92e8: d8bc 0000 0000 addl #0,%d4 <-- this const
531 0x402a92ee: 4a84 tstl %d4
532 0x402a92f0: 6e0a bles 0x402a92fc
533 0x402a92f2: 246a 0000 moveal %a2@(0),%a2 <-- this offset
535 *******************************************************************************/
537 bool patcher_instanceof_interface(u1 *sp)
540 constant_classref *cr;
544 /* get stuff from the stack */
546 ra = (u1 *) *((ptrint *) (sp + 6 * 4));
547 cr = (constant_classref *) *((ptrint *) (sp + 1 * 4));
549 /* get the fieldinfo */
550 if (!(c = resolve_classref_eager(cr)))
553 /* patch back original code */
554 patcher_patch_back(sp);
556 /* if we show NOPs, we have to skip them */
557 if (opt_shownops) ra += PATCHER_CALL_SIZE;
559 /* patch super class index */
561 assert( *((u2*)(ra + 8)) == 0xd8bc );
562 *((s4 *) (ra + 10 )) = disp;
564 disp = OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*);
566 assert( (s2)disp == disp);
567 assert ( *((s2*)(ra+18)) == 0x246a );
569 *((s2 *) (ra + 20)) = disp;
571 /* synchronize instruction cache */
572 md_icacheflush(ra + 10, 12);
577 /* patcher_checkcast_interface *************************************************
579 0x402a9400: 61ff 0000 03b6 bsrl 0x402a97b8
580 0x402a9406: 266a 0000 moveal %a2@(0),%a3
581 0x402a940a: 282b 0010 movel %a3@(16),%d4
582 0x402a940e: d8bc 0000 0000 addl #0,%d4 <-- this 0
583 0x402a9414: 4a84 tstl %d4
584 0x402a9416: 6e02 bgts 0x402a941a
586 0x402a9418: 4afc illegal
587 0x402a941a: 286b 0000 moveal %a3@(0),%a4 <-- and this 0 offset
589 *******************************************************************************/
591 bool patcher_checkcast_interface(u1 *sp)
594 constant_classref *cr;
598 /* get stuff from the stack */
599 ra = (u1 *) *((ptrint *) (sp + 6 * 4));
600 cr = (constant_classref *) *((ptrint *) (sp + 1 * 4));
602 /* get the fieldinfo */
603 if (!(c = resolve_classref_eager(cr)))
606 /* patch back original code */
607 patcher_patch_back(sp);
609 /* if we show NOPs, we have to skip them */
610 if (opt_shownops) ra += PATCHER_CALL_SIZE;
612 /* patch super class index */
614 assert ( *((u2 *)(ra + 8)) == 0xd8bc );
615 *((s4 *) (ra + 10)) = disp;
617 disp = OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*);
618 assert( *((u2 *)(ra + 22)) == 0x286b );
619 assert( (s2)disp == disp);
620 *((s2 *) (ra + 24)) = disp;
622 /* synchronize instruction cache */
623 md_icacheflush(ra + 10, 16);
628 /* patcher_resolve_native_function *********************************************
632 *******************************************************************************/
634 bool patcher_resolve_native_function(u1 *sp)
640 /* get stuff from the stack */
641 m = (methodinfo *) *((ptrint *) (sp + 1 * 4));
642 disp = *((s4 *) (sp + 6 * 4));
644 /* resolve native function */
645 if (!(f = native_resolve_function(m)))
648 /* patch back original code */
649 patcher_patch_back(sp);
651 /* patch native function pointer */
652 if (opt_shownops) disp += PATCHER_CALL_SIZE;
653 *((ptrint *) (disp + 2)) = (ptrint) f;
655 /* synchronize data cache */
656 md_icacheflush(disp + 2, SIZEOF_VOID_P);
662 /* patcher_invokeinterface *****************************************************
665 0x40adb03e: moveal %a2@(0),%a3 0x266a0000 <-- no patching
666 0x40adb042: moveal %a3@(0),%a3 0x266b0000 <-- patch this 0000
667 0x40adb046: moveal %a3@(0),%a4 0xxxxx0000 <-- patch this 0000
668 0x40adb04a: jsr %a4@ 0xxxxx
671 *******************************************************************************/
673 bool patcher_invokeinterface(u1 *sp)
676 unresolved_method *um;
680 /* get stuff from the stack */
681 ra = (u1 *) *((ptrint *) (sp + 6 * 4));
682 um = (unresolved_method *) *((ptrint *) (sp + 1 * 4));
685 /* get the fieldinfo */
686 if (!(m = resolve_method_eager(um)))
689 /* patch back original code */
690 patcher_patch_back(sp);
692 /* if we show NOPs, we have to skip them */
693 if (opt_shownops) ra += PATCHER_CALL_SIZE;
694 assert( *((uint32_t*)ra) == 0x246f0000 );
696 /* patch interfacetable index (first #0) */
697 disp = OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr*) * m->class->index;
698 /* XXX this disp is negative, check!
699 * assert( (disp & 0x0000ffff) == disp);*/
700 *((uint16_t *) (ra + 5 * 2)) = disp;
702 /* patch method offset (second #0) */
703 disp = sizeof(methodptr) * (m - m->class->methods);
704 assert( (disp & 0x0000ffff) == disp);
705 *((uint16_t *) (ra + 7 * 2)) = disp;
707 /* synchronize instruction cache */
708 md_icacheflush(ra + 5 * 2, 2 * 2);
713 * These are local overrides for various environment variables in Emacs.
714 * Please do not remove this and leave it at the end of the file, where
715 * Emacs will automagically detect them.
716 * ---------------------------------------------------------------------
719 * indent-tabs-mode: t
723 * vim:noexpandtab:sw=4:ts=4: