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