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