CACAO
patcher.cpp
Go to the documentation of this file.
1 /* src/vm/jit/alpha/patcher.cpp - Alpha 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 <cassert>
29 
30 #include "vm/types.hpp"
31 
32 #include "vm/jit/aarch64/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 
47 #include "vm/jit/asmpart.hpp"
50 #include "vm/jit/methodheader.hpp"
51 
52 
53 /**
54  * Helper function to patch in the correct LOAD instruction
55  * as we have ambiguity.
56  */
57 static void patch_helper_ldr(u1 *codeptr, s4 offset, bool isint)
58 {
59  assert(offset >= -255);
60 
61  codegendata codegen;
62  codegendata *cd = &codegen; // just a 'dummy' codegendata so we can reuse emit methods
63  cd->mcodeptr = codeptr;
64  u4 code = *((s4 *) cd->mcodeptr);
65  u1 targetreg = code & 0x1f;
66  u1 basereg = (code >> 5) & 0x1f;
67  u8 oldptr = (u8) cd->mcodeptr;
68  if (isint)
69  emit_ldr_imm32(cd, targetreg, basereg, offset);
70  else
71  emit_ldr_imm(cd, targetreg, basereg, offset);
72  assert(((u8) cd->mcodeptr) - oldptr == 4);
73 }
74 
75 
76 static void patch_helper_cmp_imm(u1 *codeptr, s4 offset)
77 {
78  codegendata codegen;
79  codegendata *cd = &codegen; // just a 'dummy' codegendata so we can reuse emit methods
80  cd->mcodeptr = codeptr;
81  u4 code = *((s4 *) cd->mcodeptr);
82  u1 reg = (code >> 5) & 0x1f;
83  u8 oldptr = (u8) cd->mcodeptr;
84  if (offset >= 0)
85  emit_cmn_imm32(cd, reg, offset);
86  else
87  emit_cmp_imm32(cd, reg, -offset);
88  assert(((u8) cd->mcodeptr) - oldptr == 4);
89 }
90 
91 static void patch_helper_mov_imm(u1 *codeptr, s4 offset)
92 {
93  codegendata codegen;
94  codegendata *cd = &codegen; // just a 'dummy' codegendata so we can reuse emit methods
95  cd->mcodeptr = codeptr;
96  u4 code = *((s4 *) cd->mcodeptr);
97  u1 reg = code & 0x1f;
98  u8 oldptr = (u8) cd->mcodeptr;
99  if (offset >= 0)
100  emit_mov_imm(cd, reg, offset);
101  else
102  emit_movn_imm(cd, reg, -offset-1);
103  assert(((u8) cd->mcodeptr) - oldptr == 4);
104 }
105 
106 
107 
108 /* patcher_patch_code **********************************************************
109 
110  Just patches back the original machine code.
111 
112 *******************************************************************************/
113 
115 {
116  // Patch back original code.
117  *((uint32_t*) pr->mpc) = pr->mcode;
118 
119  // Synchronize instruction cache.
120  md_icacheflush((void*) pr->mpc, 4);
121 }
122 
123 
124 /* patcher_resolve_classref_to_classinfo ***************************************
125 
126  ACONST:
127 
128  <patched call postition>
129  a61bff80 ldq a0,-128(pv)
130 
131  MULTIANEWARRAY:
132 
133  <patched call position>
134  a63bff80 ldq a1,-128(pv)
135  47de0412 mov sp,a2
136  a77bff78 ldq pv,-136(pv)
137  6b5b4000 jsr (pv)
138 
139  ARRAYCHECKCAST:
140 
141  <patched call position>
142  a63bfe60 ldq a1,-416(pv)
143  a77bfe58 ldq pv,-424(pv)
144  6b5b4000 jsr (pv)
145 
146 *******************************************************************************/
147 
149 {
150  constant_classref *cr;
151  u1 *datap;
152  classinfo *c;
153 
154  /* get stuff from the stack */
155 
156  cr = (constant_classref *) pr->ref;
157  datap = (u1 *) pr->datap;
158 
159  /* get the classinfo */
160 
161  if (!(c = resolve_classref_eager(cr)))
162  return false;
163 
164  /* patch the classinfo pointer */
165  *((ptrint *) datap) = (ptrint) c;
166 
167  // Synchronize data cache
168  md_dcacheflush(datap, SIZEOF_VOID_P);
169 
170  // Patch back the original code.
171  patcher_patch_code(pr);
172 
173  return true;
174 }
175 
176 
177 /* patcher_resolve_classref_to_vftbl *******************************************
178 
179  CHECKCAST (class):
180  INSTANCEOF (class):
181 
182  <patched call position>
183  a7940000 ldq at,0(a4)
184  a7bbff28 ldq gp,-216(pv)
185 
186 *******************************************************************************/
187 
189 {
190  constant_classref *cr;
191  u1 *datap;
192  classinfo *c;
193 
194  /* get stuff from the stack */
195 
196  cr = (constant_classref *) pr->ref;
197  datap = (u1 *) pr->datap;
198 
199  /* get the fieldinfo */
200 
201  if (!(c = resolve_classref_eager(cr)))
202  return false;
203 
204  /* patch super class' vftbl */
205  *((ptrint *) datap) = (ptrint) c->vftbl;
206 
207  // Synchronize data cache
208  md_dcacheflush(datap, SIZEOF_VOID_P);
209 
210  // Patch back the original code.
211  patcher_patch_code(pr);
212 
213  return true;
214 }
215 
216 
217 /* patcher_resolve_classref_to_flags *******************************************
218 
219  CHECKCAST/INSTANCEOF:
220 
221  <patched call position>
222 
223 *******************************************************************************/
224 
226 {
227  constant_classref *cr;
228  u1 *datap;
229  classinfo *c;
230 
231  /* get stuff from the stack */
232 
233  cr = (constant_classref *) pr->ref;
234  datap = (u1 *) pr->datap;
235 
236  /* get the fieldinfo */
237 
238  if (!(c = resolve_classref_eager(cr)))
239  return false;
240 
241  /* patch class flags */
242  *((s4 *) datap) = (s4) c->flags;
243 
244  // Synchronize data cache
245  md_dcacheflush(datap, 4);
246 
247  // Patch back the original code.
248  patcher_patch_code(pr);
249 
250  return true;
251 }
252 
253 
254 /* patcher_get_putstatic *******************************************************
255 
256  Machine code:
257 
258  <patched call position>
259  a73bff98 ldq t11,-104(pv)
260  a2590000 ldl a2,0(t11)
261 
262 *******************************************************************************/
263 
265 {
266  unresolved_field *uf;
267  u1 *datap;
268  fieldinfo *fi;
269 
270  /* get stuff from the stack */
271 
272  uf = (unresolved_field *) pr->ref;
273  datap = (u1 *) pr->datap;
274 
275  /* get the fieldinfo */
276 
277  if (!(fi = resolve_field_eager(uf)))
278  return false;
279 
280  /* check if the field's class is initialized */
281 
282  if (!(fi->clazz->state & CLASS_INITIALIZED))
283  if (!initialize_class(fi->clazz))
284  return false;
285 
286  /* patch the field value's address */
287  *((intptr_t *) datap) = (intptr_t) fi->value;
288 
289  // Synchroinze data cache
290  md_dcacheflush(datap, SIZEOF_VOID_P);
291 
292  // Patch back the original code.
293  patcher_patch_code(pr);
294 
295  return true;
296 }
297 
298 
299 /* patcher_get_putfield ********************************************************
300 
301  Machine code:
302 
303  <patched call position>
304  a2af0020 ldl a5,32(s6)
305 
306 *******************************************************************************/
307 
309 {
310  unresolved_field *uf;
311  fieldinfo *fi;
312 
313  uf = (unresolved_field *) pr->ref;
314 
315  /* get the fieldinfo */
316 
317  if (!(fi = resolve_field_eager(uf)))
318  return false;
319 
320  /* We need some stuff for code generation */
321  codegendata codegen;
322  codegen.mcodeptr = (u1 *) &pr->mcode;
323  AsmEmitter asme(&codegen);
324  u4 code = *((s4 *) codegen.mcodeptr);
325  u1 targetreg = code & 0x1f;
326  u1 basereg = (code >> 5) & 0x1f;
327 
328  /* patch the field's offset into the instruction */
329  u1 isload = (pr->mcode >> 22) & 0x3;
330  if (isload) {
331  switch (fi->type) {
332  case TYPE_ADR:
333  asme.ald(targetreg, basereg, fi->offset);
334  break;
335  case TYPE_LNG:
336  asme.lld(targetreg, basereg, fi->offset);
337  break;
338  case TYPE_INT:
339  asme.ild(targetreg, basereg, fi->offset);
340  break;
341  case TYPE_FLT:
342  asme.fld(targetreg, basereg, fi->offset);
343  break;
344  case TYPE_DBL:
345  asme.dld(targetreg, basereg, fi->offset);
346  break;
347  default:
348  os::abort("Unsupported type in patcher_get_putfield");
349  }
350  } else {
351  switch (fi->type) {
352  case TYPE_ADR:
353  asme.ast(targetreg, basereg, fi->offset);
354  break;
355  case TYPE_LNG:
356  asme.lst(targetreg, basereg, fi->offset);
357  break;
358  case TYPE_INT:
359  asme.ist(targetreg, basereg, fi->offset);
360  break;
361  case TYPE_FLT:
362  asme.fst(targetreg, basereg, fi->offset);
363  break;
364  case TYPE_DBL:
365  asme.dst(targetreg, basereg, fi->offset);
366  break;
367  default:
368  os::abort("Unsupported type in patcher_get_putfield");
369  }
370  }
371 
372  // Synchronize instruction cache
373  md_icacheflush((void*)pr->mpc, 8);
374 
375  // Patch back the original code.
376  patcher_patch_code(pr);
377 
378  return true;
379 }
380 
381 
382 /* patcher_invokestatic_special ************************************************
383 
384  Machine code:
385 
386  <patched call position>
387  a77bffa8 ldq pv,-88(pv)
388  6b5b4000 jsr (pv)
389 
390 ******************************************************************************/
391 
393 {
394  unresolved_method *um;
395  u1 *datap;
396  methodinfo *m;
397 
398  /* get stuff from the stack */
399 
400  um = (unresolved_method *) pr->ref;
401  datap = (u1 *) pr->datap;
402 
403  /* get the fieldinfo */
404 
405  if (!(m = resolve_method_eager(um)))
406  return false;
407 
408  /* patch stubroutine */
409  *((ptrint *) datap) = (ptrint) m->stubroutine;
410 
411  // Synchronize data cache
412  md_dcacheflush(datap, SIZEOF_VOID_P);
413 
414  // Patch back the original code.
415  patcher_patch_code(pr);
416 
417  return true;
418 }
419 
420 
421 /* patcher_invokevirtual *******************************************************
422 
423  Machine code:
424 
425  <patched call position>
426  a7900000 ldr x16, [x0]
427  a77c0100 ldr x17, [x16, #patched]
428  6b5b4000 blr x17
429 
430 *******************************************************************************/
431 
432 
434 {
435  u1 *ra;
436  unresolved_method *um;
437  methodinfo *m;
438 
439  /* get stuff from the stack */
440 
441  ra = (u1 *) pr->mpc;
442  um = (unresolved_method *) pr->ref;
443 
444  /* get the fieldinfo */
445 
446  if (!(m = resolve_method_eager(um)))
447  return false;
448 
449  /* patch vftbl index */
450  s4 disp = OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * m->vftblindex;
451  patch_helper_ldr((ra + 4), disp, false);
452 
453  // Synchronize instruction cache
454  md_icacheflush(ra + 4, 4);
455 
456  // Patch back the original code.
457  patcher_patch_code(pr);
458 
459  return true;
460 }
461 
462 
463 /* patcher_invokeinterface *****************************************************
464 
465  Machine code:
466 
467  <patched call position>
468  mov x9, <interfacetable index>
469  mov x10, <method offset>
470  ldr x16, [x0, _]
471  ldr x16, [x16, x9]
472  ldr x17, [x16, x10]
473 
474 *******************************************************************************/
475 
476 
478 {
479  u1 *ra;
480  unresolved_method *um;
481  methodinfo *m;
482 
483  /* get stuff from the stack */
484 
485  ra = (u1 *) pr->mpc;
486  um = (unresolved_method *) pr->ref;
487 
488  /* get the fieldinfo */
489 
490  if (!(m = resolve_method_eager(um)))
491  return false;
492 
493  /* patch interfacetable index */
494 
495  s4 offset = OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr*) * m->clazz->index;
496  patch_helper_mov_imm((ra + 4) , offset);
497 
498  /* patch method offset */
499  offset = (s4) (sizeof(methodptr) * (m - m->clazz->methods));
500  patch_helper_mov_imm((ra + 8), offset);
501 
502  // Synchronize instruction cache
503  md_icacheflush(ra + 4, 8);
504 
505  // Patch back the original code.
506  patcher_patch_code(pr);
507 
508  return true;
509 }
510 
511 
512 /* patcher_checkcast_interface *************************************************
513 
514  Machine code:
515 
516  <patched call position>
517  ldr w11, [x10, _]
518  cmp w11, <super index to patch>
519  b.?
520  <illegal instruction for classcast ex>
521  mov x11, <second offset to patch>
522  ldr x11, [x10, x11]
523 
524 *******************************************************************************/
525 
527 {
528  u1 *ra;
529  constant_classref *cr;
530  classinfo *c;
531 
532  /* get stuff from the stack */
533 
534  ra = (u1 *) pr->mpc;
535  cr = (constant_classref *) pr->ref;
536 
537  /* get the fieldinfo */
538 
539  if (!(c = resolve_classref_eager(cr)))
540  return false;
541 
542  /* patch super class index */
543  s4 offset = (s4) (-(c->index));
544  patch_helper_cmp_imm((ra + 1 * 4), offset);
545 
546  offset = (s4) (OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*));
547  patch_helper_mov_imm((ra + 4 * 4), offset);
548 
549  // Synchronize instruction cache
550  md_icacheflush(ra + 4, 4 * 4);
551 
552  // Patch back the original code.
553  patcher_patch_code(pr);
554 
555  return true;
556 }
557 
558 
559 /* patcher_instanceof_interface ************************************************
560 
561  Machine code:
562 
563  <patched call position>
564  ldr w11, [w9, OFFSET(vftbl_t, interfacetablelength)]
565  cmp w11, <superindex to patch>
566  b.le <somewhere below>
567  mov x11, <second offset to patch>
568  ldr x9, [x9, x11]
569 
570 *******************************************************************************/
571 
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 super class index */
589 
590  s4 offset = (s4) (-(c->index));
591  patch_helper_cmp_imm((ra + 2 * 4), offset);
592 
593  offset = (OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*));
594  patch_helper_mov_imm((ra + 4 * 4), offset);
595 
596  // Synchronize instruction cache
597  md_icacheflush(ra + 2 * 4, 3 * 4);
598 
599  // Patch back the original code.
600  patcher_patch_code(pr);
601 
602  return true;
603 }
604 
605 
606 /*
607  * These are local overrides for various environment variables in Emacs.
608  * Please do not remove this and leave it at the end of the file, where
609  * Emacs will automagically detect them.
610  * ---------------------------------------------------------------------
611  * Local variables:
612  * mode: c++
613  * indent-tabs-mode: t
614  * c-basic-offset: 4
615  * tab-width: 4
616  * End:
617  * vim:noexpandtab:sw=4:ts=4:
618  */
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
#define emit_movn_imm(cd, Xd, imm)
Definition: emit-asm.hpp:144
bool patcher_invokeinterface(patchref_t *pr)
Definition: patcher.cpp:477
#define emit_cmn_imm32(cd, Wn, imm)
Definition: emit-asm.hpp:274
s4 state
Definition: class.hpp:115
static void md_dcacheflush(void *addr, int nbytes)
Definition: md.hpp:163
uint8_t u1
Definition: types.hpp:40
u1 * methodptr
Definition: global.hpp:40
static void patch_helper_ldr(u1 *codeptr, s4 offset, bool isint)
Helper function to patch in the correct LOAD instruction as we have ambiguity.
Definition: patcher.cpp:57
static void patch_helper_mov_imm(u1 *codeptr, s4 offset)
Definition: patcher.cpp:91
#define emit_ldr_imm(cd, Xt, Xn, imm)
Definition: emit-asm.hpp:219
u1 * stubroutine
Definition: method.hpp:102
s4 vftblindex
Definition: method.hpp:81
#define emit_ldr_imm32(cd, Xt, Xn, imm)
Definition: emit-asm.hpp:225
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
uint64_t u8
Definition: types.hpp:49
imm_union * value
Definition: field.hpp:67
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
static void abort()
Definition: os.hpp:196
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
s4 type
Definition: field.hpp:60
methodinfo * resolve_method_eager(unresolved_method *ref)
Definition: resolve.cpp:2236
uintptr_t datap
#define emit_mov_imm(cd, Xd, imm)
Definition: emit-asm.hpp:142
uint32_t mcode
classinfo * resolve_classref_eager(constant_classref *ref)
Definition: resolve.cpp:961
static void patch_helper_cmp_imm(u1 *codeptr, s4 offset)
Definition: patcher.cpp:76
uintptr_t ptrint
Definition: types.hpp:54
static void md_icacheflush(void *addr, int nbytes)
Definition: md.hpp:151
uintptr_t mpc
#define emit_cmp_imm32(cd, Xn, imm)
Definition: emit-asm.hpp:271
#define OFFSET(s, el)
Definition: memory.hpp:90
bool patcher_resolve_classref_to_vftbl(patchref_t *pr)
Definition: patcher.cpp:188
bool patcher_instanceof_interface(patchref_t *pr)
Definition: patcher.cpp:572