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_create_extern_stackframeinfo for
105 md_codegen_get_pv_from_pc. */
108 fprintf(stderr, "EXT STACKFRAME: sfi=%x pv=%x, sp=%x, xpc=%x\n", &sfi, pv, sp+7*4, xpc);
110 stacktrace_create_extern_stackframeinfo(&sfi, pv, sp + 7 * 4, xpc, xpc);
112 /* call the proper patcher function */
113 result = (patcher_function)(sp);
116 /* remove the stackframeinfo */
117 stacktrace_remove_stackframeinfo(&sfi);
119 /* check for return value and exit accordingly */
120 if (result == false) {
121 e = exceptions_get_and_clear_exception();
127 PATCHER_MARK_PATCHED_MONITOREXIT;
134 static void patcher_patch_back(u1 *sp)
136 u1* xpc = (u1 *) *((ptrint *) (sp + 6 * 4));
137 u4 mcode = *((u4*) (sp + 3 * 4));
138 u4 xmcode = *((u4*) (sp + 2 * 4));
140 *((u4*)(xpc)) = mcode;
141 *((u4*)(xpc+4)) = xmcode;
142 md_icacheflush(xpc, 8);
145 /* patcher_initialize_class ****************************************************
147 Initalizes a given classinfo pointer. This function does not patch
150 *******************************************************************************/
152 bool patcher_initialize_class(u1 *sp)
155 u4 xpc, mcode, xmcode;
157 /* get stuff from the stack */
158 c = (classinfo *) *((ptrint *) (sp + 1 * 4));
160 /* check if the class is initialized */
161 if (!(c->state & CLASS_INITIALIZED))
162 if (!initialize_class(c))
165 /* patch back original code */
166 patcher_patch_back(sp);
171 /* patcher_invokevirtual *******************************************************
174 0x4029bc46: 61ff 0000 00ba bsrl 0x4029bd02
175 0x4029bc4c: 246f 0000 moveal %sp@(0),%a2
176 0x4029bc50: 266a 0000 moveal %a2@(0),%a3
177 0x4029bc54: 246b 0000 moveal %a3@(0),%a2 <-- patch this (0) offset
178 0x4029bc58: 4e92 jsr %a2@
180 *******************************************************************************/
182 bool patcher_invokevirtual(u1 *sp)
185 unresolved_method *um;
189 /* get stuff from the stack */
190 ra = (u1 *) *((ptrint *) (sp + 6 * 4));
191 um = (unresolved_method *) *((ptrint *) (sp + 1 * 4));
193 /* get the fieldinfo */
194 if (!(m = resolve_method_eager(um)))
197 /* patch back original code */
198 patcher_patch_back(sp);
200 /* if we show NOPs, we have to skip them */
201 if (opt_shownops) ra += PATCHER_CALL_SIZE;
203 assert( *((u2*)(ra+8)) == 0x286b);
205 /* patch vftbl index */
206 disp = (OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * m->vftblindex);
207 *((s2 *) (ra + 10)) = disp;
209 /* synchronize instruction cache */
210 md_icacheflush(ra + 10, 2);
215 /* patcher_invokestatic_special ************************************************
220 0x402902bc: 61ff 0000 0076 bsrl 0x40290334
221 0x402902c2: 247c 0000 0000 moveal #0,%a2 <-- this #0
222 0x402902c8: 4e92 jsr %a2@
224 ******************************************************************************/
226 bool patcher_invokestatic_special(u1 *sp)
228 unresolved_method *um;
232 /* get stuff from the stack */
233 disp = *((s4 *) (sp + 6 * 4));
234 um = (unresolved_method *) *((ptrint *) (sp + 1 * 4));
236 /* get the fieldinfo */
237 if (!(m = resolve_method_eager(um)))
240 /* patch back original code */
241 patcher_patch_back(sp);
243 /* patch stubroutine */
244 if (opt_shownops) disp += PATCHER_CALL_SIZE;
246 *((ptrint *) (disp+2)) = (ptrint) m->stubroutine;
248 /* synchronize inst cache */
250 md_icacheflush(disp+2, SIZEOF_VOID_P);
256 /* patcher_resolve_class *******************************************************
258 Resolves a given unresolved_class pointer. This function does not
261 *******************************************************************************/
263 #ifdef ENABLE_VERIFIER
264 bool patcher_resolve_class(u1 *sp)
266 unresolved_class *uc;
270 /* get stuff from the stack */
271 uc = (unresolved_class *) *((ptrint *) (sp + 1 * 4));
272 disp = *((s4 *) (sp + 6 * 4));
274 /* resolve the class */
275 if (!resolve_class(uc, resolveEager, false, &c))
278 /* patch back original code */
279 patcher_patch_back(sp);
283 #endif /* ENABLE_VERIFIER */
285 /* patcher_resolve_classref_to_classinfo ***************************************
287 0x4028f2ca: 2479 0000 0000 moveal 0x00000000,%a2
288 *******************************************************************************/
289 bool patcher_resolve_classref_to_classinfo(u1 *sp)
291 constant_classref *cr;
296 /* get stuff from the stack */
297 cr = (constant_classref *) *((ptrint *) (sp + 1 * 4));
298 disp = *((s4 *) (sp + 6 * 4));
300 /* get the classinfo */
301 if (!(c = resolve_classref_eager(cr)))
304 /* patch back original code */
305 patcher_patch_back(sp);
307 /* patch the classinfo pointer */
308 if (opt_shownops) disp += PATCHER_CALL_SIZE;
309 *((ptrint *) (disp+2)) = (ptrint) c;
311 /* synchronize inst cache */
312 md_icacheflush(disp+2, SIZEOF_VOID_P);
317 /* patcher_get_putstatic *******************************************************
321 *******************************************************************************/
323 bool patcher_get_putstatic(u1 *sp)
326 unresolved_field *uf;
331 /* get stuff from the stack */
332 uf = (unresolved_field *) *((ptrint *) (sp + 1 * 4));
333 disp = *((s4 *) (sp + 6 * 4));
335 /* get the fieldinfo */
336 if (!(fi = resolve_field_eager(uf)))
339 /* check if the field's class is initialized */
340 if (!(fi->class->state & CLASS_INITIALIZED))
341 if (!initialize_class(fi->class))
344 /* patch back original code */
345 patcher_patch_back(sp);
347 /* patch the field value's address */
348 if (opt_shownops) disp += PATCHER_CALL_SIZE;
349 assert(*((uint16_t*)(disp)) == 0x247c);
350 *((intptr_t *) (disp+2)) = (intptr_t) fi->value;
352 /* synchronize inst cache */
353 md_icacheflush(disp+2, SIZEOF_VOID_P);
358 /* patcher_get_putfield ********************************************************
362 <patched call position>
364 *******************************************************************************/
366 bool patcher_get_putfield(u1 *sp)
369 unresolved_field *uf;
373 ra = (u1 *) *((ptrint *) (sp + 6 * 4));
374 uf = (unresolved_field *) *((ptrint *) (sp + 1 * 4));
376 /* get the fieldinfo */
377 if (!(fi = resolve_field_eager(uf)))
380 /* patch back original code */
381 patcher_patch_back(sp);
383 /* if we show NOPs, we have to skip them */
384 if (opt_shownops) ra += PATCHER_CALL_SIZE;
386 /* patch the field's offset */
387 if (IS_LNG_TYPE(fi->type)) {
389 * 0x40d05bb2: 0x25440000 movel %d4,%a2@(0)
390 * 0x40d05bb6: 0x25430004 movel %d3,%a2@(4)
392 * both 0000 and 0004 have to be patched
395 assert( (fi->offset & 0x0000ffff) == fi->offset );
397 assert( (*((uint32_t*)ra) & 0xffff0000) == *((uint32_t*)ra) );
398 assert( (*((uint32_t*)(ra+4)) & 0xffff0004) == *((uint32_t*)(ra+4)) );
400 *((int16_t *) (ra + 2)) = (int16_t) ((fi->offset) & 0x0000ffff);
401 *((int16_t *) (ra + 6)) = (int16_t) ((fi->offset + 4) & 0x0000ffff);
403 md_icacheflush(ra, 2 * 4);
405 /* Multiple cases here, int, adr, flt and dbl. */
406 if ( (*((uint32_t*)ra) & 0xfff00000) == 0xf2200000 ) {
408 * 0x40d3ddc2: 0xf22944c0 0x0000xxxx fsmoves %a1@(0),%fp1
412 assert( (fi->offset & 0x0000ffff) == fi->offset );
413 assert( (*((uint32_t*)(ra+4)) & 0x0000ffff) == *((uint32_t*)(ra+4)) );
414 *((int16_t*)(ra+4)) = (int16_t)fi->offset;
416 md_icacheflush(ra+4, 1 * 4);
419 * 0x40adb3f6: 0x254d0000 movel %a5,%a2@(0)
423 assert( (*((uint32_t*)ra) & 0xffff0000) == *((uint32_t*)ra) );
424 assert( (fi->offset & 0x0000ffff) == fi->offset );
425 *((int16_t*)(ra+2)) = (int16_t)fi->offset;
427 /* synchronize instruction cache */
428 md_icacheflush(ra, 1 * 4);
434 /* patcher_resolve_classref_to_flags *******************************************
436 CHECKCAST/INSTANCEOF:
440 0x4029b056: 61ff 0000 013e bsrl 0x4029b196
441 0x4029b05c: 263c 0000 0000 movel #0,%d3 <-- patch this #0
442 0x4029b062: 0283 0000 0200 andil #512,%d3
445 0x402a4aa8: 61ff 0000 05c4 bsrl 0x402a506e
446 0x402a4aae: 283c 0000 0000 movel #0,%d4 <-- same here
447 0x402a4ab4: 0284 0000 0200 andil #512,%d4
450 *******************************************************************************/
452 bool patcher_resolve_classref_to_flags(u1 *sp)
454 constant_classref *cr;
458 /* get stuff from the stack */
459 cr = (constant_classref *) *((ptrint *) (sp + 1 * 4));
460 disp = *((s4 *) (sp + 6 * 4));
462 /* get the fieldinfo */
463 if (!(c = resolve_classref_eager(cr)))
466 /* patch back original code */
467 patcher_patch_back(sp);
469 /* patch class flags */
470 if (opt_shownops) disp += PATCHER_CALL_SIZE;
471 assert( (*((u2*)(disp)) == 0x263c) || (*((u2*)(disp)) == 0x283c) );
472 *((s4 *) (disp + 2)) = (s4) c->flags;
474 /* synchronize insn cache */
475 md_icacheflush(disp + 2, SIZEOF_VOID_P);
480 /* patcher_resolve_classref_to_vftbl *******************************************
483 0x4029b094: 61ff 0000 00b4 bsrl 0x4029b14a
484 0x4029b09a: 287c 0000 0000 moveal #0,%a4 <-- patch this #0
485 0x4029b0a0: 2668 0000 moveal %a0@(0),%a3
488 0x402a9300: 61ff 0000 0574 bsrl 0x402a9876
489 0x402a9306: 267c 0000 0000 moveal #0,%a3
490 0x402a930c: 246a 0000 moveal %a2@(0),%a2
493 *******************************************************************************/
495 bool patcher_resolve_classref_to_vftbl(u1 *sp)
497 constant_classref *cr;
501 /* get stuff from the stack */
502 cr = (constant_classref *) *((ptrint *) (sp + 1 * 4));
503 disp = *((s4 *) (sp + 6 * 4));
505 /* get the fieldinfo */
506 if (!(c = resolve_classref_eager(cr)))
509 /* patch back original code */
510 patcher_patch_back(sp);
512 /* patch super class' vftbl */
513 if (opt_shownops) disp += PATCHER_CALL_SIZE;
514 assert( (*((u2*)disp) == 0x287c) || (*((u2*)disp)== 0x267c) );
516 *((s4 *) (disp+2)) = (s4) c->vftbl;
518 /* synchronize insin cache */
519 md_icacheflush(disp+2, SIZEOF_VOID_P);
524 /* patcher_instanceof_interface ************************************************
528 0x402a92da: 61ff 0000 05c0 bsrl 0x402a989c
529 0x402a92e0: 246a 0000 moveal %a2@(0),%a2
530 0x402a92e4: 282a 0010 movel %a2@(16),%d4
531 0x402a92e8: d8bc 0000 0000 addl #0,%d4 <-- this const
532 0x402a92ee: 4a84 tstl %d4
533 0x402a92f0: 6e0a bles 0x402a92fc
534 0x402a92f2: 246a 0000 moveal %a2@(0),%a2 <-- this offset
536 *******************************************************************************/
538 bool patcher_instanceof_interface(u1 *sp)
541 constant_classref *cr;
545 /* get stuff from the stack */
547 ra = (u1 *) *((ptrint *) (sp + 6 * 4));
548 cr = (constant_classref *) *((ptrint *) (sp + 1 * 4));
550 /* get the fieldinfo */
551 if (!(c = resolve_classref_eager(cr)))
554 /* patch back original code */
555 patcher_patch_back(sp);
557 /* if we show NOPs, we have to skip them */
558 if (opt_shownops) ra += PATCHER_CALL_SIZE;
560 /* patch super class index */
562 assert( *((u2*)(ra + 8)) == 0xd8bc );
563 *((s4 *) (ra + 10 )) = disp;
565 disp = OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*);
567 assert( (s2)disp == disp);
568 assert ( *((s2*)(ra+18)) == 0x246a );
570 *((s2 *) (ra + 20)) = disp;
572 /* synchronize instruction cache */
573 md_icacheflush(ra + 10, 12);
578 /* patcher_checkcast_interface *************************************************
580 0x402a9400: 61ff 0000 03b6 bsrl 0x402a97b8
581 0x402a9406: 266a 0000 moveal %a2@(0),%a3
582 0x402a940a: 282b 0010 movel %a3@(16),%d4
583 0x402a940e: d8bc 0000 0000 addl #0,%d4 <-- this 0
584 0x402a9414: 4a84 tstl %d4
585 0x402a9416: 6e02 bgts 0x402a941a
587 0x402a9418: 4afc illegal
588 0x402a941a: 286b 0000 moveal %a3@(0),%a4 <-- and this 0 offset
590 *******************************************************************************/
592 bool patcher_checkcast_interface(u1 *sp)
595 constant_classref *cr;
599 /* get stuff from the stack */
600 ra = (u1 *) *((ptrint *) (sp + 6 * 4));
601 cr = (constant_classref *) *((ptrint *) (sp + 1 * 4));
603 /* get the fieldinfo */
604 if (!(c = resolve_classref_eager(cr)))
607 /* patch back original code */
608 patcher_patch_back(sp);
610 /* if we show NOPs, we have to skip them */
611 if (opt_shownops) ra += PATCHER_CALL_SIZE;
613 /* patch super class index */
615 assert ( *((u2 *)(ra + 8)) == 0xd8bc );
616 *((s4 *) (ra + 10)) = disp;
618 disp = OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*);
619 assert( *((u2 *)(ra + 22)) == 0x286b );
620 assert( (s2)disp == disp);
621 *((s2 *) (ra + 24)) = disp;
623 /* synchronize instruction cache */
624 md_icacheflush(ra + 10, 16);
629 /* patcher_resolve_native_function *********************************************
633 *******************************************************************************/
635 #if !defined(WITH_STATIC_CLASSPATH)
636 bool patcher_resolve_native_function(u1 *sp)
642 /* get stuff from the stack */
643 m = (methodinfo *) *((ptrint *) (sp + 1 * 4));
644 disp = *((s4 *) (sp + 6 * 4));
646 /* resolve native function */
647 if (!(f = native_resolve_function(m)))
650 /* patch back original code */
651 patcher_patch_back(sp);
653 /* patch native function pointer */
654 if (opt_shownops) disp += PATCHER_CALL_SIZE;
655 *((ptrint *) (disp + 2)) = (ptrint) f;
657 /* synchronize data cache */
658 md_icacheflush(disp + 2, SIZEOF_VOID_P);
662 #endif /* !defined(WITH_STATIC_CLASSPATH) */
665 /* patcher_invokeinterface *****************************************************
668 0x40adb03e: moveal %a2@(0),%a3 0x266a0000 <-- no patching
669 0x40adb042: moveal %a3@(0),%a3 0x266b0000 <-- patch this 0000
670 0x40adb046: moveal %a3@(0),%a4 0xxxxx0000 <-- patch this 0000
671 0x40adb04a: jsr %a4@ 0xxxxx
674 *******************************************************************************/
676 bool patcher_invokeinterface(u1 *sp)
679 unresolved_method *um;
683 /* get stuff from the stack */
684 ra = (u1 *) *((ptrint *) (sp + 6 * 4));
685 um = (unresolved_method *) *((ptrint *) (sp + 1 * 4));
688 /* get the fieldinfo */
689 if (!(m = resolve_method_eager(um)))
692 /* patch back original code */
693 patcher_patch_back(sp);
695 /* if we show NOPs, we have to skip them */
696 if (opt_shownops) ra += PATCHER_CALL_SIZE;
697 assert( *((uint32_t*)ra) == 0x246f0000 );
699 /* patch interfacetable index (first #0) */
700 disp = OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr*) * m->class->index;
701 /* XXX this disp is negative, check!
702 * assert( (disp & 0x0000ffff) == disp);*/
703 *((uint16_t *) (ra + 5 * 2)) = disp;
705 /* patch method offset (second #0) */
706 disp = sizeof(methodptr) * (m - m->class->methods);
707 assert( (disp & 0x0000ffff) == disp);
708 *((uint16_t *) (ra + 7 * 2)) = disp;
710 /* synchronize instruction cache */
711 md_icacheflush(ra + 5 * 2, 2 * 2);
716 * These are local overrides for various environment variables in Emacs.
717 * Please do not remove this and leave it at the end of the file, where
718 * Emacs will automagically detect them.
719 * ---------------------------------------------------------------------
722 * indent-tabs-mode: t
726 * vim:noexpandtab:sw=4:ts=4: