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