75f7f1c10b4206b048e65013032952b9d395e81d
[cacao.git] / src / vm / jit / i386 / patcher.c
1 /* src/vm/jit/i386/patcher.c - i386 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 <stdint.h>
31
32 #include "vm/types.h"
33
34 #include "vm/jit/i386/codegen.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/patcher-common.h"
45 #include "vm/jit/stacktrace.h"
46
47 #include "vmcore/class.h"
48 #include "vmcore/field.h"
49 #include "vmcore/options.h"
50 #include "vm/resolve.h"
51 #include "vmcore/references.h"
52
53
54 #define PATCH_BACK_ORIGINAL_MCODE *((u2 *) pr->mpc) = (u2) pr->mcode
55
56
57 /* patcher_patch_code **********************************************************
58
59    Just patches back the original machine code.
60
61 *******************************************************************************/
62
63 void patcher_patch_code(patchref_t *pr)
64 {
65         PATCH_BACK_ORIGINAL_MCODE;
66 }
67
68
69 /* patcher_get_putstatic *******************************************************
70
71    Machine code:
72
73    <patched call position>
74    b8 00 00 00 00             mov    $0x00000000,%eax
75
76 *******************************************************************************/
77
78 bool patcher_get_putstatic(patchref_t *pr)
79 {
80         u1               *ra;
81         unresolved_field *uf;
82         fieldinfo        *fi;
83
84         /* get stuff from the stack */
85
86         ra    = (u1 *)               pr->mpc;
87         uf    = (unresolved_field *) pr->ref;
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         /* if we show disassembly, we have to skip the nop's */
103
104         if (opt_shownops)
105                 ra = ra + PATCHER_CALL_SIZE;
106
107         /* patch the field value's address */
108
109         *((intptr_t *) (ra + 1)) = (intptr_t) fi->value;
110
111         return true;
112 }
113
114
115 /* patcher_getfield ************************************************************
116
117    Machine code:
118
119    <patched call position>
120    8b 88 00 00 00 00          mov    0x00000000(%eax),%ecx
121
122 *******************************************************************************/
123
124 bool patcher_getfield(patchref_t *pr)
125 {
126         u1               *ra;
127         unresolved_field *uf;
128         fieldinfo        *fi;
129
130         /* get stuff from the stack */
131
132         ra    = (u1 *)               pr->mpc;
133         uf    = (unresolved_field *) pr->ref;
134
135         /* get the fieldinfo */
136
137         if (!(fi = resolve_field_eager(uf)))
138                 return false;
139
140         PATCH_BACK_ORIGINAL_MCODE;
141
142         /* if we show disassembly, we have to skip the nop's */
143
144         if (opt_shownops)
145                 ra = ra + PATCHER_CALL_SIZE;
146
147         /* patch the field's offset */
148
149         *((u4 *) (ra + 2)) = (u4) (fi->offset);
150
151         /* if the field has type long, we need to patch the second move too */
152
153         if (fi->type == TYPE_LNG)
154                 *((u4 *) (ra + 6 + 2)) = (u4) (fi->offset + 4);
155
156         return true;
157 }
158
159
160 /* patcher_putfield ************************************************************
161
162    Machine code:
163
164    <patched call position>
165    8b 88 00 00 00 00          mov    0x00000000(%eax),%ecx
166
167 *******************************************************************************/
168
169 bool patcher_putfield(patchref_t *pr)
170 {
171         u1               *ra;
172         unresolved_field *uf;
173         fieldinfo        *fi;
174
175         /* get stuff from the stack */
176
177         ra    = (u1 *)               pr->mpc;
178         uf    = (unresolved_field *) pr->ref;
179
180         /* get the fieldinfo */
181
182         if (!(fi = resolve_field_eager(uf)))
183                 return false;
184
185         PATCH_BACK_ORIGINAL_MCODE;
186
187         /* if we show disassembly, we have to skip the nop's */
188
189         if (opt_shownops)
190                 ra = ra + PATCHER_CALL_SIZE;
191
192         /* patch the field's offset */
193
194         if (fi->type != TYPE_LNG) {
195                 *((u4 *) (ra + 2)) = (u4) (fi->offset);
196         }
197         else {
198                 /* The long code is special:
199                  *
200                  * 89 8d 00 00 00 00          mov    %ecx,0x00000000(%ebp)
201                  * 89 95 00 00 00 00          mov    %edx,0x00000000(%ebp)
202                  */
203
204                 *((u4 *) (ra + 2))     = (u4) (fi->offset);
205                 *((u4 *) (ra + 6 + 2)) = (u4) (fi->offset + 4);
206         }
207
208         return true;
209 }
210
211
212 /* patcher_putfieldconst *******************************************************
213
214    Machine code:
215
216    <patched call position>
217    c7 85 00 00 00 00 7b 00 00 00    movl   $0x7b,0x0(%ebp)
218
219 *******************************************************************************/
220
221 bool patcher_putfieldconst(patchref_t *pr)
222 {
223         u1               *ra;
224         unresolved_field *uf;
225         fieldinfo        *fi;
226
227         /* get stuff from the stack */
228
229         ra    = (u1 *)               pr->mpc;
230         uf    = (unresolved_field *) pr->ref;
231
232         /* get the fieldinfo */
233
234         if (!(fi = resolve_field_eager(uf)))
235                 return false;
236
237         PATCH_BACK_ORIGINAL_MCODE;
238
239         /* if we show disassembly, we have to skip the nop's */
240
241         if (opt_shownops)
242                 ra = ra + PATCHER_CALL_SIZE;
243
244         /* patch the field's offset */
245
246         if (!IS_2_WORD_TYPE(fi->type)) {
247                 *((u4 *) (ra + 2)) = (u4) (fi->offset);
248         }
249         else {
250                 /* long/double code is different:
251                  *
252                  * c7 80 00 00 00 00 c8 01 00 00    movl   $0x1c8,0x0(%eax)
253                  * c7 80 04 00 00 00 00 00 00 00    movl   $0x0,0x4(%eax)
254                  */
255
256                 *((u4 *) (ra + 2))      = (u4) (fi->offset);
257                 *((u4 *) (ra + 10 + 2)) = (u4) (fi->offset + 4);
258         }
259
260         return true;
261 }
262
263
264 /* patcher_aconst **************************************************************
265
266    Machine code:
267
268    <patched call postition>
269    c7 04 24 00 00 00 00       movl   $0x0000000,(%esp)
270    b8 00 00 00 00             mov    $0x0000000,%eax
271
272 *******************************************************************************/
273
274 bool patcher_aconst(patchref_t *pr)
275 {
276         u1                *ra;
277         constant_classref *cr;
278         classinfo         *c;
279
280         /* get stuff from the stack */
281
282         ra    = (u1 *)                pr->mpc;
283         cr    = (constant_classref *) pr->ref;
284
285         /* get the classinfo */
286
287         if (!(c = resolve_classref_eager(cr)))
288                 return false;
289
290         PATCH_BACK_ORIGINAL_MCODE;
291
292         /* if we show disassembly, we have to skip the nop's */
293
294         if (opt_shownops)
295                 ra = ra + PATCHER_CALL_SIZE;
296
297         /* patch the classinfo pointer */
298
299         *((ptrint *) (ra + 1)) = (ptrint) c;
300
301         return true;
302 }
303
304
305 /* patcher_builtin_multianewarray **********************************************
306
307    Machine code:
308
309    <patched call position>
310    c7 04 24 02 00 00 00       movl   $0x2,(%esp)
311    c7 44 24 04 00 00 00 00    movl   $0x00000000,0x4(%esp)
312    89 e0                      mov    %esp,%eax
313    83 c0 0c                   add    $0xc,%eax
314    89 44 24 08                mov    %eax,0x8(%esp)
315    b8 00 00 00 00             mov    $0x00000000,%eax
316    ff d0                      call   *%eax
317
318 *******************************************************************************/
319
320 bool patcher_builtin_multianewarray(patchref_t *pr)
321 {
322         u1                *ra;
323         constant_classref *cr;
324         classinfo         *c;
325
326         /* get stuff from the stack */
327
328         ra    = (u1 *)                pr->mpc;
329         cr    = (constant_classref *) pr->ref;
330
331         /* get the classinfo */
332
333         if (!(c = resolve_classref_eager(cr)))
334                 return false;
335
336         PATCH_BACK_ORIGINAL_MCODE;
337
338         /* if we show disassembly, we have to skip the nop's */
339
340         if (opt_shownops)
341                 ra = ra + PATCHER_CALL_SIZE;
342
343         /* patch the classinfo pointer */
344
345         *((ptrint *) (ra + 7 + 4)) = (ptrint) c;
346
347         return true;
348 }
349
350
351 /* patcher_builtin_arraycheckcast **********************************************
352
353    Machine code:
354
355    <patched call position>
356    c7 44 24 04 00 00 00 00    movl   $0x00000000,0x4(%esp)
357    ba 00 00 00 00             mov    $0x00000000,%edx
358    ff d2                      call   *%edx
359
360 *******************************************************************************/
361
362 bool patcher_builtin_arraycheckcast(patchref_t *pr)
363 {
364         u1                *ra;
365         constant_classref *cr;
366         classinfo         *c;
367
368         /* get stuff from the stack */
369
370         ra    = (u1 *)                pr->mpc;
371         cr    = (constant_classref *) pr->ref;
372
373         /* get the classinfo */
374
375         if (!(c = resolve_classref_eager(cr)))
376                 return false;
377
378         PATCH_BACK_ORIGINAL_MCODE;
379
380         /* if we show disassembly, we have to skip the nop's */
381
382         if (opt_shownops)
383                 ra = ra + PATCHER_CALL_SIZE;
384
385         /* patch the classinfo pointer */
386
387         *((ptrint *) (ra + 4)) = (ptrint) c;
388
389         /* patch new function address */
390
391         *((ptrint *) (ra + 8 + 1)) = (ptrint) BUILTIN_arraycheckcast;
392
393         return true;
394 }
395
396
397 /* patcher_invokestatic_special ************************************************
398
399    Machine code:
400
401    <patched call position>
402    b9 00 00 00 00             mov    $0x00000000,%ecx
403    ff d1                      call   *%ecx
404
405 *******************************************************************************/
406
407 bool patcher_invokestatic_special(patchref_t *pr)
408 {
409         u1                *ra;
410         unresolved_method *um;
411         methodinfo        *m;
412
413         /* get stuff from the stack */
414
415         ra    = (u1 *)                pr->mpc;
416         um    = (unresolved_method *) pr->ref;
417
418         /* get the fieldinfo */
419
420         if (!(m = resolve_method_eager(um)))
421                 return false;
422
423         PATCH_BACK_ORIGINAL_MCODE;
424
425         /* if we show disassembly, we have to skip the nop's */
426
427         if (opt_shownops)
428                 ra = ra + PATCHER_CALL_SIZE;
429
430         /* patch stubroutine */
431
432         *((ptrint *) (ra + 1)) = (ptrint) m->stubroutine;
433
434         return true;
435 }
436
437
438 /* patcher_invokevirtual *******************************************************
439
440    Machine code:
441
442    <patched call position>
443    8b 08                      mov    (%eax),%ecx
444    8b 81 00 00 00 00          mov    0x00000000(%ecx),%eax
445    ff d0                      call   *%eax
446
447 *******************************************************************************/
448
449 bool patcher_invokevirtual(patchref_t *pr)
450 {
451         u1                *ra;
452         unresolved_method *um;
453         methodinfo        *m;
454
455         /* get stuff from the stack */
456
457         ra    = (u1 *)                pr->mpc;
458         um    = (unresolved_method *) pr->ref;
459
460         /* get the fieldinfo */
461
462         if (!(m = resolve_method_eager(um)))
463                 return false;
464
465         PATCH_BACK_ORIGINAL_MCODE;
466
467         /* if we show disassembly, we have to skip the nop's */
468
469         if (opt_shownops)
470                 ra = ra + PATCHER_CALL_SIZE;
471
472         /* patch vftbl index */
473
474         *((s4 *) (ra + 2 + 2)) = (s4) (OFFSET(vftbl_t, table[0]) +
475                                                                    sizeof(methodptr) * m->vftblindex);
476
477         return true;
478 }
479
480
481 /* patcher_invokeinterface *****************************************************
482
483    Machine code:
484
485    <patched call position>
486    8b 00                      mov    (%eax),%eax
487    8b 88 00 00 00 00          mov    0x00000000(%eax),%ecx
488    8b 81 00 00 00 00          mov    0x00000000(%ecx),%eax
489    ff d0                      call   *%eax
490
491 *******************************************************************************/
492
493 bool patcher_invokeinterface(patchref_t *pr)
494 {
495         u1                *ra;
496         unresolved_method *um;
497         methodinfo        *m;
498
499         /* get stuff from the stack */
500
501         ra    = (u1 *)                pr->mpc;
502         um    = (unresolved_method *) pr->ref;
503
504         /* get the fieldinfo */
505
506         if (!(m = resolve_method_eager(um)))
507                 return false;
508
509         PATCH_BACK_ORIGINAL_MCODE;
510
511         /* if we show disassembly, we have to skip the nop's */
512
513         if (opt_shownops)
514                 ra = ra + PATCHER_CALL_SIZE;
515
516         /* patch interfacetable index */
517
518         *((s4 *) (ra + 2 + 2)) = (s4) (OFFSET(vftbl_t, interfacetable[0]) -
519                                                                    sizeof(methodptr) * m->class->index);
520
521         /* patch method offset */
522
523         *((s4 *) (ra + 2 + 6 + 2)) =
524                 (s4) (sizeof(methodptr) * (m - m->class->methods));
525
526         return true;
527 }
528
529
530 /* patcher_checkcast_instanceof_flags ******************************************
531
532    Machine code:
533
534    <patched call position>
535    b9 00 00 00 00             mov    $0x00000000,%ecx
536
537 *******************************************************************************/
538
539 bool patcher_checkcast_instanceof_flags(patchref_t *pr)
540 {
541         u1                *ra;
542         constant_classref *cr;
543         classinfo         *c;
544
545         /* get stuff from the stack */
546
547         ra    = (u1 *)                pr->mpc;
548         cr    = (constant_classref *) pr->ref;
549
550         /* get the fieldinfo */
551
552         if (!(c = resolve_classref_eager(cr)))
553                 return false;
554
555         PATCH_BACK_ORIGINAL_MCODE;
556
557         /* if we show disassembly, we have to skip the nop's */
558
559         if (opt_shownops)
560                 ra = ra + PATCHER_CALL_SIZE;
561
562         /* patch class flags */
563
564         *((s4 *) (ra + 1)) = (s4) c->flags;
565
566         return true;
567 }
568
569
570 /* patcher_checkcast_interface *************************************************
571
572    Machine code:
573
574    <patched call position>
575    8b 91 00 00 00 00          mov    0x00000000(%ecx),%edx
576    81 ea 00 00 00 00          sub    $0x00000000,%edx
577    85 d2                      test   %edx,%edx
578    0f 8f 06 00 00 00          jg     0x00000000
579    8b 35 03 00 00 00          mov    0x3,%esi
580    8b 91 00 00 00 00          mov    0x00000000(%ecx),%edx
581
582 *******************************************************************************/
583
584 bool patcher_checkcast_interface(patchref_t *pr)
585 {
586         u1                *ra;
587         constant_classref *cr;
588         classinfo         *c;
589
590         /* get stuff from the stack */
591
592         ra    = (u1 *)                pr->mpc;
593         cr    = (constant_classref *) pr->ref;
594
595         /* get the fieldinfo */
596
597         if (!(c = resolve_classref_eager(cr)))
598                 return false;
599
600         PATCH_BACK_ORIGINAL_MCODE;
601
602         /* if we show disassembly, we have to skip the nop's */
603
604         if (opt_shownops)
605                 ra = ra + PATCHER_CALL_SIZE;
606
607         /* patch super class index */
608
609         *((s4 *) (ra + 6 + 2)) = (s4) c->index;
610
611         *((s4 *) (ra + 6 + 6 + 2 + 6 + 6 + 2)) =
612                 (s4) (OFFSET(vftbl_t, interfacetable[0]) -
613                           c->index * sizeof(methodptr*));
614
615         return true;
616 }
617
618
619 /* patcher_instanceof_interface ************************************************
620
621    Machine code:
622
623    <patched call position>
624    8b 91 00 00 00 00          mov    0x00000000(%ecx),%edx
625    81 ea 00 00 00 00          sub    $0x00000000,%edx
626    85 d2                      test   %edx,%edx
627    0f 8e 13 00 00 00          jle    0x00000000
628    8b 91 00 00 00 00          mov    0x00000000(%ecx),%edx
629
630 *******************************************************************************/
631
632 bool patcher_instanceof_interface(patchref_t *pr)
633 {
634         u1                *ra;
635         constant_classref *cr;
636         classinfo         *c;
637
638         /* get stuff from the stack */
639
640         ra    = (u1 *)                pr->mpc;
641         cr    = (constant_classref *) pr->ref;
642
643         /* get the fieldinfo */
644
645         if (!(c = resolve_classref_eager(cr)))
646                 return false;
647
648         PATCH_BACK_ORIGINAL_MCODE;
649
650         /* if we show disassembly, we have to skip the nop's */
651
652         if (opt_shownops)
653                 ra = ra + PATCHER_CALL_SIZE;
654
655         /* patch super class index */
656
657         *((s4 *) (ra + 6 + 2)) = (s4) c->index;
658
659         *((s4 *) (ra + 6 + 6 + 2 + 6 + 2)) =
660                 (s4) (OFFSET(vftbl_t, interfacetable[0]) -
661                           c->index * sizeof(methodptr*));
662
663         return true;
664 }
665
666
667 /* patcher_checkcast_class *****************************************************
668
669    Machine code:
670
671    <patched call position>
672    ba 00 00 00 00             mov    $0x00000000,%edx
673    8b 89 00 00 00 00          mov    0x00000000(%ecx),%ecx
674    8b 92 00 00 00 00          mov    0x00000000(%edx),%edx
675    29 d1                      sub    %edx,%ecx
676    ba 00 00 00 00             mov    $0x00000000,%edx
677
678 *******************************************************************************/
679
680 bool patcher_checkcast_class(patchref_t *pr)
681 {
682         u1                *ra;
683         constant_classref *cr;
684         classinfo         *c;
685
686         /* get stuff from the stack */
687
688         ra    = (u1 *)                pr->mpc;
689         cr    = (constant_classref *) pr->ref;
690
691         /* get the fieldinfo */
692
693         if (!(c = resolve_classref_eager(cr)))
694                 return false;
695
696         PATCH_BACK_ORIGINAL_MCODE;
697
698         /* if we show disassembly, we have to skip the nop's */
699
700         if (opt_shownops)
701                 ra = ra + PATCHER_CALL_SIZE;
702
703         /* patch super class' vftbl */
704
705         *((ptrint *) (ra + 1)) = (ptrint) c->vftbl;
706         *((ptrint *) (ra + 5 + 6 + 6 + 2 + 1)) = (ptrint) c->vftbl;
707
708         return true;
709 }
710
711
712 /* patcher_instanceof_class ****************************************************
713
714    Machine code:
715
716    <patched call position>
717    b9 00 00 00 00             mov    $0x0,%ecx
718    8b 40 14                   mov    0x14(%eax),%eax
719    8b 51 18                   mov    0x18(%ecx),%edx
720    8b 49 14                   mov    0x14(%ecx),%ecx
721
722 *******************************************************************************/
723
724 bool patcher_instanceof_class(patchref_t *pr)
725 {
726         u1                *ra;
727         constant_classref *cr;
728         classinfo         *c;
729
730         /* get stuff from the stack */
731
732         ra    = (u1 *)                pr->mpc;
733         cr    = (constant_classref *) pr->ref;
734
735         /* get the fieldinfo */
736
737         if (!(c = resolve_classref_eager(cr)))
738                 return false;
739
740         PATCH_BACK_ORIGINAL_MCODE;
741
742         /* if we show disassembly, we have to skip the nop's */
743
744         if (opt_shownops)
745                 ra = ra + PATCHER_CALL_SIZE;
746
747         /* patch super class' vftbl */
748
749         *((ptrint *) (ra + 1)) = (ptrint) c->vftbl;
750
751         return true;
752 }
753
754
755 /* patcher_resolve_native_function *********************************************
756
757    Is used in native stub.
758
759    Machine code:
760
761    <patched call position>
762    c7 44 24 04 28 90 01 40    movl   $0x40019028,0x4(%esp)
763
764 *******************************************************************************/
765
766 bool patcher_resolve_native_function(patchref_t *pr)
767 {
768         u1          *ra;
769         methodinfo  *m;
770         functionptr  f;
771
772         /* get stuff from the stack */
773
774         ra    = (u1 *)         pr->mpc;
775         m     = (methodinfo *) pr->ref;
776
777         /* resolve native function */
778
779         if (!(f = native_resolve_function(m)))
780                 return false;
781
782         PATCH_BACK_ORIGINAL_MCODE;
783
784         /* if we show disassembly, we have to skip the nop's */
785
786         if (opt_shownops)
787                 ra = ra + PATCHER_CALL_SIZE;
788
789         /* patch native function pointer */
790
791         *((ptrint *) (ra + 4)) = (ptrint) f;
792
793         return true;
794 }
795
796
797 /*
798  * These are local overrides for various environment variables in Emacs.
799  * Please do not remove this and leave it at the end of the file, where
800  * Emacs will automagically detect them.
801  * ---------------------------------------------------------------------
802  * Local variables:
803  * mode: c
804  * indent-tabs-mode: t
805  * c-basic-offset: 4
806  * tab-width: 4
807  * End:
808  * vim:noexpandtab:sw=4:ts=4:
809  */