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