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