* Removed all Id tags.
[cacao.git] / src / vm / jit / s390 / patcher.c
1 /* src/vm/jit/x86_64/patcher.c - x86_64 code patching functions
2
3    Copyright (C) 1996-2005, 2006 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    Contact: cacao@cacaojvm.org
26
27    Authors: Christian Thalinger
28
29    Changes: Peter Molnar
30
31 */
32
33
34 #include "config.h"
35
36 #include <assert.h>
37 #include <stdint.h>
38
39 #include "mm/memory.h"
40 #include "native/native.h"
41 #include "vm/builtin.h"
42 #include "vm/exceptions.h"
43 #include "vm/initialize.h"
44 #include "vm/jit/patcher-common.h"
45 #include "vm/jit/s390/codegen.h"
46 #include "vm/jit/s390/md-abi.h"
47 #include "vm/jit/stacktrace.h"
48 #include "vm/resolve.h"
49 #include "vm/types.h"
50 #include "vmcore/class.h"
51 #include "vmcore/field.h"
52 #include "vmcore/options.h"
53 #include "vmcore/references.h"
54
55 #define PATCH_BACK_ORIGINAL_MCODE \
56         *((u2 *) pr->mpc) = (u2) pr->mcode;
57
58 #define PATCHER_TRACE 
59
60 /* patcher_get_putstatic *******************************************************
61
62    Machine code:
63
64 *******************************************************************************/
65
66 bool patcher_get_putstatic(patchref_t *pr)
67 {
68         unresolved_field *uf;
69         u1               *datap;
70         fieldinfo        *fi;
71
72         PATCHER_TRACE;
73
74         /* get stuff from the stack */
75
76         uf    = (unresolved_field *) pr->ref;
77         datap = (u1 *)               pr->datap;
78
79         /* get the fieldinfo */
80
81         if (!(fi = resolve_field_eager(uf)))
82                 return false;
83
84         /* check if the field's class is initialized */
85
86         if (!(fi->class->state & CLASS_INITIALIZED))
87                 if (!initialize_class(fi->class))
88                         return false;
89
90         PATCH_BACK_ORIGINAL_MCODE;
91
92         /* patch the field value's address */
93
94         *((intptr_t *) datap) = (intptr_t) fi->value;
95
96         return true;
97 }
98
99
100 /* patcher_get_putfield ********************************************************
101
102    Machine code:
103
104 *******************************************************************************/
105
106 bool patcher_get_putfield(patchref_t *pr)
107 {
108         u1               *ra;
109         unresolved_field *uf;
110         fieldinfo        *fi;
111         s4                disp;
112
113         PATCHER_TRACE;
114
115         /* get stuff from the stack */
116
117         ra    = (u1 *)               pr->mpc;
118         uf    = (unresolved_field *) pr->ref;
119         disp  =                      pr->disp;
120
121         /* get the fieldinfo */
122
123         if (!(fi = resolve_field_eager(uf)))
124                 return false;
125
126         PATCH_BACK_ORIGINAL_MCODE;
127
128         /* If NOPs are generated, skip them */
129
130         if (opt_shownops)
131                 ra += PATCHER_NOPS_SKIP;
132
133         /* If there is an operand load before, skip the load size passed in disp (see ICMD_PUTFIELD) */
134
135         ra += disp;
136
137         /* patch correct offset */
138
139         if (fi->type == TYPE_LNG) {
140                 assert(N_VALID_DISP(fi->offset + 4));
141                 /* 2 RX operations, for 2 words; each already contains a 0 or 4 offset. */
142                 *((u4 *) ra ) |= (fi->offset + (*((u4 *) ra) & 0xF));
143                 ra += 4;
144                 *((u4 *) ra ) |= (fi->offset + (*((u4 *) ra) & 0xF));
145         } else {
146                 assert(N_VALID_DISP(fi->offset));
147                 /* 1 RX operation */
148                 *((u4 *) ra) |= fi->offset;
149         }
150
151         return true;
152 }
153
154 /* patcher_invokestatic_special ************************************************
155
156    Machine code:
157
158 *******************************************************************************/
159
160 bool patcher_invokestatic_special(patchref_t *pr)
161 {
162         unresolved_method *um;
163         u1                *datap;
164         methodinfo        *m;
165
166         PATCHER_TRACE;
167
168         /* get stuff from the stack */
169
170         um    = (unresolved_method *) pr->ref;
171         datap = (u1 *)                pr->datap;
172
173         /* get the fieldinfo */
174
175         if (!(m = resolve_method_eager(um)))
176                 return false;
177
178         PATCH_BACK_ORIGINAL_MCODE;
179
180         /* patch stubroutine */
181
182         *((ptrint *) datap) = (ptrint) m->stubroutine;
183
184         return true;
185 }
186
187 /* patcher_invokevirtual *******************************************************
188
189    Machine code:
190
191 *******************************************************************************/
192
193 bool patcher_invokevirtual(patchref_t *pr)
194 {
195         u1                *ra;
196         unresolved_method *um;
197         methodinfo        *m;
198         s4                 off;
199
200         PATCHER_TRACE;
201
202         /* get stuff from the stack */
203
204         ra    = (u1 *)                pr->mpc;
205         um    = (unresolved_method *) pr->ref;
206
207         /* get the fieldinfo */
208
209         if (!(m = resolve_method_eager(um)))
210                 return false;
211
212         /* patch back original code */
213
214         PATCH_BACK_ORIGINAL_MCODE;
215
216         /* If NOPs are generated, skip them */
217
218         if (opt_shownops)
219                 ra += PATCHER_NOPS_SKIP;
220
221         /* patch vftbl index */
222
223
224         off = (s4) (OFFSET(vftbl_t, table[0]) +
225                                                                    sizeof(methodptr) * m->vftblindex);
226
227         assert(N_VALID_DISP(off));
228
229         *((s4 *)(ra + 4)) |= off;
230
231         return true;
232 }
233
234
235 /* patcher_invokeinterface *****************************************************
236
237    Machine code:
238
239 *******************************************************************************/
240
241 bool patcher_invokeinterface(patchref_t *pr)
242 {
243         u1                *ra;
244         unresolved_method *um;
245         methodinfo        *m;
246         s4                 idx, off;
247
248         PATCHER_TRACE;
249
250         /* get stuff from the stack */
251
252         ra    = (u1 *)                pr->mpc;
253         um    = (unresolved_method *) pr->ref;
254
255         /* get the fieldinfo */
256
257         if (!(m = resolve_method_eager(um)))
258                 return false;
259
260         /* patch back original code */
261
262         PATCH_BACK_ORIGINAL_MCODE;
263
264         /* If NOPs are generated, skip them */
265
266         if (opt_shownops)
267                 ra += PATCHER_NOPS_SKIP;
268
269         /* get interfacetable index */
270
271         idx = (s4) (OFFSET(vftbl_t, interfacetable[0]) -
272                 sizeof(methodptr) * m->class->index);
273
274         ASSERT_VALID_IMM(idx);
275
276         /* get method offset */
277
278         off =
279                 (s4) (sizeof(methodptr) * (m - m->class->methods));
280         ASSERT_VALID_DISP(off);
281
282         /* patch them */
283
284         *((s4 *)(ra + 4)) |= (u2)idx;
285         *((s4 *)(ra + 4 + 4 + 4)) |= off;
286
287         return true;
288 }
289
290
291 /* patcher_resolve_classref_to_flags *******************************************
292
293    CHECKCAST/INSTANCEOF:
294
295    <patched call position>
296
297 *******************************************************************************/
298
299 bool patcher_resolve_classref_to_flags(patchref_t *pr)
300 {
301         constant_classref *cr;
302         u1                *datap;
303         classinfo         *c;
304
305         PATCHER_TRACE;
306
307         /* get stuff from the stack */
308
309         cr    = (constant_classref *) pr->ref;
310         datap = (u1 *)                pr->datap;
311
312         /* get the fieldinfo */
313
314         if (!(c = resolve_classref_eager(cr)))
315                 return false;
316
317         PATCH_BACK_ORIGINAL_MCODE;
318
319         /* patch class flags */
320
321         *((s4 *) datap) = (s4) c->flags;
322
323         return true;
324 }
325
326 /* patcher_resolve_classref_to_classinfo ***************************************
327
328    ACONST:
329    MULTIANEWARRAY:
330    ARRAYCHECKCAST:
331
332 *******************************************************************************/
333
334 bool patcher_resolve_classref_to_classinfo(patchref_t *pr)
335 {
336         constant_classref *cr;
337         u1                *datap;
338         classinfo         *c;
339
340         PATCHER_TRACE;
341
342         /* get stuff from the stack */
343
344         cr    = (constant_classref *) pr->ref;
345         datap = (u1 *)                pr->datap;
346
347         /* get the classinfo */
348
349         if (!(c = resolve_classref_eager(cr)))
350                 return false;
351
352         PATCH_BACK_ORIGINAL_MCODE;
353
354         /* patch the classinfo pointer */
355
356         *((ptrint *) datap) = (ptrint) c;
357
358         return true;
359 }
360
361 /* patcher_resolve_classref_to_vftbl *******************************************
362
363    CHECKCAST (class):
364    INSTANCEOF (class):
365
366 *******************************************************************************/
367
368 bool patcher_resolve_classref_to_vftbl(patchref_t *pr)
369 {
370         constant_classref *cr;
371         u1                *datap;
372         classinfo         *c;
373
374         PATCHER_TRACE;
375
376         /* get stuff from the stack */
377
378         cr    = (constant_classref *) pr->ref;
379         datap = (u1 *)                pr->datap;
380
381         /* get the fieldinfo */
382
383         if (!(c = resolve_classref_eager(cr)))
384                 return false;
385
386         PATCH_BACK_ORIGINAL_MCODE;
387
388         /* patch super class' vftbl */
389
390         *((ptrint *) datap) = (ptrint) c->vftbl;
391
392         return true;
393 }
394
395 /* patcher_checkcast_instanceof_interface **************************************
396
397    Machine code:
398
399 *******************************************************************************/
400
401 bool patcher_checkcast_instanceof_interface(patchref_t *pr)
402 {
403
404         u1                *ra;
405         constant_classref *cr;
406         classinfo         *c;
407
408         PATCHER_TRACE;
409
410         /* get stuff from the stack */
411
412         ra    = (u1 *)                pr->mpc;
413         cr    = (constant_classref *) pr->ref;
414
415         /* get the fieldinfo */
416
417         if (!(c = resolve_classref_eager(cr)))
418                 return false;
419
420         /* patch back original code */
421
422         PATCH_BACK_ORIGINAL_MCODE;
423
424         /* If NOPs are generated, skip them */
425
426         if (opt_shownops)
427                 ra += PATCHER_NOPS_SKIP;
428
429         /* patch super class index */
430
431         /* From here, split your editor and open codegen.c */
432
433         switch (*(ra + 1) >> 4) {
434                 case REG_ITMP1: 
435                         /* First M_ALD is into ITMP1 */
436                         /* INSTANCEOF code */
437
438                         *(u4 *)(ra + SZ_L + SZ_L) |= (u2)(s2)(- c->index);
439                         *(u4 *)(ra + SZ_L + SZ_L + SZ_AHI + SZ_BRC) |=
440                                 (u2)(s2)(OFFSET(vftbl_t, interfacetable[0]) -
441                                         c->index * sizeof(methodptr*));
442
443                         break;
444
445                 case REG_ITMP2:
446                         /* First M_ALD is into ITMP2 */
447                         /* CHECKCAST code */
448
449                         *(u4 *)(ra + SZ_L + SZ_L) |= (u2)(s2)(- c->index);
450                         *(u4 *)(ra + SZ_L + SZ_L + SZ_AHI + SZ_BRC + SZ_ILL) |=
451                                 (u2)(s2)(OFFSET(vftbl_t, interfacetable[0]) -
452                                         c->index * sizeof(methodptr*));
453
454                         break;
455
456                 default:
457                         assert(0);
458                         break;
459         }
460
461         return true;
462 }
463
464 /* patcher_clinit **************************************************************
465
466    May be used for GET/PUTSTATIC and in native stub.
467
468    Machine code:
469
470 *******************************************************************************/
471
472 bool patcher_clinit(patchref_t *pr)
473 {
474         classinfo *c;
475
476         PATCHER_TRACE;
477
478         /* get stuff from the stack */
479
480         c     = (classinfo *)pr->ref;
481
482         /* check if the class is initialized */
483
484         if (!(c->state & CLASS_INITIALIZED))
485                 if (!initialize_class(c))
486                         return false;
487
488         /* patch back original code */
489
490         PATCH_BACK_ORIGINAL_MCODE;
491
492         return true;
493 }
494
495
496 /* patcher_athrow_areturn ******************************************************
497
498    Machine code:
499
500    <patched call position>
501
502 *******************************************************************************/
503
504 #ifdef ENABLE_VERIFIER
505 bool patcher_athrow_areturn(patchref_t *pr)
506 {
507         unresolved_class *uc;
508
509         PATCHER_TRACE;
510
511         /* get stuff from the stack */
512
513         uc    = (unresolved_class *) pr->ref;
514
515         /* resolve the class and check subtype constraints */
516
517         if (!resolve_class_eager_no_access_check(uc))
518                 return false;
519
520         /* patch back original code */
521
522         PATCH_BACK_ORIGINAL_MCODE;
523
524         return true;
525 }
526 #endif /* ENABLE_VERIFIER */
527
528
529 /* patcher_resolve_native ******************************************************
530
531 *******************************************************************************/
532
533 #if !defined(WITH_STATIC_CLASSPATH)
534 bool patcher_resolve_native_function(patchref_t *pr)
535 {
536         methodinfo  *m;
537         u1          *datap;
538         functionptr  f;
539
540         PATCHER_TRACE;
541
542         /* get stuff from the stack */
543
544         m     = (methodinfo *) pr->ref;
545         datap = (u1 *)         pr->datap;
546
547         /* resolve native function */
548
549         if (!(f = native_resolve_function(m)))
550                 return false;
551
552         PATCH_BACK_ORIGINAL_MCODE;
553
554         /* patch native function pointer */
555
556         *((ptrint *) datap) = (ptrint) f;
557
558         return true;
559 }
560 #endif /* !defined(WITH_STATIC_CLASSPATH) */
561
562 /*
563  * These are local overrides for various environment variables in Emacs.
564  * Please do not remove this and leave it at the end of the file, where
565  * Emacs will automagically detect them.
566  * ---------------------------------------------------------------------
567  * Local variables:
568  * mode: c
569  * indent-tabs-mode: t
570  * c-basic-offset: 4
571  * tab-width: 4
572  * End:
573  * vim:noexpandtab:sw=4:ts=4:
574  */