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