* tests/regression/resolving (svn:ignore): Added.
[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 7486 2007-03-08 13:50:07Z twisti $
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.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 gen_resolveload(inst,offset) \
55         assert((offset) >= -0x0fff && (offset) <= 0x0fff); \
56         assert(!((inst) & 0x0fff)); \
57         if ((offset) <  0) { \
58                 (inst) = ((inst) & 0xff7ff000) | ((-(offset)) & 0x0fff); \
59                 /*(inst) &= ~(1 << 23);*/ \
60         } else { \
61                 (inst) = ((inst) & 0xfffff000) | ((offset) & 0x0fff); \
62                 /*(inst) |= (1 << 23);*/ \
63         }
64
65
66 /* patcher_wrapper *************************************************************
67
68    Wrapper for all patchers.  It also creates the stackframe info
69    structure.
70
71    If the return value of the patcher function is false, it gets the
72    exception object, clears the exception pointer and returns the
73    exception.
74
75 *******************************************************************************/
76
77 java_objectheader *patcher_wrapper(u1 *sp, u1 *pv, u1 *ra)
78 {
79         stackframeinfo     sfi;
80         u1                *xpc;
81         java_objectheader *o;
82         u4                 mcode;
83         functionptr        f;
84         bool               result;
85         java_objectheader *e;
86
87         /* define the patcher function */
88
89         bool (*patcher_function)(u1 *);
90
91         assert(pv != NULL);
92
93         /* get stuff from the stack */
94
95         xpc = (u1 *)                *((ptrint *) (sp + 4 * 4));
96         o   = (java_objectheader *) *((ptrint *) (sp + 3 * 4));
97         f   = (functionptr)         *((ptrint *) (sp + 0 * 4));
98
99         /* calculate and set the new return address */
100
101         xpc = xpc - 1 * 4;
102
103         *((ptrint *) (sp + 4 * 4)) = (ptrint) xpc;
104
105         /* store PV into the patcher function position */
106
107         *((ptrint *) (sp + 0 * 4)) = (ptrint) pv;
108
109         /* cast the passed function to a patcher function */
110
111         patcher_function = (bool (*)(u1 *)) (ptrint) f;
112
113         /* enter a monitor on the patching position */
114
115         PATCHER_MONITORENTER;
116
117         /* create the stackframeinfo */
118
119         stacktrace_create_extern_stackframeinfo(&sfi, pv, sp + 8 * 4, ra, xpc);
120
121         /* call the proper patcher function */
122
123         result = (patcher_function)(sp);
124
125         /* remove the stackframeinfo */
126
127         stacktrace_remove_stackframeinfo(&sfi);
128
129         /* check for an error, get the exception and return it */
130
131         if (result == false) {
132                 e = exceptions_get_and_clear_exception();
133
134                 PATCHER_MONITOREXIT;
135
136                 return e;
137         }
138
139         /* patch back original code */
140
141         mcode = *((u4 *) (sp + 2 * 4));
142
143         *((u4 *) xpc) = mcode;
144
145         /* synchronize instruction cache */
146
147         md_icacheflush(xpc, 1 * 4);
148
149         PATCHER_MARK_PATCHED_MONITOREXIT;
150
151         return NULL;
152 }
153
154
155 /* patcher_get_putstatic *******************************************************
156
157    Machine code:
158
159    <patched call position>
160    e51c103c    ldr   r1, [ip, #-60]
161
162 *******************************************************************************/
163
164 bool patcher_get_putstatic(u1 *sp)
165 {
166         s4                disp;
167         unresolved_field *uf;
168         u1               *pv;
169         fieldinfo        *fi;
170
171         /* get stuff from the stack */
172
173         disp =                      *((s4 *)     (sp + 5 * 4));
174         uf   = (unresolved_field *) *((ptrint *) (sp + 1 * 4));
175         pv   = (u1 *)               *((ptrint *) (sp + 0 * 4));
176
177         /* get the fieldinfo */
178
179         if (!(fi = resolve_field_eager(uf)))
180                 return false;
181
182         /* check if the field's class is initialized */
183
184         if (!(fi->class->state & CLASS_INITIALIZED))
185                 if (!initialize_class(fi->class))
186                         return false;
187
188         /* patch the field value's address */
189
190         *((ptrint *) (pv + disp)) = (ptrint) &(fi->value);
191
192         return true;
193 }
194
195
196 /* patcher_get_putfield ********************************************************
197
198    Machine code:
199
200    <patched call position>
201    e58a8000    str   r8, [sl, #__]
202
203 *******************************************************************************/
204
205 bool patcher_get_putfield(u1 *sp)
206 {
207         u1                *ra;
208         u4                 mcode;
209         unresolved_field  *uf;
210         u1                *pv;
211         fieldinfo         *fi;
212
213         /* get stuff from the stack */
214         ra    = (u1*)                 *((ptrint *) (sp + 4 * 4));
215         mcode =                       *((u4 *)     (sp + 2 * 4));
216         uf    = (unresolved_field*)   *((ptrint *) (sp + 1 * 4));
217         pv    = (u1*)                 *((ptrint *) (sp + 0 * 4));
218
219         /* get the fieldinfo */
220
221         if (!(fi = resolve_field_eager(uf)))
222                 return false;
223
224         /* if we show disassembly, we have to skip the nop */
225
226         if (opt_showdisassemble) {
227                 ra = ra + 1 * 4;
228
229                 /* patch the field's offset into the instruction */
230
231                 switch(fi->type) {
232                 case TYPE_ADR:
233                 case TYPE_INT:
234 #if defined(ENABLE_SOFTFLOAT)
235                 case TYPE_FLT:
236 #endif
237                         assert(fi->offset <= 0x0fff);
238                         *((u4 *) (ra + 0 * 4)) |= (fi->offset & 0x0fff);
239                         break;
240
241                 case TYPE_LNG:
242 #if defined(ENABLE_SOFTFLOAT)
243                 case TYPE_DBL:
244 #endif
245                         assert((fi->offset + 4) <= 0x0fff);
246                         *((u4 *) (ra + 0 * 4)) |= ((fi->offset + 0) & 0x0fff);
247                         *((u4 *) (ra + 1 * 4)) |= ((fi->offset + 4) & 0x0fff);
248                         break;
249
250 #if !defined(ENABLE_SOFTFLOAT)
251                 case TYPE_FLT:
252                 case TYPE_DBL:
253                         assert(fi->offset <= 0x03ff);
254                         *((u4 *) (ra + 0 * 4)) |= ((fi->offset >> 2) & 0x00ff);
255                         break;
256 #endif
257                 }
258         }
259         else {
260                 /* patch the field's offset into the instruction stored on the
261                    stack and the next instruction in the code */
262
263                 switch(fi->type) {
264                 case TYPE_ADR:
265                 case TYPE_INT:
266 #if defined(ENABLE_SOFTFLOAT)
267                 case TYPE_FLT:
268 #endif
269                         assert(fi->offset <= 0x0fff);
270                         *((u4 *) (sp + 2 * 4)) |= (fi->offset & 0x0fff);
271                         break;
272
273                 case TYPE_LNG:
274 #if defined(ENABLE_SOFTFLOAT)
275                 case TYPE_DBL:
276 #endif
277                         assert((fi->offset + 4) <= 0x0fff);
278                         *((u4 *) (sp + 2 * 4)) |= ((fi->offset + 0) & 0x0fff);
279                         *((u4 *) (ra + 1 * 4)) |= ((fi->offset + 4) & 0x0fff);
280                         break;
281
282 #if !defined(ENABLE_SOFTFLOAT)
283                 case TYPE_FLT:
284                 case TYPE_DBL:
285                         assert(fi->offset <= 0x03ff);
286                         *((u4 *) (sp + 2 * 4)) |= ((fi->offset >> 2) & 0x00ff);
287                         break;
288 #endif
289                 }
290         }
291
292         /* synchronize instruction cache */
293
294         md_icacheflush(ra, 2 * 4);
295
296         return true;
297 }
298
299
300 /* patcher_aconst **************************************************************
301
302    Machine code:
303
304    <patched call postition>
305    e51cc030    ldr   r0, [ip, #-48]
306
307 *******************************************************************************/
308
309 bool patcher_aconst(u1 *sp)
310 {
311         s4                 disp;
312         constant_classref *cr;
313         u1                *pv;
314         classinfo         *c;
315
316         /* get stuff from the stack */
317
318         disp =                       *((s4 *)     (sp + 5 * 4));
319         cr   = (constant_classref *) *((ptrint *) (sp + 1 * 4));
320         pv   = (u1 *)                *((ptrint *) (sp + 0 * 4));
321
322         /* get the classinfo */
323
324         if (!(c = resolve_classref_eager(cr)))
325                 return false;
326
327         /* patch the classinfo pointer */
328
329         *((ptrint *) (pv + disp)) = (ptrint) c;
330
331         return true;
332 }
333
334
335 /* patcher_builtin_multianewarray **********************************************
336
337    Machine code:
338
339    <patched call position>
340    e3a00002    mov   r0, #2  ; 0x2
341    e51c1064    ldr   r1, [ip, #-100]
342    e1a0200d    mov   r2, sp
343    e1a0e00f    mov   lr, pc
344    e51cf068    ldr   pc, [ip, #-104]
345
346 *******************************************************************************/
347
348 bool patcher_builtin_multianewarray(u1 *sp)
349 {
350         s4                 disp;
351         constant_classref *cr;
352         u1                *pv;
353         classinfo         *c;
354
355         /* get stuff from the stack */
356
357         disp =                       *((s4 *)     (sp + 5 * 4));
358         cr   = (constant_classref *) *((ptrint *) (sp + 1 * 4));
359         pv   = (u1 *)                *((ptrint *) (sp + 0 * 4));
360
361         /* get the classinfo */
362
363         if (!(c = resolve_classref_eager(cr)))
364                 return false;
365
366         /* patch the classinfo pointer */
367
368         *((ptrint *) (pv + disp)) = (ptrint) c;
369
370         return true;
371 }
372
373
374 /* patcher_builtin_arraycheckcast **********************************************
375
376    Machine code:
377
378    <patched call position>
379    e51c1120    ldr   r1, [ip, #-288]
380    e1a0e00f    mov   lr, pc
381    e51cf124    ldr   pc, [ip, #-292]
382
383 *******************************************************************************/
384
385 bool patcher_builtin_arraycheckcast(u1 *sp)
386 {
387         s4                 disp;
388         constant_classref *cr;
389         u1                *pv;
390         classinfo         *c;
391
392         /* get stuff from the stack */
393
394         disp =                       *((s4 *)     (sp + 5 * 4));
395         cr   = (constant_classref *) *((ptrint *) (sp + 1 * 4));
396         pv   = (u1 *)                *((ptrint *) (sp + 0 * 4));
397
398         /* get the classinfo */
399
400         if (!(c = resolve_classref_eager(cr)))
401                 return false;
402
403         /* patch the classinfo pointer */
404
405         *((ptrint *) (pv + disp)) = (ptrint) c;
406
407         return true;
408 }
409
410
411 /* patcher_invokestatic_special ************************************************
412
413    Machine code:
414
415    <patched call position>
416    e51cc02c    ldr   ip, [ip, #-44]
417    e1a0e00f    mov   lr, pc
418    e1a0f00c    mov   pc, ip
419
420 ******************************************************************************/
421
422 bool patcher_invokestatic_special(u1 *sp)
423 {
424         s4                 disp;
425         unresolved_method *um;
426         u1                *pv;
427         methodinfo        *m;
428
429         /* get stuff from the stack */
430
431         disp  =                       *((s4 *)     (sp + 5 * 4));
432         um    = (unresolved_method*)  *((ptrint *) (sp + 1 * 4));
433         pv    = (u1*)                 *((ptrint *) (sp + 0 * 4));
434
435         /* get the methodinfo */
436
437         if (!(m = resolve_method_eager(um)))
438                 return false;
439
440         /* patch stubroutine */
441
442         *((ptrint *) (pv + disp)) = (ptrint) m->stubroutine;
443
444         return true;
445 }
446
447
448 /* patcher_invokevirtual *******************************************************
449
450    Machine code:
451
452    <patched call position>
453    e590b000    ldr   fp, [r0]
454    e59bc000    ldr   ip, [fp, #__]
455    e1a0e00f    mov   lr, pc
456    e1a0f00c    mov   pc, ip
457
458 *******************************************************************************/
459
460 bool patcher_invokevirtual(u1 *sp)
461 {
462         u1                *ra;
463         unresolved_method *um;
464         methodinfo        *m;
465
466         /* get stuff from the stack */
467
468         ra = (u1 *)                *((ptrint *) (sp + 4 * 4));
469         um = (unresolved_method *) *((ptrint *) (sp + 1 * 4));
470
471         /* get the methodinfo */
472
473         if (!(m = resolve_method_eager(um)))
474                 return false;
475
476         /* if we show disassembly, we have to skip the nop */
477
478         if (opt_showdisassemble)
479                 ra = ra + 1 * 4;
480
481         /* patch vftbl index */
482
483         gen_resolveload(*((s4 *) (ra + 1 * 4)), (s4) (OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * m->vftblindex));
484
485         /* synchronize instruction cache */
486
487         md_icacheflush(ra + 1 * 4, 1 * 4);
488
489         return true;
490 }
491
492
493 /* patcher_invokeinterface *****************************************************
494
495    Machine code:
496
497    <patched call position>
498    e590b000    ldr   fp, [r0]
499    e59bb000    ldr   fp, [fp, #__]
500    e59bc000    ldr   ip, [fp, #__]
501    e1a0e00f    mov   lr, pc
502    e1a0f00c    mov   pc, ip
503
504
505 *******************************************************************************/
506
507 bool patcher_invokeinterface(u1 *sp)
508 {
509         u1                *ra;
510         unresolved_method *um;
511         methodinfo        *m;
512
513         /* get stuff from the stack */
514
515         ra = (u1 *)                *((ptrint *) (sp + 4 * 4));
516         um = (unresolved_method *) *((ptrint *) (sp + 1 * 4));
517
518         /* get the methodinfo */
519
520         if (!(m = resolve_method_eager(um)))
521                 return false;
522
523         /* if we show disassembly, we have to skip the nop */
524
525         if (opt_showdisassemble)
526                 ra = ra + 1 * 4;
527
528         /* patch interfacetable index */
529
530         gen_resolveload(*((s4 *) (ra + 1 * 4)), (s4) (OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr*) * m->class->index));
531
532         /* patch method offset */
533
534         gen_resolveload(*((s4 *) (ra + 2 * 4)), (s4) (sizeof(methodptr) * (m - m->class->methods)));
535
536         /* synchronize instruction cache */
537
538         md_icacheflush(ra + 1 * 4, 2 * 4);
539
540         return true;
541 }
542
543
544 /* patcher_checkcast_instanceof_flags ******************************************
545
546    Machine code:
547
548    <patched call position>
549
550 *******************************************************************************/
551
552 bool patcher_checkcast_instanceof_flags(u1 *sp)
553 {
554         s4                 disp;
555         constant_classref *cr;
556         u1                *pv;
557         classinfo         *c;
558
559         /* get stuff from the stack */
560
561         disp  =                       *((s4 *)     (sp + 5 * 4));
562         cr    = (constant_classref *) *((ptrint *) (sp + 1 * 4));
563         pv    = (u1 *)                *((ptrint *) (sp + 0 * 4));
564
565         /* get the classinfo */
566
567         if (!(c = resolve_classref_eager(cr)))
568                 return false;
569
570         /* patch class flags */
571
572         *((s4 *) (pv + disp)) = (s4) c->flags;
573
574         return true;
575 }
576
577
578 /* patcher_checkcast_instanceof_interface **************************************
579
580    Machine code:
581
582    <patched call position>
583    e59ab000    ldr   fp, [sl]
584    e59b9010    ldr   r9, [fp, #16]
585    e3590000    cmp   r9, #0  ; 0x0
586    da000000    ble   0x000000
587    e59b9000    ldr   r9, [fp, #__]
588    e1190009    tst   r9, r9
589    0a000000    beq   0x000000
590
591 *******************************************************************************/
592
593 bool patcher_checkcast_instanceof_interface(u1 *sp)
594 {
595         u1                *ra;
596         constant_classref *cr;
597         classinfo         *c;
598
599         /* get stuff from the stack */
600
601         ra = (u1 *)                *((ptrint *) (sp + 4 * 4));
602         cr = (constant_classref *) *((ptrint *) (sp + 1 * 4));
603
604         /* get the classinfo */
605
606         if (!(c = resolve_classref_eager(cr)))
607                 return false;
608
609         /* if we show disassembly, we have to skip the nop */
610
611         if (opt_showdisassemble)
612                 ra = ra + 4;
613
614         /* patch super class index */
615
616         assert(*((s4 *) (ra + 2 * 4)) == 0xe3590000);
617         assert(c->index <= 0xff);
618
619         *((s4 *) (ra + 2 * 4)) |= (s4) (c->index & 0x000000ff);
620
621         /* patch super class vftbl index */
622
623         gen_resolveload(*((s4 *) (ra + 4 * 4)), (s4) (OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr*) * c->index));
624
625         /* synchronize instruction cache */
626
627         md_icacheflush(ra + 2 * 4, 3 * 4);
628
629         return true;
630 }
631
632
633 /* patcher_checkcast_instanceof_class ******************************************
634
635    Machine code:
636
637    <patched call position>
638
639 *******************************************************************************/
640
641 bool patcher_checkcast_instanceof_class(u1 *sp)
642 {
643         s4                 disp;
644         constant_classref *cr;
645         u1                *pv;
646         classinfo         *c;
647
648         /* get stuff from the stack */
649
650         disp =                       *((s4 *)     (sp + 5 * 4));
651         cr   = (constant_classref *) *((ptrint *) (sp + 1 * 4));
652         pv   = (u1 *)                *((ptrint *) (sp + 0 * 4));
653
654         /* get the classinfo */
655
656         if (!(c = resolve_classref_eager(cr)))
657                 return false;
658
659         /* patch super class' vftbl */
660
661         *((ptrint *) (pv + disp)) = (ptrint) c->vftbl;
662
663         return true;
664 }
665
666
667 /* patcher_clinit **************************************************************
668
669    XXX
670
671 *******************************************************************************/
672
673 bool patcher_clinit(u1 *sp)
674 {
675         classinfo *c;
676
677         /* get stuff from the stack */
678
679         c = (classinfo *) *((ptrint *) (sp + 1 * 4));
680
681         /* check if the class is initialized */
682
683         if (!(c->state & CLASS_INITIALIZED))
684                 if (!initialize_class(c))
685                         return false;
686
687         return true;
688 }
689
690
691 /* patcher_athrow_areturn ******************************************************
692
693    Machine code:
694
695    <patched call position>
696
697 *******************************************************************************/
698
699 #ifdef ENABLE_VERIFIER
700 bool patcher_athrow_areturn(u1 *sp)
701 {
702         unresolved_class *uc;
703
704         /* get stuff from the stack */
705
706         uc = (unresolved_class *) *((ptrint *) (sp + 1 * 4));
707
708         /* resolve the class and check subtype constraints */
709
710         if (!resolve_class_eager_no_access_check(uc))
711                 return false;
712
713         return true;
714 }
715 #endif /* ENABLE_VERIFIER */
716
717
718 /* patcher_resolve_native ******************************************************
719
720    XXX
721
722 *******************************************************************************/
723
724 #if !defined(WITH_STATIC_CLASSPATH)
725 bool patcher_resolve_native(u1 *sp)
726 {
727         s4           disp;
728         methodinfo  *m;
729         u1          *pv;
730         functionptr  f;
731
732         /* get stuff from the stack */
733
734         disp =                *((s4 *)     (sp + 5 * 4));
735         m    = (methodinfo *) *((ptrint *) (sp + 1 * 4));
736         pv   = (u1 *)         *((ptrint *) (sp + 0 * 4));
737
738         /* resolve native function */
739
740         if (!(f = native_resolve_function(m)))
741                 return false;
742
743         /* patch native function pointer */
744
745         *((ptrint *) (pv + disp)) = (ptrint) f;
746
747         return true;
748 }
749 #endif /* !defined(WITH_STATIC_CLASSPATH) */
750
751
752 /*
753  * These are local overrides for various environment variables in Emacs.
754  * Please do not remove this and leave it at the end of the file, where
755  * Emacs will automagically detect them.
756  * ---------------------------------------------------------------------
757  * Local variables:
758  * mode: c
759  * indent-tabs-mode: t
760  * c-basic-offset: 4
761  * tab-width: 4
762  * End:
763  * vim:noexpandtab:sw=4:ts=4:
764  */