d4cc235ead539a31a803eb94e46c261ff3c7e6e5
[cacao.git] / src / vm / jit / x86_64 / patcher.c
1 /* src/vm/jit/x86_64/patcher.c - x86_64 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/x86_64/codegen.h"
33
34 #include "mm/memory.h"
35
36 #include "native/native.h"
37
38 #include "vm/builtin.h"
39 #include "vm/initialize.h"
40
41 #include "vm/jit/patcher-common.h"
42
43 #include "vmcore/class.h"
44 #include "vmcore/field.h"
45 #include "vmcore/options.h"
46 #include "vmcore/references.h"
47 #include "vm/resolve.h"
48
49
50 #define PATCH_BACK_ORIGINAL_MCODE \
51     do { \
52         *((uint16_t *) pr->mpc) = (uint16_t) pr->mcode; \
53     } while (0)
54
55
56 /* patcher_patch_code **********************************************************
57
58    Just patches back the original machine code.
59
60 *******************************************************************************/
61
62 void patcher_patch_code(patchref_t *pr)
63 {
64         PATCH_BACK_ORIGINAL_MCODE;
65 }
66
67
68 /* patcher_resolve_classref_to_classinfo ***************************************
69
70    ACONST:
71
72    <patched call position>
73    48 bf a0 f0 92 00 00 00 00 00    mov    $0x92f0a0,%rdi
74
75    MULTIANEWARRAY:
76
77    <patched call position>
78    48 be 30 40 b2 00 00 00 00 00    mov    $0xb24030,%rsi
79    48 89 e2                         mov    %rsp,%rdx
80    48 b8 7c 96 4b 00 00 00 00 00    mov    $0x4b967c,%rax
81    48 ff d0                         callq  *%rax
82
83    ARRAYCHECKCAST:
84
85    <patched call position>
86    48 be b8 3f b2 00 00 00 00 00    mov    $0xb23fb8,%rsi
87    48 b8 00 00 00 00 00 00 00 00    mov    $0x0,%rax
88    48 ff d0                         callq  *%rax
89
90 *******************************************************************************/
91
92 bool patcher_resolve_classref_to_classinfo(patchref_t *pr)
93 {
94         constant_classref *cr;
95         intptr_t          *datap;
96         classinfo         *c;
97
98         cr    = (constant_classref *) pr->ref;
99         datap = (intptr_t *)          pr->datap;
100
101         /* get the classinfo */
102
103         if (!(c = resolve_classref_eager(cr)))
104                 return false;
105
106         PATCH_BACK_ORIGINAL_MCODE;
107
108         /* patch the classinfo pointer */
109
110         *datap = (intptr_t) c;
111
112         return true;
113 }
114
115
116 /* patcher_resolve_classref_to_vftbl *******************************************
117
118    CHECKCAST (class):
119    INSTANCEOF (class):
120
121    <patched call position>
122
123 *******************************************************************************/
124
125 bool patcher_resolve_classref_to_vftbl(patchref_t *pr)
126 {
127         constant_classref *cr;
128         intptr_t          *datap;
129         classinfo         *c;
130
131         /* get stuff from the stack */
132
133         cr    = (constant_classref *) pr->ref;
134         datap = (intptr_t *)          pr->datap;
135
136         /* get the fieldinfo */
137
138         if (!(c = resolve_classref_eager(cr)))
139                 return false;
140
141         PATCH_BACK_ORIGINAL_MCODE;
142
143         /* patch super class' vftbl */
144
145         *datap = (intptr_t) c->vftbl;
146
147         return true;
148 }
149
150
151 /* patcher_resolve_classref_to_flags *******************************************
152
153    CHECKCAST/INSTANCEOF:
154
155    <patched call position>
156
157 *******************************************************************************/
158
159 bool patcher_resolve_classref_to_flags(patchref_t *pr)
160 {
161         constant_classref *cr;
162         int32_t           *datap;
163         classinfo         *c;
164         uint8_t           *ra;
165
166         cr    = (constant_classref *) pr->ref;
167         datap = (int32_t *)           pr->datap;
168         ra    = (uint8_t *)           pr->mpc;
169
170         /* get the fieldinfo */
171
172         if (!(c = resolve_classref_eager(cr)))
173                 return false;
174
175         PATCH_BACK_ORIGINAL_MCODE;
176
177         /* if we show disassembly, we have to skip the nop's */
178
179         if (opt_shownops)
180                 ra = ra + PATCHER_CALL_SIZE;
181
182         /* patch class flags */
183
184 /*      *datap = c->flags; */
185         *((int32_t *) (ra + 2)) = c->flags;
186
187         return true;
188 }
189
190
191 /* patcher_get_putstatic *******************************************************
192
193    Machine code:
194
195    <patched call position>
196    4d 8b 15 86 fe ff ff             mov    -378(%rip),%r10
197    49 8b 32                         mov    (%r10),%rsi
198
199 *******************************************************************************/
200
201 bool patcher_get_putstatic(patchref_t *pr)
202 {
203         unresolved_field *uf;
204         intptr_t         *datap;
205         fieldinfo        *fi;
206
207         uf    = (unresolved_field *) pr->ref;
208         datap = (intptr_t *)         pr->datap;
209
210         /* get the fieldinfo */
211
212         if (!(fi = resolve_field_eager(uf)))
213                 return false;
214
215         /* check if the field's class is initialized */
216
217         if (!(fi->clazz->state & CLASS_INITIALIZED))
218                 if (!initialize_class(fi->clazz))
219                         return false;
220
221         PATCH_BACK_ORIGINAL_MCODE;
222
223         /* patch the field value's address */
224
225         *datap = (intptr_t) fi->value;
226
227         return true;
228 }
229
230
231 /* patcher_get_putfield ********************************************************
232
233    Machine code:
234
235    <patched call position>
236    45 8b 8f 00 00 00 00             mov    0x0(%r15),%r9d
237
238 *******************************************************************************/
239
240 bool patcher_get_putfield(patchref_t *pr)
241 {
242         uint8_t          *ra;
243         unresolved_field *uf;
244         fieldinfo        *fi;
245         uint8_t           byte;
246
247         ra = (uint8_t *)          pr->mpc;
248         uf = (unresolved_field *) pr->ref;
249
250         /* get the fieldinfo */
251
252         if (!(fi = resolve_field_eager(uf)))
253                 return false;
254
255         PATCH_BACK_ORIGINAL_MCODE;
256
257         /* if we show disassembly, we have to skip the nop's */
258
259         if (opt_shownops)
260                 ra = ra + PATCHER_CALL_SIZE;
261
262         /* Patch the field's offset: we check for the field type, because
263            the instructions have different lengths. */
264
265         if (IS_INT_LNG_TYPE(fi->type)) {
266                 /* Check for special case: %rsp or %r12 as base register. */
267
268                 byte = *(ra + 3);
269
270                 if (byte == 0x24)
271                         *((int32_t *) (ra + 4)) = fi->offset;
272                 else
273                         *((int32_t *) (ra + 3)) = fi->offset;
274         }
275         else {
276                 /* Check for special case: %rsp or %r12 as base register. */
277
278                 byte = *(ra + 5);
279
280                 if (byte == 0x24)
281                         *((int32_t *) (ra + 6)) = fi->offset;
282                 else
283                         *((int32_t *) (ra + 5)) = fi->offset;
284         }
285
286         return true;
287 }
288
289
290 /* patcher_putfieldconst *******************************************************
291
292    Machine code:
293
294    <patched call position>
295    41 c7 85 00 00 00 00 7b 00 00 00    movl   $0x7b,0x0(%r13)
296
297 *******************************************************************************/
298
299 bool patcher_putfieldconst(patchref_t *pr)
300 {
301         uint8_t          *ra;
302         unresolved_field *uf;
303         fieldinfo        *fi;
304         uint8_t           byte;
305
306         ra = (uint8_t *)          pr->mpc;
307         uf = (unresolved_field *) pr->ref;
308
309         /* get the fieldinfo */
310
311         if (!(fi = resolve_field_eager(uf)))
312                 return false;
313
314         PATCH_BACK_ORIGINAL_MCODE;
315
316         /* if we show disassembly, we have to skip the nop's */
317
318         if (opt_shownops)
319                 ra = ra + PATCHER_CALL_SIZE;
320
321         /* patch the field's offset */
322
323         if (IS_2_WORD_TYPE(fi->type) || IS_ADR_TYPE(fi->type)) {
324                 /* handle special case when the base register is %r12 */
325
326                 byte = *(ra + 12);
327
328                 if (byte == 0x94) {
329                         *((uint32_t *) (ra + 14))      = fi->offset;
330                 }
331                 else {
332                         *((uint32_t *) (ra + 13))      = fi->offset;
333                 }
334         }
335         else {
336                 /* handle special case when the base register is %r12 */
337
338                 byte = *(ra + 2);
339
340                 if (byte == 0x84)
341                         *((uint32_t *) (ra + 4)) = fi->offset;
342                 else
343                         *((uint32_t *) (ra + 3)) = fi->offset;
344         }
345
346         return true;
347 }
348
349
350 /* patcher_invokestatic_special ************************************************
351
352    Machine code:
353
354    <patched call position>
355    49 ba 00 00 00 00 00 00 00 00    mov    $0x0,%r10
356    49 ff d2                         callq  *%r10
357
358 *******************************************************************************/
359
360 bool patcher_invokestatic_special(patchref_t *pr)
361 {
362         unresolved_method *um;
363         intptr_t          *datap;
364         methodinfo        *m;
365
366         /* get stuff from the stack */
367
368         um    = (unresolved_method *) pr->ref;
369         datap = (intptr_t *)          pr->datap;
370
371         /* get the fieldinfo */
372
373         if (!(m = resolve_method_eager(um)))
374                 return false;
375
376         PATCH_BACK_ORIGINAL_MCODE;
377
378         /* patch stubroutine */
379
380         *datap = (intptr_t) m->stubroutine;
381
382         return true;
383 }
384
385
386 /* patcher_invokevirtual *******************************************************
387
388    Machine code:
389
390    <patched call position>
391    4c 8b 17                         mov    (%rdi),%r10
392    49 8b 82 00 00 00 00             mov    0x0(%r10),%rax
393    48 ff d0                         callq  *%rax
394
395 *******************************************************************************/
396
397 bool patcher_invokevirtual(patchref_t *pr)
398 {
399         uint8_t           *ra;
400         unresolved_method *um;
401         methodinfo        *m;
402
403         ra = (uint8_t *)           pr->mpc;
404         um = (unresolved_method *) pr->ref;
405
406         /* get the methodinfo */
407
408         if (!(m = resolve_method_eager(um)))
409                 return false;
410
411         PATCH_BACK_ORIGINAL_MCODE;
412
413         /* if we show disassembly, we have to skip the nop's */
414
415         if (opt_shownops)
416                 ra = ra + PATCHER_CALL_SIZE;
417
418         /* patch vftbl index */
419
420         *((int32_t *) (ra + 3 + 3)) =
421                 (int32_t) (OFFSET(vftbl_t, table[0]) +
422                                    sizeof(methodptr) * m->vftblindex);
423
424         return true;
425 }
426
427
428 /* patcher_invokeinterface *****************************************************
429
430    Machine code:
431
432    <patched call position>
433    4c 8b 17                         mov    (%rdi),%r10
434    4d 8b 92 00 00 00 00             mov    0x0(%r10),%r10
435    49 8b 82 00 00 00 00             mov    0x0(%r10),%rax
436    48 ff d0                         callq  *%rax
437
438 *******************************************************************************/
439
440 bool patcher_invokeinterface(patchref_t *pr)
441 {
442         uint8_t           *ra;
443         unresolved_method *um;
444         methodinfo        *m;
445
446         /* get stuff from the stack */
447
448         ra = (uint8_t *)           pr->mpc;
449         um = (unresolved_method *) pr->ref;
450
451         /* get the fieldinfo */
452
453         if (!(m = resolve_method_eager(um)))
454                 return false;
455
456         PATCH_BACK_ORIGINAL_MCODE;
457
458         /* if we show disassembly, we have to skip the nop's */
459
460         if (opt_shownops)
461                 ra = ra + PATCHER_CALL_SIZE;
462
463         /* patch interfacetable index */
464
465         *((int32_t *) (ra + 3 + 3)) =
466                 (int32_t) (OFFSET(vftbl_t, interfacetable[0]) -
467                                    sizeof(methodptr) * m->clazz->index);
468
469         /* patch method offset */
470
471         *((int32_t *) (ra + 3 + 7 + 3)) =
472                 (int32_t) (sizeof(methodptr) * (m - m->clazz->methods));
473
474         return true;
475 }
476
477
478 /* patcher_checkcast_interface *************************************************
479
480    Machine code:
481
482    <patched call position>
483    45 8b 9a 1c 00 00 00             mov    0x1c(%r10),%r11d
484    41 81 fb 00 00 00 00             cmp    $0x0,%r11d
485    0f 8f 08 00 00 00                jg     0x00002aaaaae511d5
486    48 8b 0c 25 03 00 00 00          mov    0x3,%rcx
487    4d 8b 9a 00 00 00 00             mov    0x0(%r10),%r11
488
489 *******************************************************************************/
490
491 bool patcher_checkcast_interface(patchref_t *pr)
492 {
493         uint8_t           *ra;
494         constant_classref *cr;
495         classinfo         *c;
496
497         ra = (uint8_t *)           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         /* if we show disassembly, we have to skip the nop's */
508
509         if (opt_shownops)
510                 ra = ra + PATCHER_CALL_SIZE;
511
512         /* patch super class index */
513
514         *((int32_t *) (ra + 7 + 3)) = c->index;
515
516         *((int32_t *) (ra + 7 + 7 + 6 + 8 + 3)) =
517                 (int32_t) (OFFSET(vftbl_t, interfacetable[0]) -
518                                    c->index * sizeof(methodptr*));
519
520         return true;
521 }
522
523
524 /* patcher_instanceof_interface ************************************************
525
526    Machine code:
527
528    <patched call position>
529    45 8b 9a 1c 00 00 00             mov    0x1c(%r10),%r11d
530    41 81 fb 00 00 00 00             cmp    $0x0,%r11d
531    0f 8e 94 04 00 00                jle    0x00002aaaaab018f8
532    4d 8b 9a 00 00 00 00             mov    0x0(%r10),%r11
533
534 *******************************************************************************/
535
536 bool patcher_instanceof_interface(patchref_t *pr)
537 {
538         uint8_t           *ra;
539         constant_classref *cr;
540         classinfo         *c;
541
542         ra = (uint8_t *)           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 super class index */
558
559         *((int32_t *) (ra + 7 + 3)) = c->index;
560
561         *((int32_t *) (ra + 7 + 7 + 6 + 3)) =
562                 (int32_t) (OFFSET(vftbl_t, interfacetable[0]) -
563                                    c->index * sizeof(methodptr*));
564
565         return true;
566 }
567
568
569 /*
570  * These are local overrides for various environment variables in Emacs.
571  * Please do not remove this and leave it at the end of the file, where
572  * Emacs will automagically detect them.
573  * ---------------------------------------------------------------------
574  * Local variables:
575  * mode: c
576  * indent-tabs-mode: t
577  * c-basic-offset: 4
578  * tab-width: 4
579  * End:
580  * vim:noexpandtab:sw=4:ts=4:
581  */