* src/vm/jit/jit.cpp: Eliminate one instance of useless cache flushing.
[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, 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/powerpc64/md.h"
35
36 #include "mm/memory.hpp"
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 /* patcher_get_putstatic *******************************************************
70
71    Machine code:
72
73    <patched call position>
74    816dffc8    lwz   r11,-56(r13)
75    80ab0000    lwz   r5,0(r11)
76
77 *******************************************************************************/
78
79 bool patcher_get_putstatic(patchref_t* pr)
80 {
81         unresolved_field* uf    = (unresolved_field*) pr->ref;
82         uintptr_t*        datap = (uintptr_t*)        pr->datap;
83
84         // Resolve the field.
85         fieldinfo* fi = resolve_field_eager(uf);
86
87         if (fi == NULL)
88                 return false;
89
90         // Check if the field's class is initialized.
91         if (!(fi->clazz->state & CLASS_INITIALIZED))
92                 if (!initialize_class(fi->clazz))
93                         return false;
94
95         // Patch the field value's address.
96         *datap = (uintptr_t) fi->value;
97
98         // Synchronize data cache.
99         md_dcacheflush(datap, SIZEOF_VOID_P);
100
101         // Patch back the original code.
102         patcher_patch_code(pr);
103
104         return true;
105 }
106
107
108 /* patcher_get_putfield ********************************************************
109
110    Machine code:
111
112    <patched call position>
113    811f0014    lwz   r8,20(r31)
114
115 *******************************************************************************/
116
117 bool patcher_get_putfield(patchref_t* pr)
118 {
119         unresolved_field* uf = (unresolved_field*) pr->ref;
120
121         // Resolve the field.
122         fieldinfo* fi = resolve_field_eager(uf);
123
124         if (fi == NULL)
125                 return false;
126
127         // Patch the field offset in the patcher.  We also need this to
128         // validate patchers.
129         pr->mcode |= (int16_t) (fi->offset & 0x0000ffff);
130
131         // Patch back the original code.
132         patcher_patch_code(pr);
133
134         return true;
135 }
136
137
138 /* patcher_invokestatic_special ************************************************
139
140    Machine code:
141
142    <patched call position>
143    81adffd8    lwz   r13,-40(r13)
144    7da903a6    mtctr r13
145    4e800421    bctrl
146
147 ******************************************************************************/
148
149 bool patcher_invokestatic_special(patchref_t* pr)
150 {
151         unresolved_method* um    = (unresolved_method*) pr->ref;
152         uintptr_t*         datap = (uintptr_t*)         pr->datap;
153
154         // Resolve the method.
155         methodinfo* m = resolve_method_eager(um);
156
157         if (m == NULL)
158                 return false;
159
160         // Patch stubroutine.
161         *datap = (uintptr_t) m->stubroutine;
162
163         // Synchronize data cache.
164         md_dcacheflush(datap, SIZEOF_VOID_P);
165
166         // Patch back the original code.
167         patcher_patch_code(pr);
168
169         return true;
170 }
171
172
173 /* patcher_invokevirtual *******************************************************
174
175    Machine code:
176
177    <patched call position>
178    81830000    lwz   r12,0(r3)
179    81ac0088    lwz   r13,136(r12)
180    7da903a6    mtctr r13
181    4e800421    bctrl
182
183 *******************************************************************************/
184
185 bool patcher_invokevirtual(patchref_t* pr)
186 {
187         uint32_t*          pc = (uint32_t*)          pr->mpc;
188         unresolved_method* um = (unresolved_method*) pr->ref;
189
190         // Resolve the method.
191         methodinfo* m = resolve_method_eager(um);
192
193         if (m == NULL)
194                 return false;
195
196         // Patch vftbl index.
197         int32_t disp = (OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * m->vftblindex);
198
199         pc[1] |= (disp & 0x0000ffff);
200
201         // Synchronize instruction cache.
202         md_icacheflush(pc + 1, 1 * 4);
203
204         // Patch back the original code.
205         patcher_patch_code(pr);
206
207         return true;
208 }
209
210
211 /* patcher_invokeinterface *****************************************************
212
213    Machine code:
214
215    <patched call position>
216    81830000    lwz   r12,0(r3)
217    818cffd0    lwz   r12,-48(r12)
218    81ac000c    lwz   r13,12(r12)
219    7da903a6    mtctr r13
220    4e800421    bctrl
221
222 *******************************************************************************/
223
224 bool patcher_invokeinterface(patchref_t* pr)
225 {
226         uint32_t*          pc = (uint32_t*)          pr->mpc;
227         unresolved_method* um = (unresolved_method*) pr->ref;
228
229         // Resolve the method.
230         methodinfo* m = resolve_method_eager(um);
231
232         if (m == NULL)
233                 return false;
234
235         // Patch interfacetable index.
236         int32_t disp = OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr*) * m->clazz->index;
237
238         // XXX TWISTI: check displacement
239         pc[1] |= (disp & 0x0000ffff);
240
241         // Patch method offset.
242         disp = sizeof(methodptr) * (m - m->clazz->methods);
243
244         // XXX TWISTI: check displacement
245         pc[2] |= (disp & 0x0000ffff);
246
247         // Synchronize instruction cache.
248         md_icacheflush(pc + 1, 2 * 4);
249
250         // Patch back the original code.
251         patcher_patch_code(pr);
252
253         return true;
254 }
255
256
257 /* patcher_checkcast_interface **************************************
258
259    Machine code:
260
261    <patched call position>
262    81870000    lwz   r12,0(r7)
263    800c0010    lwz   r0,16(r12)
264    34000000    addic.        r0,r0,0
265    408101fc    bgt-  0x3002e518         FIXME
266    83c00003    lwz   r30,3(0)           FIXME
267    800c0000    lwz   r0,0(r12)
268
269 *******************************************************************************/
270
271 bool patcher_checkcast_interface(patchref_t* pr)
272 {
273         uint32_t*          pc = (uint32_t*)          pr->mpc;
274         constant_classref* cr = (constant_classref*) pr->ref;
275
276         // Resolve the class.
277         classinfo* c = resolve_classref_eager(cr);
278
279         if (c == NULL)
280                 return false;
281
282         // Patch super class index.
283         int32_t disp = -(c->index);
284         pc[2] |= (disp & 0x0000ffff);
285
286         disp = OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*);
287         pc[5] |= (disp & 0x0000ffff);
288
289         // Synchronize instruction cache.
290         md_icacheflush(pc + 2, 4 * 4);
291
292         // Patch back the original code.
293         patcher_patch_code(pr);
294
295         return true;
296 }
297
298
299 /* patcher_instanceof_interface **************************************
300
301    Machine code:
302
303    <patched call position>
304    81870000    lwz   r12,0(r7)
305    800c0010    lwz   r0,16(r12)
306    34000000    addic.        r0,r0,0
307    408101fc    ble-  0x3002e518
308    800c0000    lwz   r0,0(r12)
309
310 *******************************************************************************/
311
312 bool patcher_instanceof_interface(patchref_t* pr)
313 {
314         uint32_t*          pc = (uint32_t*)          pr->mpc;
315         constant_classref* cr = (constant_classref*) pr->ref;
316
317         // Resolve the class.
318         classinfo* c = resolve_classref_eager(cr);
319
320         if (c == NULL)
321                 return false;
322
323         // Patch super class index.
324         int32_t disp = -(c->index);
325         pc[2] |= (disp & 0x0000ffff);
326
327         disp = OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*);
328         pc[4] |= (disp & 0x0000ffff);
329
330         // Synchronize instruction cache.
331         md_icacheflush(pc + 2, 3 * 4);
332
333         // Patch back the original code.
334         patcher_patch_code(pr);
335
336         return true;
337 }
338
339
340 /* patcher_resolve_classref_to_classinfo ***************************************
341
342    ACONST:
343
344    <patched call postition>
345    806dffc4    lwz   r3,-60(r13)
346    81adffc0    lwz   r13,-64(r13)
347    7da903a6    mtctr r13
348    4e800421    bctrl
349
350
351    MULTIANEWARRAY:
352
353    <patched call position>
354    808dffc0    lwz   r4,-64(r13)
355    38a10038    addi  r5,r1,56
356    81adffbc    lwz   r13,-68(r13)
357    7da903a6    mtctr r13
358    4e800421    bctrl
359
360
361    ARRAYCHECKCAST:
362
363    <patched call position>
364    808dffd8    lwz   r4,-40(r13)
365    81adffd4    lwz   r13,-44(r13)
366    7da903a6    mtctr r13
367    4e800421    bctrl
368
369 *******************************************************************************/
370
371 bool patcher_resolve_classref_to_classinfo(patchref_t* pr)
372 {
373         constant_classref* cr    = (constant_classref*) pr->ref;
374         uintptr_t*         datap = (uintptr_t*)         pr->datap;
375
376         // Resolve the class.
377         classinfo* c = resolve_classref_eager(cr);
378
379         if (c == NULL)
380                 return false;
381
382         // Patch the classinfo pointer.
383         *datap = (uintptr_t) c;
384
385         // Synchronize data cache.
386         md_dcacheflush(datap, SIZEOF_VOID_P);
387
388         // Patch back the original code.
389         patcher_patch_code(pr);
390
391         return true;
392 }
393
394
395 /* patcher_resolve_classref_to_vftbl *******************************************
396
397    CHECKCAST (class):
398
399    <patched call position>
400    81870000    lwz   r12,0(r7)
401    800c0014    lwz   r0,20(r12)
402    818dff78    lwz   r12,-136(r13)
403
404
405    INSTANCEOF (class):
406
407    <patched call position>
408    817d0000    lwz   r11,0(r29)
409    818dff8c    lwz   r12,-116(r13)
410
411 *******************************************************************************/
412
413 bool patcher_resolve_classref_to_vftbl(patchref_t* pr)
414 {
415         constant_classref* cr    = (constant_classref*) pr->ref;
416         uintptr_t*         datap = (uintptr_t*)         pr->datap;
417
418         // Resolve the class.
419         classinfo* c = resolve_classref_eager(cr);
420
421         if (c == NULL)
422                 return false;
423
424         // Patch super class' vftbl.
425         *datap = (uintptr_t) c->vftbl;
426
427         // Synchronize data cache.
428         md_dcacheflush(datap, SIZEOF_VOID_P);
429
430         // Patch back the original code.
431         patcher_patch_code(pr);
432
433         return true;
434 }
435
436 /* patcher_resolve_classref_to_flags *******************************************
437
438    CHECKCAST/INSTANCEOF:
439
440    <patched call position>
441    818dff7c    lwz   r12,-132(r13)
442
443 *******************************************************************************/
444
445 bool patcher_resolve_classref_to_flags(patchref_t* pr)
446 {
447         constant_classref* cr    = (constant_classref*) pr->ref;
448         int32_t*           datap = (int32_t*)           pr->datap;
449
450         // Resolve the class.
451         classinfo* c = resolve_classref_eager(cr);
452
453         if (c == NULL)
454                 return false;
455
456         // Patch class flags.
457         *datap = (int32_t) c->flags;
458
459         // Synchronize data cache.
460         md_dcacheflush(datap, SIZEOF_VOID_P);
461
462         // Patch back the original code.
463         patcher_patch_code(pr);
464
465         return true;
466 }
467
468
469 /*
470  * These are local overrides for various environment variables in Emacs.
471  * Please do not remove this and leave it at the end of the file, where
472  * Emacs will automagically detect them.
473  * ---------------------------------------------------------------------
474  * Local variables:
475  * mode: c
476  * indent-tabs-mode: t
477  * c-basic-offset: 4
478  * tab-width: 4
479  * End:
480  * vim:noexpandtab:sw=4:ts=4:
481  */