8ad124171a6d825d8339193cd0a9e40df5c5319b
[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 R. Grafl, A. Krall, C. Kruegel,
4    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6    J. Wenninger, Institut f. Computersprachen - TU Wien
7
8    This file is part of CACAO.
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2, or (at
13    your option) any later version.
14
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23    02110-1301, USA.
24
25    $Id: patcher.c 8268 2007-08-07 13:24:43Z twisti $
26
27 */
28
29
30 #include "config.h"
31
32 #include <assert.h>
33 #include <stdint.h>
34
35 #include "vm/types.h"
36
37 #include "vm/jit/mips/codegen.h"
38
39 #include "mm/memory.h"
40
41 #include "native/native.h"
42
43 #include "vm/builtin.h"
44 #include "vm/exceptions.h"
45 #include "vm/initialize.h"
46
47 #include "vm/jit/asmpart.h"
48 #include "vm/jit/md.h"
49 #include "vm/jit/patcher-common.h"
50
51 #include "vmcore/class.h"
52 #include "vmcore/field.h"
53 #include "vmcore/options.h"
54 #include "vm/resolve.h"
55 #include "vmcore/references.h"
56
57
58 #define PATCH_BACK_ORIGINAL_MCODE \
59         *((u4 *) pr->mpc) = (u4) pr->mcode; \
60         md_icacheflush((u1 *) pr->mpc, PATCHER_CALL_SIZE);
61
62
63 /* patcher_initialize_class ****************************************************
64
65    Initalizes a given classinfo pointer.  This function does not patch
66    any data.
67
68 *******************************************************************************/
69
70 bool patcher_initialize_class(patchref_t *pr)
71 {
72         classinfo *c;
73
74         /* get stuff from the stack */
75
76         c = (classinfo *) pr->ref;
77
78         /* check if the class is initialized */
79
80         if (!(c->state & CLASS_INITIALIZED))
81                 if (!initialize_class(c))
82                         return false;
83
84         PATCH_BACK_ORIGINAL_MCODE;
85
86         return true;
87 }
88
89
90 /* patcher_resolve_class *****************************************************
91
92    Initalizes a given classinfo pointer.  This function does not patch
93    any data.
94
95 *******************************************************************************/
96
97 #ifdef ENABLE_VERIFIER
98 bool patcher_resolve_class(patchref_t *pr)
99 {
100         unresolved_class *uc;
101
102         /* get stuff from the stack */
103
104         uc = (unresolved_class *) pr->ref;
105
106         /* resolve the class and check subtype constraints */
107
108         if (!resolve_class_eager_no_access_check(uc))
109                 return false;
110
111         PATCH_BACK_ORIGINAL_MCODE;
112
113         return true;
114 }
115 #endif /* ENABLE_VERIFIER */
116
117
118 /* patcher_get_putstatic *******************************************************
119
120    Machine code:
121
122    <patched call position>
123    dfc1ffb8    ld       at,-72(s8)
124    fc250000    sd       a1,0(at)
125
126 *******************************************************************************/
127
128 bool patcher_get_putstatic(patchref_t *pr)
129 {
130         unresolved_field *uf;
131         u1               *datap;
132         fieldinfo        *fi;
133
134         /* get stuff from the stack */
135
136         uf    = (unresolved_field *) pr->ref;
137         datap = (u1 *)               pr->datap;
138
139         /* get the fieldinfo */
140
141         if (!(fi = resolve_field_eager(uf)))
142                 return false;
143
144         /* check if the field's class is initialized */
145
146         if (!(fi->class->state & CLASS_INITIALIZED))
147                 if (!initialize_class(fi->class))
148                         return false;
149
150         PATCH_BACK_ORIGINAL_MCODE;
151
152         /* patch the field value's address */
153
154         *((intptr_t *) datap) = (intptr_t) fi->value;
155
156         /* synchronize data cache */
157
158         md_dcacheflush(datap, SIZEOF_VOID_P);
159
160         return true;
161 }
162
163
164 /* patcher_get_putfield ********************************************************
165
166    Machine code:
167
168    <patched call position>
169    8ee90020    lw       a5,32(s7)
170
171 *******************************************************************************/
172
173 bool patcher_get_putfield(patchref_t *pr)
174 {
175         u1               *ra;
176         unresolved_field *uf;
177         fieldinfo        *fi;
178
179         /* get stuff from the stack */
180
181         ra = (u1 *)               pr->mpc;
182         uf = (unresolved_field *) pr->ref;
183
184         /* get the fieldinfo */
185
186         if (!(fi = resolve_field_eager(uf)))
187                 return false;
188
189         PATCH_BACK_ORIGINAL_MCODE;
190
191         /* if we show disassembly, we have to skip the nop's */
192
193         if (opt_shownops)
194                 ra = ra + PATCHER_CALL_SIZE;
195
196 #if SIZEOF_VOID_P == 4
197         if (IS_LNG_TYPE(fi->type)) {
198 # if WORDS_BIGENDIAN == 1
199                 /* ATTENTION: order of these instructions depend on M_LLD_INTERN */
200                 *((u4 *) (ra + 0 * 4)) |= (s2) ((fi->offset + 0) & 0x0000ffff);
201                 *((u4 *) (ra + 1 * 4)) |= (s2) ((fi->offset + 4) & 0x0000ffff);
202 # else
203                 /* ATTENTION: order of these instructions depend on M_LLD_INTERN */
204                 *((u4 *) (ra + 0 * 4)) |= (s2) ((fi->offset + 4) & 0x0000ffff);
205                 *((u4 *) (ra + 1 * 4)) |= (s2) ((fi->offset + 0) & 0x0000ffff);
206 # endif
207         }
208         else
209 #endif
210                 *((u4 *) (ra + 0 * 4)) |= (s2) (fi->offset & 0x0000ffff);
211
212         /* synchronize instruction cache */
213
214         md_icacheflush(ra, 2 * 4);
215
216         return true;
217 }
218
219
220 /* patcher_resolve_classref_to_classinfo ***************************************
221
222    ACONST:
223
224    <patched call postition>
225    dfc4ff98    ld       a0,-104(s8)
226
227    MULTIANEWARRAY:
228
229    <patched call position>
230    dfc5ff90    ld       a1,-112(s8)
231    03a03025    move     a2,sp
232    dfd9ff88    ld       t9,-120(s8)
233    0320f809    jalr     t9
234    00000000    nop
235
236    ARRAYCHECKCAST:
237
238    <patched call position>
239    dfc5ffc0    ld       a1,-64(s8)
240    dfd9ffb8    ld       t9,-72(s8)
241    0320f809    jalr     t9
242    00000000    nop
243
244 *******************************************************************************/
245
246 bool patcher_resolve_classref_to_classinfo(patchref_t *pr)
247 {
248         constant_classref *cr;
249         u1                *datap;
250         classinfo         *c;
251
252         /* get stuff from the stack */
253
254         cr    = (constant_classref *) pr->ref;
255         datap = (u1 *)                pr->datap;
256
257         /* get the classinfo */
258
259         if (!(c = resolve_classref_eager(cr)))
260                 return false;
261
262         PATCH_BACK_ORIGINAL_MCODE;
263
264         /* patch the classinfo pointer */
265
266         *((intptr_t *) datap) = (intptr_t) c;
267
268         /* synchronize data cache */
269
270         md_dcacheflush(datap, SIZEOF_VOID_P);
271
272         return true;
273 }
274
275
276 /* patcher_resolve_classref_to_vftbl *******************************************
277
278    CHECKCAST (class):
279    INSTANCEOF (class):
280
281    <patched call position>
282    dd030000    ld       v1,0(a4)
283    dfd9ff18    ld       t9,-232(s8)
284
285 *******************************************************************************/
286
287 bool patcher_resolve_classref_to_vftbl(patchref_t *pr)
288 {
289         constant_classref *cr;
290         u1                *datap;
291         classinfo         *c;
292
293         /* get stuff from the stack */
294
295         cr    = (constant_classref *) pr->ref;
296         datap = (u1 *)                pr->datap;
297
298         /* get the fieldinfo */
299
300         if (!(c = resolve_classref_eager(cr)))
301                 return false;
302
303         PATCH_BACK_ORIGINAL_MCODE;
304
305         /* patch super class' vftbl */
306
307         *((intptr_t *) datap) = (intptr_t) c->vftbl;
308
309         /* synchronize data cache */
310
311         md_dcacheflush(datap, SIZEOF_VOID_P);
312
313         return true;
314 }
315
316
317 /* patcher_resolve_classref_to_flags *******************************************
318
319    CHECKCAST/INSTANCEOF:
320
321    <patched call position>
322    8fc3ff24    lw       v1,-220(s8)
323    30630200    andi     v1,v1,512
324    1060000d    beq      v1,zero,0x000000001051824c
325    00000000    nop
326
327 *******************************************************************************/
328
329 bool patcher_resolve_classref_to_flags(patchref_t *pr)
330 {
331         constant_classref *cr;
332         u1                *datap;
333         classinfo         *c;
334
335         /* get stuff from the stack */
336
337         cr    = (constant_classref *) pr->ref;
338         datap = (u1 *)                pr->datap;
339
340         /* get the fieldinfo */
341
342         if (!(c = resolve_classref_eager(cr)))
343                 return false;
344
345         PATCH_BACK_ORIGINAL_MCODE;
346
347         /* patch class flags */
348
349         *((int32_t *) datap) = (int32_t) c->flags;
350
351         /* synchronize data cache */
352
353         md_dcacheflush(datap, sizeof(int32_t));
354
355         return true;
356 }
357
358
359 /* patcher_resolve_native ******************************************************
360
361    XXX
362
363 *******************************************************************************/
364
365 #if !defined(WITH_STATIC_CLASSPATH)
366 bool patcher_resolve_native_function(patchref_t *pr)
367 {
368         methodinfo  *m;
369         u1          *datap;
370         functionptr  f;
371
372         /* get stuff from the stack */
373
374         m     = (methodinfo *) pr->ref;
375         datap = (u1 *)         pr->datap;
376
377         /* resolve native function */
378
379         if (!(f = native_resolve_function(m)))
380                 return false;
381
382         PATCH_BACK_ORIGINAL_MCODE;
383
384         /* patch native function pointer */
385
386         *((ptrint *) datap) = (ptrint) f;
387
388         /* synchronize data cache */
389
390         md_dcacheflush(datap, SIZEOF_VOID_P);
391
392         return true;
393 }
394 #endif /* !defined(WITH_STATIC_CLASSPATH) */
395
396
397 /* patcher_invokestatic_special ************************************************
398
399    Machine code:
400
401    <patched call position>
402    dfdeffc0    ld       s8,-64(s8)
403    03c0f809    jalr     s8
404    00000000    nop
405
406 ******************************************************************************/
407
408 bool patcher_invokestatic_special(patchref_t *pr)
409 {
410         unresolved_method *um;
411         u1                *datap;
412         methodinfo        *m;
413
414         /* get stuff from the stack */
415
416         um    = (unresolved_method *) pr->ref;
417         datap = (u1 *)                pr->datap;
418
419         /* get the fieldinfo */
420
421         if (!(m = resolve_method_eager(um)))
422                 return false;
423
424         PATCH_BACK_ORIGINAL_MCODE;
425
426         /* patch stubroutine */
427
428         *((ptrint *) datap) = (ptrint) m->stubroutine;
429
430         /* synchronize data cache */
431
432         md_dcacheflush(datap, SIZEOF_VOID_P);
433
434         return true;
435 }
436
437
438 /* patcher_invokevirtual *******************************************************
439
440    Machine code:
441
442    <patched call position>
443    dc990000    ld       t9,0(a0)
444    df3e0040    ld       s8,64(t9)
445    03c0f809    jalr     s8
446    00000000    nop
447
448 *******************************************************************************/
449
450 bool patcher_invokevirtual(patchref_t *pr)
451 {
452         u1                *ra;
453         unresolved_method *um;
454         methodinfo        *m;
455
456         /* get stuff from the stack */
457
458         ra = (u1 *)                pr->mpc;
459         um = (unresolved_method *) pr->ref;
460
461         /* get the fieldinfo */
462
463         if (!(m = resolve_method_eager(um)))
464                 return false;
465
466         PATCH_BACK_ORIGINAL_MCODE;
467
468         /* if we show disassembly, we have to skip the nop's */
469
470         if (opt_shownops)
471                 ra = ra + PATCHER_CALL_SIZE;
472
473         /* patch vftbl index */
474
475         *((s4 *) (ra + 1 * 4)) |=
476                 (s4) ((OFFSET(vftbl_t, table[0]) +
477                            sizeof(methodptr) * m->vftblindex) & 0x0000ffff);
478
479         /* synchronize instruction cache */
480
481         md_icacheflush(ra + 1 * 4, 1 * 4);
482
483         return true;
484 }
485
486
487 /* patcher_invokeinterface *****************************************************
488
489    Machine code:
490
491    <patched call position>
492    dc990000    ld       t9,0(a0)
493    df39ffa0    ld       t9,-96(t9)
494    df3e0018    ld       s8,24(t9)
495    03c0f809    jalr     s8
496    00000000    nop
497
498 *******************************************************************************/
499
500 bool patcher_invokeinterface(patchref_t *pr)
501 {
502         u1                *ra;
503         unresolved_method *um;
504         methodinfo        *m;
505
506         /* get stuff from the stack */
507
508         ra = (u1 *)                pr->mpc;
509         um = (unresolved_method *) pr->ref;
510
511         /* get the fieldinfo */
512
513         if (!(m = resolve_method_eager(um)))
514                 return false;
515
516         PATCH_BACK_ORIGINAL_MCODE;
517
518         /* if we show disassembly, we have to skip the nop's */
519
520         if (opt_shownops)
521                 ra = ra + PATCHER_CALL_SIZE;
522
523         /* patch interfacetable index */
524
525         *((s4 *) (ra + 1 * 4)) |=
526                 (s4) ((OFFSET(vftbl_t, interfacetable[0]) -
527                            sizeof(methodptr*) * m->class->index) & 0x0000ffff);
528
529         /* patch method offset */
530
531         *((s4 *) (ra + 2 * 4)) |=
532                 (s4) ((sizeof(methodptr) * (m - m->class->methods)) & 0x0000ffff);
533
534         /* synchronize instruction cache */
535
536         md_icacheflush(ra + 1 * 4, 2 * 4);
537
538         return true;
539 }
540
541
542 /* patcher_checkcast_interface *************************************************
543
544    Machine code:
545
546    <patched call position>
547    dd030000    ld       v1,0(a4)
548    8c79001c    lw       t9,28(v1)
549    27390000    addiu    t9,t9,0
550    1b200082    blez     t9,zero,0x000000001051843c
551    00000000    nop
552    dc790000    ld       t9,0(v1)
553
554 *******************************************************************************/
555
556 bool patcher_checkcast_interface(patchref_t *pr)
557 {
558         u1                *ra;
559         constant_classref *cr;
560         classinfo         *c;
561
562         /* get stuff from the stack */
563
564         ra = (u1 *)                pr->mpc;
565         cr = (constant_classref *) pr->ref;
566
567         /* get the fieldinfo */
568
569         if (!(c = resolve_classref_eager(cr)))
570                 return false;
571
572         PATCH_BACK_ORIGINAL_MCODE;
573
574         /* if we show disassembly, we have to skip the nop's */
575
576         if (opt_shownops)
577                 ra = ra + PATCHER_CALL_SIZE;
578
579         /* patch super class index */
580
581         *((s4 *) (ra + 2 * 4)) |= (s4) (-(c->index) & 0x0000ffff);
582         /*      *((s4 *) (ra + 5 * 4)) |= (s4) ((OFFSET(vftbl_t, interfacetable[0]) - */
583         /*                                                                       c->index * sizeof(methodptr*)) & 0x0000ffff); */
584         *((s4 *) (ra + 6 * 4)) |=
585                 (s4) ((OFFSET(vftbl_t, interfacetable[0]) -
586                            c->index * sizeof(methodptr*)) & 0x0000ffff);
587
588         /* synchronize instruction cache */
589
590         md_icacheflush(ra + 2 * 4, 5 * 4);
591
592         return true;
593 }
594
595
596 /* patcher_instanceof_interface ************************************************
597
598    Machine code:
599
600    <patched call position>
601    dd030000    ld       v1,0(a4)
602    8c79001c    lw       t9,28(v1)
603    27390000    addiu    t9,t9,0
604    1b200082    blez     t9,zero,0x000000001051843c
605    00000000    nop
606    dc790000    ld       t9,0(v1)
607
608 *******************************************************************************/
609
610 bool patcher_instanceof_interface(patchref_t *pr)
611 {
612         u1                *ra;
613         constant_classref *cr;
614         classinfo         *c;
615
616         /* get stuff from the stack */
617
618         ra = (u1 *)                pr->mpc;
619         cr = (constant_classref *) pr->ref;
620
621         /* get the fieldinfo */
622
623         if (!(c = resolve_classref_eager(cr)))
624                 return false;
625
626         PATCH_BACK_ORIGINAL_MCODE;
627
628         /* if we show disassembly, we have to skip the nop's */
629
630         if (opt_shownops)
631                 ra = ra + PATCHER_CALL_SIZE;
632
633         /* patch super class index */
634
635         *((s4 *) (ra + 2 * 4)) |= (s4) (-(c->index) & 0x0000ffff);
636         *((s4 *) (ra + 5 * 4)) |=
637                 (s4) ((OFFSET(vftbl_t, interfacetable[0]) -
638                            c->index * sizeof(methodptr*)) & 0x0000ffff);
639
640         /* synchronize instruction cache */
641
642         md_icacheflush(ra + 2 * 4, 4 * 4);
643
644         return true;
645 }
646
647
648 /*
649  * These are local overrides for various environment variables in Emacs.
650  * Please do not remove this and leave it at the end of the file, where
651  * Emacs will automagically detect them.
652  * ---------------------------------------------------------------------
653  * Local variables:
654  * mode: c
655  * indent-tabs-mode: t
656  * c-basic-offset: 4
657  * tab-width: 4
658  * End:
659  * vim:noexpandtab:sw=4:ts=4:
660  */