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