* Updated to jitcache-arm-x86 branch d4f6023b26c5+d1b5b1c106ac
[cacao.git] / src / vm / jit / arm / patcher.c
1 /* src/vm/jit/arm/patcher.c - ARM code patching functions
2
3    Copyright (C) 1996-2005, 2006, 2007, 2008
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5    Copyright (C) 2008 Theobroma Systems Ltd.
6
7    This file is part of CACAO.
8
9    This program is free software; you can redistribute it and/or
10    modify it under the terms of the GNU General Public License as
11    published by the Free Software Foundation; either version 2, or (at
12    your option) any later version.
13
14    This program is distributed in the hope that it will be useful, but
15    WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17    General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22    02110-1301, USA.
23
24 */
25
26
27 #include "config.h"
28
29 #include <assert.h>
30 #include <stdint.h>
31
32 #include "vm/types.h"
33
34 #include "vm/jit/arm/md.h"
35
36 #include "mm/memory.h"
37
38 #include "native/native.hpp"
39
40 #include "vm/jit/builtin.hpp"
41 #include "vm/class.h"
42 #include "vm/field.hpp"
43 #include "vm/initialize.h"
44 #include "vm/options.h"
45 #include "vm/references.h"
46 #include "vm/resolve.h"
47
48 #include "vm/jit/asmpart.h"
49 #include "vm/jit/patcher-common.hpp"
50
51
52 #define gen_resolveload(inst,offset) \
53         assert((offset) >= -0x0fff && (offset) <= 0x0fff); \
54         assert(!((inst) & 0x0fff)); \
55         if ((offset) <  0) { \
56                 (inst) = ((inst) & 0xff7ff000) | ((-(offset)) & 0x0fff); \
57                 /*(inst) &= ~(1 << 23);*/ \
58         } else { \
59                 (inst) = ((inst) & 0xfffff000) | ((offset) & 0x0fff); \
60                 /*(inst) |= (1 << 23);*/ \
61         }
62
63 /* This is the same as gen_resolveload but does not check whether the opcode
64  * is 'clean' (= current offset is zero).
65  */
66 #define gen_resolveload_unchecked(inst,offset) \
67         assert((offset) >= -0x0fff && (offset) <= 0x0fff); \
68         if ((offset) <  0) { \
69                 (inst) = ((inst) & 0xff7ff000) | ((-(offset)) & 0x0fff); \
70                 /*(inst) &= ~(1 << 23);*/ \
71         } else { \
72                 (inst) = ((inst) & 0xfffff000) | ((offset) & 0x0fff); \
73                 /*(inst) |= (1 << 23);*/ \
74         }
75
76 /* patch_md ********************************************************************
77
78    Patch back address in a machine dependent way 
79
80 *******************************************************************************/
81 void patch_md(s4 md_patch, ptrint dest, void* ref)
82 {
83         gen_resolveload_unchecked(*((s4 *) dest), (s4) ref);
84 }
85
86 /* patcher_patch_code **********************************************************
87
88    Just patches back the original machine code.
89
90 *******************************************************************************/
91
92 void patcher_patch_code(patchref_t *pr)
93 {
94     *((uint32_t*) pr->mpc) = (uint32_t) pr->mcode;
95     md_icacheflush((void*) pr->mpc, 1 * 4);
96 }
97
98
99 /**
100  * Check if the trap instruction at the given PC is valid.
101  *
102  * @param pc Program counter.
103  *
104  * @return true if valid, false otherwise.
105  */
106 bool patcher_is_valid_trap_instruction_at(void* pc)
107 {
108         uint32_t mcode = *((uint32_t*) pc);
109
110         // Check for the undefined instruction we use.
111         if ((mcode & 0x0ff000f0) != 0x07f000f0) {
112                 return false;
113         }
114
115         return true;
116 }
117
118
119 /* patcher_get_putstatic *******************************************************
120
121    Machine code:
122
123    <patched call position>
124    e51c103c    ldr   r1, [ip, #-60]
125
126 *******************************************************************************/
127
128 bool patcher_get_putstatic(patchref_t *pr)
129 {
130         unresolved_field* uf    = (unresolved_field *) pr->ref;
131         uintptr_t*        datap = (uintptr_t*)         pr->datap;
132
133         // Resolve the field.
134         fieldinfo* fi = resolve_field_eager(uf);
135
136         if (fi == NULL)
137                 return false;
138
139         // Check if the field's class is initialized.
140         if (!(fi->clazz->state & CLASS_INITIALIZED))
141                 if (!initialize_class(fi->clazz))
142                         return false;
143
144         // Patch the field value's address.
145         *datap = (uintptr_t) fi->value;
146
147         // Patch back the original code.
148         patcher_patch_code(pr);
149
150         return true;
151 }
152
153
154 /* patcher_get_putfield ********************************************************
155
156    Machine code:
157
158    <patched call position>
159    e58a8000    str   r8, [sl, #__]
160
161 *******************************************************************************/
162
163 bool patcher_get_putfield(patchref_t *pr)
164 {
165         uint32_t*         pc = (uint32_t*)         pr->mpc;
166         unresolved_field* uf = (unresolved_field*) pr->ref;
167
168         // Resolve the field.
169         fieldinfo* fi = resolve_field_eager(uf);
170
171         if (fi == NULL)
172                 return false;
173
174         // Patch the field's offset into the instruction.
175
176         switch(fi->type) {
177         case TYPE_ADR:
178         case TYPE_INT:
179 #if defined(ENABLE_SOFTFLOAT)
180         case TYPE_FLT:
181 #endif
182                 assert(fi->offset <= 0x0fff);
183                 pr->mcode |= (fi->offset & 0x0fff);
184                 break;
185
186         case TYPE_LNG:
187 #if defined(ENABLE_SOFTFLOAT)
188         case TYPE_DBL:
189 #endif
190                 assert((fi->offset + 4) <= 0x0fff);
191                 pr->mcode |= ((fi->offset + 0) & 0x0fff);
192                 pc[1] &= 0xfffff000;
193                 pc[1] |= ((fi->offset + 4) & 0x0fff);
194                 break;
195
196 #if !defined(ENABLE_SOFTFLOAT)
197         case TYPE_FLT:
198         case TYPE_DBL:
199                 assert(fi->offset <= 0x03ff);
200                 pr->mcode |= ((fi->offset >> 2) & 0x00ff);
201                 break;
202 #endif
203         }
204
205         // Synchronize instruction cache.
206         md_icacheflush(pc, 2 * 4);
207
208         // Patch back the original code.
209         patcher_patch_code(pr);
210
211         return true;
212 }
213
214
215 /* patcher_resolve_classref_to_classinfo ***************************************
216
217    ACONST - Machine code:
218
219    <patched call postition>
220    e51cc030    ldr   r0, [ip, #-48]
221
222    MULTIANEWARRAY - Machine code:
223     
224    <patched call position>
225    e3a00002    mov   r0, #2  ; 0x2
226    e51c1064    ldr   r1, [ip, #-100]
227    e1a0200d    mov   r2, sp
228    e1a0e00f    mov   lr, pc
229    e51cf068    ldr   pc, [ip, #-104]
230
231    ARRAYCHECKCAST - Machine code:
232
233    <patched call position>
234    e51c1120    ldr   r1, [ip, #-288]
235    e1a0e00f    mov   lr, pc
236    e51cf124    ldr   pc, [ip, #-292]
237
238 *******************************************************************************/
239
240 bool patcher_resolve_classref_to_classinfo(patchref_t *pr)
241 {
242         constant_classref* cr    = (constant_classref *) pr->ref;
243         uintptr_t*         datap = (uintptr_t*)          pr->datap;
244
245         // Resolve the class.
246         classinfo* c = resolve_classref_eager(cr);
247
248         if (c == NULL)
249                 return false;
250
251         // Patch the classinfo pointer.
252         *datap = (uintptr_t) c;
253
254         // Patch back the original code.
255         patcher_patch_code(pr);
256
257         return true;
258 }
259
260
261 /* patcher_invokestatic_special ************************************************
262
263    Machine code:
264
265    <patched call position>
266    e51cc02c    ldr   ip, [ip, #-44]
267    e1a0e00f    mov   lr, pc
268    e1a0f00c    mov   pc, ip
269
270 ******************************************************************************/
271
272 bool patcher_invokestatic_special(patchref_t *pr)
273 {
274         unresolved_method* um    = (unresolved_method*) pr->ref;
275         uintptr_t*         datap = (uintptr_t*)         pr->datap;
276
277         // Reolve the method.
278         methodinfo* m = resolve_method_eager(um);
279
280         if (m == NULL)
281                 return false;
282
283         // Patch stubroutine.
284         *datap = (uintptr_t) m->stubroutine;
285
286         // Patch back the original code.
287         patcher_patch_code(pr);
288
289         return true;
290 }
291
292
293 /* patcher_invokevirtual *******************************************************
294
295    Machine code:
296
297    <patched call position>
298    e590b000    ldr   fp, [r0]
299    e59bc000    ldr   ip, [fp, #__]
300    e1a0e00f    mov   lr, pc
301    e1a0f00c    mov   pc, ip
302
303 *******************************************************************************/
304
305 bool patcher_invokevirtual(patchref_t *pr)
306 {
307         uint32_t*          pc = (uint32_t*)           pr->mpc;
308         unresolved_method* um = (unresolved_method *) pr->ref;
309
310         // Resolve the method.
311         methodinfo* m = resolve_method_eager(um);
312
313         if (m == NULL)
314                 return false;
315
316         // Patch vftbl index.
317         gen_resolveload(pc[1], (int32_t) (OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * m->vftblindex));
318
319         // Synchronize instruction cache.
320         md_icacheflush(pc + 1, 1 * 4);
321
322         // Patch back the original code.
323         patcher_patch_code(pr);
324
325         return true;
326 }
327
328
329 /* patcher_invokeinterface *****************************************************
330
331    Machine code:
332
333    <patched call position>
334    e590b000    ldr   fp, [r0]
335    e59bb000    ldr   fp, [fp, #__]
336    e59bc000    ldr   ip, [fp, #__]
337    e1a0e00f    mov   lr, pc
338    e1a0f00c    mov   pc, ip
339
340
341 *******************************************************************************/
342
343 bool patcher_invokeinterface(patchref_t *pr)
344 {
345         uint32_t*          pc = (uint32_t*)           pr->mpc;
346         unresolved_method* um = (unresolved_method *) pr->ref;
347
348         // Resolve the method.
349         methodinfo* m = resolve_method_eager(um);
350
351         if (m == NULL)
352                 return false;
353
354         // Patch interfacetable index.
355         gen_resolveload(pc[1], (int32_t) (OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr*) * m->clazz->index));
356
357         // Patch method offset.
358         gen_resolveload(pc[2], (int32_t) (sizeof(methodptr) * (m - m->clazz->methods)));
359
360         // Synchronize instruction cache.
361         md_icacheflush(pc + 1, 2 * 4);
362
363         // Patch back the original code.
364         patcher_patch_code(pr);
365
366         return true;
367 }
368
369
370 /* patcher_checkcast_instanceof_flags ******************************************
371
372    Machine code:
373
374    <patched call position>
375
376 *******************************************************************************/
377
378 bool patcher_resolve_classref_to_flags(patchref_t *pr)
379 {
380         constant_classref* cr    = (constant_classref*) pr->ref;
381         int32_t*           datap = (int32_t*)           pr->datap;
382
383         // Resolve the class.
384         classinfo* c = resolve_classref_eager(cr);
385
386         if (c == NULL)
387                 return false;
388
389         // Patch class flags.
390         *datap = (int32_t) c->flags;
391
392         // Patch back the original code.
393         patcher_patch_code(pr);
394
395         return true;
396 }
397
398
399 /* patcher_resolve_classref_to_index *******************************************
400
401    Machine code:
402
403    <patched call position>
404
405 *******************************************************************************/
406
407 bool patcher_resolve_classref_to_index(patchref_t *pr)
408 {
409         constant_classref* cr    = (constant_classref*) pr->ref;
410         int32_t*           datap = (int32_t*)           pr->datap;
411
412         // Resolve the class.
413         classinfo* c = resolve_classref_eager(cr);
414
415         if (c == NULL)
416                 return false;
417
418         // Patch super class index.
419         *datap = (int32_t) c->index;
420
421         // Patch back the original code.
422         patcher_patch_code(pr);
423
424         return true;
425 }
426
427
428 /* patcher_resolve_classref_to_vftbl *******************************************
429
430    Machine code:
431
432    <patched call position>
433
434 *******************************************************************************/
435
436 bool patcher_resolve_classref_to_vftbl(patchref_t *pr)
437 {
438         constant_classref* cr    = (constant_classref*) pr->ref;
439         uintptr_t*         datap = (uintptr_t*)         pr->datap;
440
441         // Resolve the class.
442
443         classinfo* c = resolve_classref_eager(cr);
444
445         if (c == NULL)
446                 return false;
447
448         // Patch super class' vftbl.
449         *datap = (uintptr_t) c->vftbl;
450
451         // Patch back the original code.
452         patcher_patch_code(pr);
453
454         return true;
455 }
456
457
458 /*
459  * These are local overrides for various environment variables in Emacs.
460  * Please do not remove this and leave it at the end of the file, where
461  * Emacs will automagically detect them.
462  * ---------------------------------------------------------------------
463  * Local variables:
464  * mode: c
465  * indent-tabs-mode: t
466  * c-basic-offset: 4
467  * tab-width: 4
468  * End:
469  * vim:noexpandtab:sw=4:ts=4:
470  */