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