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