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