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)
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 */
94 xpc = xpc - PATCHER_CALL_SIZE;
95 *((ptrint *) (sp + 6 * 4)) = (ptrint) xpc;
97 /* patch back original code */
99 *((u4*)(xpc)) = mcode;
100 *((u4*)(xpc+4)) = xmcode;
101 md_icacheflush(xpc, 8);
103 /* cast the passed function to a patcher function */
105 patcher_function = (bool (*)(u1 *)) (ptrint) f;
107 /* enter a monitor on the patching position */
109 PATCHER_MONITORENTER;
111 /* create the stackframeinfo */
113 /* RA is passed as NULL, but the XPC is correct and can be used in
114 stacktrace_create_extern_stackframeinfo for
115 md_codegen_get_pv_from_pc. */
117 stacktrace_create_extern_stackframeinfo(&sfi, pv, sp + 7 * 4, xpc, xpc);
119 /* call the proper patcher function */
121 result = (patcher_function)(sp);
123 /* remove the stackframeinfo */
125 stacktrace_remove_stackframeinfo(&sfi);
127 /* check for return value and exit accordingly */
129 if (result == false) {
130 e = exceptions_get_and_clear_exception();
136 PATCHER_MARK_PATCHED_MONITOREXIT;
141 /* patcher_initialize_class ****************************************************
143 Initalizes a given classinfo pointer. This function does not patch
146 *******************************************************************************/
148 bool patcher_initialize_class(u1 *sp)
152 /* get stuff from the stack */
154 c = (classinfo *) *((ptrint *) (sp + 1 * 4));
156 /* check if the class is initialized */
158 if (!(c->state & CLASS_INITIALIZED))
159 if (!initialize_class(c))
165 /* patcher_invokevirtual *******************************************************
168 0x4029bc46: 61ff 0000 00ba bsrl 0x4029bd02
169 0x4029bc4c: 246f 0000 moveal %sp@(0),%a2
170 0x4029bc50: 266a 0000 moveal %a2@(0),%a3
171 0x4029bc54: 246b 0000 moveal %a3@(0),%a2 <-- patch this (0) offset
172 0x4029bc58: 4e92 jsr %a2@
174 *******************************************************************************/
176 bool patcher_invokevirtual(u1 *sp)
179 unresolved_method *um;
183 /* get stuff from the stack */
184 ra = (u1 *) *((ptrint *) (sp + 6 * 4));
185 um = (unresolved_method *) *((ptrint *) (sp + 1 * 4));
187 /* get the fieldinfo */
188 if (!(m = resolve_method_eager(um)))
191 /* if we show NOPs, we have to skip them */
192 if (opt_shownops) ra += PATCHER_CALL_SIZE;
194 assert( *((u2*)(ra+8)) == 0x246b);
196 /* patch vftbl index */
197 disp = (OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * m->vftblindex);
198 *((s2 *) (ra + 10)) = disp;
200 /* synchronize instruction cache */
201 md_icacheflush(ra + 10, 2);
206 /* patcher_invokestatic_special ************************************************
211 0x402902bc: 61ff 0000 0076 bsrl 0x40290334
212 0x402902c2: 247c 0000 0000 moveal #0,%a2 <-- this #0
213 0x402902c8: 4e92 jsr %a2@
215 ******************************************************************************/
217 bool patcher_invokestatic_special(u1 *sp)
219 unresolved_method *um;
223 /* get stuff from the stack */
225 disp = *((s4 *) (sp + 6 * 4));
226 um = (unresolved_method *) *((ptrint *) (sp + 1 * 4));
228 /* get the fieldinfo */
230 if (!(m = resolve_method_eager(um)))
233 /* patch stubroutine */
235 if (opt_shownops) disp += PATCHER_CALL_SIZE;
237 *((ptrint *) (disp+2)) = (ptrint) m->stubroutine;
239 /* synchronize inst cache */
241 md_icacheflush(disp+2, SIZEOF_VOID_P);
247 /* patcher_resolve_class *******************************************************
249 Resolves a given unresolved_class pointer. This function does not
252 *******************************************************************************/
254 #ifdef ENABLE_VERIFIER
255 bool patcher_resolve_class(u1 *sp)
257 unresolved_class *uc;
260 /* get stuff from the stack */
262 uc = (unresolved_class *) *((ptrint *) (sp + 2 * 4));
264 /* resolve the class */
267 if (!resolve_class(uc, resolveEager, false, &c))
272 #endif /* ENABLE_VERIFIER */
274 /* patcher_resolve_classref_to_classinfo ***************************************
276 0x4028f2ca: 2479 0000 0000 moveal 0x00000000,%a2
277 *******************************************************************************/
278 bool patcher_resolve_classref_to_classinfo(u1 *sp)
280 constant_classref *cr;
285 /* get stuff from the stack */
287 cr = (constant_classref *) *((ptrint *) (sp + 1 * 4));
288 disp = *((s4 *) (sp + 6 * 4));
290 /* get the classinfo */
292 if (!(c = resolve_classref_eager(cr)))
295 /* patch the classinfo pointer */
297 if (opt_shownops) disp += PATCHER_CALL_SIZE;
299 *((ptrint *) (disp+2)) = (ptrint) c;
301 /* synchronize inst cache */
303 md_icacheflush(disp+2, SIZEOF_VOID_P);
308 /* patcher_get_putstatic *******************************************************
312 *******************************************************************************/
314 bool patcher_get_putstatic(u1 *sp)
318 unresolved_field *uf;
323 /* get stuff from the stack */
325 ra = (u1 *) *((ptrint *) (sp + 5 * 4));
326 mcode = *((u4 *) (sp + 3 * 4));
327 uf = (unresolved_field *) *((ptrint *) (sp + 2 * 4));
328 disp = *((s4 *) (sp + 1 * 4));
329 pv = (u1 *) *((ptrint *) (sp + 0 * 4));
331 /* get the fieldinfo */
335 if (!(fi = resolve_field_eager(uf)))
338 /* check if the field's class is initialized */
340 if (!(fi->class->state & CLASS_INITIALIZED))
341 if (!initialize_class(fi->class))
344 /* patch the field value's address */
346 *((ptrint *) (pv + disp)) = (ptrint) &(fi->value);
348 /* synchronize data cache */
350 md_dcacheflush(pv + disp, SIZEOF_VOID_P);
355 /* patcher_get_putfield ********************************************************
359 <patched call position>
361 *******************************************************************************/
363 bool patcher_get_putfield(u1 *sp)
366 unresolved_field *uf;
370 ra = (u1 *) *((ptrint *) (sp + 6 * 4));
371 uf = (unresolved_field *) *((ptrint *) (sp + 1 * 4));
373 /* get the fieldinfo */
377 if (!(fi = resolve_field_eager(uf)))
380 /* if we show NOPs, we have to skip them */
383 /* patch the field's offset */
385 if (IS_LNG_TYPE(fi->type)) {
386 /* If the field has type long, we have to patch two
387 instructions. But we have to check which instruction
388 is first. We do that with the offset of the first
391 disp = *((u4 *) (ra + 1 * 4));
394 *((u4 *) (ra + 1 * 4)) |= (s2) ((fi->offset + 4) & 0x0000ffff);
395 *((u4 *) (ra + 2 * 4)) |= (s2) ((fi->offset + 0) & 0x0000ffff);
398 *((u4 *) (ra + 1 * 4)) |= (s2) ((fi->offset + 0) & 0x0000ffff);
399 *((u4 *) (ra + 2 * 4)) |= (s2) ((fi->offset + 4) & 0x0000ffff);
403 *((u4 *) (ra + 1 * 4)) |= (s2) (fi->offset & 0x0000ffff);
406 if (IS_LNG_TYPE(fi->type)) {
408 disp = *((u4 *) (sp + 3 * 4));
410 /* We patch the first instruction in the patcher stub
411 stack and the second in the code. The first
412 instruction is patched back later in
416 *((u4 *) (sp + 3 * 4)) |= (s2) ((fi->offset + 4) & 0x0000ffff);
417 *((u4 *) (ra + 1 * 4)) |= (s2) ((fi->offset + 0) & 0x0000ffff);
420 *((u4 *) (sp + 3 * 4)) |= (s2) ((fi->offset + 0) & 0x0000ffff);
421 *((u4 *) (ra + 1 * 4)) |= (s2) ((fi->offset + 4) & 0x0000ffff);
425 *((u4 *) (sp + 3 * 4)) |= (s2) (fi->offset & 0x0000ffff);
428 /* synchronize instruction cache */
430 md_icacheflush(ra + 1 * 4, 2 * 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 class flags */
467 if (opt_shownops) disp += PATCHER_CALL_SIZE;
468 assert( (*((u2*)(disp)) == 0x263c) || (*((u2*)(disp)) == 0x283c) );
469 *((s4 *) (disp + 2)) = (s4) c->flags;
471 /* synchronize insn cache */
472 md_icacheflush(disp + 2, SIZEOF_VOID_P);
477 /* patcher_resolve_classref_to_vftbl *******************************************
480 0x4029b094: 61ff 0000 00b4 bsrl 0x4029b14a
481 0x4029b09a: 287c 0000 0000 moveal #0,%a4 <-- patch this #0
482 0x4029b0a0: 2668 0000 moveal %a0@(0),%a3
485 0x402a9300: 61ff 0000 0574 bsrl 0x402a9876
486 0x402a9306: 267c 0000 0000 moveal #0,%a3
487 0x402a930c: 246a 0000 moveal %a2@(0),%a2
490 *******************************************************************************/
492 bool patcher_resolve_classref_to_vftbl(u1 *sp)
494 constant_classref *cr;
498 /* get stuff from the stack */
499 cr = (constant_classref *) *((ptrint *) (sp + 1 * 4));
500 disp = *((s4 *) (sp + 6 * 4));
502 /* get the fieldinfo */
503 if (!(c = resolve_classref_eager(cr)))
506 /* patch super class' vftbl */
507 if (opt_shownops) disp += PATCHER_CALL_SIZE;
508 assert( (*((u2*)disp) == 0x287c) || (*((u2*)disp)== 0x267c) );
510 *((s4 *) (disp+2)) = (s4) c->vftbl;
512 /* synchronize insin cache */
513 md_icacheflush(disp+2, SIZEOF_VOID_P);
518 /* patcher_instanceof_interface ************************************************
522 0x402a92da: 61ff 0000 05c0 bsrl 0x402a989c
523 0x402a92e0: 246a 0000 moveal %a2@(0),%a2
524 0x402a92e4: 282a 0010 movel %a2@(16),%d4
525 0x402a92e8: d8bc 0000 0000 addl #0,%d4 <-- this const
526 0x402a92ee: 4a84 tstl %d4
527 0x402a92f0: 6e0a bles 0x402a92fc
528 0x402a92f2: 246a 0000 moveal %a2@(0),%a2 <-- this offset
530 *******************************************************************************/
532 bool patcher_instanceof_interface(u1 *sp)
535 constant_classref *cr;
539 /* get stuff from the stack */
541 ra = (u1 *) *((ptrint *) (sp + 6 * 4));
542 cr = (constant_classref *) *((ptrint *) (sp + 1 * 4));
544 /* get the fieldinfo */
545 if (!(c = resolve_classref_eager(cr)))
548 /* if we show NOPs, we have to skip them */
549 if (opt_shownops) ra += PATCHER_CALL_SIZE;
551 /* patch super class index */
553 assert( *((u2*)(ra + 8)) == 0xd8bc );
554 *((s4 *) (ra + 10 )) = disp;
556 disp = OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*);
558 assert( (s2)disp == disp);
559 assert ( *((s2*)(ra+18)) == 0x246a );
561 *((s2 *) (ra + 20)) = disp;
563 /* synchronize instruction cache */
564 md_icacheflush(ra + 10, 12);
569 /* patcher_checkcast_interface *************************************************
571 0x402a9400: 61ff 0000 03b6 bsrl 0x402a97b8
572 0x402a9406: 266a 0000 moveal %a2@(0),%a3
573 0x402a940a: 282b 0010 movel %a3@(16),%d4
574 0x402a940e: d8bc 0000 0000 addl #0,%d4 <-- this 0
575 0x402a9414: 4a84 tstl %d4
576 0x402a9416: 6e02 bgts 0x402a941a
578 0x402a9418: 4afc illegal
579 0x402a941a: 286b 0000 moveal %a3@(0),%a4 <-- and this 0 offset
581 *******************************************************************************/
583 bool patcher_checkcast_interface(u1 *sp)
586 constant_classref *cr;
590 /* get stuff from the stack */
591 ra = (u1 *) *((ptrint *) (sp + 6 * 4));
592 cr = (constant_classref *) *((ptrint *) (sp + 1 * 4));
594 /* get the fieldinfo */
595 if (!(c = resolve_classref_eager(cr)))
598 /* if we show NOPs, we have to skip them */
599 if (opt_shownops) ra += PATCHER_CALL_SIZE;
601 /* patch super class index */
603 assert ( *((u2 *)(ra + 8)) == 0xd8bc );
604 *((s4 *) (ra + 10)) = disp;
606 disp = OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*);
607 assert( *((u2 *)(ra + 22)) == 0x286b );
608 assert( (s2)disp == disp);
609 *((s2 *) (ra + 24)) = disp;
611 /* synchronize instruction cache */
612 md_icacheflush(ra + 10, 16);
617 /* patcher_resolve_native_function *********************************************
621 *******************************************************************************/
623 #if !defined(WITH_STATIC_CLASSPATH)
624 bool patcher_resolve_native_function(u1 *sp)
630 /* get stuff from the stack */
631 m = (methodinfo *) *((ptrint *) (sp + 1 * 4));
632 disp = *((s4 *) (sp + 6 * 4));
634 /* resolve native function */
635 if (!(f = native_resolve_function(m)))
638 /* patch native function pointer */
639 if (opt_shownops) disp += PATCHER_CALL_SIZE;
640 *((ptrint *) (disp + 2)) = (ptrint) f;
642 /* synchronize data cache */
643 md_icacheflush(disp + 2, SIZEOF_VOID_P);
647 #endif /* !defined(WITH_STATIC_CLASSPATH) */
650 /* patcher_invokeinterface *****************************************************
655 *******************************************************************************/
657 bool patcher_invokeinterface(u1 *sp)
660 unresolved_method *um;
664 /* get stuff from the stack */
665 ra = (u1 *) *((ptrint *) (sp + 6 * 4));
666 um = (unresolved_method *) *((ptrint *) (sp + 1 * 4));
670 /* get the fieldinfo */
671 if (!(m = resolve_method_eager(um)))
674 /* if we show NOPs, we have to skip them */
675 if (opt_shownops) ra = ra + PATCHER_CALL_SIZE;
677 /* patch interfacetable index (first #0) */
678 disp = OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr*) * m->class->index;
680 /* XXX TWISTI: check displacement */
681 *((s4 *) (ra + 1 * 4)) |= (disp & 0x0000ffff);
683 /* patch method offset (second #0) */
684 disp = sizeof(methodptr) * (m - m->class->methods);
686 /* XXX TWISTI: check displacement */
687 *((s4 *) (ra + 2 * 4)) |= (disp & 0x0000ffff);
689 /* synchronize instruction cache */
690 md_icacheflush(ra + 1 * 4, 2 * 4);