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