* Merged in twisti-branch.
[cacao.git] / src / vm / jit / m68k / patcher.c
1 /* src/vm/jit/m68k/patcher.c - m68k patcher 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: arch.h 5330 2006-09-05 18:43:12Z edwin $
26
27 */
28
29 #include "config.h"
30
31 #include <assert.h>
32
33 #include "vm/types.h"
34
35 #include "mm/memory.h"
36 #include "native/native.h"
37
38 #include "vm/builtin.h"
39 #include "vm/exceptions.h"
40 #include "vm/initialize.h"
41 #include "vm/resolve.h"
42
43 #include "vm/jit/asmpart.h"
44 #include "vm/jit/patcher.h"
45 #include "vm/jit/md.h"
46 #include "vm/jit/methodheader.h"
47 #include "vm/jit/stacktrace.h"
48
49 #include "vmcore/class.h"
50 #include "vmcore/field.h"
51 #include "vmcore/options.h"
52 #include "vmcore/references.h"
53
54 #include "codegen.h"
55
56 /* patcher_wrapper *************************************************************
57
58    Wrapper for all patchers.  It also creates the stackframe info
59    structure.
60
61    If the return value of the patcher function is false, it gets the
62    exception object, clears the exception pointer and returns the
63    exception.
64
65 *******************************************************************************/
66
67 java_objectheader *patcher_wrapper(u1 *sp, u1 *pv, u1 *ra)
68 {
69         stackframeinfo     sfi;
70         u1                *xpc;
71         java_objectheader *o;
72         functionptr        f;
73         bool               result;
74         java_objectheader *e;
75         u4                 mcode, xmcode;
76
77         /* define the patcher function */
78
79         bool (*patcher_function)(u1 *);
80
81         /* get stuff from the stack */
82
83         xpc = (u1 *)                *((ptrint *) (sp + 6 * 4));
84         /* REG_ITMP3                              sp + 5 * 4 */
85         o   = (java_objectheader *) *((ptrint *) (sp + 4 * 4));
86         mcode =                     *((u4*)      (sp + 3 * 4));
87         xmcode =                    *((u4*)      (sp + 2 * 4));
88         /* unresolved file                        sp + 1 * 4 */
89         f   = (functionptr)         *((ptrint *) (sp + 0 * 4));
90
91
92         /* calculate and set the new return address */
93
94         xpc = xpc - PATCHER_CALL_SIZE;
95         *((ptrint *) (sp + 6 * 4)) = (ptrint) xpc;
96
97         /* patch back original code */
98
99         *((u4*)(xpc))   = mcode;
100         *((u4*)(xpc+4)) = xmcode;
101         md_icacheflush(xpc, 8);
102
103         /* cast the passed function to a patcher function */
104
105         patcher_function = (bool (*)(u1 *)) (ptrint) f;
106
107         /* enter a monitor on the patching position */
108
109         PATCHER_MONITORENTER;
110
111         /* create the stackframeinfo */
112
113         /* RA is passed as NULL, but the XPC is correct and can be used in
114            stacktrace_create_extern_stackframeinfo for
115            md_codegen_get_pv_from_pc. */
116
117         stacktrace_create_extern_stackframeinfo(&sfi, pv, sp + 7 * 4, xpc, xpc);
118
119         /* call the proper patcher function */
120
121         result = (patcher_function)(sp);
122
123         /* remove the stackframeinfo */
124
125         stacktrace_remove_stackframeinfo(&sfi);
126
127         /* check for return value and exit accordingly */
128
129         if (result == false) {
130                 e = exceptions_get_and_clear_exception();
131
132                 PATCHER_MONITOREXIT;
133
134                 return e;
135         }
136         PATCHER_MARK_PATCHED_MONITOREXIT;
137
138         return NULL;
139 }
140
141 /* patcher_initialize_class ****************************************************
142
143    Initalizes a given classinfo pointer.  This function does not patch
144    any data.
145
146 *******************************************************************************/
147
148 bool patcher_initialize_class(u1 *sp)
149 {
150         classinfo *c;
151
152         /* get stuff from the stack */
153
154         c = (classinfo *) *((ptrint *) (sp + 1 * 4));
155
156         /* check if the class is initialized */
157
158         if (!(c->state & CLASS_INITIALIZED))
159                 if (!initialize_class(c))
160                         return false;
161
162         return true;
163 }
164
165 /* patcher_invokevirtual *******************************************************
166
167    Machine code:
168 0x4029bc46:   61ff 0000 00ba    bsrl 0x4029bd02
169 0x4029bc4c:   246f 0000         moveal %sp@(0),%a2
170 0x4029bc50:   266a 0000         moveal %a2@(0),%a3
171 0x4029bc54:   246b 0000         moveal %a3@(0),%a2      <-- patch this (0) offset
172 0x4029bc58:   4e92              jsr %a2@
173
174 *******************************************************************************/
175
176 bool patcher_invokevirtual(u1 *sp)
177 {
178         u1                *ra;
179         unresolved_method *um;
180         methodinfo        *m;
181         s2                 disp;
182
183         /* get stuff from the stack */
184         ra = (u1 *)                *((ptrint *) (sp + 6 * 4));
185         um = (unresolved_method *) *((ptrint *) (sp + 1 * 4));
186
187         /* get the fieldinfo */
188         if (!(m = resolve_method_eager(um)))
189                 return false;
190
191         /* if we show NOPs, we have to skip them */
192         if (opt_shownops) ra += PATCHER_CALL_SIZE;
193
194         assert( *((u2*)(ra+8)) == 0x246b);
195
196         /* patch vftbl index */
197         disp = (OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * m->vftblindex);
198         *((s2 *) (ra + 10)) = disp;
199
200         /* synchronize instruction cache */
201         md_icacheflush(ra + 10, 2);
202
203         return true;
204 }
205
206 /* patcher_invokestatic_special ************************************************
207
208    Machine code:
209
210    INVOKESPECIAL
211 0x402902bc:   61ff 0000 0076    bsrl 0x40290334
212 0x402902c2:   247c 0000 0000    moveal #0,%a2           <-- this #0
213 0x402902c8:   4e92              jsr %a2@
214
215 ******************************************************************************/
216
217 bool patcher_invokestatic_special(u1 *sp)
218 {
219         unresolved_method *um;
220         s4                 disp;
221         methodinfo        *m;
222
223         /* get stuff from the stack */
224
225         disp =                       *((s4 *)     (sp + 6 * 4));
226         um   = (unresolved_method *) *((ptrint *) (sp + 1 * 4));
227
228         /* get the fieldinfo */
229
230         if (!(m = resolve_method_eager(um)))
231                 return false;
232
233         /* patch stubroutine */
234
235         if (opt_shownops) disp += PATCHER_CALL_SIZE;
236
237         *((ptrint *) (disp+2)) = (ptrint) m->stubroutine;
238
239         /* synchronize inst cache */
240
241         md_icacheflush(disp+2, SIZEOF_VOID_P);
242
243         return true;
244 }
245
246
247 /* patcher_resolve_class *******************************************************
248
249    Resolves a given unresolved_class pointer.  This function does not
250    patch any data.
251
252 *******************************************************************************/
253
254 #ifdef ENABLE_VERIFIER
255 bool patcher_resolve_class(u1 *sp)
256 {
257         unresolved_class *uc;
258         classinfo        *c;
259
260         /* get stuff from the stack */
261
262         uc = (unresolved_class *) *((ptrint *) (sp + 2 * 4));
263
264         /* resolve the class */
265         assert(0);
266
267         if (!resolve_class(uc, resolveEager, false, &c))
268                 return false;
269
270         return true;
271 }
272 #endif /* ENABLE_VERIFIER */
273
274 /* patcher_resolve_classref_to_classinfo ***************************************
275   ACONST:
276         0x4028f2ca:   2479 0000 0000    moveal 0x00000000,%a2
277 *******************************************************************************/
278 bool patcher_resolve_classref_to_classinfo(u1 *sp)
279 {
280         constant_classref *cr;
281         s4                 disp;
282         u1                *pv;
283         classinfo         *c;
284
285         /* get stuff from the stack */
286
287         cr   = (constant_classref *) *((ptrint *) (sp + 1 * 4));
288         disp =                       *((s4 *)     (sp + 6 * 4));
289
290         /* get the classinfo */
291
292         if (!(c = resolve_classref_eager(cr)))
293                 return false;
294
295         /* patch the classinfo pointer */
296
297         if (opt_shownops) disp += PATCHER_CALL_SIZE;
298
299         *((ptrint *) (disp+2)) = (ptrint) c;
300
301         /* synchronize inst cache */
302
303         md_icacheflush(disp+2, SIZEOF_VOID_P);
304
305         return true;
306 }
307
308 /* patcher_get_putstatic *******************************************************
309
310    Machine code:
311
312 *******************************************************************************/
313
314 bool patcher_get_putstatic(u1 *sp)
315 {
316         u1               *ra;
317         u4                mcode;
318         unresolved_field *uf;
319         s4                disp;
320         u1               *pv;
321         fieldinfo        *fi;
322
323         /* get stuff from the stack */
324
325         ra    = (u1 *)                *((ptrint *) (sp + 5 * 4));
326         mcode =                       *((u4 *)     (sp + 3 * 4));
327         uf    = (unresolved_field *)  *((ptrint *) (sp + 2 * 4));
328         disp  =                       *((s4 *)     (sp + 1 * 4));
329         pv    = (u1 *)                *((ptrint *) (sp + 0 * 4));
330
331         /* get the fieldinfo */
332
333         assert(0);
334
335         if (!(fi = resolve_field_eager(uf)))
336                 return false;
337
338         /* check if the field's class is initialized */
339
340         if (!(fi->class->state & CLASS_INITIALIZED))
341                 if (!initialize_class(fi->class))
342                         return false;
343
344         /* patch the field value's address */
345
346         *((ptrint *) (pv + disp)) = (ptrint) &(fi->value);
347
348         /* synchronize data cache */
349
350         md_dcacheflush(pv + disp, SIZEOF_VOID_P);
351
352         return true;
353 }
354
355 /* patcher_get_putfield ********************************************************
356
357    Machine code:
358
359    <patched call position>
360
361 *******************************************************************************/
362
363 bool patcher_get_putfield(u1 *sp)
364 {
365         u1               *ra;
366         unresolved_field *uf;
367         fieldinfo        *fi;
368         s2                disp;
369
370         ra = (u1 *)               *((ptrint *) (sp + 6 * 4));
371         uf = (unresolved_field *) *((ptrint *) (sp + 1 * 4));
372
373         /* get the fieldinfo */
374
375         assert(0);
376
377         if (!(fi = resolve_field_eager(uf)))
378                 return false;
379
380         /* if we show NOPs, we have to skip them */
381
382         if (opt_shownops) {
383                 /* patch the field's offset */
384
385                 if (IS_LNG_TYPE(fi->type)) {
386                         /* If the field has type long, we have to patch two
387                            instructions.  But we have to check which instruction
388                            is first.  We do that with the offset of the first
389                            instruction. */
390
391                         disp = *((u4 *) (ra + 1 * 4));
392
393                         if (disp == 4) {
394                                 *((u4 *) (ra + 1 * 4)) |= (s2) ((fi->offset + 4) & 0x0000ffff);
395                                 *((u4 *) (ra + 2 * 4)) |= (s2) ((fi->offset + 0) & 0x0000ffff);
396                         }
397                         else {
398                                 *((u4 *) (ra + 1 * 4)) |= (s2) ((fi->offset + 0) & 0x0000ffff);
399                                 *((u4 *) (ra + 2 * 4)) |= (s2) ((fi->offset + 4) & 0x0000ffff);
400                         }
401                 }
402                 else
403                         *((u4 *) (ra + 1 * 4)) |= (s2) (fi->offset & 0x0000ffff);
404         }
405         else {
406                 if (IS_LNG_TYPE(fi->type)) {
407
408                         disp = *((u4 *) (sp + 3 * 4));
409
410                         /* We patch the first instruction in the patcher stub
411                            stack and the second in the code.  The first
412                            instruction is patched back later in
413                            patcher_wrapper. */
414
415                         if (disp == 4) {
416                                 *((u4 *) (sp + 3 * 4)) |= (s2) ((fi->offset + 4) & 0x0000ffff);
417                                 *((u4 *) (ra + 1 * 4)) |= (s2) ((fi->offset + 0) & 0x0000ffff);
418                         }
419                         else {
420                                 *((u4 *) (sp + 3 * 4)) |= (s2) ((fi->offset + 0) & 0x0000ffff);
421                                 *((u4 *) (ra + 1 * 4)) |= (s2) ((fi->offset + 4) & 0x0000ffff);
422                         }
423                 }
424                 else
425                         *((u4 *) (sp + 3 * 4)) |= (s2) (fi->offset & 0x0000ffff);
426         }
427
428         /* synchronize instruction cache */
429
430         md_icacheflush(ra + 1 * 4, 2 * 4);
431
432         return true;
433 }
434 /* patcher_resolve_classref_to_flags *******************************************
435
436    CHECKCAST/INSTANCEOF:
437
438
439 CHECKCAST:
440 0x4029b056:   61ff 0000 013e    bsrl 0x4029b196
441 0x4029b05c:   263c 0000 0000    movel #0,%d3            <-- patch this #0
442 0x4029b062:   0283 0000 0200    andil #512,%d3
443
444 INSTANCEOF:
445 0x402a4aa8:   61ff 0000 05c4    bsrl 0x402a506e
446 0x402a4aae:   283c 0000 0000    movel #0,%d4            <-- same here
447 0x402a4ab4:   0284 0000 0200    andil #512,%d4
448
449
450 *******************************************************************************/
451
452 bool patcher_resolve_classref_to_flags(u1 *sp)
453 {
454         constant_classref *cr;
455         s4                 disp;
456         classinfo         *c;
457
458         /* get stuff from the stack */
459         cr   = (constant_classref *) *((ptrint *) (sp + 1 * 4));
460         disp =                       *((s4 *)     (sp + 6 * 4));
461
462         /* get the fieldinfo */
463         if (!(c = resolve_classref_eager(cr)))
464                 return false;
465
466         /* patch class flags */
467         if (opt_shownops) disp += PATCHER_CALL_SIZE;
468         assert( (*((u2*)(disp)) == 0x263c) || (*((u2*)(disp)) == 0x283c) );
469         *((s4 *) (disp + 2)) = (s4) c->flags;
470
471         /* synchronize insn cache */
472         md_icacheflush(disp + 2, SIZEOF_VOID_P);
473
474         return true;
475 }
476
477 /* patcher_resolve_classref_to_vftbl *******************************************
478
479    CHECKCAST (class):
480 0x4029b094:   61ff 0000 00b4    bsrl 0x4029b14a
481 0x4029b09a:   287c 0000 0000    moveal #0,%a4           <-- patch this #0
482 0x4029b0a0:   2668 0000         moveal %a0@(0),%a3
483
484    INSTANCEOF (class):
485 0x402a9300:   61ff 0000 0574    bsrl 0x402a9876
486 0x402a9306:   267c 0000 0000    moveal #0,%a3
487 0x402a930c:   246a 0000         moveal %a2@(0),%a2
488
489
490 *******************************************************************************/
491
492 bool patcher_resolve_classref_to_vftbl(u1 *sp)
493 {
494         constant_classref *cr;
495         s4                 disp;
496         classinfo         *c;
497
498         /* get stuff from the stack */
499         cr   = (constant_classref *) *((ptrint *) (sp + 1 * 4));
500         disp =                       *((s4 *)     (sp + 6 * 4));
501
502         /* get the fieldinfo */
503         if (!(c = resolve_classref_eager(cr)))
504                 return false;
505
506         /* patch super class' vftbl */
507         if (opt_shownops) disp += PATCHER_CALL_SIZE;
508         assert( (*((u2*)disp) == 0x287c) || (*((u2*)disp)== 0x267c) );
509
510         *((s4 *) (disp+2)) = (s4) c->vftbl;
511
512         /* synchronize insin cache */
513         md_icacheflush(disp+2, SIZEOF_VOID_P);
514
515         return true;
516 }
517
518 /* patcher_instanceof_interface ************************************************
519
520    Machine code:
521
522 0x402a92da:   61ff 0000 05c0    bsrl 0x402a989c
523 0x402a92e0:   246a 0000         moveal %a2@(0),%a2
524 0x402a92e4:   282a 0010         movel %a2@(16),%d4
525 0x402a92e8:   d8bc 0000 0000    addl #0,%d4             <-- this const
526 0x402a92ee:   4a84              tstl %d4
527 0x402a92f0:   6e0a              bles 0x402a92fc
528 0x402a92f2:   246a 0000         moveal %a2@(0),%a2      <-- this offset
529
530 *******************************************************************************/
531
532 bool patcher_instanceof_interface(u1 *sp)
533 {
534         u1                *ra;
535         constant_classref *cr;
536         classinfo         *c;
537         s4                 disp;
538
539         /* get stuff from the stack */
540
541         ra = (u1 *)                *((ptrint *) (sp + 6 * 4));
542         cr = (constant_classref *) *((ptrint *) (sp + 1 * 4));
543
544         /* get the fieldinfo */
545         if (!(c = resolve_classref_eager(cr)))
546                 return false;
547
548         /* if we show NOPs, we have to skip them */
549         if (opt_shownops) ra += PATCHER_CALL_SIZE;
550                 
551         /* patch super class index */
552         disp = -(c->index);
553         assert( *((u2*)(ra + 8)) == 0xd8bc );
554         *((s4 *) (ra + 10 )) = disp;
555
556         disp = OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*);
557
558         assert( (s2)disp  == disp);
559         assert ( *((s2*)(ra+18)) == 0x246a );
560
561         *((s2 *) (ra + 20)) = disp;
562
563         /* synchronize instruction cache */
564         md_icacheflush(ra + 10, 12);
565
566         return true;
567 }
568
569 /* patcher_checkcast_interface *************************************************
570
571 0x402a9400:   61ff 0000 03b6    bsrl 0x402a97b8
572 0x402a9406:   266a 0000         moveal %a2@(0),%a3
573 0x402a940a:   282b 0010         movel %a3@(16),%d4
574 0x402a940e:   d8bc 0000 0000    addl #0,%d4             <-- this 0
575 0x402a9414:   4a84              tstl %d4
576 0x402a9416:   6e02              bgts 0x402a941a
577               1234              tstb %d0
578 0x402a9418:   4afc              illegal
579 0x402a941a:   286b 0000         moveal %a3@(0),%a4      <-- and this 0 offset
580
581 *******************************************************************************/
582
583 bool patcher_checkcast_interface(u1 *sp)
584 {
585         u1                *ra;
586         constant_classref *cr;
587         classinfo         *c;
588         s4                 disp;
589
590         /* get stuff from the stack */
591         ra = (u1 *)                *((ptrint *) (sp + 6 * 4));
592         cr = (constant_classref *) *((ptrint *) (sp + 1 * 4));
593
594         /* get the fieldinfo */
595         if (!(c = resolve_classref_eager(cr)))
596                 return false;
597
598         /* if we show NOPs, we have to skip them */
599         if (opt_shownops) ra += PATCHER_CALL_SIZE;
600
601         /* patch super class index */
602         disp = -(c->index);
603         assert ( *((u2 *)(ra + 8)) == 0xd8bc );
604         *((s4 *) (ra + 10)) = disp;
605
606         disp = OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*);
607         assert( *((u2 *)(ra + 22)) == 0x286b );
608         assert( (s2)disp == disp);
609         *((s2 *) (ra + 24)) = disp;
610         
611         /* synchronize instruction cache */
612         md_icacheflush(ra + 10, 16);
613
614         return true;
615 }
616
617 /* patcher_resolve_native_function *********************************************
618
619    XXX
620
621 *******************************************************************************/
622
623 #if !defined(WITH_STATIC_CLASSPATH)
624 bool patcher_resolve_native_function(u1 *sp)
625 {
626         methodinfo  *m;
627         s4           disp;
628         functionptr  f;
629
630         /* get stuff from the stack */
631         m    = (methodinfo *) *((ptrint *) (sp + 1 * 4));
632         disp =                *((s4 *)     (sp + 6 * 4));
633
634         /* resolve native function */
635         if (!(f = native_resolve_function(m)))
636                 return false;
637
638         /* patch native function pointer */
639         if (opt_shownops) disp += PATCHER_CALL_SIZE;
640         *((ptrint *) (disp + 2)) = (ptrint) f;
641
642         /* synchronize data cache */
643         md_icacheflush(disp + 2, SIZEOF_VOID_P);
644
645         return true;
646 }
647 #endif /* !defined(WITH_STATIC_CLASSPATH) */
648
649
650 /* patcher_invokeinterface *****************************************************
651
652    Machine code:
653
654
655 *******************************************************************************/
656
657 bool patcher_invokeinterface(u1 *sp)
658 {
659         u1                *ra;
660         unresolved_method *um;
661         methodinfo        *m;
662         s4                 disp;
663
664         /* get stuff from the stack */
665         ra = (u1 *)                *((ptrint *) (sp + 6 * 4));
666         um = (unresolved_method *) *((ptrint *) (sp + 1 * 4));
667
668         assert(0);
669
670         /* get the fieldinfo */
671         if (!(m = resolve_method_eager(um)))
672                 return false;
673
674         /* if we show NOPs, we have to skip them */
675         if (opt_shownops) ra = ra + PATCHER_CALL_SIZE;
676
677         /* patch interfacetable index (first #0) */
678         disp = OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr*) * m->class->index;
679
680         /* XXX TWISTI: check displacement */
681         *((s4 *) (ra + 1 * 4)) |= (disp & 0x0000ffff);
682
683         /* patch method offset (second #0) */
684         disp = sizeof(methodptr) * (m - m->class->methods);
685
686         /* XXX TWISTI: check displacement */
687         *((s4 *) (ra + 2 * 4)) |= (disp & 0x0000ffff);
688
689         /* synchronize instruction cache */
690         md_icacheflush(ra + 1 * 4, 2 * 4);
691
692         return true;
693 }
694