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