1 /* src/vm/jit/i386/patcher.c - i386 code patching functions
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
8 This file is part of CACAO.
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.
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.
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
34 #include "vm/jit/i386/codegen.h"
36 #include "mm/memory.h"
38 #include "native/native.h"
40 #include "vm/builtin.h"
41 #include "vm/exceptions.h"
42 #include "vm/initialize.h"
44 #include "vm/jit/patcher-common.h"
45 #include "vm/jit/stacktrace.h"
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"
54 #define PATCH_BACK_ORIGINAL_MCODE *((u2 *) pr->mpc) = (u2) pr->mcode
57 /* patcher_patch_code **********************************************************
59 Just patches back the original machine code.
61 *******************************************************************************/
63 void patcher_patch_code(patchref_t *pr)
65 PATCH_BACK_ORIGINAL_MCODE;
69 /* patcher_get_putstatic *******************************************************
73 <patched call position>
74 b8 00 00 00 00 mov $0x00000000,%eax
76 *******************************************************************************/
78 bool patcher_get_putstatic(patchref_t *pr)
84 /* get stuff from the stack */
87 uf = (unresolved_field *) pr->ref;
89 /* get the fieldinfo */
91 if (!(fi = resolve_field_eager(uf)))
94 /* check if the field's class is initialized */
96 if (!(fi->class->state & CLASS_INITIALIZED))
97 if (!initialize_class(fi->class))
100 PATCH_BACK_ORIGINAL_MCODE;
102 /* if we show disassembly, we have to skip the nop's */
105 ra = ra + PATCHER_CALL_SIZE;
107 /* patch the field value's address */
109 *((intptr_t *) (ra + 1)) = (intptr_t) fi->value;
115 /* patcher_getfield ************************************************************
119 <patched call position>
120 8b 88 00 00 00 00 mov 0x00000000(%eax),%ecx
122 *******************************************************************************/
124 bool patcher_getfield(patchref_t *pr)
127 unresolved_field *uf;
130 /* get stuff from the stack */
133 uf = (unresolved_field *) pr->ref;
135 /* get the fieldinfo */
137 if (!(fi = resolve_field_eager(uf)))
140 PATCH_BACK_ORIGINAL_MCODE;
142 /* if we show disassembly, we have to skip the nop's */
145 ra = ra + PATCHER_CALL_SIZE;
147 /* patch the field's offset */
149 *((u4 *) (ra + 2)) = (u4) (fi->offset);
151 /* if the field has type long, we need to patch the second move too */
153 if (fi->type == TYPE_LNG)
154 *((u4 *) (ra + 6 + 2)) = (u4) (fi->offset + 4);
160 /* patcher_putfield ************************************************************
164 <patched call position>
165 8b 88 00 00 00 00 mov 0x00000000(%eax),%ecx
167 *******************************************************************************/
169 bool patcher_putfield(patchref_t *pr)
172 unresolved_field *uf;
175 /* get stuff from the stack */
178 uf = (unresolved_field *) pr->ref;
180 /* get the fieldinfo */
182 if (!(fi = resolve_field_eager(uf)))
185 PATCH_BACK_ORIGINAL_MCODE;
187 /* if we show disassembly, we have to skip the nop's */
190 ra = ra + PATCHER_CALL_SIZE;
192 /* patch the field's offset */
194 if (fi->type != TYPE_LNG) {
195 *((u4 *) (ra + 2)) = (u4) (fi->offset);
198 /* The long code is special:
200 * 89 8d 00 00 00 00 mov %ecx,0x00000000(%ebp)
201 * 89 95 00 00 00 00 mov %edx,0x00000000(%ebp)
204 *((u4 *) (ra + 2)) = (u4) (fi->offset);
205 *((u4 *) (ra + 6 + 2)) = (u4) (fi->offset + 4);
212 /* patcher_putfieldconst *******************************************************
216 <patched call position>
217 c7 85 00 00 00 00 7b 00 00 00 movl $0x7b,0x0(%ebp)
219 *******************************************************************************/
221 bool patcher_putfieldconst(patchref_t *pr)
224 unresolved_field *uf;
227 /* get stuff from the stack */
230 uf = (unresolved_field *) pr->ref;
232 /* get the fieldinfo */
234 if (!(fi = resolve_field_eager(uf)))
237 PATCH_BACK_ORIGINAL_MCODE;
239 /* if we show disassembly, we have to skip the nop's */
242 ra = ra + PATCHER_CALL_SIZE;
244 /* patch the field's offset */
246 if (!IS_2_WORD_TYPE(fi->type)) {
247 *((u4 *) (ra + 2)) = (u4) (fi->offset);
250 /* long/double code is different:
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)
256 *((u4 *) (ra + 2)) = (u4) (fi->offset);
257 *((u4 *) (ra + 10 + 2)) = (u4) (fi->offset + 4);
264 /* patcher_aconst **************************************************************
268 <patched call postition>
269 c7 04 24 00 00 00 00 movl $0x0000000,(%esp)
270 b8 00 00 00 00 mov $0x0000000,%eax
272 *******************************************************************************/
274 bool patcher_aconst(patchref_t *pr)
277 constant_classref *cr;
280 /* get stuff from the stack */
283 cr = (constant_classref *) pr->ref;
285 /* get the classinfo */
287 if (!(c = resolve_classref_eager(cr)))
290 PATCH_BACK_ORIGINAL_MCODE;
292 /* if we show disassembly, we have to skip the nop's */
295 ra = ra + PATCHER_CALL_SIZE;
297 /* patch the classinfo pointer */
299 *((ptrint *) (ra + 1)) = (ptrint) c;
305 /* patcher_builtin_multianewarray **********************************************
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)
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
318 *******************************************************************************/
320 bool patcher_builtin_multianewarray(patchref_t *pr)
323 constant_classref *cr;
326 /* get stuff from the stack */
329 cr = (constant_classref *) pr->ref;
331 /* get the classinfo */
333 if (!(c = resolve_classref_eager(cr)))
336 PATCH_BACK_ORIGINAL_MCODE;
338 /* if we show disassembly, we have to skip the nop's */
341 ra = ra + PATCHER_CALL_SIZE;
343 /* patch the classinfo pointer */
345 *((ptrint *) (ra + 7 + 4)) = (ptrint) c;
351 /* patcher_builtin_arraycheckcast **********************************************
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
360 *******************************************************************************/
362 bool patcher_builtin_arraycheckcast(patchref_t *pr)
365 constant_classref *cr;
368 /* get stuff from the stack */
371 cr = (constant_classref *) pr->ref;
373 /* get the classinfo */
375 if (!(c = resolve_classref_eager(cr)))
378 PATCH_BACK_ORIGINAL_MCODE;
380 /* if we show disassembly, we have to skip the nop's */
383 ra = ra + PATCHER_CALL_SIZE;
385 /* patch the classinfo pointer */
387 *((ptrint *) (ra + 4)) = (ptrint) c;
389 /* patch new function address */
391 *((ptrint *) (ra + 8 + 1)) = (ptrint) BUILTIN_arraycheckcast;
397 /* patcher_invokestatic_special ************************************************
401 <patched call position>
402 b9 00 00 00 00 mov $0x00000000,%ecx
405 *******************************************************************************/
407 bool patcher_invokestatic_special(patchref_t *pr)
410 unresolved_method *um;
413 /* get stuff from the stack */
416 um = (unresolved_method *) pr->ref;
418 /* get the fieldinfo */
420 if (!(m = resolve_method_eager(um)))
423 PATCH_BACK_ORIGINAL_MCODE;
425 /* if we show disassembly, we have to skip the nop's */
428 ra = ra + PATCHER_CALL_SIZE;
430 /* patch stubroutine */
432 *((ptrint *) (ra + 1)) = (ptrint) m->stubroutine;
438 /* patcher_invokevirtual *******************************************************
442 <patched call position>
443 8b 08 mov (%eax),%ecx
444 8b 81 00 00 00 00 mov 0x00000000(%ecx),%eax
447 *******************************************************************************/
449 bool patcher_invokevirtual(patchref_t *pr)
452 unresolved_method *um;
455 /* get stuff from the stack */
458 um = (unresolved_method *) pr->ref;
460 /* get the fieldinfo */
462 if (!(m = resolve_method_eager(um)))
465 PATCH_BACK_ORIGINAL_MCODE;
467 /* if we show disassembly, we have to skip the nop's */
470 ra = ra + PATCHER_CALL_SIZE;
472 /* patch vftbl index */
474 *((s4 *) (ra + 2 + 2)) = (s4) (OFFSET(vftbl_t, table[0]) +
475 sizeof(methodptr) * m->vftblindex);
481 /* patcher_invokeinterface *****************************************************
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
491 *******************************************************************************/
493 bool patcher_invokeinterface(patchref_t *pr)
496 unresolved_method *um;
499 /* get stuff from the stack */
502 um = (unresolved_method *) pr->ref;
504 /* get the fieldinfo */
506 if (!(m = resolve_method_eager(um)))
509 PATCH_BACK_ORIGINAL_MCODE;
511 /* if we show disassembly, we have to skip the nop's */
514 ra = ra + PATCHER_CALL_SIZE;
516 /* patch interfacetable index */
518 *((s4 *) (ra + 2 + 2)) = (s4) (OFFSET(vftbl_t, interfacetable[0]) -
519 sizeof(methodptr) * m->class->index);
521 /* patch method offset */
523 *((s4 *) (ra + 2 + 6 + 2)) =
524 (s4) (sizeof(methodptr) * (m - m->class->methods));
530 /* patcher_checkcast_instanceof_flags ******************************************
534 <patched call position>
535 b9 00 00 00 00 mov $0x00000000,%ecx
537 *******************************************************************************/
539 bool patcher_checkcast_instanceof_flags(patchref_t *pr)
542 constant_classref *cr;
545 /* get stuff from the stack */
548 cr = (constant_classref *) pr->ref;
550 /* get the fieldinfo */
552 if (!(c = resolve_classref_eager(cr)))
555 PATCH_BACK_ORIGINAL_MCODE;
557 /* if we show disassembly, we have to skip the nop's */
560 ra = ra + PATCHER_CALL_SIZE;
562 /* patch class flags */
564 *((s4 *) (ra + 1)) = (s4) c->flags;
570 /* patcher_checkcast_interface *************************************************
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
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
582 *******************************************************************************/
584 bool patcher_checkcast_interface(patchref_t *pr)
587 constant_classref *cr;
590 /* get stuff from the stack */
593 cr = (constant_classref *) pr->ref;
595 /* get the fieldinfo */
597 if (!(c = resolve_classref_eager(cr)))
600 PATCH_BACK_ORIGINAL_MCODE;
602 /* if we show disassembly, we have to skip the nop's */
605 ra = ra + PATCHER_CALL_SIZE;
607 /* patch super class index */
609 *((s4 *) (ra + 6 + 2)) = (s4) c->index;
611 *((s4 *) (ra + 6 + 6 + 2 + 6 + 6 + 2)) =
612 (s4) (OFFSET(vftbl_t, interfacetable[0]) -
613 c->index * sizeof(methodptr*));
619 /* patcher_instanceof_interface ************************************************
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
627 0f 8e 13 00 00 00 jle 0x00000000
628 8b 91 00 00 00 00 mov 0x00000000(%ecx),%edx
630 *******************************************************************************/
632 bool patcher_instanceof_interface(patchref_t *pr)
635 constant_classref *cr;
638 /* get stuff from the stack */
641 cr = (constant_classref *) pr->ref;
643 /* get the fieldinfo */
645 if (!(c = resolve_classref_eager(cr)))
648 PATCH_BACK_ORIGINAL_MCODE;
650 /* if we show disassembly, we have to skip the nop's */
653 ra = ra + PATCHER_CALL_SIZE;
655 /* patch super class index */
657 *((s4 *) (ra + 6 + 2)) = (s4) c->index;
659 *((s4 *) (ra + 6 + 6 + 2 + 6 + 2)) =
660 (s4) (OFFSET(vftbl_t, interfacetable[0]) -
661 c->index * sizeof(methodptr*));
667 /* patcher_checkcast_class *****************************************************
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
676 ba 00 00 00 00 mov $0x00000000,%edx
678 *******************************************************************************/
680 bool patcher_checkcast_class(patchref_t *pr)
683 constant_classref *cr;
686 /* get stuff from the stack */
689 cr = (constant_classref *) pr->ref;
691 /* get the fieldinfo */
693 if (!(c = resolve_classref_eager(cr)))
696 PATCH_BACK_ORIGINAL_MCODE;
698 /* if we show disassembly, we have to skip the nop's */
701 ra = ra + PATCHER_CALL_SIZE;
703 /* patch super class' vftbl */
705 *((ptrint *) (ra + 1)) = (ptrint) c->vftbl;
706 *((ptrint *) (ra + 5 + 6 + 6 + 2 + 1)) = (ptrint) c->vftbl;
712 /* patcher_instanceof_class ****************************************************
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
722 *******************************************************************************/
724 bool patcher_instanceof_class(patchref_t *pr)
727 constant_classref *cr;
730 /* get stuff from the stack */
733 cr = (constant_classref *) pr->ref;
735 /* get the fieldinfo */
737 if (!(c = resolve_classref_eager(cr)))
740 PATCH_BACK_ORIGINAL_MCODE;
742 /* if we show disassembly, we have to skip the nop's */
745 ra = ra + PATCHER_CALL_SIZE;
747 /* patch super class' vftbl */
749 *((ptrint *) (ra + 1)) = (ptrint) c->vftbl;
755 /* patcher_resolve_native_function *********************************************
757 Is used in native stub.
761 <patched call position>
762 c7 44 24 04 28 90 01 40 movl $0x40019028,0x4(%esp)
764 *******************************************************************************/
766 bool patcher_resolve_native_function(patchref_t *pr)
772 /* get stuff from the stack */
775 m = (methodinfo *) pr->ref;
777 /* resolve native function */
779 if (!(f = native_resolve_function(m)))
782 PATCH_BACK_ORIGINAL_MCODE;
784 /* if we show disassembly, we have to skip the nop's */
787 ra = ra + PATCHER_CALL_SIZE;
789 /* patch native function pointer */
791 *((ptrint *) (ra + 4)) = (ptrint) f;
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 * ---------------------------------------------------------------------
804 * indent-tabs-mode: t
808 * vim:noexpandtab:sw=4:ts=4: