* src/vm/field.c: Moved to .cpp
[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.h"
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.h"
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         uint32_t*          pc = (uint32_t*)           pr->mpc;
324         unresolved_method* um = (unresolved_method *) pr->ref;
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         gen_resolveload(pc[1], (int32_t) (OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr*) * m->clazz->index));
334
335         // Patch method offset.
336         gen_resolveload(pc[2], (int32_t) (sizeof(methodptr) * (m - m->clazz->methods)));
337
338         // Synchronize instruction cache.
339         md_icacheflush(pc + 1, 2 * 4);
340
341         // Patch back the original code.
342         patcher_patch_code(pr);
343
344         return true;
345 }
346
347
348 /* patcher_checkcast_instanceof_flags ******************************************
349
350    Machine code:
351
352    <patched call position>
353
354 *******************************************************************************/
355
356 bool patcher_resolve_classref_to_flags(patchref_t *pr)
357 {
358         constant_classref* cr    = (constant_classref*) pr->ref;
359         int32_t*           datap = (int32_t*)           pr->datap;
360
361         // Resolve the class.
362         classinfo* c = resolve_classref_eager(cr);
363
364         if (c == NULL)
365                 return false;
366
367         // Patch class flags.
368         *datap = (int32_t) c->flags;
369
370         // Patch back the original code.
371         patcher_patch_code(pr);
372
373         return true;
374 }
375
376
377 /* patcher_resolve_classref_to_index *******************************************
378
379    Machine code:
380
381    <patched call position>
382
383 *******************************************************************************/
384
385 bool patcher_resolve_classref_to_index(patchref_t *pr)
386 {
387         constant_classref* cr    = (constant_classref*) pr->ref;
388         int32_t*           datap = (int32_t*)           pr->datap;
389
390         // Resolve the class.
391         classinfo* c = resolve_classref_eager(cr);
392
393         if (c == NULL)
394                 return false;
395
396         // Patch super class index.
397         *datap = (int32_t) c->index;
398
399         // Patch back the original code.
400         patcher_patch_code(pr);
401
402         return true;
403 }
404
405
406 /* patcher_resolve_classref_to_vftbl *******************************************
407
408    Machine code:
409
410    <patched call position>
411
412 *******************************************************************************/
413
414 bool patcher_resolve_classref_to_vftbl(patchref_t *pr)
415 {
416         constant_classref* cr    = (constant_classref*) pr->ref;
417         uintptr_t*         datap = (uintptr_t*)         pr->datap;
418
419         // Resolve the class.
420
421         classinfo* c = resolve_classref_eager(cr);
422
423         if (c == NULL)
424                 return false;
425
426         // Patch super class' vftbl.
427         *datap = (uintptr_t) c->vftbl;
428
429         // Patch back the original code.
430         patcher_patch_code(pr);
431
432         return true;
433 }
434
435
436 /*
437  * These are local overrides for various environment variables in Emacs.
438  * Please do not remove this and leave it at the end of the file, where
439  * Emacs will automagically detect them.
440  * ---------------------------------------------------------------------
441  * Local variables:
442  * mode: c
443  * indent-tabs-mode: t
444  * c-basic-offset: 4
445  * tab-width: 4
446  * End:
447  * vim:noexpandtab:sw=4:ts=4:
448  */