b2ccfdeceb9c91ec385e3cf4a217125b4d6410e0
[cacao.git] / src / vm / jit / powerpc64 / patcher.c
1 /* src/vm/jit/powerpc64/patcher.c - PowerPC64 code patching 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
28 #include "config.h"
29
30 #include <assert.h>
31 #include <stdint.h>
32
33 #include "vm/types.h"
34
35 #include "vm/jit/powerpc64/md.h"
36
37 #include "mm/memory.h"
38
39 #include "native/native.h"
40
41 #include "vm/builtin.h"
42 #include "vm/exceptions.h"
43 #include "vm/initialize.h"
44
45 #include "vm/jit/asmpart.h"
46 #include "vm/jit/methodheader.h"
47 #include "vm/jit/patcher-common.h"
48 #include "vm/jit/stacktrace.h"
49
50 #include "vmcore/class.h"
51 #include "vmcore/field.h"
52 #include "vmcore/options.h"
53 #include "vmcore/references.h"
54 #include "vm/resolve.h"
55
56
57 /* patcher_patch_code **********************************************************
58
59    Just patches back the original machine code.
60
61 *******************************************************************************/
62
63 void patcher_patch_code(patchref_t *pr)
64 {
65         /* patch back original code */
66
67         *((u4 *) pr->mpc) = pr->mcode;
68
69         /* synchronize instruction cache */
70
71         md_icacheflush(pr->mpc, 4);
72 }
73
74
75 /* patcher_get_putstatic *******************************************************
76
77    Machine code:
78
79    <patched call position>
80    816dffc8    lwz   r11,-56(r13)
81    80ab0000    lwz   r5,0(r11)
82
83 *******************************************************************************/
84
85 bool patcher_get_putstatic(patchref_t *pr)
86 {
87         u1               *ra;
88         u4                mcode;
89         unresolved_field *uf;
90         u1               *datap;
91         fieldinfo        *fi;
92
93         /* get stuff from the stack */
94
95         ra    = (u1 *)                pr->mpc;
96         mcode =                       pr->mcode;
97         uf    = (unresolved_field *)  pr->ref;
98         datap = (u1 *)                pr->datap;
99
100         /* get the fieldinfo */
101
102         if (!(fi = resolve_field_eager(uf)))
103                 return false;
104
105         /* check if the field's class is initialized */
106
107         if (!(fi->class->state & CLASS_INITIALIZED))
108                 if (!initialize_class(fi->class))
109                         return false;
110
111         /* patch back original code */
112
113         *((u4 *) ra) = mcode;
114
115         /* synchronize instruction cache */
116
117         md_icacheflush(ra, 4);
118
119         /* patch the field value's address */
120
121         *((intptr_t *) datap) = (intptr_t) fi->value;
122
123         /* synchronize data cache */
124
125         md_dcacheflush(datap, SIZEOF_VOID_P);
126
127         return true;
128 }
129
130
131 /* patcher_get_putfield ********************************************************
132
133    Machine code:
134
135    <patched call position>
136    811f0014    lwz   r8,20(r31)
137
138 *******************************************************************************/
139
140 bool patcher_get_putfield(patchref_t *pr)
141 {
142         u1               *ra;
143         u4                mcode;
144         unresolved_field *uf;
145         fieldinfo        *fi;
146
147         ra    = (u1 *)                pr->mpc;
148         mcode =                       pr->mcode;
149         uf    = (unresolved_field *)  pr->ref;
150
151         /* get the fieldinfo */
152
153         if (!(fi = resolve_field_eager(uf)))
154                 return false;
155
156         /* patch back original code */
157
158         *((u4 *) ra) = mcode;
159
160         /* synchronize instruction cache */
161
162         md_icacheflush(ra, 4);
163
164         /* if we show disassembly, we have to skip the nop */
165
166         if (opt_shownops)
167                 ra = ra + 4;
168
169         /* patch the field's offset */
170
171         *((u4 *) ra) |= (s2) (fi->offset & 0x0000ffff);
172
173         /* synchronize instruction cache */
174
175         md_icacheflush(ra, 8);
176
177         return true;
178 }
179
180
181 /* patcher_invokestatic_special ************************************************
182
183    Machine code:
184
185    <patched call position>
186    81adffd8    lwz   r13,-40(r13)
187    7da903a6    mtctr r13
188    4e800421    bctrl
189
190 ******************************************************************************/
191
192 bool patcher_invokestatic_special(patchref_t *pr)
193 {
194         u1                *ra;
195         u4                 mcode;
196         unresolved_method *um;
197         u1                *datap;
198         methodinfo        *m;
199
200         /* get stuff from the stack */
201
202         ra    = (u1 *)                pr->mpc;
203         mcode =                       pr->mcode;
204         um    = (unresolved_method *) pr->ref;
205         datap = (u1 *)                pr->datap;
206
207         /* get the fieldinfo */
208
209         if (!(m = resolve_method_eager(um)))
210                 return false;
211
212         /* patch back original code */
213
214         *((u4 *) ra) = mcode;
215
216         /* synchronize instruction cache */
217
218         md_icacheflush(ra, 4);
219
220         /* patch stubroutine */
221
222         *((ptrint *) datap) = (ptrint) m->stubroutine;
223
224         /* synchronize data cache */
225
226         md_dcacheflush(datap, SIZEOF_VOID_P);
227
228         return true;
229 }
230
231
232 /* patcher_invokevirtual *******************************************************
233
234    Machine code:
235
236    <patched call position>
237    81830000    lwz   r12,0(r3)
238    81ac0088    lwz   r13,136(r12)
239    7da903a6    mtctr r13
240    4e800421    bctrl
241
242 *******************************************************************************/
243
244 bool patcher_invokevirtual(patchref_t *pr)
245 {
246         u1                *ra;
247         u4                 mcode;
248         unresolved_method *um;
249         methodinfo        *m;
250         s4                 disp;
251
252         /* get stuff from the stack */
253
254         ra    = (u1 *)                pr->mpc;
255         mcode =                       pr->mcode;
256         um    = (unresolved_method *) pr->ref;
257
258         /* get the fieldinfo */
259
260         if (!(m = resolve_method_eager(um)))
261                 return false;
262
263         /* patch back original code */
264
265         *((u4 *) ra) = mcode;
266
267         /* synchronize instruction cache */
268
269         md_icacheflush(ra, 4);
270
271         /* if we show disassembly, we have to skip the nop */
272
273         if (opt_shownops)
274                 ra = ra + 4;
275
276         /* patch vftbl index */
277
278         disp = (OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * m->vftblindex);
279
280         *((s4 *) (ra + 4)) |= (disp & 0x0000ffff);
281
282         /* synchronize instruction cache */
283
284         md_icacheflush(ra, 2 * 4);
285
286         return true;
287 }
288
289
290 /* patcher_invokeinterface *****************************************************
291
292    Machine code:
293
294    <patched call position>
295    81830000    lwz   r12,0(r3)
296    818cffd0    lwz   r12,-48(r12)
297    81ac000c    lwz   r13,12(r12)
298    7da903a6    mtctr r13
299    4e800421    bctrl
300
301 *******************************************************************************/
302
303 bool patcher_invokeinterface(patchref_t *pr)
304 {
305         u1                *ra;
306         u4                 mcode;
307         unresolved_method *um;
308         methodinfo        *m;
309         s4                 disp;
310
311         /* get stuff from the stack */
312
313         ra    = (u1 *)                pr->mpc;
314         mcode =                       pr->mcode;
315         um    = (unresolved_method *) pr->ref;
316
317         /* get the fieldinfo */
318
319         if (!(m = resolve_method_eager(um)))
320                 return false;
321
322         /* patch back original code */
323
324         *((u4 *) ra) = mcode;
325
326         /* synchronize instruction cache */
327
328         md_icacheflush(ra, 4);
329
330         /* if we show disassembly, we have to skip the nop */
331
332         if (opt_shownops)
333                 ra = ra + 4;
334
335         /* patch interfacetable index */
336
337         disp = OFFSET(vftbl_t, interfacetable[0]) -
338                 sizeof(methodptr*) * m->class->index;
339
340         /* XXX TWISTI: check displacement */
341
342         *((s4 *) (ra + 1 * 4)) |= (disp & 0x0000ffff);
343
344         /* patch method offset */
345
346         disp = sizeof(methodptr) * (m - m->class->methods);
347
348         /* XXX TWISTI: check displacement */
349
350         *((s4 *) (ra + 2 * 4)) |= (disp & 0x0000ffff);
351
352         /* synchronize instruction cache */
353
354         md_icacheflush(ra, 3 * 4);
355
356         return true;
357 }
358
359
360 /* patcher_checkcast_interface **************************************
361
362    Machine code:
363
364    <patched call position>
365    81870000    lwz   r12,0(r7)
366    800c0010    lwz   r0,16(r12)
367    34000000    addic.        r0,r0,0
368    408101fc    bgt-  0x3002e518         FIXME
369    83c00003    lwz   r30,3(0)           FIXME
370    800c0000    lwz   r0,0(r12)
371
372 *******************************************************************************/
373
374 bool patcher_checkcast_interface(patchref_t *pr)
375 {
376         u1                *ra;
377         constant_classref *cr;
378         classinfo         *c;
379         s4                 disp;
380         u4                 mcode;
381
382         /* get stuff from stack */
383         ra    = (u1 *)                pr->mpc;
384         mcode =                       pr->mcode;
385         cr    = (constant_classref *) pr->ref;
386
387         /* get the fieldinfo */
388         if (!(c = resolve_classref_eager(cr)))  {
389                 return false;
390         }
391
392         /* patch back original code */
393         *((u4 *) ra) = mcode;
394
395         /* synchronize instruction cache */
396
397         md_icacheflush(ra, 4);
398
399         /* if we show NOPs, we have to skip them */
400         if (opt_shownops)
401                 ra = ra +4;
402
403         /* patch super class index */
404         disp = -(c->index);
405
406         *((s4*)(ra + 2*4)) |= (disp & 0x0000ffff);
407
408         disp = OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*);
409
410         *((s4 *)(ra + 5*4)) |= (disp & 0x0000ffff);
411
412         /* sync instruction cache */
413         md_icacheflush(ra, 6*4);
414
415         return true;
416 }
417
418
419 /* patcher_instanceof_interface **************************************
420
421    Machine code:
422
423    <patched call position>
424    81870000    lwz   r12,0(r7)
425    800c0010    lwz   r0,16(r12)
426    34000000    addic.        r0,r0,0
427    408101fc    ble-  0x3002e518
428    800c0000    lwz   r0,0(r12)
429
430 *******************************************************************************/
431
432 bool patcher_instanceof_interface(patchref_t *pr)
433 {
434         u1                *ra;
435         u4                 mcode;
436         constant_classref *cr;
437         classinfo         *c;
438         s4                 disp;
439
440         /* get stuff from the stack */
441
442         ra    = (u1 *)                pr->mpc;
443         mcode =                       pr->mcode;
444         cr    = (constant_classref *) pr->ref;
445
446         /* get the fieldinfo */
447
448         if (!(c = resolve_classref_eager(cr)))
449                 return false;
450
451         /* patch back original code */
452
453         *((u4 *) ra) = mcode;
454
455         /* synchronize instruction cache */
456
457         md_icacheflush(ra, 4);
458
459         /* if we show disassembly, we have to skip the nop */
460
461         if (opt_shownops)
462                 ra = ra + 4;
463
464         /* patch super class index */
465
466         disp = -(c->index);
467
468         *((s4 *) (ra + 2 * 4)) |= (disp & 0x0000ffff);
469
470         disp = OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*);
471
472         *((s4 *) (ra + 4 * 4)) |= (disp & 0x0000ffff);
473
474         /* synchronize instruction cache */
475
476         md_icacheflush(ra, 5 * 4);
477
478         return true;
479 }
480
481
482 /* patcher_resolve_classref_to_classinfo ***************************************
483
484    ACONST:
485
486    <patched call postition>
487    806dffc4    lwz   r3,-60(r13)
488    81adffc0    lwz   r13,-64(r13)
489    7da903a6    mtctr r13
490    4e800421    bctrl
491
492
493    MULTIANEWARRAY:
494
495    <patched call position>
496    808dffc0    lwz   r4,-64(r13)
497    38a10038    addi  r5,r1,56
498    81adffbc    lwz   r13,-68(r13)
499    7da903a6    mtctr r13
500    4e800421    bctrl
501
502
503    ARRAYCHECKCAST:
504
505    <patched call position>
506    808dffd8    lwz   r4,-40(r13)
507    81adffd4    lwz   r13,-44(r13)
508    7da903a6    mtctr r13
509    4e800421    bctrl
510
511 *******************************************************************************/
512
513 bool patcher_resolve_classref_to_classinfo(patchref_t *pr)
514 {
515         constant_classref *cr;
516         u1                *datap, *ra;
517         u4                 mcode;
518         classinfo         *c;
519
520         /* get stuff from the stack */
521
522         ra    = (u1 *)                pr->mpc;
523         mcode =                       pr->mcode;
524         cr    = (constant_classref *) pr->ref;
525         datap = (u1 *)                pr->datap;
526
527         /* get the classinfo */
528
529         if (!(c = resolve_classref_eager(cr)))
530                 return false;
531
532         /* patch back original code */
533
534         *((u4 *) ra) = mcode;
535
536         /* synchronize instruction cache */
537
538         md_icacheflush(ra, 4);
539
540         /* patch the classinfo pointer */
541
542         *((ptrint *) datap) = (ptrint) c;
543
544         /* synchronize data cache */
545
546         md_dcacheflush(datap, SIZEOF_VOID_P);
547
548         return true;
549 }
550
551
552 /* patcher_resolve_classref_to_vftbl *******************************************
553
554    CHECKCAST (class):
555
556    <patched call position>
557    81870000    lwz   r12,0(r7)
558    800c0014    lwz   r0,20(r12)
559    818dff78    lwz   r12,-136(r13)
560
561
562    INSTANCEOF (class):
563
564    <patched call position>
565    817d0000    lwz   r11,0(r29)
566    818dff8c    lwz   r12,-116(r13)
567
568 *******************************************************************************/
569
570 bool patcher_resolve_classref_to_vftbl(patchref_t *pr)
571 {
572         constant_classref *cr;
573         u1                *datap, *ra;
574         u4                 mcode;
575         classinfo         *c;
576
577         /* get stuff from the stack */
578
579         ra    = (u1 *)                pr->mpc;
580         mcode =                       pr->mcode;
581         cr    = (constant_classref *) pr->ref;
582         datap = (u1 *)                pr->datap;
583
584         /* get the fieldinfo */
585
586         if (!(c = resolve_classref_eager(cr)))
587                 return false;
588
589         /* patch back original code */
590
591         *((u4 *) ra) = mcode;
592
593         /* synchronize instruction cache */
594
595         md_icacheflush(ra, 4);
596
597         /* patch super class' vftbl */
598
599         *((ptrint *) datap) = (ptrint) c->vftbl;
600
601         /* synchronize data cache */
602
603         md_dcacheflush(datap, SIZEOF_VOID_P);
604
605         return true;
606 }
607
608 /* patcher_resolve_classref_to_flags *******************************************
609
610    CHECKCAST/INSTANCEOF:
611
612    <patched call position>
613    818dff7c    lwz   r12,-132(r13)
614
615 *******************************************************************************/
616
617 bool patcher_resolve_classref_to_flags(patchref_t *pr)
618 {
619         constant_classref *cr;
620         u1                *datap, *ra;
621         u4                 mcode;
622         classinfo         *c;
623
624         /* get stuff from the stack */
625
626         ra    = (u1 *)                pr->mpc;
627         mcode =                       pr->mcode;
628         cr    = (constant_classref *) pr->ref;
629         datap = (u1 *)                pr->datap;
630
631         /* get the fieldinfo */
632
633         if (!(c = resolve_classref_eager(cr)))
634                 return false;
635
636         /* patch back original code */
637
638         *((u4 *) ra) = mcode;
639
640         /* synchronize instruction cache */
641
642         md_icacheflush(ra, 4);
643
644         /* patch class flags */
645
646         *((s4 *) datap) = (s4) c->flags;
647
648         /* synchronize data cache */
649
650         md_dcacheflush(datap, SIZEOF_VOID_P);
651
652         return true;
653 }
654
655
656 /*
657  * These are local overrides for various environment variables in Emacs.
658  * Please do not remove this and leave it at the end of the file, where
659  * Emacs will automagically detect them.
660  * ---------------------------------------------------------------------
661  * Local variables:
662  * mode: c
663  * indent-tabs-mode: t
664  * c-basic-offset: 4
665  * tab-width: 4
666  * End:
667  * vim:noexpandtab:sw=4:ts=4:
668  */