* src/vm/jit/s390/emit.c,
[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 7581 2007-03-26 07:23:16Z 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 #include "vm/jit/s390/codegen.h"
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         ASSERT_VALID_BRANCH(disp);      
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
249         ra = *((u1 **) (sp + framesize - SIZEOF_VOID_P));
250
251         return ra;
252 }
253
254
255 /* md_get_method_patch_address *************************************************
256
257    Gets the patch address of the currently compiled method. The offset
258    is extracted from the load instruction(s) before the jump and added
259    to the right base address (PV or REG_METHODPTR).
260
261    INVOKESTATIC/SPECIAL:
262
263 0x7748d7b2:   a7 18 ff d4                      lhi      %r1,-44  
264 (load dseg offset)
265 0x7748d7b6:   58 d1 d0 00                      l        %r13,0(%r1,%r13)
266 (load pv)
267 0x7748d7ba:   0d ed                            basr     %r14,%r13
268 (jump to pv)
269
270    INVOKEVIRTUAL:
271
272 0x7748d82a:   58 c0 20 00                      l        %r12,0(%r2)
273 (load mptr)
274 0x7748d82e:   58 d0 c0 00                      l        %r13,0(%r12)
275 (load pv from mptr)
276 0x7748d832:   0d ed                            basr     %r14,%r13
277 (jump to pv)
278
279
280    INVOKEINTERFACE:
281
282 last 2 instructions the same as in invokevirtual
283
284 *******************************************************************************/
285
286 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
287 {
288         u1  base;
289         s4  offset;
290         u1 *pa;                             /* patch address                      */
291
292         /* go back to the load before the call instruction */
293
294         ra = ra - 2 /* sizeof bcr */ - 4 /* sizeof l */;
295
296         /* get the base register of the load */
297
298         base = ra[2] >> 4;
299
300         /* check for the different calls */
301
302         if (base == 0xd) { /* pv relative */
303                 /* INVOKESTATIC/SPECIAL */
304
305                 /* the offset is in the load before the load */
306
307                 offset = *((s2 *) (ra - 2));
308
309                 /* add the offset to the procedure vector */
310
311                 pa = sfi->pv + offset;
312         }
313         else if (base == 0xc) { /* mptr relative */
314                 /* INVOKEVIRTUAL/INTERFACE */
315
316                 offset = *((u2 *)(ra + 2)) & 0xFFF;
317
318                 /* add offset to method pointer */
319                 
320                 pa = mptr + offset;
321         }
322         else {
323                 /* catch any problems */
324                 assert(0); 
325         }
326
327         return pa;
328 }
329
330
331 /* md_codegen_get_pv_from_pc ***************************************************
332
333    On this architecture just a wrapper function to
334    codegen_get_pv_from_pc.
335
336 *******************************************************************************/
337
338 u1 *md_codegen_get_pv_from_pc(u1 *ra)
339 {
340         u1 *pv;
341
342         /* Get the start address of the function which contains this
343        address from the method table. */
344
345         pv = codegen_get_pv_from_pc(ra);
346
347         return pv;
348 }
349
350
351 /* md_cacheflush ***************************************************************
352
353    Calls the system's function to flush the instruction and data
354    cache.
355
356 *******************************************************************************/
357
358 void md_cacheflush(u1 *addr, s4 nbytes)
359 {
360         /* do nothing */
361 }
362
363
364 /* md_icacheflush **************************************************************
365
366    Calls the system's function to flush the instruction cache.
367
368 *******************************************************************************/
369
370 void md_icacheflush(u1 *addr, s4 nbytes)
371 {
372         /* do nothing */
373 }
374
375
376 /* md_dcacheflush **************************************************************
377
378    Calls the system's function to flush the data cache.
379
380 *******************************************************************************/
381
382 void md_dcacheflush(u1 *addr, s4 nbytes)
383 {
384         /* do nothing */
385 }
386
387
388 /* md_patch_replacement_point **************************************************
389
390    Patch the given replacement point.
391
392 *******************************************************************************/
393 #if 0
394 void md_patch_replacement_point(rplpoint *rp)
395 {
396     u8 mcode;
397
398         /* XXX this is probably unsafe! */
399
400         /* save the current machine code */
401         mcode = *(u8*)rp->pc;
402
403         /* write spinning instruction */
404         *(u2*)(rp->pc) = 0xebfe;
405
406         /* write 5th byte */
407         rp->pc[4] = (rp->mcode >> 32);
408
409         /* write first word */
410     *(u4*)(rp->pc) = (u4) rp->mcode;
411
412         /* store saved mcode */
413         rp->mcode = mcode;
414         
415 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
416         {
417                 u1* u1ptr = rp->pc;
418                 DISASSINSTR(u1ptr);
419                 fflush(stdout);
420         }
421 #endif
422                         
423     /* XXX if required asm_cacheflush(rp->pc,8); */
424 }
425 #endif
426 /*
427  * These are local overrides for various environment variables in Emacs.
428  * Please do not remove this and leave it at the end of the file, where
429  * Emacs will automagically detect them.
430  * ---------------------------------------------------------------------
431  * Local variables:
432  * mode: c
433  * indent-tabs-mode: t
434  * c-basic-offset: 4
435  * tab-width: 4
436  * End:
437  * vim:noexpandtab:sw=4:ts=4:
438  */