0aad1ca2c043873c1e0cd7da9c6f6b6bfff1c48f
[cacao.git] / src / vm / jit / arm / patcher.c
1 /* src/vm/jit/arm/patcher.c - ARM 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/arm/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/patcher-common.h"
45
46 #include "vmcore/field.h"
47 #include "vmcore/options.h"
48 #include "vmcore/references.h"
49 #include "vm/resolve.h"
50
51
52 #define PATCH_BACK_ORIGINAL_MCODE \
53     *((u4 *) pr->mpc) = (u4) pr->mcode; \
54     md_icacheflush((u1 *) pr->mpc, 1 * 4);
55
56 #define gen_resolveload(inst,offset) \
57         assert((offset) >= -0x0fff && (offset) <= 0x0fff); \
58         assert(!((inst) & 0x0fff)); \
59         if ((offset) <  0) { \
60                 (inst) = ((inst) & 0xff7ff000) | ((-(offset)) & 0x0fff); \
61                 /*(inst) &= ~(1 << 23);*/ \
62         } else { \
63                 (inst) = ((inst) & 0xfffff000) | ((offset) & 0x0fff); \
64                 /*(inst) |= (1 << 23);*/ \
65         }
66
67
68 /* patcher_patch_code **********************************************************
69
70    Just patches back the original machine code.
71
72 *******************************************************************************/
73
74 void patcher_patch_code(patchref_t *pr)
75 {
76         PATCH_BACK_ORIGINAL_MCODE;
77 }
78
79
80 /* patcher_get_putstatic *******************************************************
81
82    Machine code:
83
84    <patched call position>
85    e51c103c    ldr   r1, [ip, #-60]
86
87 *******************************************************************************/
88
89 bool patcher_get_putstatic(patchref_t *pr)
90 {
91         unresolved_field *uf;
92         u1               *datap;
93         fieldinfo        *fi;
94
95         /* get stuff from the stack */
96
97         uf    = (unresolved_field *) pr->ref;
98         datap = (u1 *)               pr->datap;
99
100         /* get the fieldinfo */
101
102         if (!(fi = resolve_field_eager(uf)))
103                 return false;
104
105         /* check if the field's class is initialized */
106
107         if (!(fi->class->state & CLASS_INITIALIZED))
108                 if (!initialize_class(fi->class))
109                         return false;
110
111         PATCH_BACK_ORIGINAL_MCODE;
112
113         /* patch the field value's address */
114
115         *((intptr_t *) datap) = (intptr_t) fi->value;
116
117         return true;
118 }
119
120
121 /* patcher_get_putfield ********************************************************
122
123    Machine code:
124
125    <patched call position>
126    e58a8000    str   r8, [sl, #__]
127
128 *******************************************************************************/
129
130 bool patcher_get_putfield(patchref_t *pr)
131 {
132         u1                *ra;
133         u4                 mcode;
134         unresolved_field  *uf;
135         fieldinfo         *fi;
136
137         /* get stuff from the stack */
138         ra    = (u1*)                 pr->mpc;
139         mcode =                       pr->mcode;
140         uf    = (unresolved_field*)   pr->ref;
141
142         /* get the fieldinfo */
143
144         if (!(fi = resolve_field_eager(uf)))
145                 return false;
146
147         PATCH_BACK_ORIGINAL_MCODE;
148
149         /* if we show disassembly, we have to skip the nop */
150
151         if (opt_shownops)
152                 ra = ra + 1 * 4;
153
154         /* patch the field's offset into the instruction */
155
156         switch(fi->type) {
157         case TYPE_ADR:
158         case TYPE_INT:
159 #if defined(ENABLE_SOFTFLOAT)
160         case TYPE_FLT:
161 #endif
162                 assert(fi->offset <= 0x0fff);
163                 *((u4 *) (ra + 0 * 4)) |= (fi->offset & 0x0fff);
164                 break;
165
166         case TYPE_LNG:
167 #if defined(ENABLE_SOFTFLOAT)
168         case TYPE_DBL:
169 #endif
170                 assert((fi->offset + 4) <= 0x0fff);
171                 *((u4 *) (ra + 0 * 4)) |= ((fi->offset + 0) & 0x0fff);
172                 *((u4 *) (ra + 1 * 4)) &= 0xfffff000;
173                 *((u4 *) (ra + 1 * 4)) |= ((fi->offset + 4) & 0x0fff);
174                 break;
175
176 #if !defined(ENABLE_SOFTFLOAT)
177         case TYPE_FLT:
178         case TYPE_DBL:
179                 assert(fi->offset <= 0x03ff);
180                 *((u4 *) (ra + 0 * 4)) |= ((fi->offset >> 2) & 0x00ff);
181                 break;
182 #endif
183         }
184
185         /* synchronize instruction cache */
186
187         md_icacheflush(ra, 2 * 4);
188
189         return true;
190 }
191
192
193 /* patcher_resolve_classref_to_classinfo ***************************************
194
195    ACONST - Machine code:
196
197    <patched call postition>
198    e51cc030    ldr   r0, [ip, #-48]
199
200    MULTIANEWARRAY - Machine code:
201     
202    <patched call position>
203    e3a00002    mov   r0, #2  ; 0x2
204    e51c1064    ldr   r1, [ip, #-100]
205    e1a0200d    mov   r2, sp
206    e1a0e00f    mov   lr, pc
207    e51cf068    ldr   pc, [ip, #-104]
208
209    ARRAYCHECKCAST - Machine code:
210
211    <patched call position>
212    e51c1120    ldr   r1, [ip, #-288]
213    e1a0e00f    mov   lr, pc
214    e51cf124    ldr   pc, [ip, #-292]
215
216 *******************************************************************************/
217
218 bool patcher_resolve_classref_to_classinfo(patchref_t *pr)
219 {
220         constant_classref *cr;
221         u1                *datap;
222         classinfo         *c;
223
224         /* get stuff from the stack */
225
226         cr    = (constant_classref *) pr->ref;
227         datap = (u1 *)                pr->datap;
228
229         /* get the classinfo */
230
231         if (!(c = resolve_classref_eager(cr)))
232                 return false;
233
234         PATCH_BACK_ORIGINAL_MCODE;
235
236         /* patch the classinfo pointer */
237
238         *((ptrint *) datap) = (ptrint) c;
239
240         return true;
241 }
242
243
244 /* patcher_invokestatic_special ************************************************
245
246    Machine code:
247
248    <patched call position>
249    e51cc02c    ldr   ip, [ip, #-44]
250    e1a0e00f    mov   lr, pc
251    e1a0f00c    mov   pc, ip
252
253 ******************************************************************************/
254
255 bool patcher_invokestatic_special(patchref_t *pr)
256 {
257         unresolved_method *um;
258         u1                *datap;
259         methodinfo        *m;
260
261         /* get stuff from the stack */
262
263         um    = (unresolved_method*) pr->ref;
264         datap = (u1 *)               pr->datap;
265
266         /* get the methodinfo */
267
268         if (!(m = resolve_method_eager(um)))
269                 return false;
270
271         PATCH_BACK_ORIGINAL_MCODE;
272
273         /* patch stubroutine */
274
275         *((ptrint *) datap) = (ptrint) m->stubroutine;
276
277         return true;
278 }
279
280
281 /* patcher_invokevirtual *******************************************************
282
283    Machine code:
284
285    <patched call position>
286    e590b000    ldr   fp, [r0]
287    e59bc000    ldr   ip, [fp, #__]
288    e1a0e00f    mov   lr, pc
289    e1a0f00c    mov   pc, ip
290
291 *******************************************************************************/
292
293 bool patcher_invokevirtual(patchref_t *pr)
294 {
295         u1                *ra;
296         unresolved_method *um;
297         methodinfo        *m;
298
299         /* get stuff from the stack */
300
301         ra = (u1 *)                pr->mpc;
302         um = (unresolved_method *) pr->ref;
303
304         /* get the methodinfo */
305
306         if (!(m = resolve_method_eager(um)))
307                 return false;
308
309         PATCH_BACK_ORIGINAL_MCODE;
310
311         /* if we show disassembly, we have to skip the nop */
312
313         if (opt_shownops)
314                 ra = ra + 1 * 4;
315
316         /* patch vftbl index */
317
318         gen_resolveload(*((s4 *) (ra + 1 * 4)), (s4) (OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * m->vftblindex));
319
320         /* synchronize instruction cache */
321
322         md_icacheflush(ra + 1 * 4, 1 * 4);
323
324         return true;
325 }
326
327
328 /* patcher_invokeinterface *****************************************************
329
330    Machine code:
331
332    <patched call position>
333    e590b000    ldr   fp, [r0]
334    e59bb000    ldr   fp, [fp, #__]
335    e59bc000    ldr   ip, [fp, #__]
336    e1a0e00f    mov   lr, pc
337    e1a0f00c    mov   pc, ip
338
339
340 *******************************************************************************/
341
342 bool patcher_invokeinterface(patchref_t *pr)
343 {
344         u1                *ra;
345         unresolved_method *um;
346         methodinfo        *m;
347
348         /* get stuff from the stack */
349
350         ra = (u1 *)                pr->mpc;
351         um = (unresolved_method *) pr->ref;
352
353         /* get the methodinfo */
354
355         if (!(m = resolve_method_eager(um)))
356                 return false;
357
358         PATCH_BACK_ORIGINAL_MCODE;
359
360         /* if we show disassembly, we have to skip the nop */
361
362         if (opt_shownops)
363                 ra = ra + 1 * 4;
364
365         /* patch interfacetable index */
366
367         gen_resolveload(*((s4 *) (ra + 1 * 4)), (s4) (OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr*) * m->clazz->index));
368
369         /* patch method offset */
370
371         gen_resolveload(*((s4 *) (ra + 2 * 4)), (s4) (sizeof(methodptr) * (m - m->clazz->methods)));
372
373         /* synchronize instruction cache */
374
375         md_icacheflush(ra + 1 * 4, 2 * 4);
376
377         return true;
378 }
379
380
381 /* patcher_checkcast_instanceof_flags ******************************************
382
383    Machine code:
384
385    <patched call position>
386
387 *******************************************************************************/
388
389 bool patcher_resolve_classref_to_flags(patchref_t *pr)
390 {
391         constant_classref *cr;
392         u1                *datap;
393         classinfo         *c;
394
395         /* get stuff from the stack */
396
397         cr    = (constant_classref *) pr->ref;
398         datap = (u1 *)                pr->datap;
399
400         /* get the classinfo */
401
402         if (!(c = resolve_classref_eager(cr)))
403                 return false;
404
405         PATCH_BACK_ORIGINAL_MCODE;
406
407         /* patch class flags */
408
409         *((s4 *) datap) = (s4) c->flags;
410
411         return true;
412 }
413
414
415 /* patcher_resolve_classref_to_index *******************************************
416
417    Machine code:
418
419    <patched call position>
420
421 *******************************************************************************/
422
423 bool patcher_resolve_classref_to_index(patchref_t *pr)
424 {
425         constant_classref *cr;
426         u1                *datap;
427         classinfo         *c;
428
429         /* get stuff from the stack */
430
431         cr    = (constant_classref *) pr->ref;
432         datap = (u1 *)                pr->datap;
433
434         /* get the classinfo */
435
436         if (!(c = resolve_classref_eager(cr)))
437                 return false;
438
439         PATCH_BACK_ORIGINAL_MCODE;
440
441         /* patch super class index */
442
443         *((s4 *) datap) = (s4) c->index;
444
445         return true;
446 }
447
448
449 /* patcher_resolve_classref_to_vftbl *******************************************
450
451    Machine code:
452
453    <patched call position>
454
455 *******************************************************************************/
456
457 bool patcher_resolve_classref_to_vftbl(patchref_t *pr)
458 {
459         constant_classref *cr;
460         u1                *datap;
461         classinfo         *c;
462
463         /* get stuff from the stack */
464
465         cr    = (constant_classref *) pr->ref;
466         datap = (u1 *)                pr->datap;
467
468         /* get the classinfo */
469
470         if (!(c = resolve_classref_eager(cr)))
471                 return false;
472
473         PATCH_BACK_ORIGINAL_MCODE;
474
475         /* patch super class' vftbl */
476
477         *((ptrint *) datap) = (ptrint) c->vftbl;
478
479         return true;
480 }
481
482
483 /*
484  * These are local overrides for various environment variables in Emacs.
485  * Please do not remove this and leave it at the end of the file, where
486  * Emacs will automagically detect them.
487  * ---------------------------------------------------------------------
488  * Local variables:
489  * mode: c
490  * indent-tabs-mode: t
491  * c-basic-offset: 4
492  * tab-width: 4
493  * End:
494  * vim:noexpandtab:sw=4:ts=4:
495  */