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