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