* 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 7839 2007-04-29 22:46:56Z pm $
32
33 */
34
35 #define _GNU_SOURCE
36
37 #include "config.h"
38
39 #include <assert.h>
40 #include <stdlib.h>
41 #include <ucontext.h>
42
43 #include "vm/jit/s390/md-abi.h"
44
45 #if defined(ENABLE_THREADS)
46 # include "threads/native/threads.h"
47 #endif
48
49 #include "vm/exceptions.h"
50 #include "vm/signallocal.h"
51 #include "vm/jit/asmpart.h"
52 #include "vm/jit/stacktrace.h"
53
54 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
55 #include "vmcore/options.h" /* XXX debug */
56 #include "vm/jit/disass.h" /* XXX debug */
57 #endif
58
59 #include "vm/jit/codegen-common.h"
60 #include "vm/jit/s390/codegen.h"
61
62 #include <assert.h>
63 #define OOPS() assert(0);
64
65 /* prototypes *****************************************************************/
66
67 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p);
68
69 /* md_init *********************************************************************
70
71    Do some machine dependent initialization.
72
73 *******************************************************************************/
74
75 void md_init(void)
76 {
77         struct sigaction act;
78         
79         act.sa_sigaction = md_signal_handler_sigill;
80         act.sa_flags     = SA_NODEFER | SA_SIGINFO;
81
82         if (sigaction(SIGILL, &act, NULL) == -1)        {
83                 vm_abort("%s: error registering SIGILL signal handler.", __FUNCTION__);
84         }
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                *pv;
100         u1                *sp;
101         u1                *ra;
102         u1                *xpc;
103         s4                 type;
104         ptrint             val;
105         java_objectheader *e;
106         s4                 base;
107         s4                 is_null;
108
109         _uc = (ucontext_t *) _p;
110         _mc = &_uc->uc_mcontext;
111
112         xpc = (u1 *)_mc->psw.addr;
113
114         /* Check opcodes and verify it is a null pointer exception */
115
116         switch (xpc[0]) {
117                 case 0x58: /* L */
118                 case 0x50: /* ST */
119                         base = (xpc[2] >> 4) & 0xF;
120                         if (base == 0) {
121                                 is_null = 1;
122                         } else if (_mc->gregs[base] == 0) {
123                                 is_null = 1;
124                         } else {
125                                 is_null = 0;
126                         }
127                         break;
128         }
129
130         if (! is_null) {
131                 vm_abort("%s: segmentation fault at %p, aborting.", __FUNCTION__, xpc);
132         }
133
134         pv = (u1 *)_mc->gregs[REG_PV];
135         sp = (u1 *)_mc->gregs[REG_SP];
136         ra = xpc;
137         type = EXCEPTION_HARDWARE_NULLPOINTER;
138         val = 0;
139
140         e = exceptions_new_hardware_exception(pv, sp, ra, xpc, type, val);
141
142         _mc->gregs[REG_ITMP2_XPC] = (ptrint) xpc;
143         _mc->gregs[REG_ITMP1_XPTR] = (ptrint) e;
144         _mc->psw.addr = (ptrint) asm_handle_exception;
145 }
146
147 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p) {
148         ucontext_t        *_uc;
149         mcontext_t        *_mc;
150         u1                *xpc;
151         u1                *ra;
152         u1                *pv;
153         u1                *sp;
154         s4                 type;
155         ptrint             val;
156         java_objectheader *e;
157         s4                 reg;
158
159         _uc = (ucontext_t *) _p;
160         _mc = &_uc->uc_mcontext;
161         xpc = ra = siginfo->si_addr;
162
163         /* Our trap instruction has the format: { 0x02, one_byte_of_data }. */
164
165         if ((siginfo->si_code == ILL_ILLOPC) && (xpc[0] == 0x02)) {
166
167                 /* bits 7-4 contain a register holding a value */
168                 reg = (xpc[1] >> 4) & 0xF;
169
170                 /* bits 3-0 designate the exception type */
171                 type = xpc[1] & 0xF;  
172
173                 pv = (u1 *)_mc->gregs[REG_PV];
174                 sp = (u1 *)_mc->gregs[REG_SP];
175                 val = (ptrint)_mc->gregs[reg];
176
177                 e = exceptions_new_hardware_exception(pv, sp, ra, xpc, type, val);
178
179                 _mc->gregs[REG_ITMP1_XPTR] = (ptrint)e;
180                 _mc->gregs[REG_ITMP2_XPC] = (ptrint)xpc;
181                 _mc->psw.addr = (ptrint) asm_handle_exception;
182
183         } else {
184                 vm_abort("%s: illegal instruction at %p, aborting.", __FUNCTION__, xpc);
185         }
186 }
187
188 /* md_signal_handler_sigfpe ****************************************************
189
190    ArithmeticException signal handler for hardware divide by zero
191    check.
192
193 *******************************************************************************/
194
195 void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
196 {
197         ucontext_t         *_uc;
198         mcontext_t         *_mc;
199         u1                 *pv;
200         u1                 *sp;
201         u1                 *ra;
202         u1                 *xpc;
203         u1                 *pc;
204         s4                  r1, r2;
205         s4                  type;
206         ptrint              val;
207         java_objectheader  *e;
208
209         _uc = (ucontext_t *) _p;
210         _mc = &_uc->uc_mcontext;
211
212         /* Instruction that raised signal */
213         xpc = siginfo->si_addr;
214
215         /* Check opcodes */
216
217         if (xpc[0] == 0x1D) { /* DR */
218
219                 r1 = (xpc[1] >> 4) & 0xF;
220                 r2 = xpc[1] & 0xF;
221
222                 if (
223                         (_mc->gregs[r1] == 0xFFFFFFFF) &&
224                         (_mc->gregs[r1 + 1] == 0x80000000) && 
225                         (_mc->gregs[r2] == 0xFFFFFFFF)
226                 ) {
227                         /* handle special case */
228                         /* next instruction */
229                         pc = (u1 *)_mc->psw.addr;
230                         /* reminder */
231                         _mc->gregs[r1] = 0;
232                         /* quotient */
233                         _mc->gregs[r1 + 1] = 0x80000000;
234                         /* continue at next instruction */
235                         _mc->psw.addr = (ptrint) pc;
236
237                         return;
238                 } else if (_mc->gregs[r2] == 0) {
239                         /* division by 0 */
240
241                         pv = (u1 *)_mc->gregs[REG_PV];
242                         sp = (u1 *)_mc->gregs[REG_SP];
243                         ra = xpc;
244
245                         type = EXCEPTION_HARDWARE_ARITHMETIC;
246                         val = 0;
247
248                         e = exceptions_new_hardware_exception(pv, sp, ra, xpc, type, val);
249
250                         _mc->gregs[REG_ITMP1_XPTR] = (ptrint)e;
251                         _mc->gregs[REG_ITMP2_XPC] = (ptrint)xpc;
252                         _mc->psw.addr = (ptrint) asm_handle_exception;
253
254                         return;
255                 }
256         }
257
258         /* Could not handle signal */
259
260         vm_abort("%s: floating point exception at %p, aborting.", __FUNCTION__, xpc);
261 }
262
263
264 /* md_signal_handler_sigusr2 ***************************************************
265
266    Signal handler for profiling sampling.
267
268 *******************************************************************************/
269
270 #if defined(ENABLE_THREADS)
271 void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
272 {
273         threadobject *t;
274         ucontext_t   *_uc;
275         mcontext_t   *_mc;
276         u1           *pc;
277
278         t = THREADOBJECT;
279
280         _uc = (ucontext_t *) _p;
281         _mc = &_uc->uc_mcontext;
282
283         /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
284            different to the ones in <ucontext.h>. */
285
286         pc = (u1 *) _mc->psw.addr;
287
288         t->pc = pc;
289 }
290 #endif
291
292
293 #if defined(ENABLE_THREADS)
294 void thread_restartcriticalsection(ucontext_t *_uc)
295 {
296         mcontext_t *_mc;
297         void       *pc;
298
299         _mc = &_uc->uc_mcontext;
300
301         pc = critical_find_restart_point((void *) _mc->psw.addr);
302
303         if (pc != NULL)
304                 _mc->psw.addr = (ptrint) pc;
305 }
306 #endif
307
308
309 /* md_codegen_patch_branch *****************************************************
310
311    Back-patches a branch instruction.
312
313 *******************************************************************************/
314
315 void md_codegen_patch_branch(codegendata *cd, s4 branchmpc, s4 targetmpc)
316 {
317
318         s4 *mcodeptr;
319         s4  disp;                           /* branch displacement                */
320
321         /* calculate the patch position */
322
323         mcodeptr = (s4 *) (cd->mcodebase + branchmpc);
324
325         /* Calculate the branch displacement. */
326
327         disp = targetmpc - branchmpc;
328         disp += 4; /* size of branch */
329         disp /= 2; /* specified in halfwords */
330
331         ASSERT_VALID_BRANCH(disp);      
332
333         /* patch the branch instruction before the mcodeptr */
334
335         mcodeptr[-1] |= (disp & 0xFFFF);
336 }
337
338
339 /* md_stacktrace_get_returnaddress *********************************************
340
341    Returns the return address of the current stackframe, specified by
342    the passed stack pointer and the stack frame size.
343
344 *******************************************************************************/
345
346 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
347 {
348         u1 *ra;
349
350         /* on S390 the return address is located on the top of the stackframe */
351
352         ra = *((u1 **) (sp + framesize - SIZEOF_VOID_P));
353
354         return ra;
355 }
356
357
358 /* md_get_method_patch_address *************************************************
359
360    Gets the patch address of the currently compiled method. The offset
361    is extracted from the load instruction(s) before the jump and added
362    to the right base address (PV or REG_METHODPTR).
363
364    INVOKESTATIC/SPECIAL:
365
366 0x7748d7b2:   a7 18 ff d4                      lhi      %r1,-44  
367 (load dseg offset)
368 0x7748d7b6:   58 d1 d0 00                      l        %r13,0(%r1,%r13)
369 (load pv)
370 0x7748d7ba:   0d ed                            basr     %r14,%r13
371 (jump to pv)
372
373    INVOKEVIRTUAL:
374
375 0x7748d82a:   58 c0 20 00                      l        %r12,0(%r2)
376 (load mptr)
377 0x7748d82e:   58 d0 c0 00                      l        %r13,0(%r12)
378 (load pv from mptr)
379 0x7748d832:   0d ed                            basr     %r14,%r13
380 (jump to pv)
381
382
383    INVOKEINTERFACE:
384
385 last 2 instructions the same as in invokevirtual
386
387 *******************************************************************************/
388
389 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
390 {
391         u1  base;
392         s4  offset;
393         u1 *pa;                             /* patch address                      */
394
395         /* go back to the load before the call instruction */
396
397         ra = ra - 2 /* sizeof bcr */ - 4 /* sizeof l */;
398
399         /* get the base register of the load */
400
401         base = ra[2] >> 4;
402
403         /* check for the different calls */
404
405         if (base == 0xd) { /* pv relative */
406                 /* INVOKESTATIC/SPECIAL */
407
408                 /* the offset is in the load before the load */
409
410                 offset = *((s2 *) (ra - 2));
411
412                 /* add the offset to the procedure vector */
413
414                 pa = sfi->pv + offset;
415         }
416         else if (base == 0xc) { /* mptr relative */
417                 /* INVOKEVIRTUAL/INTERFACE */
418
419                 offset = *((u2 *)(ra + 2)) & 0xFFF;
420
421                 /* add offset to method pointer */
422                 
423                 pa = mptr + offset;
424         }
425         else {
426                 /* catch any problems */
427                 assert(0); 
428         }
429
430         return pa;
431 }
432
433
434 /* md_codegen_get_pv_from_pc ***************************************************
435
436    On this architecture just a wrapper function to
437    codegen_get_pv_from_pc.
438
439 *******************************************************************************/
440
441 u1 *md_codegen_get_pv_from_pc(u1 *ra)
442 {
443         u1 *pv;
444
445         /* Get the start address of the function which contains this
446        address from the method table. */
447
448         pv = codegen_get_pv_from_pc(ra);
449
450         return pv;
451 }
452
453
454 /* md_cacheflush ***************************************************************
455
456    Calls the system's function to flush the instruction and data
457    cache.
458
459 *******************************************************************************/
460
461 void md_cacheflush(u1 *addr, s4 nbytes)
462 {
463         /* do nothing */
464 }
465
466
467 /* md_icacheflush **************************************************************
468
469    Calls the system's function to flush the instruction cache.
470
471 *******************************************************************************/
472
473 void md_icacheflush(u1 *addr, s4 nbytes)
474 {
475         /* do nothing */
476 }
477
478
479 /* md_dcacheflush **************************************************************
480
481    Calls the system's function to flush the data cache.
482
483 *******************************************************************************/
484
485 void md_dcacheflush(u1 *addr, s4 nbytes)
486 {
487         /* do nothing */
488 }
489
490
491 /* md_patch_replacement_point **************************************************
492
493    Patch the given replacement point.
494
495 *******************************************************************************/
496 #if 0
497 void md_patch_replacement_point(rplpoint *rp)
498 {
499     u8 mcode;
500
501         /* XXX this is probably unsafe! */
502
503         /* save the current machine code */
504         mcode = *(u8*)rp->pc;
505
506         /* write spinning instruction */
507         *(u2*)(rp->pc) = 0xebfe;
508
509         /* write 5th byte */
510         rp->pc[4] = (rp->mcode >> 32);
511
512         /* write first word */
513     *(u4*)(rp->pc) = (u4) rp->mcode;
514
515         /* store saved mcode */
516         rp->mcode = mcode;
517         
518 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
519         {
520                 u1* u1ptr = rp->pc;
521                 DISASSINSTR(u1ptr);
522                 fflush(stdout);
523         }
524 #endif
525                         
526     /* XXX if required asm_cacheflush(rp->pc,8); */
527 }
528 #endif
529 /*
530  * These are local overrides for various environment variables in Emacs.
531  * Please do not remove this and leave it at the end of the file, where
532  * Emacs will automagically detect them.
533  * ---------------------------------------------------------------------
534  * Local variables:
535  * mode: c
536  * indent-tabs-mode: t
537  * c-basic-offset: 4
538  * tab-width: 4
539  * End:
540  * vim:noexpandtab:sw=4:ts=4:
541  */