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