Merge from subtype.
[cacao.git] / src / vm / jit / mips / patcher.c
1 /* src/vm/jit/mips/patcher.c - MIPS code patching functions
2
3    Copyright (C) 1996-2005, 2006, 2007, 2008
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 <assert.h>
29 #include <stdint.h>
30
31 #include "vm/jit/mips/codegen.h"
32 #include "vm/jit/mips/md.h"
33
34 #include "mm/memory.h"
35
36 #include "native/native.hpp"
37
38 #include "vm/jit/builtin.hpp"
39 #include "vm/class.hpp"
40 #include "vm/field.hpp"
41 #include "vm/initialize.hpp"
42 #include "vm/options.h"
43 #include "vm/references.h"
44 #include "vm/resolve.hpp"
45
46 #include "vm/jit/asmpart.h"
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         *((uint32_t*) pr->mpc) = (uint32_t) pr->mcode;
59         md_icacheflush((void*) pr->mpc, PATCHER_CALL_SIZE);
60 }
61
62
63 /* patcher_get_putstatic *******************************************************
64
65    Machine code:
66
67    <patched call position>
68    dfc1ffb8    ld       at,-72(s8)
69    fc250000    sd       a1,0(at)
70
71 *******************************************************************************/
72
73 bool patcher_get_putstatic(patchref_t *pr)
74 {
75         unresolved_field* uf    = (unresolved_field *) pr->ref;
76         uintptr_t*        datap = (uintptr_t*)         pr->datap;
77
78         // Resolve the field.
79         fieldinfo* fi = resolve_field_eager(uf);
80
81         if (fi == NULL)
82                 return false;
83
84         // Check if the field's class is initialized.
85         if (!(fi->clazz->state & CLASS_INITIALIZED))
86                 if (!initialize_class(fi->clazz))
87                         return false;
88
89         // Patch the field value's address.
90         *datap = (uintptr_t) fi->value;
91
92         // Synchronize data cache.
93         md_dcacheflush(datap, SIZEOF_VOID_P);
94
95         // Patch back the original code.
96         patcher_patch_code(pr);
97
98         return true;
99 }
100
101
102 /* patcher_get_putfield ********************************************************
103
104    Machine code:
105
106    <patched call position>
107    8ee90020    lw       a5,32(s7)
108
109 *******************************************************************************/
110
111 bool patcher_get_putfield(patchref_t *pr)
112 {
113         uint32_t*         pc = (uint32_t*)         pr->mpc;
114         unresolved_field* uf = (unresolved_field*) pr->ref;
115
116         // Resolve the field.
117         fieldinfo* fi = resolve_field_eager(uf);
118
119         if (fi == NULL)
120                 return false;
121
122 #if SIZEOF_VOID_P == 4
123         if (IS_LNG_TYPE(fi->type)) {
124 # if WORDS_BIGENDIAN == 1
125                 // ATTENTION: order of these instructions depend on M_LLD_INTERN.
126                 // The first instruction is patched back later.
127                 pr->mcode |= (int16_t) ((fi->offset + 0) & 0x0000ffff);
128                 pc[1]     |= (int16_t) ((fi->offset + 4) & 0x0000ffff);
129 # else
130                 // ATTENTION: order of these instructions depend on M_LLD_INTERN.
131                 // The first instruction is patched back later.
132                 pr->mcode |= (int16_t) ((fi->offset + 4) & 0x0000ffff);
133                 pc[1]     |= (int16_t) ((fi->offset + 0) & 0x0000ffff);
134 # endif
135         }
136         else
137 #endif
138         {
139                 // The instruction is patched back later.
140                 pr->mcode |= (int16_t) (fi->offset & 0x0000ffff);
141         }
142
143         // Synchronize instruction cache.
144         md_icacheflush(pc, 2 * 4);
145
146         // Patch back the original code.
147         patcher_patch_code(pr);
148
149         return true;
150 }
151
152
153 /* patcher_resolve_classref_to_classinfo ***************************************
154
155    ACONST:
156
157    <patched call postition>
158    dfc4ff98    ld       a0,-104(s8)
159
160    MULTIANEWARRAY:
161
162    <patched call position>
163    dfc5ff90    ld       a1,-112(s8)
164    03a03025    move     a2,sp
165    dfd9ff88    ld       t9,-120(s8)
166    0320f809    jalr     t9
167    00000000    nop
168
169    ARRAYCHECKCAST:
170
171    <patched call position>
172    dfc5ffc0    ld       a1,-64(s8)
173    dfd9ffb8    ld       t9,-72(s8)
174    0320f809    jalr     t9
175    00000000    nop
176
177 *******************************************************************************/
178
179 bool patcher_resolve_classref_to_classinfo(patchref_t *pr)
180 {
181         constant_classref* cr    = (constant_classref*) pr->ref;
182         uintptr_t*         datap = (uintptr_t*)         pr->datap;
183
184         // Resolve the class.
185         classinfo* c = resolve_classref_eager(cr);
186
187         if (c == NULL)
188                 return false;
189
190         // Patch the class.
191         *datap = (uintptr_t) c;
192
193         // Synchronize data cache.
194         md_dcacheflush(datap, SIZEOF_VOID_P);
195
196         // Patch back the original code.
197         patcher_patch_code(pr);
198
199         return true;
200 }
201
202
203 /* patcher_resolve_classref_to_vftbl *******************************************
204
205    CHECKCAST (class):
206    INSTANCEOF (class):
207
208    <patched call position>
209    dd030000    ld       v1,0(a4)
210    dfd9ff18    ld       t9,-232(s8)
211
212 *******************************************************************************/
213
214 bool patcher_resolve_classref_to_vftbl(patchref_t *pr)
215 {
216         constant_classref* cr    = (constant_classref *) pr->ref;
217         uintptr_t*         datap = (uintptr_t*)          pr->datap;
218
219         // Resolve the field.
220         classinfo* c = resolve_classref_eager(cr);
221
222         if (c == NULL)
223                 return false;
224
225         // Patch super class' vftbl.
226         *datap = (uintptr_t) c->vftbl;
227
228         // Synchronize data cache.
229         md_dcacheflush(datap, SIZEOF_VOID_P);
230
231         // Patch back the original code.
232         patcher_patch_code(pr);
233
234         return true;
235 }
236
237
238 /* patcher_resolve_classref_to_flags *******************************************
239
240    CHECKCAST/INSTANCEOF:
241
242    <patched call position>
243    8fc3ff24    lw       v1,-220(s8)
244    30630200    andi     v1,v1,512
245    1060000d    beq      v1,zero,0x000000001051824c
246    00000000    nop
247
248 *******************************************************************************/
249
250 bool patcher_resolve_classref_to_flags(patchref_t *pr)
251 {
252         constant_classref* cr    = (constant_classref*) pr->ref;
253         int32_t*           datap = (int32_t*)           pr->datap;
254
255         // Resolve the class.
256         classinfo* c = resolve_classref_eager(cr);
257
258         if (c == NULL)
259                 return false;
260
261         // Patch class flags.
262         *datap = (int32_t) c->flags;
263
264         // Synchronize data cache.
265         md_dcacheflush(datap, sizeof(int32_t));
266
267         // Patch back the original code.
268         patcher_patch_code(pr);
269
270         return true;
271 }
272
273
274 /* patcher_invokestatic_special ************************************************
275
276    Machine code:
277
278    <patched call position>
279    dfdeffc0    ld       s8,-64(s8)
280    03c0f809    jalr     s8
281    00000000    nop
282
283 ******************************************************************************/
284
285 bool patcher_invokestatic_special(patchref_t *pr)
286 {
287         unresolved_method* um    = (unresolved_method*) pr->ref;
288         void**             datap = (void*)              pr->datap;
289
290         // Resolve the method.
291         methodinfo* m = resolve_method_eager(um);
292
293         if (m == NULL)
294                 return false;
295
296         // Patch stubroutine.
297         *datap = (void*) m->stubroutine;
298
299         // Synchronize data cache.
300         md_dcacheflush(datap, SIZEOF_VOID_P);
301
302         // Patch back the original code.
303         patcher_patch_code(pr);
304
305         return true;
306 }
307
308
309 /* patcher_invokevirtual *******************************************************
310
311    Machine code:
312
313    <patched call position>
314    dc990000    ld       t9,0(a0)
315    df3e0040    ld       s8,64(t9)
316    03c0f809    jalr     s8
317    00000000    nop
318
319 *******************************************************************************/
320
321 bool patcher_invokevirtual(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 vftbl index.
333         pc[1] |= (int32_t) ((OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * m->vftblindex) & 0x0000ffff);
334
335         // Synchronize instruction cache.
336         md_icacheflush(pc + 1, 1 * 4);
337
338         // Patch back the original code.
339         patcher_patch_code(pr);
340
341         return true;
342 }
343
344
345 /* patcher_invokeinterface *****************************************************
346
347    Machine code:
348
349    <patched call position>
350    dc990000    ld       t9,0(a0)
351    df39ffa0    ld       t9,-96(t9)
352    df3e0018    ld       s8,24(t9)
353    03c0f809    jalr     s8
354    00000000    nop
355
356 *******************************************************************************/
357
358 bool patcher_invokeinterface(patchref_t *pr)
359 {
360         uint32_t*          pc = (uint32_t*)          pr->mpc;
361         unresolved_method* um = (unresolved_method*) pr->ref;
362
363         // Resovlve the method.
364         methodinfo* m = resolve_method_eager(um);
365
366         if (m == NULL)
367                 return false;
368
369         // Patch interfacetable index.
370         pc[1] |= (int32_t) ((OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr*) * m->clazz->index) & 0x0000ffff);
371
372         // Patch method offset.
373         pc[2] |= (int32_t) ((sizeof(methodptr) * (m - m->clazz->methods)) & 0x0000ffff);
374
375         // Synchronize instruction cache.
376         md_icacheflush(pc + 1, 2 * 4);
377
378         // Patch back the original code.
379         patcher_patch_code(pr);
380
381         return true;
382 }
383
384
385 /* patcher_checkcast_interface *************************************************
386
387    Machine code:
388
389    <patched call position>
390    dd030000    ld       v1,0(a4)
391    8c79001c    lw       t9,28(v1)
392    27390000    addiu    t9,t9,0
393    1b200082    blez     t9,zero,0x000000001051843c
394    00000000    nop
395    dc790000    ld       t9,0(v1)
396
397 *******************************************************************************/
398
399 bool patcher_checkcast_interface(patchref_t *pr)
400 {
401         uint32_t*          pc = (uint32_t*)          pr->mpc;
402         constant_classref* cr = (constant_classref*) pr->ref;
403
404         // Resolve the class.
405         classinfo* c = resolve_classref_eager(cr);
406
407         if (c == NULL)
408                 return false;
409
410         // Patch super class index.
411         pc[2] |= (int32_t) (-(c->index) & 0x0000ffff);
412         pc[6] |= (int32_t) ((OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*)) & 0x0000ffff);
413
414         // Synchronize instruction cache.
415         md_icacheflush(pc + 2, 5 * 4);
416
417         // Patch back the original code.
418         patcher_patch_code(pr);
419
420         return true;
421 }
422
423
424 /* patcher_instanceof_interface ************************************************
425
426    Machine code:
427
428    <patched call position>
429    dd030000    ld       v1,0(a4)
430    8c79001c    lw       t9,28(v1)
431    27390000    addiu    t9,t9,0
432    1b200082    blez     t9,zero,0x000000001051843c
433    00000000    nop
434    dc790000    ld       t9,0(v1)
435
436 *******************************************************************************/
437
438 bool patcher_instanceof_interface(patchref_t *pr)
439 {
440         uint32_t*          pc = (uint32_t*)          pr->mpc;
441         constant_classref* cr = (constant_classref*) pr->ref;
442
443         // Resolve the method.
444         classinfo* c = resolve_classref_eager(cr);
445
446         if (c == NULL)
447                 return false;
448
449         // Patch super class index.
450         pc[2] |= (int32_t) (-(c->index) & 0x0000ffff);
451         pc[5] |= (int32_t) ((OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*)) & 0x0000ffff);
452
453         // Synchronize instruction cache.
454         md_icacheflush(pc + 2, 4 * 4);
455
456         // Patch back the original code.
457         patcher_patch_code(pr);
458
459         return true;
460 }
461
462
463 /*
464  * These are local overrides for various environment variables in Emacs.
465  * Please do not remove this and leave it at the end of the file, where
466  * Emacs will automagically detect them.
467  * ---------------------------------------------------------------------
468  * Local variables:
469  * mode: c
470  * indent-tabs-mode: t
471  * c-basic-offset: 4
472  * tab-width: 4
473  * End:
474  * vim:noexpandtab:sw=4:ts=4:
475  */