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