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-common.h"
44 #include "vm/jit/md.h"
45 #include "vm/jit/stacktrace.h"
47 #include "vmcore/class.h"
48 #include "vmcore/field.h"
49 #include "vmcore/options.h"
50 #include "vmcore/references.h"
54 #define PATCH_BACK_ORIGINAL_MCODE *((u4*)(pr->mpc)) = pr->mcode
56 /* patcher_initialize_class ****************************************************
58 just patch back original code
60 *******************************************************************************/
63 void patcher_patch_code(patchref_t *pr)
66 u1* xpc = (u1 *) *((ptrint *) (sp + 6 * 4));
67 u4 mcode = *((u4*) (sp + 3 * 4));
68 u4 xmcode = *((u4*) (sp + 2 * 4));
70 *((u4*)(xpc)) = mcode;
71 *((u4*)(xpc+4)) = xmcode;
74 PATCH_BACK_ORIGINAL_MCODE;
75 md_icacheflush((void*)pr->mpc, 2);
81 /* patcher_initialize_class ****************************************************
83 Initalizes a given classinfo pointer. This function does not patch
86 *******************************************************************************/
88 bool patcher_initialize_class(patchref_t *pr)
91 u4 xpc, mcode, xmcode;
93 /* get stuff from the stack */
94 c = (classinfo *) *((ptrint *) (sp + 1 * 4));
96 /* check if the class is initialized */
97 if (!(c->state & CLASS_INITIALIZED))
98 if (!initialize_class(c))
101 /* patch back original code */
102 patcher_patch_back(sp);
108 /* patcher_invokevirtual *******************************************************
111 0x4029bc46: 61ff 0000 00ba bsrl 0x4029bd02
112 0x4029bc4c: 246f 0000 moveal %sp@(0),%a2
113 0x4029bc50: 266a 0000 moveal %a2@(0),%a3
114 0x4029bc54: 246b 0000 moveal %a3@(0),%a2 <-- patch this (0) offset
115 0x4029bc58: 4e92 jsr %a2@
117 *******************************************************************************/
119 bool patcher_invokevirtual(patchref_t *pr)
122 unresolved_method *um;
126 /* get stuff from the stack */
128 um = (unresolved_method *) pr->ref;
130 /* get the fieldinfo */
131 if (!(m = resolve_method_eager(um)))
134 /* patch back original code */
135 PATCH_BACK_ORIGINAL_MCODE;
137 /* if we show NOPs, we have to skip them */
138 if (opt_shownops) ra += PATCHER_CALL_SIZE;
140 assert( *((u2*)(ra+8)) == 0x286b);
142 /* patch vftbl index */
143 disp = (OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * m->vftblindex);
144 *((s2 *) (ra + 10)) = disp;
146 /* synchronize instruction cache */
147 md_icacheflush(pr->mpc, 10 + 2 + PATCHER_CALL_SIZE);
152 /* patcher_invokestatic_special ************************************************
157 0x402902bc: 61ff 0000 0076 bsrl 0x40290334
158 0x402902c2: 247c 0000 0000 moveal #0,%a2 <-- this #0
159 0x402902c8: 4e92 jsr %a2@
161 ******************************************************************************/
163 bool patcher_invokestatic_special(patchref_t *pr)
165 unresolved_method *um;
169 /* get stuff from the stack */
171 um = (unresolved_method *) pr->ref;
173 /* get the fieldinfo */
174 if (!(m = resolve_method_eager(um)))
177 /* patch back original code */
178 PATCH_BACK_ORIGINAL_MCODE;
180 /* patch stubroutine */
181 if (opt_shownops) disp += PATCHER_CALL_SIZE;
183 *((ptrint *) (disp+2)) = (ptrint) m->stubroutine;
185 /* synchronize inst cache */
187 md_icacheflush(pr->mpc, PATCHER_CALL_SIZE+2+SIZEOF_VOID_P);
193 /* patcher_resolve_classref_to_classinfo ***************************************
195 0x4028f2ca: 2479 0000 0000 moveal 0x00000000,%a2
196 *******************************************************************************/
197 bool patcher_resolve_classref_to_classinfo(patchref_t *pr)
199 constant_classref *cr;
204 /* get stuff from the stack */
205 cr = (constant_classref *) pr->ref;
208 /* get the classinfo */
209 if (!(c = resolve_classref_eager(cr)))
212 /* patch back original code */
213 PATCH_BACK_ORIGINAL_MCODE;
215 /* patch the classinfo pointer */
216 if (opt_shownops) disp += PATCHER_CALL_SIZE;
217 *((ptrint *) (disp+2)) = (ptrint) c;
219 /* synchronize inst cache */
220 md_icacheflush(pr->mpc, PATCHER_CALL_SIZE + 2 + SIZEOF_VOID_P);
225 /* patcher_get_putstatic *******************************************************
229 *******************************************************************************/
231 bool patcher_get_putstatic(patchref_t *pr)
233 unresolved_field *uf;
237 /* get stuff from the stack */
238 uf = (unresolved_field *) pr->ref;
241 /* get the fieldinfo */
242 if (!(fi = resolve_field_eager(uf)))
245 /* check if the field's class is initialized */
246 if (!(fi->class->state & CLASS_INITIALIZED))
247 if (!initialize_class(fi->class))
250 /* patch back original code */
251 PATCH_BACK_ORIGINAL_MCODE;
252 md_icacheflush(pr->mpc, 2);
254 /* patch the field value's address */
255 if (opt_shownops) disp += PATCHER_CALL_SIZE;
256 assert(*((uint16_t*)(disp)) == 0x247c);
257 *((intptr_t *) (disp+2)) = (intptr_t) fi->value;
259 /* synchronize inst cache */
260 md_icacheflush((void*)(disp+2), SIZEOF_VOID_P);
265 /* patcher_get_putfield ********************************************************
269 <patched call position>
271 *******************************************************************************/
273 bool patcher_get_putfield(patchref_t *pr)
276 unresolved_field *uf;
280 uf = (unresolved_field *) pr->ref;
282 /* get the fieldinfo */
283 if (!(fi = resolve_field_eager(uf)))
286 /* patch back original code */
287 PATCH_BACK_ORIGINAL_MCODE;
288 md_icacheflush(pr->mpc, 2);
290 /* if we show NOPs, we have to skip them */
291 if (opt_shownops) ra += PATCHER_CALL_SIZE;
293 /* patch the field's offset */
294 if (IS_LNG_TYPE(fi->type)) {
296 * 0x40d05bb2: 0x25440000 movel %d4,%a2@(0)
297 * 0x40d05bb6: 0x25430004 movel %d3,%a2@(4)
299 * both 0000 and 0004 have to be patched
302 assert( (fi->offset & 0x0000ffff) == fi->offset );
304 assert( (*((uint32_t*)ra) & 0xffff0000) == *((uint32_t*)ra) );
305 assert( (*((uint32_t*)(ra+4)) & 0xffff0004) == *((uint32_t*)(ra+4)) );
307 *((int16_t *) (ra + 2)) = (int16_t) ((fi->offset) & 0x0000ffff);
308 *((int16_t *) (ra + 6)) = (int16_t) ((fi->offset + 4) & 0x0000ffff);
310 md_icacheflush(ra, 2 * 4);
312 /* Multiple cases here, int, adr, flt and dbl. */
313 if ( (*((uint32_t*)ra) & 0xfff00000) == 0xf2200000 ) {
315 * 0x40d3ddc2: 0xf22944c0 0x0000xxxx fsmoves %a1@(0),%fp1
319 assert( (fi->offset & 0x0000ffff) == fi->offset );
320 assert( (*((uint32_t*)(ra+4)) & 0x0000ffff) == *((uint32_t*)(ra+4)) );
321 *((int16_t*)(ra+4)) = (int16_t)fi->offset;
323 md_icacheflush(ra+4, 1 * 4);
326 * 0x40adb3f6: 0x254d0000 movel %a5,%a2@(0)
330 assert( (*((uint32_t*)ra) & 0xffff0000) == *((uint32_t*)ra) );
331 assert( (fi->offset & 0x0000ffff) == fi->offset );
332 *((int16_t*)(ra+2)) = (int16_t)fi->offset;
334 /* synchronize instruction cache */
335 md_icacheflush(ra, 1 * 4);
341 /* patcher_resolve_classref_to_flags *******************************************
343 CHECKCAST/INSTANCEOF:
347 0x4029b056: 61ff 0000 013e bsrl 0x4029b196
348 0x4029b05c: 263c 0000 0000 movel #0,%d3 <-- patch this #0
349 0x4029b062: 0283 0000 0200 andil #512,%d3
352 0x402a4aa8: 61ff 0000 05c4 bsrl 0x402a506e
353 0x402a4aae: 283c 0000 0000 movel #0,%d4 <-- same here
354 0x402a4ab4: 0284 0000 0200 andil #512,%d4
357 *******************************************************************************/
359 bool patcher_resolve_classref_to_flags(patchref_t *pr)
361 constant_classref *cr;
365 /* get stuff from the stack */
366 cr = (constant_classref *) pr->ref;
369 /* get the fieldinfo */
370 if (!(c = resolve_classref_eager(cr)))
373 /* patch back original code */
374 PATCH_BACK_ORIGINAL_MCODE;
375 md_icacheflush(pr->mpc, 2);
377 /* patch class flags */
378 if (opt_shownops) disp += PATCHER_CALL_SIZE;
379 assert( (*((u2*)(disp)) == 0x263c) || (*((u2*)(disp)) == 0x283c) );
380 *((s4 *) (disp + 2)) = (s4) c->flags;
382 /* synchronize insn cache */
383 md_icacheflush((void*)(disp + 2), SIZEOF_VOID_P);
388 /* patcher_resolve_classref_to_vftbl *******************************************
391 0x4029b094: 61ff 0000 00b4 bsrl 0x4029b14a
392 0x4029b09a: 287c 0000 0000 moveal #0,%a4 <-- patch this #0
393 0x4029b0a0: 2668 0000 moveal %a0@(0),%a3
396 0x402a9300: 61ff 0000 0574 bsrl 0x402a9876
397 0x402a9306: 267c 0000 0000 moveal #0,%a3
398 0x402a930c: 246a 0000 moveal %a2@(0),%a2
401 *******************************************************************************/
403 bool patcher_resolve_classref_to_vftbl(patchref_t *pr)
405 constant_classref *cr;
409 /* get stuff from the stack */
410 cr = (constant_classref *) pr->ref;
413 /* get the fieldinfo */
414 if (!(c = resolve_classref_eager(cr)))
417 /* patch back original code */
418 PATCH_BACK_ORIGINAL_MCODE;
419 md_icacheflush(pr->mpc, 2);
421 /* patch super class' vftbl */
422 if (opt_shownops) disp += PATCHER_CALL_SIZE;
423 assert( (*((u2*)disp) == 0x287c) || (*((u2*)disp)== 0x267c) );
425 *((s4 *) (disp+2)) = (s4) c->vftbl;
427 /* synchronize insin cache */
428 md_icacheflush((void*)(disp+2), SIZEOF_VOID_P);
433 /* patcher_instanceof_interface ************************************************
437 0x402a92da: 61ff 0000 05c0 bsrl 0x402a989c
438 0x402a92e0: 246a 0000 moveal %a2@(0),%a2
439 0x402a92e4: 282a 0010 movel %a2@(16),%d4
440 0x402a92e8: d8bc 0000 0000 addl #0,%d4 <-- this const
441 0x402a92ee: 4a84 tstl %d4
442 0x402a92f0: 6e0a bles 0x402a92fc
443 0x402a92f2: 246a 0000 moveal %a2@(0),%a2 <-- this offset
445 *******************************************************************************/
447 bool patcher_instanceof_interface(patchref_t *pr)
450 constant_classref *cr;
454 /* get stuff from the stack */
457 cr = (constant_classref *) pr->ref;
459 /* get the fieldinfo */
460 if (!(c = resolve_classref_eager(cr)))
463 /* patch back original code */
464 PATCH_BACK_ORIGINAL_MCODE;
465 md_icacheflush(pr->mpc, 2);
467 /* if we show NOPs, we have to skip them */
468 if (opt_shownops) ra += PATCHER_CALL_SIZE;
470 /* patch super class index */
472 assert( *((u2*)(ra + 8)) == 0xd8bc );
473 *((s4 *) (ra + 10 )) = disp;
475 disp = OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*);
477 assert( (s2)disp == disp);
478 assert ( *((s2*)(ra+18)) == 0x246a );
480 *((s2 *) (ra + 20)) = disp;
482 /* synchronize instruction cache */
483 md_icacheflush((void*)(ra + 10), 12);
488 /* patcher_checkcast_interface *************************************************
490 0x402a9400: 61ff 0000 03b6 bsrl 0x402a97b8
491 0x402a9406: 266a 0000 moveal %a2@(0),%a3
492 0x402a940a: 282b 0010 movel %a3@(16),%d4
493 0x402a940e: d8bc 0000 0000 addl #0,%d4 <-- this 0
494 0x402a9414: 4a84 tstl %d4
495 0x402a9416: 6e02 bgts 0x402a941a
497 0x402a9418: 4afc illegal
498 0x402a941a: 286b 0000 moveal %a3@(0),%a4 <-- and this 0 offset
500 *******************************************************************************/
502 bool patcher_checkcast_interface(patchref_t *pr)
505 constant_classref *cr;
509 /* get stuff from the stack */
511 cr = (constant_classref *) pr->ref;
513 /* get the fieldinfo */
514 if (!(c = resolve_classref_eager(cr)))
517 /* patch back original code */
518 PATCH_BACK_ORIGINAL_MCODE;
519 md_icacheflush(pr->mpc, 2);
521 /* if we show NOPs, we have to skip them */
522 if (opt_shownops) ra += PATCHER_CALL_SIZE;
524 /* patch super class index */
526 assert ( *((u2 *)(ra + 8)) == 0xd8bc );
527 *((s4 *) (ra + 10)) = disp;
529 disp = OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*);
530 assert( *((u2 *)(ra + 22)) == 0x286b );
531 assert( (s2)disp == disp);
532 *((s2 *) (ra + 24)) = disp;
534 /* synchronize instruction cache */
535 md_icacheflush((void*)(ra + 10), 16);
541 /* patcher_resolve_native_function *********************************************
545 *******************************************************************************/
547 bool patcher_resolve_native_function(patchref_t *pr)
553 /* get stuff from the stack */
554 m = (methodinfo *) pr->ref;
557 /* resolve native function */
558 if (!(f = native_resolve_function(m)))
561 /* patch back original code */
562 PATCH_BACK_ORIGINAL_MCODE;
563 md_icacheflush(pr->mpc, 2);
565 /* patch native function pointer */
566 if (opt_shownops) disp += PATCHER_CALL_SIZE;
567 *((ptrint *) (disp + 2)) = (ptrint) f;
569 /* synchronize data cache */
570 md_icacheflush((void*)(disp + 2), SIZEOF_VOID_P);
576 /* patcher_invokeinterface *****************************************************
579 0x40adb03e: moveal %a2@(0),%a3 0x266a0000 <-- no patching
580 0x40adb042: moveal %a3@(0),%a3 0x266b0000 <-- patch this 0000
581 0x40adb046: moveal %a3@(0),%a4 0xxxxx0000 <-- patch this 0000
582 0x40adb04a: jsr %a4@ 0xxxxx
585 *******************************************************************************/
587 bool patcher_invokeinterface(patchref_t *pr)
590 unresolved_method *um;
594 /* get stuff from the stack */
596 um = (unresolved_method *) pr->ref;
599 /* get the fieldinfo */
600 if (!(m = resolve_method_eager(um)))
603 /* patch back original code */
604 PATCH_BACK_ORIGINAL_MCODE;
605 md_icacheflush(pr->mpc, 2);
607 /* if we show NOPs, we have to skip them */
608 if (opt_shownops) ra += PATCHER_CALL_SIZE;
609 assert( *((uint32_t*)ra) == 0x246f0000 );
611 /* patch interfacetable index (first #0) */
612 disp = OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr*) * m->class->index;
613 /* XXX this disp is negative, check!
614 * assert( (disp & 0x0000ffff) == disp);*/
615 *((uint16_t *) (ra + 5 * 2)) = disp;
617 /* patch method offset (second #0) */
618 disp = sizeof(methodptr) * (m - m->class->methods);
619 assert( (disp & 0x0000ffff) == disp);
620 *((uint16_t *) (ra + 7 * 2)) = disp;
622 /* synchronize instruction cache */
623 md_icacheflush((void*)(ra + 5 * 2), 2 * 2);
628 * These are local overrides for various environment variables in Emacs.
629 * Please do not remove this and leave it at the end of the file, where
630 * Emacs will automagically detect them.
631 * ---------------------------------------------------------------------
634 * indent-tabs-mode: t
638 * vim:noexpandtab:sw=4:ts=4: