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