1 /* src/vm/jit/m68k/patcher.c - m68k patcher functions
3 Copyright (C) 1996-2005, 2006, 2007, 2008
4 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
6 This file is part of CACAO.
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2, or (at
11 your option) any later version.
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
32 #include "vm/jit/m68k/md.h"
34 #include "mm/memory.h"
35 #include "native/native.hpp"
37 #include "vm/jit/builtin.hpp"
38 #include "vm/class.hpp"
39 #include "vm/field.hpp"
40 #include "vm/initialize.hpp"
41 #include "vm/options.h"
42 #include "vm/references.h"
43 #include "vm/resolve.hpp"
45 #include "vm/jit/asmpart.h"
46 #include "vm/jit/patcher-common.hpp"
50 #define PATCH_BACK_ORIGINAL_MCODE *((u4*)(pr->mpc)) = pr->mcode
52 /* patcher_initialize_class ****************************************************
54 just patch back original code
56 *******************************************************************************/
59 void patcher_patch_code(patchref_t *pr)
62 u1* xpc = (u1 *) *((ptrint *) (sp + 6 * 4));
63 u4 mcode = *((u4*) (sp + 3 * 4));
64 u4 xmcode = *((u4*) (sp + 2 * 4));
66 *((u4*)(xpc)) = mcode;
67 *((u4*)(xpc+4)) = xmcode;
70 PATCH_BACK_ORIGINAL_MCODE;
71 md_icacheflush((void*)pr->mpc, 2);
77 /* patcher_initialize_class ****************************************************
79 Initalizes a given classinfo pointer. This function does not patch
82 *******************************************************************************/
84 bool patcher_initialize_class(patchref_t *pr)
87 u4 xpc, mcode, xmcode;
89 /* get stuff from the stack */
90 c = (classinfo *) *((ptrint *) (sp + 1 * 4));
92 /* check if the class is initialized */
93 if (!(c->state & CLASS_INITIALIZED))
94 if (!initialize_class(c))
97 /* patch back original code */
98 patcher_patch_back(sp);
104 /* patcher_invokevirtual *******************************************************
107 0x4029bc46: 61ff 0000 00ba bsrl 0x4029bd02
108 0x4029bc4c: 246f 0000 moveal %sp@(0),%a2
109 0x4029bc50: 266a 0000 moveal %a2@(0),%a3
110 0x4029bc54: 246b 0000 moveal %a3@(0),%a2 <-- patch this (0) offset
111 0x4029bc58: 4e92 jsr %a2@
113 *******************************************************************************/
115 bool patcher_invokevirtual(patchref_t *pr)
118 unresolved_method *um;
122 /* get stuff from the stack */
124 um = (unresolved_method *) pr->ref;
126 /* get the fieldinfo */
127 if (!(m = resolve_method_eager(um)))
130 /* patch back original code */
131 PATCH_BACK_ORIGINAL_MCODE;
133 assert( *((u2*)(ra+8)) == 0x286b);
135 /* patch vftbl index */
136 disp = (OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * m->vftblindex);
137 *((s2 *) (ra + 10)) = disp;
139 /* synchronize instruction cache */
140 md_icacheflush(pr->mpc, 10 + 2 + PATCHER_CALL_SIZE);
145 /* patcher_invokestatic_special ************************************************
150 0x402902bc: 61ff 0000 0076 bsrl 0x40290334
151 0x402902c2: 247c 0000 0000 moveal #0,%a2 <-- this #0
152 0x402902c8: 4e92 jsr %a2@
154 ******************************************************************************/
156 bool patcher_invokestatic_special(patchref_t *pr)
158 unresolved_method *um;
162 /* get stuff from the stack */
164 um = (unresolved_method *) pr->ref;
166 /* get the fieldinfo */
167 if (!(m = resolve_method_eager(um)))
170 /* patch back original code */
171 PATCH_BACK_ORIGINAL_MCODE;
173 *((ptrint *) (disp+2)) = (ptrint) m->stubroutine;
175 /* synchronize inst cache */
177 md_icacheflush(pr->mpc, PATCHER_CALL_SIZE+2+SIZEOF_VOID_P);
183 /* patcher_resolve_classref_to_classinfo ***************************************
185 0x4028f2ca: 2479 0000 0000 moveal 0x00000000,%a2
186 *******************************************************************************/
187 bool patcher_resolve_classref_to_classinfo(patchref_t *pr)
189 constant_classref *cr;
194 /* get stuff from the stack */
195 cr = (constant_classref *) pr->ref;
198 /* get the classinfo */
199 if (!(c = resolve_classref_eager(cr)))
202 /* patch back original code */
203 PATCH_BACK_ORIGINAL_MCODE;
205 /* patch the classinfo pointer */
206 *((ptrint *) (disp+2)) = (ptrint) c;
208 /* synchronize inst cache */
209 md_icacheflush(pr->mpc, PATCHER_CALL_SIZE + 2 + SIZEOF_VOID_P);
214 /* patcher_get_putstatic *******************************************************
218 *******************************************************************************/
220 bool patcher_get_putstatic(patchref_t *pr)
222 unresolved_field *uf;
226 /* get stuff from the stack */
227 uf = (unresolved_field *) pr->ref;
230 /* get the fieldinfo */
231 if (!(fi = resolve_field_eager(uf)))
234 /* check if the field's class is initialized */
235 if (!(fi->clazz->state & CLASS_INITIALIZED))
236 if (!initialize_class(fi->clazz))
239 /* patch back original code */
240 PATCH_BACK_ORIGINAL_MCODE;
241 md_icacheflush(pr->mpc, 2);
243 /* patch the field value's address */
244 assert(*((uint16_t*)(disp)) == 0x247c);
245 *((intptr_t *) (disp+2)) = (intptr_t) fi->value;
247 /* synchronize inst cache */
248 md_icacheflush((void*)(disp+2), SIZEOF_VOID_P);
253 /* patcher_get_putfield ********************************************************
257 <patched call position>
259 *******************************************************************************/
261 bool patcher_get_putfield(patchref_t *pr)
264 unresolved_field *uf;
268 uf = (unresolved_field *) pr->ref;
270 /* get the fieldinfo */
271 if (!(fi = resolve_field_eager(uf)))
274 /* patch back original code */
275 PATCH_BACK_ORIGINAL_MCODE;
276 md_icacheflush(pr->mpc, 2);
278 /* patch the field's offset */
279 if (IS_LNG_TYPE(fi->type)) {
281 * 0x40d05bb2: 0x25440000 movel %d4,%a2@(0)
282 * 0x40d05bb6: 0x25430004 movel %d3,%a2@(4)
284 * both 0000 and 0004 have to be patched
287 assert( (fi->offset & 0x0000ffff) == fi->offset );
289 assert( (*((uint32_t*)ra) & 0xffff0000) == *((uint32_t*)ra) );
290 assert( (*((uint32_t*)(ra+4)) & 0xffff0004) == *((uint32_t*)(ra+4)) );
292 *((int16_t *) (ra + 2)) = (int16_t) ((fi->offset) & 0x0000ffff);
293 *((int16_t *) (ra + 6)) = (int16_t) ((fi->offset + 4) & 0x0000ffff);
295 md_icacheflush(ra, 2 * 4);
297 /* Multiple cases here, int, adr, flt and dbl. */
298 if ( (*((uint32_t*)ra) & 0xfff00000) == 0xf2200000 ) {
300 * 0x40d3ddc2: 0xf22944c0 0x0000xxxx fsmoves %a1@(0),%fp1
304 assert( (fi->offset & 0x0000ffff) == fi->offset );
305 assert( (*((uint32_t*)(ra+4)) & 0x0000ffff) == *((uint32_t*)(ra+4)) );
306 *((int16_t*)(ra+4)) = (int16_t)fi->offset;
308 md_icacheflush(ra+4, 1 * 4);
311 * 0x40adb3f6: 0x254d0000 movel %a5,%a2@(0)
315 assert( (*((uint32_t*)ra) & 0xffff0000) == *((uint32_t*)ra) );
316 assert( (fi->offset & 0x0000ffff) == fi->offset );
317 *((int16_t*)(ra+2)) = (int16_t)fi->offset;
319 /* synchronize instruction cache */
320 md_icacheflush(ra, 1 * 4);
326 /* patcher_resolve_classref_to_flags *******************************************
328 CHECKCAST/INSTANCEOF:
332 0x4029b056: 61ff 0000 013e bsrl 0x4029b196
333 0x4029b05c: 263c 0000 0000 movel #0,%d3 <-- patch this #0
334 0x4029b062: 0283 0000 0200 andil #512,%d3
337 0x402a4aa8: 61ff 0000 05c4 bsrl 0x402a506e
338 0x402a4aae: 283c 0000 0000 movel #0,%d4 <-- same here
339 0x402a4ab4: 0284 0000 0200 andil #512,%d4
342 *******************************************************************************/
344 bool patcher_resolve_classref_to_flags(patchref_t *pr)
346 constant_classref *cr;
350 /* get stuff from the stack */
351 cr = (constant_classref *) pr->ref;
354 /* get the fieldinfo */
355 if (!(c = resolve_classref_eager(cr)))
358 /* patch back original code */
359 PATCH_BACK_ORIGINAL_MCODE;
360 md_icacheflush(pr->mpc, 2);
362 /* patch class flags */
363 assert( (*((u2*)(disp)) == 0x263c) || (*((u2*)(disp)) == 0x283c) );
364 *((s4 *) (disp + 2)) = (s4) c->flags;
366 /* synchronize insn cache */
367 md_icacheflush((void*)(disp + 2), SIZEOF_VOID_P);
372 /* patcher_resolve_classref_to_vftbl *******************************************
375 0x4029b094: 61ff 0000 00b4 bsrl 0x4029b14a
376 0x4029b09a: 287c 0000 0000 moveal #0,%a4 <-- patch this #0
377 0x4029b0a0: 2668 0000 moveal %a0@(0),%a3
380 0x402a9300: 61ff 0000 0574 bsrl 0x402a9876
381 0x402a9306: 267c 0000 0000 moveal #0,%a3
382 0x402a930c: 246a 0000 moveal %a2@(0),%a2
385 *******************************************************************************/
387 bool patcher_resolve_classref_to_vftbl(patchref_t *pr)
389 constant_classref *cr;
393 /* get stuff from the stack */
394 cr = (constant_classref *) pr->ref;
397 /* get the fieldinfo */
398 if (!(c = resolve_classref_eager(cr)))
401 /* patch back original code */
402 PATCH_BACK_ORIGINAL_MCODE;
403 md_icacheflush(pr->mpc, 2);
405 /* patch super class' vftbl */
406 assert( (*((u2*)disp) == 0x287c) || (*((u2*)disp)== 0x267c) );
408 *((s4 *) (disp+2)) = (s4) c->vftbl;
410 /* synchronize insin cache */
411 md_icacheflush((void*)(disp+2), SIZEOF_VOID_P);
416 /* patcher_instanceof_interface ************************************************
420 0x402a92da: 61ff 0000 05c0 bsrl 0x402a989c
421 0x402a92e0: 246a 0000 moveal %a2@(0),%a2
422 0x402a92e4: 282a 0010 movel %a2@(16),%d4
423 0x402a92e8: d8bc 0000 0000 addl #0,%d4 <-- this const
424 0x402a92ee: 4a84 tstl %d4
425 0x402a92f0: 6e0a bles 0x402a92fc
426 0x402a92f2: 246a 0000 moveal %a2@(0),%a2 <-- this offset
428 *******************************************************************************/
430 bool patcher_instanceof_interface(patchref_t *pr)
433 constant_classref *cr;
437 /* get stuff from the stack */
440 cr = (constant_classref *) pr->ref;
442 /* get the fieldinfo */
443 if (!(c = resolve_classref_eager(cr)))
446 /* patch back original code */
447 PATCH_BACK_ORIGINAL_MCODE;
448 md_icacheflush(pr->mpc, 2);
450 /* patch super class index */
452 assert( *((u2*)(ra + 8)) == 0xd8bc );
453 *((s4 *) (ra + 10 )) = disp;
455 disp = OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*);
457 assert( (s2)disp == disp);
458 assert ( *((s2*)(ra+18)) == 0x246a );
460 *((s2 *) (ra + 20)) = disp;
462 /* synchronize instruction cache */
463 md_icacheflush((void*)(ra + 10), 12);
468 /* patcher_checkcast_interface *************************************************
470 0x402a9400: 61ff 0000 03b6 bsrl 0x402a97b8
471 0x402a9406: 266a 0000 moveal %a2@(0),%a3
472 0x402a940a: 282b 0010 movel %a3@(16),%d4
473 0x402a940e: d8bc 0000 0000 addl #0,%d4 <-- this 0
474 0x402a9414: 4a84 tstl %d4
475 0x402a9416: 6e02 bgts 0x402a941a
477 0x402a9418: 4afc illegal
478 0x402a941a: 286b 0000 moveal %a3@(0),%a4 <-- and this 0 offset
480 *******************************************************************************/
482 bool patcher_checkcast_interface(patchref_t *pr)
485 constant_classref *cr;
489 /* get stuff from the stack */
491 cr = (constant_classref *) pr->ref;
493 /* get the fieldinfo */
494 if (!(c = resolve_classref_eager(cr)))
497 /* patch back original code */
498 PATCH_BACK_ORIGINAL_MCODE;
499 md_icacheflush(pr->mpc, 2);
501 /* patch super class index */
503 assert ( *((u2 *)(ra + 8)) == 0xd8bc );
504 *((s4 *) (ra + 10)) = disp;
506 disp = OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*);
507 assert( *((u2 *)(ra + 22)) == 0x286b );
508 assert( (s2)disp == disp);
509 *((s2 *) (ra + 24)) = disp;
511 /* synchronize instruction cache */
512 md_icacheflush((void*)(ra + 10), 16);
518 /* patcher_resolve_native_function *********************************************
522 *******************************************************************************/
524 bool patcher_resolve_native_function(patchref_t *pr)
530 /* get stuff from the stack */
531 m = (methodinfo *) pr->ref;
534 /* resolve native function */
535 if (!(f = native_resolve_function(m)))
538 /* patch back original code */
539 PATCH_BACK_ORIGINAL_MCODE;
540 md_icacheflush(pr->mpc, 2);
542 /* patch native function pointer */
543 *((ptrint *) (disp + 2)) = (ptrint) f;
545 /* synchronize data cache */
546 md_icacheflush((void*)(disp + 2), SIZEOF_VOID_P);
552 /* patcher_invokeinterface *****************************************************
555 0x40adb03e: moveal %a2@(0),%a3 0x266a0000 <-- no patching
556 0x40adb042: moveal %a3@(0),%a3 0x266b0000 <-- patch this 0000
557 0x40adb046: moveal %a3@(0),%a4 0xxxxx0000 <-- patch this 0000
558 0x40adb04a: jsr %a4@ 0xxxxx
561 *******************************************************************************/
563 bool patcher_invokeinterface(patchref_t *pr)
566 unresolved_method *um;
570 /* get stuff from the stack */
572 um = (unresolved_method *) pr->ref;
575 /* get the fieldinfo */
576 if (!(m = resolve_method_eager(um)))
579 /* patch back original code */
580 PATCH_BACK_ORIGINAL_MCODE;
581 md_icacheflush(pr->mpc, 2);
583 /* if we show NOPs, we have to skip them */
584 assert( *((uint32_t*)ra) == 0x246f0000 );
586 /* patch interfacetable index (first #0) */
587 disp = OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr*) * m->clazz->index;
588 /* XXX this disp is negative, check!
589 * assert( (disp & 0x0000ffff) == disp);*/
590 *((uint16_t *) (ra + 5 * 2)) = disp;
592 /* patch method offset (second #0) */
593 disp = sizeof(methodptr) * (m - m->clazz->methods);
594 assert( (disp & 0x0000ffff) == disp);
595 *((uint16_t *) (ra + 7 * 2)) = disp;
597 /* synchronize instruction cache */
598 md_icacheflush((void*)(ra + 5 * 2), 2 * 2);
605 * These are local overrides for various environment variables in Emacs.
606 * Please do not remove this and leave it at the end of the file, where
607 * Emacs will automagically detect them.
608 * ---------------------------------------------------------------------
611 * indent-tabs-mode: t
615 * vim:noexpandtab:sw=4:ts=4: