* src/vm/class.c: Moved to C++.
[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    Copyright (C) 2008 Theobroma Systems Ltd.
6
7    This file is part of CACAO.
8
9    This program is free software; you can redistribute it and/or
10    modify it under the terms of the GNU General Public License as
11    published by the Free Software Foundation; either version 2, or (at
12    your option) any later version.
13
14    This program is distributed in the hope that it will be useful, but
15    WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17    General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22    02110-1301, USA.
23
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 "vm/jit/powerpc/md.h"
35
36 #include "mm/memory.h"
37
38 #include "native/native.hpp"
39
40 #include "vm/jit/builtin.hpp"
41 #include "vm/class.hpp"
42 #include "vm/field.hpp"
43 #include "vm/initialize.hpp"
44 #include "vm/options.h"
45 #include "vm/references.h"
46 #include "vm/resolve.hpp"
47
48 #include "vm/jit/asmpart.h"
49 #include "vm/jit/methodheader.h"
50 #include "vm/jit/patcher-common.hpp"
51
52
53 /* patcher_patch_code **********************************************************
54
55    Just patches back the original machine code.
56
57 *******************************************************************************/
58
59 void patcher_patch_code(patchref_t *pr)
60 {
61         // Patch back original code.
62         *((uint32_t*) pr->mpc) = pr->mcode;
63
64         // Synchronize instruction cache.
65         md_icacheflush((void*) pr->mpc, 1 * 4);
66 }
67
68
69 /**
70  * Check if the trap instruction at the given PC is valid.
71  *
72  * @param pc Program counter.
73  *
74  * @return true if valid, false otherwise.
75  */
76 bool patcher_is_valid_trap_instruction_at(void* pc)
77 {
78         uint32_t mcode = *((uint32_t*) pc);
79
80         // Check for the undefined instruction we use.
81         return (mcode == 0x00000000);
82 }
83
84
85 /* patcher_resolve_classref_to_classinfo ***************************************
86
87    ACONST:
88
89    <patched call postition>
90    806dffc4    lwz   r3,-60(r13)
91    81adffc0    lwz   r13,-64(r13)
92    7da903a6    mtctr r13
93    4e800421    bctrl
94
95
96    MULTIANEWARRAY:
97
98    <patched call position>
99    808dffc0    lwz   r4,-64(r13)
100    38a10038    addi  r5,r1,56
101    81adffbc    lwz   r13,-68(r13)
102    7da903a6    mtctr r13
103    4e800421    bctrl
104
105
106    ARRAYCHECKCAST:
107
108    <patched call position>
109    808dffd8    lwz   r4,-40(r13)
110    81adffd4    lwz   r13,-44(r13)
111    7da903a6    mtctr r13
112    4e800421    bctrl
113
114 *******************************************************************************/
115
116 bool patcher_resolve_classref_to_classinfo(patchref_t *pr)
117 {
118         constant_classref * cr    = (constant_classref*) pr->ref;
119         uintptr_t*          datap = (uintptr_t*)         pr->datap;
120
121         // Resolve the class.
122         classinfo* c = resolve_classref_eager(cr);
123
124         if (c == NULL)
125                 return false;
126
127         // Patch the class pointer.
128         *datap = (uintptr_t) c;
129
130         // Synchronize data cache.
131         md_dcacheflush(datap, SIZEOF_VOID_P);
132
133         // Patch back the original code.
134         patcher_patch_code(pr);
135
136         return true;
137 }
138
139
140 /* patcher_resolve_classref_to_vftbl *******************************************
141
142    CHECKCAST (class):
143
144    <patched call position>
145    81870000    lwz   r12,0(r7)
146    800c0014    lwz   r0,20(r12)
147    818dff78    lwz   r12,-136(r13)
148
149
150    INSTANCEOF (class):
151
152    <patched call position>
153    817d0000    lwz   r11,0(r29)
154    818dff8c    lwz   r12,-116(r13)
155
156 *******************************************************************************/
157
158 bool patcher_resolve_classref_to_vftbl(patchref_t *pr)
159 {
160         constant_classref* cr    = (constant_classref*) pr->ref;
161         uintptr_t*         datap = (uintptr_t*)         pr->datap;
162
163         // Resolve the class.
164         classinfo* c = resolve_classref_eager(cr);
165
166         if (c == NULL)
167                 return false;
168
169         // Patch super class' vftbl.
170         *datap = (uintptr_t) c->vftbl;
171
172         // Synchronize data cache.
173         md_dcacheflush(datap, SIZEOF_VOID_P);
174
175         // Patch back the original code.
176         patcher_patch_code(pr);
177
178         return true;
179 }
180
181
182 /* patcher_resolve_classref_to_flags *******************************************
183
184    CHECKCAST/INSTANCEOF:
185
186    <patched call position>
187    818dff7c    lwz   r12,-132(r13)
188
189 *******************************************************************************/
190
191 bool patcher_resolve_classref_to_flags(patchref_t *pr)
192 {
193         constant_classref* cr    = (constant_classref*) pr->ref;
194         int32_t*           datap = (int32_t*)           pr->datap;
195
196         // Resolve the class.
197         classinfo* c = resolve_classref_eager(cr);
198
199         if (c == NULL)
200                 return false;
201
202         // Patch class flags.
203         *datap = c->flags;
204
205         // Synchronize data cache.
206         md_dcacheflush(datap, SIZEOF_VOID_P);
207
208         // Patch back the original code.
209         patcher_patch_code(pr);
210
211         return true;
212 }
213
214
215 /* patcher_get_putstatic *******************************************************
216
217    Machine code:
218
219    <patched call position>
220    816dffc8    lwz   r11,-56(r13)
221    80ab0000    lwz   r5,0(r11)
222
223 *******************************************************************************/
224
225 bool patcher_get_putstatic(patchref_t *pr)
226 {
227         unresolved_field* uf    = (unresolved_field*) pr->ref;
228         uintptr_t*        datap = (uintptr_t*)        pr->datap;
229
230         // Resolve the field.
231         fieldinfo* fi = resolve_field_eager(uf);
232
233         if (fi == NULL)
234                 return false;
235
236         // Check if the field's class is initialized.
237         if (!(fi->clazz->state & CLASS_INITIALIZED))
238                 if (!initialize_class(fi->clazz))
239                         return false;
240
241         // Patch the field value's address.
242         *datap = (uintptr_t) fi->value;
243
244         // Synchronize data cache.
245         md_dcacheflush(datap, SIZEOF_VOID_P);
246
247         // Patch back the original code.
248         patcher_patch_code(pr);
249
250         return true;
251 }
252
253
254 /* patcher_get_putfield ********************************************************
255
256    Machine code:
257
258    <patched call position>
259    811f0014    lwz   r8,20(r31)
260
261 *******************************************************************************/
262
263 bool patcher_get_putfield(patchref_t *pr)
264 {
265         uint32_t*         pc = (uint32_t*)         pr->mpc;
266         unresolved_field* uf = (unresolved_field*) pr->ref;
267
268         // Resolve the field.
269         fieldinfo* fi = resolve_field_eager(uf);
270
271         if (fi == NULL)
272                 return false;
273
274         // Patch the field's offset.
275         if (IS_LNG_TYPE(fi->type)) {
276                 /* If the field has type long, we have to patch two
277                    instructions.  But we have to check which instruction
278                    is first.  We do that with the offset of the first
279                    instruction. */
280
281                 uint32_t disp = (pr->mcode & 0x0000ffff);
282
283                 if (disp == 4) {
284                         pr->mcode &= 0xffff0000;
285                         pr->mcode |= ((fi->offset + 4) & 0x0000ffff);
286                         pc[1] |= ((fi->offset + 0) & 0x0000ffff);
287                 }
288                 else {
289                         pr->mcode |= ((fi->offset + 0) & 0x0000ffff);
290                         pc[1] &= 0xffff0000;
291                         pc[1] |= ((fi->offset + 4) & 0x0000ffff);
292                 }
293
294                 // Synchronize instruction cache.
295                 md_icacheflush(pc + 1, 1 * 4);
296         }
297         else {
298                 pr->mcode |= (fi->offset & 0x0000ffff);
299         }
300
301         // Patch back the original code.
302         patcher_patch_code(pr);
303
304         return true;
305 }
306
307
308 /* patcher_invokestatic_special ************************************************
309
310    Machine code:
311
312    <patched call position>
313    81adffd8    lwz   r13,-40(r13)
314    7da903a6    mtctr r13
315    4e800421    bctrl
316
317 ******************************************************************************/
318
319 bool patcher_invokestatic_special(patchref_t *pr)
320 {
321         unresolved_method* um    = (unresolved_method*) pr->ref;
322         uintptr_t*         datap = (uintptr_t*)         pr->datap;
323
324         // Resolve the method.
325         methodinfo* m = resolve_method_eager(um);
326
327         if (m == NULL)
328                 return false;
329
330         // Patch stubroutine.
331         *datap = (uintptr_t) m->stubroutine;
332
333         // Synchronize data cache.
334         md_dcacheflush(datap, SIZEOF_VOID_P);
335
336         // Patch back the original code.
337         patcher_patch_code(pr);
338
339         return true;
340 }
341
342
343 /* patcher_invokevirtual *******************************************************
344
345    Machine code:
346
347    <patched call position>
348    81830000    lwz   r12,0(r3)
349    81ac0088    lwz   r13,136(r12)
350    7da903a6    mtctr r13
351    4e800421    bctrl
352
353 *******************************************************************************/
354
355 bool patcher_invokevirtual(patchref_t *pr)
356 {
357         uint32_t*          pc = (uint32_t*)          pr->mpc;
358         unresolved_method* um = (unresolved_method*) pr->ref;
359
360         // Resolve the method.
361         methodinfo* m = resolve_method_eager(um);
362
363         if (m == NULL)
364                 return false;
365
366         // Patch vftbl index.
367         int32_t disp = (OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * m->vftblindex);
368
369         pc[1] |= (disp & 0x0000ffff);
370
371         // Synchronize instruction cache.
372         md_icacheflush(pc + 1, 1 * 4);
373
374         // Patch back the original code.
375         patcher_patch_code(pr);
376
377         return true;
378 }
379
380
381 /* patcher_invokeinterface *****************************************************
382
383    Machine code:
384
385    <patched call position>
386    81830000    lwz   r12,0(r3)
387    818cffd0    lwz   r12,-48(r12)
388    81ac000c    lwz   r13,12(r12)
389    7da903a6    mtctr r13
390    4e800421    bctrl
391
392 *******************************************************************************/
393
394 bool patcher_invokeinterface(patchref_t *pr)
395 {
396         uint32_t*          pc = (uint32_t*)          pr->mpc;
397         unresolved_method* um = (unresolved_method*) pr->ref;
398
399         // Resolve the method.
400         methodinfo* m = resolve_method_eager(um);
401
402         if (m == NULL)
403                 return false;
404
405         // Patch interfacetable index.
406         int32_t disp = OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr*) * m->clazz->index;
407
408         /* XXX TWISTI: check displacement */
409         pc[1] |= (disp & 0x0000ffff);
410
411         // Patch method offset.
412         disp = sizeof(methodptr) * (m - m->clazz->methods);
413
414         /* XXX TWISTI: check displacement */
415         pc[2] |= (disp & 0x0000ffff);
416
417         // Synchronize instruction cache.
418         md_icacheflush(pc + 1, 2 * 4);
419
420         // Patch back the original code.
421         patcher_patch_code(pr);
422
423         return true;
424 }
425
426
427 /* patcher_checkcast_interface *************************************************
428
429    Machine code:
430
431    <patched call position>
432    81870000    lwz     r12,0(r7)
433    800c0010    lwz     r0,16(r12)
434    34000000    addic.  r0,r0,0
435    41810008    bgt-    0x014135d8
436    83c00003    lwz     r30,3(0)
437    800c0000    lwz     r0,0(r12)
438
439 *******************************************************************************/
440
441 bool patcher_checkcast_interface(patchref_t *pr)
442 {
443         uint32_t*          pc = (uint32_t*)          pr->mpc;
444         constant_classref* cr = (constant_classref*) pr->ref;
445
446         // Resolve the class.
447         classinfo* c = resolve_classref_eager(cr);
448
449         if (c == NULL)
450                 return false;
451
452         // Patch super class index.
453         int32_t disp = -(c->index);
454         pc[2] |= (disp & 0x0000ffff);
455
456         disp = OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*);
457         pc[5] |= (disp & 0x0000ffff);
458
459         // Synchronize instruction cache.
460         md_icacheflush(pc + 2, 4 * 4);
461
462         // Patch back the original code.
463         patcher_patch_code(pr);
464
465         return true;
466 }
467
468
469 /* patcher_instanceof_interface ************************************************
470
471    Machine code:
472
473    <patched call position>
474    81870000    lwz     r12,0(r7)
475    800c0010    lwz     r0,16(r12)
476    34000000    addic.  r0,r0,0
477    41810008    bgt-    0x014135d8
478    83c00003    lwz     r30,3(0)
479    800c0000    lwz     r0,0(r12)
480
481 *******************************************************************************/
482
483 bool patcher_instanceof_interface(patchref_t *pr)
484 {
485         uint32_t*          pc = (uint32_t*)          pr->mpc;
486         constant_classref* cr = (constant_classref*) pr->ref;
487
488         // Resolve the class.
489         classinfo* c = resolve_classref_eager(cr);
490
491         if (c == NULL)
492                 return false;
493
494         // Patch super class index.
495         int32_t disp = -(c->index);
496         pc[2] |= (disp & 0x0000ffff);
497
498         disp = OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*);
499         pc[4] |= (disp & 0x0000ffff);
500
501         // Synchronize instruction cache.
502         md_icacheflush(pc + 2, 3 * 4);
503
504         // Patch back the original code.
505         patcher_patch_code(pr);
506
507         return true;
508 }
509
510
511 /*
512  * These are local overrides for various environment variables in Emacs.
513  * Please do not remove this and leave it at the end of the file, where
514  * Emacs will automagically detect them.
515  * ---------------------------------------------------------------------
516  * Local variables:
517  * mode: c
518  * indent-tabs-mode: t
519  * c-basic-offset: 4
520  * tab-width: 4
521  * End:
522  * vim:noexpandtab:sw=4:ts=4:
523  */