Merge from subtype.
[cacao.git] / src / vm / jit / m68k / patcher.c
1 /* src/vm/jit/m68k/patcher.c - m68k patcher functions
2
3    Copyright (C) 1996-2005, 2006, 2007, 2008
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5
6    This file is part of CACAO.
7
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.
12
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.
17
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
21    02110-1301, USA.
22
23 */
24
25 #include "config.h"
26
27 #include <assert.h>
28 #include <stdint.h>
29
30 #include "vm/types.h"
31
32 #include "vm/jit/m68k/md.h"
33
34 #include "mm/memory.h"
35 #include "native/native.hpp"
36
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"
44
45 #include "vm/jit/asmpart.h"
46 #include "vm/jit/patcher-common.hpp"
47
48 #include "codegen.h"
49
50 #define PATCH_BACK_ORIGINAL_MCODE  *((u4*)(pr->mpc)) = pr->mcode
51
52 /* patcher_initialize_class ****************************************************
53
54         just patch back original code
55
56 *******************************************************************************/
57
58
59 void patcher_patch_code(patchref_t *pr) 
60 {
61 #if 0
62         u1* xpc    = (u1 *)      *((ptrint *) (sp + 6 * 4));
63         u4 mcode  = *((u4*)      (sp + 3 * 4));
64         u4 xmcode = *((u4*)      (sp + 2 * 4));
65
66         *((u4*)(xpc))   = mcode;
67         *((u4*)(xpc+4)) = xmcode;
68 #endif
69
70         PATCH_BACK_ORIGINAL_MCODE;
71         md_icacheflush((void*)pr->mpc, 2);
72
73 }
74
75
76 #if 0
77 /* patcher_initialize_class ****************************************************
78
79    Initalizes a given classinfo pointer.  This function does not patch
80    any data.
81
82 *******************************************************************************/
83
84 bool patcher_initialize_class(patchref_t *pr)
85 {
86         classinfo *c;
87         u4                 xpc, mcode, xmcode;
88
89         /* get stuff from the stack */
90         c = (classinfo *) *((ptrint *) (sp + 1 * 4));
91
92         /* check if the class is initialized */
93         if (!(c->state & CLASS_INITIALIZED))
94                 if (!initialize_class(c))
95                         return false;
96
97         /* patch back original code */
98         patcher_patch_back(sp);
99
100         return true;
101 }
102 #endif
103
104 /* patcher_invokevirtual *******************************************************
105
106    Machine code:
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@
112
113 *******************************************************************************/
114
115 bool patcher_invokevirtual(patchref_t *pr)
116 {
117         u1                *ra;
118         unresolved_method *um;
119         methodinfo        *m;
120         s2                 disp;
121
122         /* get stuff from the stack */
123         ra = (u1 *)                pr->mpc;
124         um = (unresolved_method *) pr->ref;
125
126         /* get the fieldinfo */
127         if (!(m = resolve_method_eager(um)))
128                 return false;
129
130         /* patch back original code */
131         PATCH_BACK_ORIGINAL_MCODE;
132
133         assert( *((u2*)(ra+8)) == 0x286b);
134
135         /* patch vftbl index */
136         disp = (OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * m->vftblindex);
137         *((s2 *) (ra + 10)) = disp;
138
139         /* synchronize instruction cache */
140         md_icacheflush(pr->mpc, 10 + 2 + PATCHER_CALL_SIZE);
141
142         return true;
143 }
144
145 /* patcher_invokestatic_special ************************************************
146
147    Machine code:
148
149    INVOKESPECIAL
150 0x402902bc:   61ff 0000 0076    bsrl 0x40290334
151 0x402902c2:   247c 0000 0000    moveal #0,%a2           <-- this #0
152 0x402902c8:   4e92              jsr %a2@
153
154 ******************************************************************************/
155
156 bool patcher_invokestatic_special(patchref_t *pr)
157 {
158         unresolved_method *um;
159         s4                 disp;
160         methodinfo        *m;
161
162         /* get stuff from the stack */
163         disp =                       pr->mpc;
164         um   = (unresolved_method *) pr->ref;
165
166         /* get the fieldinfo */
167         if (!(m = resolve_method_eager(um)))
168                 return false;
169
170         /* patch back original code */
171         PATCH_BACK_ORIGINAL_MCODE;
172
173         *((ptrint *) (disp+2)) = (ptrint) m->stubroutine;
174
175         /* synchronize inst cache */
176
177         md_icacheflush(pr->mpc, PATCHER_CALL_SIZE+2+SIZEOF_VOID_P);
178
179         return true;
180 }
181
182
183 /* patcher_resolve_classref_to_classinfo ***************************************
184   ACONST:
185         0x4028f2ca:   2479 0000 0000    moveal 0x00000000,%a2
186 *******************************************************************************/
187 bool patcher_resolve_classref_to_classinfo(patchref_t *pr)
188 {
189         constant_classref *cr;
190         s4                 disp;
191         u1                *pv;
192         classinfo         *c;
193
194         /* get stuff from the stack */
195         cr   = (constant_classref *) pr->ref;
196         disp =                       pr->mpc;
197
198         /* get the classinfo */
199         if (!(c = resolve_classref_eager(cr)))
200                 return false;
201
202         /* patch back original code */
203         PATCH_BACK_ORIGINAL_MCODE;
204
205         /* patch the classinfo pointer */
206         *((ptrint *) (disp+2)) = (ptrint) c;
207
208         /* synchronize inst cache */
209         md_icacheflush(pr->mpc, PATCHER_CALL_SIZE + 2 + SIZEOF_VOID_P);
210
211         return true;
212 }
213
214 /* patcher_get_putstatic *******************************************************
215
216    Machine code:
217
218 *******************************************************************************/
219
220 bool patcher_get_putstatic(patchref_t *pr)
221 {
222         unresolved_field *uf;
223         s4                disp;
224         fieldinfo        *fi;
225
226         /* get stuff from the stack */
227         uf    = (unresolved_field *)  pr->ref;
228         disp  =                       pr->mpc;
229
230         /* get the fieldinfo */
231         if (!(fi = resolve_field_eager(uf)))
232                 return false;
233
234         /* check if the field's class is initialized */
235         if (!(fi->clazz->state & CLASS_INITIALIZED))
236                 if (!initialize_class(fi->clazz))
237                         return false;
238
239         /* patch back original code */
240         PATCH_BACK_ORIGINAL_MCODE;
241         md_icacheflush(pr->mpc, 2);
242
243         /* patch the field value's address */
244         assert(*((uint16_t*)(disp)) == 0x247c);
245         *((intptr_t *) (disp+2)) = (intptr_t) fi->value;
246
247         /* synchronize inst cache */
248         md_icacheflush((void*)(disp+2), SIZEOF_VOID_P);
249
250         return true;
251 }
252
253 /* patcher_get_putfield ********************************************************
254
255    Machine code:
256
257    <patched call position>
258
259 *******************************************************************************/
260
261 bool patcher_get_putfield(patchref_t *pr)
262 {
263         u1               *ra;
264         unresolved_field *uf;
265         fieldinfo        *fi;
266
267         ra = (u1 *)               pr->mpc;
268         uf = (unresolved_field *) pr->ref;
269
270         /* get the fieldinfo */
271         if (!(fi = resolve_field_eager(uf)))
272                 return false;
273
274         /* patch back original code */
275         PATCH_BACK_ORIGINAL_MCODE;
276         md_icacheflush(pr->mpc, 2);
277
278         /* patch the field's offset */
279         if (IS_LNG_TYPE(fi->type)) {
280                 /*
281                  *      0x40d05bb2:     0x25440000      movel %d4,%a2@(0)
282                  *      0x40d05bb6:     0x25430004      movel %d3,%a2@(4)
283                  *                                            ^^^^
284                  *                                            both 0000 and 0004 have to be patched
285                  */
286
287                 assert( (fi->offset & 0x0000ffff) == fi->offset );
288
289                 assert( (*((uint32_t*)ra) & 0xffff0000) == *((uint32_t*)ra) );
290                 assert( (*((uint32_t*)(ra+4)) & 0xffff0004) == *((uint32_t*)(ra+4)) );
291
292                 *((int16_t *) (ra + 2)) = (int16_t) ((fi->offset) & 0x0000ffff);
293                 *((int16_t *) (ra + 6)) = (int16_t) ((fi->offset + 4) & 0x0000ffff);
294
295                 md_icacheflush(ra, 2 * 4);
296         } else  {
297                 /*      Multiple cases here, int, adr, flt and dbl. */
298                 if ( (*((uint32_t*)ra) & 0xfff00000) == 0xf2200000 )    {
299                         /* flt/dbl case 
300                          * 0x40d3ddc2:     0xf22944c0 0x0000xxxx        fsmoves %a1@(0),%fp1
301                          *                                  ^^^^
302                          *                                  patch here 
303                          */
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;
307
308                         md_icacheflush(ra+4, 1 * 4);
309                 } else  {
310                         /*      int/adr case
311                          *      0x40adb3f6:     0x254d0000      movel %a5,%a2@(0)
312                          *                            ^^^^                     ^
313                          *                            to be patched
314                          */
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;
318
319                         /* synchronize instruction cache */
320                         md_icacheflush(ra, 1 * 4);
321                 }
322         }
323
324         return true;
325 }
326 /* patcher_resolve_classref_to_flags *******************************************
327
328    CHECKCAST/INSTANCEOF:
329
330
331 CHECKCAST:
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
335
336 INSTANCEOF:
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
340
341
342 *******************************************************************************/
343
344 bool patcher_resolve_classref_to_flags(patchref_t *pr)
345 {
346         constant_classref *cr;
347         s4                 disp;
348         classinfo         *c;
349
350         /* get stuff from the stack */
351         cr   = (constant_classref *) pr->ref;
352         disp =                       pr->mpc;
353
354         /* get the fieldinfo */
355         if (!(c = resolve_classref_eager(cr)))
356                 return false;
357
358         /* patch back original code */
359         PATCH_BACK_ORIGINAL_MCODE;
360         md_icacheflush(pr->mpc, 2);
361
362         /* patch class flags */
363         assert( (*((u2*)(disp)) == 0x263c) || (*((u2*)(disp)) == 0x283c) );
364         *((s4 *) (disp + 2)) = (s4) c->flags;
365
366         /* synchronize insn cache */
367         md_icacheflush((void*)(disp + 2), SIZEOF_VOID_P);
368
369         return true;
370 }
371
372 /* patcher_resolve_classref_to_vftbl *******************************************
373
374    CHECKCAST (class):
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
378
379    INSTANCEOF (class):
380 0x402a9300:   61ff 0000 0574    bsrl 0x402a9876
381 0x402a9306:   267c 0000 0000    moveal #0,%a3
382 0x402a930c:   246a 0000         moveal %a2@(0),%a2
383
384
385 *******************************************************************************/
386
387 bool patcher_resolve_classref_to_vftbl(patchref_t *pr)
388 {
389         constant_classref *cr;
390         s4                 disp;
391         classinfo         *c;
392
393         /* get stuff from the stack */
394         cr   = (constant_classref *) pr->ref;
395         disp =                       pr->mpc;
396
397         /* get the fieldinfo */
398         if (!(c = resolve_classref_eager(cr)))
399                 return false;
400
401         /* patch back original code */
402         PATCH_BACK_ORIGINAL_MCODE;
403         md_icacheflush(pr->mpc, 2);
404
405         /* patch super class' vftbl */
406         assert( (*((u2*)disp) == 0x287c) || (*((u2*)disp)== 0x267c) );
407
408         *((s4 *) (disp+2)) = (s4) c->vftbl;
409
410         /* synchronize insin cache */
411         md_icacheflush((void*)(disp+2), SIZEOF_VOID_P);
412
413         return true;
414 }
415
416 /* patcher_instanceof_interface ************************************************
417
418    Machine code:
419
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
427
428 *******************************************************************************/
429
430 bool patcher_instanceof_interface(patchref_t *pr)
431 {
432         u1                *ra;
433         constant_classref *cr;
434         classinfo         *c;
435         s4                 disp;
436
437         /* get stuff from the stack */
438
439         ra = (u1 *)                pr->mpc;
440         cr = (constant_classref *) pr->ref;
441
442         /* get the fieldinfo */
443         if (!(c = resolve_classref_eager(cr)))
444                 return false;
445
446         /* patch back original code */
447         PATCH_BACK_ORIGINAL_MCODE;
448         md_icacheflush(pr->mpc, 2);
449
450         /* patch super class index */
451         disp = -(c->index);
452         assert( *((u2*)(ra + 8)) == 0xd8bc );
453         *((s4 *) (ra + 10 )) = disp;
454
455         disp = OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*);
456
457         assert( (s2)disp  == disp);
458         assert ( *((s2*)(ra+18)) == 0x246a );
459
460         *((s2 *) (ra + 20)) = disp;
461
462         /* synchronize instruction cache */
463         md_icacheflush((void*)(ra + 10), 12);
464
465         return true;
466 }
467
468 /* patcher_checkcast_interface *************************************************
469
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
476               1234              tstb %d0
477 0x402a9418:   4afc              illegal
478 0x402a941a:   286b 0000         moveal %a3@(0),%a4      <-- and this 0 offset
479
480 *******************************************************************************/
481
482 bool patcher_checkcast_interface(patchref_t *pr)
483 {
484         u1                *ra;
485         constant_classref *cr;
486         classinfo         *c;
487         s4                 disp;
488
489         /* get stuff from the stack */
490         ra = (u1 *)                pr->mpc;
491         cr = (constant_classref *) pr->ref;
492
493         /* get the fieldinfo */
494         if (!(c = resolve_classref_eager(cr)))
495                 return false;
496
497         /* patch back original code */
498         PATCH_BACK_ORIGINAL_MCODE;
499         md_icacheflush(pr->mpc, 2);
500
501         /* patch super class index */
502         disp = -(c->index);
503         assert ( *((u2 *)(ra + 8)) == 0xd8bc );
504         *((s4 *) (ra + 10)) = disp;
505
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;
510         
511         /* synchronize instruction cache */
512         md_icacheflush((void*)(ra + 10), 16);
513
514         return true;
515 }
516
517 #if 0
518 /* patcher_resolve_native_function *********************************************
519
520    XXX
521
522 *******************************************************************************/
523
524 bool patcher_resolve_native_function(patchref_t *pr)
525 {
526         methodinfo  *m;
527         s4           disp;
528         functionptr  f;
529
530         /* get stuff from the stack */
531         m    = (methodinfo *) pr->ref;
532         disp =                pr->mpc;
533
534         /* resolve native function */
535         if (!(f = native_resolve_function(m)))
536                 return false;
537
538         /* patch back original code */
539         PATCH_BACK_ORIGINAL_MCODE;
540         md_icacheflush(pr->mpc, 2);
541
542         /* patch native function pointer */
543         *((ptrint *) (disp + 2)) = (ptrint) f;
544
545         /* synchronize data cache */
546         md_icacheflush((void*)(disp + 2), SIZEOF_VOID_P);
547
548         return true;
549 }
550 #endif
551
552 /* patcher_invokeinterface *****************************************************
553
554    Machine code:
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                  
559
560
561 *******************************************************************************/
562
563 bool patcher_invokeinterface(patchref_t *pr)
564 {
565         u1                *ra;
566         unresolved_method *um;
567         methodinfo        *m;
568         s4                 disp;
569
570         /* get stuff from the stack */
571         ra = (u1 *)                pr->mpc;
572         um = (unresolved_method *) pr->ref;
573
574
575         /* get the fieldinfo */
576         if (!(m = resolve_method_eager(um)))
577                 return false;
578
579         /* patch back original code */
580         PATCH_BACK_ORIGINAL_MCODE;
581         md_icacheflush(pr->mpc, 2);
582
583         /* if we show NOPs, we have to skip them */
584         assert( *((uint32_t*)ra) == 0x246f0000 );
585
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;
591
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;
596
597         /* synchronize instruction cache */
598         md_icacheflush((void*)(ra + 5 * 2), 2 * 2);
599
600         return true;
601 }
602
603
604 /*
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  * ---------------------------------------------------------------------
609  * Local variables:
610  * mode: c
611  * indent-tabs-mode: t
612  * c-basic-offset: 4
613  * tab-width: 4
614  * End:
615  * vim:noexpandtab:sw=4:ts=4:
616  */