1a3e1ba637e9391fecb39b81b1cf310f988c5c0b
[cacao.git] / src / vm / jit / s390 / md.c
1 /* src/vm/jit/x86_64/md.c - machine dependent x86_64 Linux 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: Edwin Steiner
30
31    $Id: md.c 7534 2007-03-16 23:00:18Z pm $
32
33 */
34
35 #define REG_RSP 0
36 #define REG_RIP 0
37 #define REG_RAX 0
38 #define REG_R10 0
39 #define REG_RIP 0
40 #define REG_RSP 0
41 #define REG_RIP 0
42 #define REG_RAX 0
43 #define REG_R10 0
44 #define REG_RIP 0
45
46
47 #define _GNU_SOURCE
48
49 #include "config.h"
50
51 #include <assert.h>
52 #include <stdlib.h>
53 #include <ucontext.h>
54
55 #include "vm/jit/s390/md-abi.h"
56
57 #if defined(ENABLE_THREADS)
58 # include "threads/native/threads.h"
59 #endif
60
61 #include "vm/exceptions.h"
62 #include "vm/signallocal.h"
63 #include "vm/jit/asmpart.h"
64 #include "vm/jit/stacktrace.h"
65
66 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
67 #include "vmcore/options.h" /* XXX debug */
68 #include "vm/jit/disass.h" /* XXX debug */
69 #endif
70
71 #include "vm/jit/codegen-common.h"
72
73 #include <assert.h>
74 #define OOPS() assert(0);
75
76 /* md_init *********************************************************************
77
78    Do some machine dependent initialization.
79
80 *******************************************************************************/
81
82 void md_init(void)
83 {
84         /* nothing to do */
85 }
86
87
88 /* md_signal_handler_sigsegv ***************************************************
89
90    NullPointerException signal handler for hardware null pointer
91    check.
92
93 *******************************************************************************/
94
95 void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
96 {
97         ucontext_t *_uc;
98         mcontext_t *_mc;
99         u1         *sp;
100         u1         *ra;
101         u1         *xpc;
102
103         _uc = (ucontext_t *) _p;
104         _mc = &_uc->uc_mcontext;
105
106         /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
107            different to the ones in <ucontext.h>. */
108
109         sp  = (u1 *) _mc->gregs[REG_RSP];
110         xpc = (u1 *) _mc->gregs[REG_RIP];
111         ra  = xpc;                          /* return address is equal to xpc     */
112
113 #if 0
114         /* check for StackOverflowException */
115
116         threads_check_stackoverflow(sp);
117 #endif
118
119         _mc->gregs[REG_RAX] =
120                 (ptrint) stacktrace_hardware_nullpointerexception(NULL, sp, ra, xpc);
121
122         _mc->gregs[REG_R10] = (ptrint) xpc;                      /* REG_ITMP2_XPC */
123         _mc->gregs[REG_RIP] = (ptrint) asm_handle_exception;
124 }
125
126
127 /* md_signal_handler_sigfpe ****************************************************
128
129    ArithmeticException signal handler for hardware divide by zero
130    check.
131
132 *******************************************************************************/
133
134 void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
135 {
136         ucontext_t  *_uc;
137         mcontext_t  *_mc;
138         u1          *sp;
139         u1          *ra;
140         u1          *xpc;
141
142         _uc = (ucontext_t *) _p;
143         _mc = &_uc->uc_mcontext;
144
145         /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
146            different to the ones in <ucontext.h>. */
147
148         sp  = (u1 *) _mc->gregs[REG_RSP];
149         xpc = (u1 *) _mc->gregs[REG_RIP];
150         ra  = xpc;                          /* return address is equal to xpc     */
151
152         _mc->gregs[REG_RAX] =
153                 (ptrint) stacktrace_hardware_arithmeticexception(NULL, sp, ra, xpc);
154
155         _mc->gregs[REG_R10] = (ptrint) xpc;                      /* REG_ITMP2_XPC */
156         _mc->gregs[REG_RIP] = (ptrint) asm_handle_exception;
157 }
158
159
160 /* md_signal_handler_sigusr2 ***************************************************
161
162    Signal handler for profiling sampling.
163
164 *******************************************************************************/
165
166 #if defined(ENABLE_THREADS)
167 void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
168 {
169         threadobject *t;
170         ucontext_t   *_uc;
171         mcontext_t   *_mc;
172         u1           *pc;
173
174         t = THREADOBJECT;
175
176         _uc = (ucontext_t *) _p;
177         _mc = &_uc->uc_mcontext;
178
179         /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
180            different to the ones in <ucontext.h>. */
181
182         pc = (u1 *) _mc->gregs[REG_RIP];
183
184         t->pc = pc;
185 }
186 #endif
187
188
189 #if defined(ENABLE_THREADS)
190 void thread_restartcriticalsection(ucontext_t *_uc)
191 {
192         mcontext_t *_mc;
193         void       *pc;
194
195         _mc = &_uc->uc_mcontext;
196
197         pc = critical_find_restart_point((void *) _mc->gregs[REG_RIP]);
198
199         if (pc != NULL)
200                 _mc->gregs[REG_RIP] = (ptrint) pc;
201 }
202 #endif
203
204
205 /* md_codegen_patch_branch *****************************************************
206
207    Back-patches a branch instruction.
208
209 *******************************************************************************/
210
211 void md_codegen_patch_branch(codegendata *cd, s4 branchmpc, s4 targetmpc)
212 {
213
214         s4 *mcodeptr;
215         s4  disp;                           /* branch displacement                */
216
217         /* calculate the patch position */
218
219         mcodeptr = (s4 *) (cd->mcodebase + branchmpc);
220
221         /* Calculate the branch displacement. */
222
223         disp = targetmpc - branchmpc;
224         disp += 4; /* size of branch */
225         disp /= 2; /* specified in halfwords */
226
227         /* TODO check for overflow */
228
229         /* patch the branch instruction before the mcodeptr */
230
231         mcodeptr[-1] |= (disp & 0xFFFF);
232 }
233
234
235 /* md_stacktrace_get_returnaddress *********************************************
236
237    Returns the return address of the current stackframe, specified by
238    the passed stack pointer and the stack frame size.
239
240 *******************************************************************************/
241
242 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
243 {
244         u1 *ra;
245
246         /* on S390 the return address is located on the top of the stackframe */
247
248         ra = *((u1 **) (sp + framesize - SIZEOF_VOID_P));
249
250         return ra;
251 }
252
253
254 /* md_get_method_patch_address *************************************************
255
256    Gets the patch address of the currently compiled method. The offset
257    is extracted from the load instruction(s) before the jump and added
258    to the right base address (PV or REG_METHODPTR).
259
260    INVOKESTATIC/SPECIAL:
261
262 0x7748d7b2:   a7 18 ff d4                      lhi      %r1,-44  
263 (load dseg offset)
264 0x7748d7b6:   58 d1 d0 00                      l        %r13,0(%r1,%r13)
265 (load pv)
266 0x7748d7ba:   0d ed                            basr     %r14,%r13
267 (jump to pv)
268
269    INVOKEVIRTUAL:
270
271 0x7748d82a:   58 c0 20 00                      l        %r12,0(%r2)
272 (load mptr)
273 0x7748d82e:   58 d0 c0 00                      l        %r13,0(%r12)
274 (load pv from mptr)
275 0x7748d832:   0d ed                            basr     %r14,%r13
276 (jump to pv)
277
278
279    INVOKEINTERFACE:
280
281 last 2 instructions the same as in invokevirtual
282
283 *******************************************************************************/
284
285 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
286 {
287         u1  base;
288         s4  offset;
289         u1 *pa;                             /* patch address                      */
290
291         /* go back to the load before the call instruction */
292
293         ra = ra - 2 /* sizeof bcr */ - 4 /* sizeof l */;
294
295         /* get the base register of the load */
296
297         base = ra[2] >> 4;
298
299         /* check for the different calls */
300
301         if (base == 0xd) { /* pv relative */
302                 /* INVOKESTATIC/SPECIAL */
303
304                 /* the offset is in the load before the load */
305
306                 offset = *((s2 *) (ra - 2));
307
308                 /* add the offset to the procedure vector */
309
310                 pa = sfi->pv + offset;
311         }
312         else if (base == 0xc) { /* mptr relative */
313                 /* INVOKEVIRTUAL/INTERFACE */
314
315                 offset = *((u2 *)(ra + 2)) & 0xFFF;
316
317                 /* add offset to method pointer */
318                 
319                 pa = mptr + offset;
320         }
321         else {
322                 /* catch any problems */
323                 assert(0); 
324         }
325
326         return pa;
327 }
328
329
330 /* md_codegen_get_pv_from_pc ***************************************************
331
332    On this architecture just a wrapper function to
333    codegen_get_pv_from_pc.
334
335 *******************************************************************************/
336
337 u1 *md_codegen_get_pv_from_pc(u1 *ra)
338 {
339         u1 *pv;
340
341         /* Get the start address of the function which contains this
342        address from the method table. */
343
344         pv = codegen_get_pv_from_pc(ra);
345
346         return pv;
347 }
348
349
350 /* md_cacheflush ***************************************************************
351
352    Calls the system's function to flush the instruction and data
353    cache.
354
355 *******************************************************************************/
356
357 void md_cacheflush(u1 *addr, s4 nbytes)
358 {
359         /* do nothing */
360 }
361
362
363 /* md_icacheflush **************************************************************
364
365    Calls the system's function to flush the instruction cache.
366
367 *******************************************************************************/
368
369 void md_icacheflush(u1 *addr, s4 nbytes)
370 {
371         /* do nothing */
372 }
373
374
375 /* md_dcacheflush **************************************************************
376
377    Calls the system's function to flush the data cache.
378
379 *******************************************************************************/
380
381 void md_dcacheflush(u1 *addr, s4 nbytes)
382 {
383         /* do nothing */
384 }
385
386
387 /* md_patch_replacement_point **************************************************
388
389    Patch the given replacement point.
390
391 *******************************************************************************/
392 #if 0
393 void md_patch_replacement_point(rplpoint *rp)
394 {
395     u8 mcode;
396
397         /* XXX this is probably unsafe! */
398
399         /* save the current machine code */
400         mcode = *(u8*)rp->pc;
401
402         /* write spinning instruction */
403         *(u2*)(rp->pc) = 0xebfe;
404
405         /* write 5th byte */
406         rp->pc[4] = (rp->mcode >> 32);
407
408         /* write first word */
409     *(u4*)(rp->pc) = (u4) rp->mcode;
410
411         /* store saved mcode */
412         rp->mcode = mcode;
413         
414 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
415         {
416                 u1* u1ptr = rp->pc;
417                 DISASSINSTR(u1ptr);
418                 fflush(stdout);
419         }
420 #endif
421                         
422     /* XXX if required asm_cacheflush(rp->pc,8); */
423 }
424 #endif
425 /*
426  * These are local overrides for various environment variables in Emacs.
427  * Please do not remove this and leave it at the end of the file, where
428  * Emacs will automagically detect them.
429  * ---------------------------------------------------------------------
430  * Local variables:
431  * mode: c
432  * indent-tabs-mode: t
433  * c-basic-offset: 4
434  * tab-width: 4
435  * End:
436  * vim:noexpandtab:sw=4:ts=4:
437  */