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