93432e094e5ee13cce25243c11f3f69c6696580e
[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.hpp"
37
38 #include "native/native.hpp"
39
40 #include "vm/jit/builtin.hpp"
41 #include "vm/class.hpp"
42 #include "vm/field.hpp"
43 #include "vm/initialize.hpp"
44 #include "vm/options.h"
45 #include "vm/references.h"
46 #include "vm/resolve.hpp"
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
64 /* patcher_patch_code **********************************************************
65
66    Just patches back the original machine code.
67
68 *******************************************************************************/
69
70 void patcher_patch_code(patchref_t *pr)
71 {
72     *((uint32_t*) pr->mpc) = (uint32_t) pr->mcode;
73     md_icacheflush((void*) pr->mpc, 1 * 4);
74 }
75
76
77 /**
78  * Check if the trap instruction at the given PC is valid.
79  *
80  * @param pc Program counter.
81  *
82  * @return true if valid, false otherwise.
83  */
84 bool patcher_is_valid_trap_instruction_at(void* pc)
85 {
86         uint32_t mcode = *((uint32_t*) pc);
87
88         // Check for the undefined instruction we use.
89         if ((mcode & 0x0ff000f0) != 0x07f000f0) {
90                 return false;
91         }
92
93         return true;
94 }
95
96
97 /* patcher_get_putstatic *******************************************************
98
99    Machine code:
100
101    <patched call position>
102    e51c103c    ldr   r1, [ip, #-60]
103
104 *******************************************************************************/
105
106 bool patcher_get_putstatic(patchref_t *pr)
107 {
108         unresolved_field* uf    = (unresolved_field *) pr->ref;
109         uintptr_t*        datap = (uintptr_t*)         pr->datap;
110
111         // Resolve the field.
112         fieldinfo* fi = resolve_field_eager(uf);
113
114         if (fi == NULL)
115                 return false;
116
117         // Check if the field's class is initialized.
118         if (!(fi->clazz->state & CLASS_INITIALIZED))
119                 if (!initialize_class(fi->clazz))
120                         return false;
121
122         // Patch the field value's address.
123         *datap = (uintptr_t) fi->value;
124
125         // Patch back the original code.
126         patcher_patch_code(pr);
127
128         return true;
129 }
130
131
132 /* patcher_get_putfield ********************************************************
133
134    Machine code:
135
136    <patched call position>
137    e58a8000    str   r8, [sl, #__]
138
139 *******************************************************************************/
140
141 bool patcher_get_putfield(patchref_t *pr)
142 {
143         uint32_t*         pc = (uint32_t*)         pr->mpc;
144         unresolved_field* uf = (unresolved_field*) pr->ref;
145
146         // Resolve the field.
147         fieldinfo* fi = resolve_field_eager(uf);
148
149         if (fi == NULL)
150                 return false;
151
152         // Patch the field's offset into the instruction.
153
154         switch(fi->type) {
155         case TYPE_ADR:
156         case TYPE_INT:
157 #if defined(ENABLE_SOFTFLOAT)
158         case TYPE_FLT:
159 #endif
160                 assert(fi->offset <= 0x0fff);
161                 pr->mcode |= (fi->offset & 0x0fff);
162                 break;
163
164         case TYPE_LNG:
165 #if defined(ENABLE_SOFTFLOAT)
166         case TYPE_DBL:
167 #endif
168                 assert((fi->offset + 4) <= 0x0fff);
169                 pr->mcode |= ((fi->offset + 0) & 0x0fff);
170                 pc[1] &= 0xfffff000;
171                 pc[1] |= ((fi->offset + 4) & 0x0fff);
172                 break;
173
174 #if !defined(ENABLE_SOFTFLOAT)
175         case TYPE_FLT:
176         case TYPE_DBL:
177                 assert(fi->offset <= 0x03ff);
178                 pr->mcode |= ((fi->offset >> 2) & 0x00ff);
179                 break;
180 #endif
181         }
182
183         // Synchronize instruction cache.
184         md_icacheflush(pc, 2 * 4);
185
186         // Patch back the original code.
187         patcher_patch_code(pr);
188
189         return true;
190 }
191
192
193 /* patcher_resolve_classref_to_classinfo ***************************************
194
195    ACONST - Machine code:
196
197    <patched call postition>
198    e51cc030    ldr   r0, [ip, #-48]
199
200    MULTIANEWARRAY - Machine code:
201     
202    <patched call position>
203    e3a00002    mov   r0, #2  ; 0x2
204    e51c1064    ldr   r1, [ip, #-100]
205    e1a0200d    mov   r2, sp
206    e1a0e00f    mov   lr, pc
207    e51cf068    ldr   pc, [ip, #-104]
208
209    ARRAYCHECKCAST - Machine code:
210
211    <patched call position>
212    e51c1120    ldr   r1, [ip, #-288]
213    e1a0e00f    mov   lr, pc
214    e51cf124    ldr   pc, [ip, #-292]
215
216 *******************************************************************************/
217
218 bool patcher_resolve_classref_to_classinfo(patchref_t *pr)
219 {
220         constant_classref* cr    = (constant_classref *) pr->ref;
221         uintptr_t*         datap = (uintptr_t*)          pr->datap;
222
223         // Resolve the class.
224         classinfo* c = resolve_classref_eager(cr);
225
226         if (c == NULL)
227                 return false;
228
229         // Patch the classinfo pointer.
230         *datap = (uintptr_t) c;
231
232         // Patch back the original code.
233         patcher_patch_code(pr);
234
235         return true;
236 }
237
238
239 /* patcher_invokestatic_special ************************************************
240
241    Machine code:
242
243    <patched call position>
244    e51cc02c    ldr   ip, [ip, #-44]
245    e1a0e00f    mov   lr, pc
246    e1a0f00c    mov   pc, ip
247
248 ******************************************************************************/
249
250 bool patcher_invokestatic_special(patchref_t *pr)
251 {
252         unresolved_method* um    = (unresolved_method*) pr->ref;
253         uintptr_t*         datap = (uintptr_t*)         pr->datap;
254
255         // Reolve the method.
256         methodinfo* m = resolve_method_eager(um);
257
258         if (m == NULL)
259                 return false;
260
261         // Patch stubroutine.
262         *datap = (uintptr_t) m->stubroutine;
263
264         // Patch back the original code.
265         patcher_patch_code(pr);
266
267         return true;
268 }
269
270
271 /* patcher_invokevirtual *******************************************************
272
273    Machine code:
274
275    <patched call position>
276    e590b000    ldr   fp, [r0]
277    e59bc000    ldr   ip, [fp, #__]
278    e1a0e00f    mov   lr, pc
279    e1a0f00c    mov   pc, ip
280
281 *******************************************************************************/
282
283 bool patcher_invokevirtual(patchref_t *pr)
284 {
285         uint32_t*          pc = (uint32_t*)           pr->mpc;
286         unresolved_method* um = (unresolved_method *) pr->ref;
287
288         // Resolve the method.
289         methodinfo* m = resolve_method_eager(um);
290
291         if (m == NULL)
292                 return false;
293
294         // Patch vftbl index.
295         gen_resolveload(pc[1], (int32_t) (OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * m->vftblindex));
296
297         // Synchronize instruction cache.
298         md_icacheflush(pc + 1, 1 * 4);
299
300         // Patch back the original code.
301         patcher_patch_code(pr);
302
303         return true;
304 }
305
306
307 /* patcher_invokeinterface *****************************************************
308
309    Machine code:
310
311    <patched call position>
312    e590b000    ldr   fp, [r0]
313    e59bb000    ldr   fp, [fp, #__]
314    e59bc000    ldr   ip, [fp, #__]
315    e1a0e00f    mov   lr, pc
316    e1a0f00c    mov   pc, ip
317
318
319 *******************************************************************************/
320
321 bool patcher_invokeinterface(patchref_t *pr)
322 {
323         unresolved_method* um    = (unresolved_method*) pr->ref;
324         int32_t*           datap = (int32_t*)           pr->datap;
325
326         // Resolve the method.
327         methodinfo* m = resolve_method_eager(um);
328
329         if (m == NULL)
330                 return false;
331
332         // Patch interfacetable index.
333         int32_t disp = OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr*) * m->clazz->index;
334         *datap = disp;
335
336         // HACK The next data segment entry is one below.
337         datap--;
338
339         // Patch method offset.
340         disp = sizeof(methodptr) * (m - m->clazz->methods);
341         *datap = disp;
342
343         // Patch back the original code.
344         patcher_patch_code(pr);
345
346         return true;
347 }
348
349
350 /* patcher_checkcast_instanceof_flags ******************************************
351
352    Machine code:
353
354    <patched call position>
355
356 *******************************************************************************/
357
358 bool patcher_resolve_classref_to_flags(patchref_t *pr)
359 {
360         constant_classref* cr    = (constant_classref*) pr->ref;
361         int32_t*           datap = (int32_t*)           pr->datap;
362
363         // Resolve the class.
364         classinfo* c = resolve_classref_eager(cr);
365
366         if (c == NULL)
367                 return false;
368
369         // Patch class flags.
370         *datap = (int32_t) c->flags;
371
372         // Patch back the original code.
373         patcher_patch_code(pr);
374
375         return true;
376 }
377
378
379 /* patcher_resolve_classref_to_index *******************************************
380
381    Machine code:
382
383    <patched call position>
384
385 *******************************************************************************/
386
387 bool patcher_resolve_classref_to_index(patchref_t *pr)
388 {
389         constant_classref* cr    = (constant_classref*) pr->ref;
390         int32_t*           datap = (int32_t*)           pr->datap;
391
392         // Resolve the class.
393         classinfo* c = resolve_classref_eager(cr);
394
395         if (c == NULL)
396                 return false;
397
398         // Patch super class index.
399         *datap = (int32_t) c->index;
400
401         // Patch back the original code.
402         patcher_patch_code(pr);
403
404         return true;
405 }
406
407
408 /* patcher_resolve_classref_to_vftbl *******************************************
409
410    Machine code:
411
412    <patched call position>
413
414 *******************************************************************************/
415
416 bool patcher_resolve_classref_to_vftbl(patchref_t *pr)
417 {
418         constant_classref* cr    = (constant_classref*) pr->ref;
419         uintptr_t*         datap = (uintptr_t*)         pr->datap;
420
421         // Resolve the class.
422
423         classinfo* c = resolve_classref_eager(cr);
424
425         if (c == NULL)
426                 return false;
427
428         // Patch super class' vftbl.
429         *datap = (uintptr_t) c->vftbl;
430
431         // Patch back the original code.
432         patcher_patch_code(pr);
433
434         return true;
435 }
436
437
438 /*
439  * These are local overrides for various environment variables in Emacs.
440  * Please do not remove this and leave it at the end of the file, where
441  * Emacs will automagically detect them.
442  * ---------------------------------------------------------------------
443  * Local variables:
444  * mode: c
445  * indent-tabs-mode: t
446  * c-basic-offset: 4
447  * tab-width: 4
448  * End:
449  * vim:noexpandtab:sw=4:ts=4:
450  */