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