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