976cdcdac93716423d31ed8942d83c7986c9e9b7
[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 #include "vm/jit/x86_64/md.h"
34
35 #include "mm/memory.h"
36
37 #include "native/native.h"
38
39 #include "vm/builtin.h"
40 #include "vm/class.h"
41 #include "vm/field.h"
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.h"
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
61 void patcher_patch_code(patchref_t *pr)
62 {
63         *((uint16_t*) pr->mpc) = (uint16_t) pr->mcode;
64         md_icacheflush((void*) pr->mpc, PATCHER_CALL_SIZE);
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    = (constant_classref*) pr->ref;
95         uintptr_t*         datap = (uintptr_t*)         pr->datap;
96
97         // Resolve the class.
98         classinfo* c = resolve_classref_eager(cr);
99
100         if (c == NULL)
101                 return false;
102
103         // Patch the class.
104         *datap = (uintptr_t) c;
105
106         // Synchronize data cache.
107         md_dcacheflush(pr->datap, SIZEOF_VOID_P);
108
109         // Patch back the original code.
110         patcher_patch_code(pr);
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    = (constant_classref*) pr->ref;
128         uintptr_t*         datap = (uintptr_t*)         pr->datap;
129
130         // Resolve the field.
131         classinfo* c = resolve_classref_eager(cr);
132
133         if (c == NULL)
134                 return false;
135
136         // Patch super class' vftbl.
137         *datap = (uintptr_t) c->vftbl;
138
139         // Synchronize data cache.
140         md_dcacheflush(pr->datap, SIZEOF_VOID_P);
141
142         // Patch back the original code.
143         patcher_patch_code(pr);
144
145         return true;
146 }
147
148
149 /* patcher_resolve_classref_to_flags *******************************************
150
151    CHECKCAST/INSTANCEOF:
152
153    <patched call position>
154
155 *******************************************************************************/
156
157 bool patcher_resolve_classref_to_flags(patchref_t *pr)
158 {
159         constant_classref* cr    = (constant_classref*) pr->ref;
160 /*      int32_t*           datap = (int32_t*)           pr->datap; */
161         uint8_t*           ra    = (uint8_t*)           pr->mpc;
162
163         // Resolve the field.
164         classinfo* c = resolve_classref_eager(cr);
165
166         if (c == NULL)
167                 return false;
168
169         // Patch class flags.
170 /*      *datap = c->flags; */
171         *((int32_t*) (ra + 2)) = c->flags;
172
173         // Synchronize data cache.
174 /*      md_dcacheflush(datap, sizeof(int32_t)); */
175         md_icacheflush(ra + 2, sizeof(int32_t));
176
177         // Patch back the original code.
178         patcher_patch_code(pr);
179
180         return true;
181 }
182
183
184 /* patcher_get_putstatic *******************************************************
185
186    Machine code:
187
188    <patched call position>
189    4d 8b 15 86 fe ff ff             mov    -378(%rip),%r10
190    49 8b 32                         mov    (%r10),%rsi
191
192 *******************************************************************************/
193
194 bool patcher_get_putstatic(patchref_t *pr)
195 {
196         unresolved_field* uf    = (unresolved_field*) pr->ref;
197         uintptr_t*        datap = (uintptr_t*)        pr->datap;
198
199         // Resolve the field.
200         fieldinfo* fi = resolve_field_eager(uf);
201
202         if (fi == NULL)
203                 return false;
204
205         // Check if the field's class is initialized/
206         if (!(fi->clazz->state & CLASS_INITIALIZED))
207                 if (!initialize_class(fi->clazz))
208                         return false;
209
210         // Patch the field value's address.
211         *datap = (uintptr_t) fi->value;
212
213         // Synchronize data cache.
214         md_dcacheflush(pr->datap, SIZEOF_VOID_P);
215
216         // Patch back the original code.
217         patcher_patch_code(pr);
218
219         return true;
220 }
221
222
223 /* patcher_get_putfield ********************************************************
224
225    Machine code:
226
227    <patched call position>
228    45 8b 8f 00 00 00 00             mov    0x0(%r15),%r9d
229
230 *******************************************************************************/
231
232 bool patcher_get_putfield(patchref_t *pr)
233 {
234         uint8_t*          pc = (uint8_t*)          pr->mpc;
235         unresolved_field* uf = (unresolved_field*) pr->ref;
236
237         // Resolve the field.
238         fieldinfo* fi = resolve_field_eager(uf);
239
240         if (fi == NULL)
241                 return false;
242
243         // Patch the field's offset: we check for the field type, because
244         // the instructions have different lengths.
245         if (IS_INT_LNG_TYPE(fi->type)) {
246                 // Check for special case: %rsp or %r12 as base register.
247                 if (pc[3] == 0x24)
248                         *((int32_t*) (pc + 4)) = fi->offset;
249                 else
250                         *((int32_t*) (pc + 3)) = fi->offset;
251         }
252         else {
253                 // Check for special case: %rsp or %r12 as base register.
254                 if (pc[5] == 0x24)
255                         *((int32_t*) (pc + 6)) = fi->offset;
256                 else
257                         *((int32_t*) (pc + 5)) = fi->offset;
258         }
259
260         // Synchronize instruction cache.
261         md_icacheflush(pc, 6 + sizeof(int32_t));
262
263         // Patch back the original code.
264         patcher_patch_code(pr);
265
266         return true;
267 }
268
269
270 /* patcher_putfieldconst *******************************************************
271
272    Machine code:
273
274    <patched call position>
275    41 c7 85 00 00 00 00 7b 00 00 00    movl   $0x7b,0x0(%r13)
276
277 *******************************************************************************/
278
279 bool patcher_putfieldconst(patchref_t *pr)
280 {
281         uint8_t*          pc = (uint8_t*)          pr->mpc;
282         unresolved_field* uf = (unresolved_field*) pr->ref;
283
284         // Resolve the field.
285         fieldinfo* fi = resolve_field_eager(uf);
286
287         if (fi == NULL)
288                 return false;
289
290         // Patch the field's offset.
291         if (IS_2_WORD_TYPE(fi->type) || IS_ADR_TYPE(fi->type)) {
292                 // Handle special case when the base register is %r12.
293                 if (pc[12] == 0x94)
294                         *((uint32_t*) (pc + 14)) = fi->offset;
295                 else
296                         *((uint32_t*) (pc + 13)) = fi->offset;
297         }
298         else {
299                 // Handle special case when the base register is %r12.
300                 if (pc[2] == 0x84)
301                         *((uint32_t*) (pc + 4)) = fi->offset;
302                 else
303                         *((uint32_t*) (pc + 3)) = fi->offset;
304         }
305
306         // Synchronize instruction cache.
307         md_icacheflush(pc, 14 + sizeof(int32_t));
308
309         // Patch back the original code.
310         patcher_patch_code(pr);
311
312         return true;
313 }
314
315
316 /* patcher_invokestatic_special ************************************************
317
318    Machine code:
319
320    <patched call position>
321    49 ba 00 00 00 00 00 00 00 00    mov    $0x0,%r10
322    49 ff d2                         callq  *%r10
323
324 *******************************************************************************/
325
326 bool patcher_invokestatic_special(patchref_t *pr)
327 {
328         unresolved_method* um    = (unresolved_method*) pr->ref;
329         uintptr_t*         datap = (uintptr_t*)         pr->datap;
330
331         // Resolve the method.
332         methodinfo* m = resolve_method_eager(um);
333
334         if (m == NULL)
335                 return false;
336
337         // Patch stubroutine.
338         *datap = (uintptr_t) m->stubroutine;
339
340         // Synchronize data cache.
341         md_dcacheflush(pr->datap, SIZEOF_VOID_P);
342
343         // Patch back the original code.
344         patcher_patch_code(pr);
345
346         return true;
347 }
348
349
350 /* patcher_invokevirtual *******************************************************
351
352    Machine code:
353
354    <patched call position>
355    4c 8b 17                         mov    (%rdi),%r10
356    49 8b 82 00 00 00 00             mov    0x0(%r10),%rax
357    48 ff d0                         callq  *%rax
358
359 *******************************************************************************/
360
361 bool patcher_invokevirtual(patchref_t *pr)
362 {
363         uint8_t*           pc = (uint8_t*)           pr->mpc;
364         unresolved_method* um = (unresolved_method*) pr->ref;
365
366         // Resovlve the method.
367         methodinfo* m = resolve_method_eager(um);
368
369         if (m == NULL)
370                 return false;
371
372         // Patch vftbl index.
373         *((int32_t*) (pc + 3 + 3)) = (int32_t) (OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * m->vftblindex);
374
375         // Synchronize instruction cache.
376         md_icacheflush(pc + 3 + 3, SIZEOF_VOID_P);
377
378         // Patch back the original code.
379         patcher_patch_code(pr);
380
381         return true;
382 }
383
384
385 /* patcher_invokeinterface *****************************************************
386
387    Machine code:
388
389    <patched call position>
390    4c 8b 17                         mov    (%rdi),%r10
391    4d 8b 92 00 00 00 00             mov    0x0(%r10),%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_invokeinterface(patchref_t *pr)
398 {
399         uint8_t*           pc = (uint8_t*)           pr->mpc;
400         unresolved_method* um = (unresolved_method*) pr->ref;
401
402         // Resolve the method.
403         methodinfo* m = resolve_method_eager(um);
404
405         if (m == NULL)
406                 return false;
407
408         // Patch interfacetable index.
409         *((int32_t*) (pc + 3 + 3)) = (int32_t) (OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr) * m->clazz->index);
410
411         // Patch method offset.
412         *((int32_t*) (pc + 3 + 7 + 3)) = (int32_t) (sizeof(methodptr) * (m - m->clazz->methods));
413
414         // Synchronize instruction cache.
415         md_icacheflush(pc + 3 + 3, SIZEOF_VOID_P + 3 + SIZEOF_VOID_P);
416
417         // Patch back the original code.
418         patcher_patch_code(pr);
419
420         return true;
421 }
422
423
424 /* patcher_checkcast_interface *************************************************
425
426    Machine code:
427
428    <patched call position>
429    45 8b 9a 1c 00 00 00             mov    0x1c(%r10),%r11d
430    41 81 fb 00 00 00 00             cmp    $0x0,%r11d
431    0f 8f 08 00 00 00                jg     0x00002aaaaae511d5
432    48 8b 0c 25 03 00 00 00          mov    0x3,%rcx
433    4d 8b 9a 00 00 00 00             mov    0x0(%r10),%r11
434
435 *******************************************************************************/
436
437 bool patcher_checkcast_interface(patchref_t *pr)
438 {
439         uint8_t*           pc = (uint8_t*)           pr->mpc;
440         constant_classref* cr = (constant_classref*) pr->ref;
441
442         // Resolve the class.
443         classinfo* c = resolve_classref_eager(cr);
444
445         if (c == NULL)
446                 return false;
447
448         // Patch super class index.
449         *((int32_t*) (pc + 7 + 3)) = c->index;
450
451         *((int32_t*) (pc + 7 + 7 + 6 + 8 + 3)) = (int32_t) (OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*));
452
453         // Synchronize instruction cache.
454         md_icacheflush(pc + 7 + 3, sizeof(int32_t) + 6 + 8 + 3 + sizeof(int32_t));
455
456         // Patch back the original code.
457         patcher_patch_code(pr);
458
459         return true;
460 }
461
462
463 /* patcher_instanceof_interface ************************************************
464
465    Machine code:
466
467    <patched call position>
468    45 8b 9a 1c 00 00 00             mov    0x1c(%r10),%r11d
469    41 81 fb 00 00 00 00             cmp    $0x0,%r11d
470    0f 8e 94 04 00 00                jle    0x00002aaaaab018f8
471    4d 8b 9a 00 00 00 00             mov    0x0(%r10),%r11
472
473 *******************************************************************************/
474
475 bool patcher_instanceof_interface(patchref_t *pr)
476 {
477         uint8_t*           pc = (uint8_t*)           pr->mpc;
478         constant_classref* cr = (constant_classref*) pr->ref;
479
480         // Resolve the class.
481         classinfo* c = resolve_classref_eager(cr);
482
483         if (c == NULL)
484                 return false;
485
486         // Patch super class index.
487         *((int32_t*) (pc + 7 + 3)) = c->index;
488
489         *((int32_t*) (pc + 7 + 7 + 6 + 3)) = (int32_t) (OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*));
490
491         // Synchronize instruction cache.
492         md_icacheflush(pc + 7 + 3, sizeof(int32_t) + 6 + 3 + sizeof(int32_t));
493
494         // Patch back the original code.
495         patcher_patch_code(pr);
496
497         return true;
498 }
499
500
501 /*
502  * These are local overrides for various environment variables in Emacs.
503  * Please do not remove this and leave it at the end of the file, where
504  * Emacs will automagically detect them.
505  * ---------------------------------------------------------------------
506  * Local variables:
507  * mode: c
508  * indent-tabs-mode: t
509  * c-basic-offset: 4
510  * tab-width: 4
511  * End:
512  * vim:noexpandtab:sw=4:ts=4:
513  */