1 /* src/vm/jit/s390/md.c - machine dependent s390 Linux functions
3 Copyright (C) 2006, 2007, 2008
4 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
6 This file is part of CACAO.
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.
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.
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
35 #include "vm/jit/s390/md-abi.h"
37 #include "threads/thread.h"
39 #include "vm/exceptions.h"
40 #include "vm/signallocal.h"
41 #include "vm/jit/asmpart.h"
42 #include "vm/jit/abi.h"
43 #include "vm/jit/methodheader.h"
44 #include "vm/jit/methodtree.h"
45 #include "vm/jit/stacktrace.h"
46 #include "vm/jit/trap.h"
48 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
49 #include "vmcore/options.h" /* XXX debug */
50 #include "vm/jit/disass.h" /* XXX debug */
53 #include "vm/jit/codegen-common.h"
54 #include "vm/jit/s390/codegen.h"
55 #include "vm/jit/s390/md.h"
58 /* prototypes *****************************************************************/
60 u1 *exceptions_handle_exception(java_object_t *xptro, u1 *xpc, u1 *pv, u1 *sp);
62 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p);
64 void md_dump_context(u1 *pc, mcontext_t *mc);
66 /* md_init *********************************************************************
68 Do some machine dependent initialization.
70 *******************************************************************************/
76 /* md_dump_context ************************************************************
78 Logs the machine context
80 *******************************************************************************/
82 void md_dump_context(u1 *pc, mcontext_t *mc) {
92 log_println("Dumping context.");
94 log_println("Program counter: 0x%08X", pc);
96 pv = methodtree_find_nocheck(pc);
99 log_println("No java method found at location.");
101 m = (*(codeinfo **)(pv + CodeinfoPointer))->m;
103 "Java method: class %s, method %s, descriptor %s.",
104 m->clazz->name->text, m->name->text, m->descriptor->text
108 #if defined(ENABLE_DISASSEMBLER)
109 log_println("Printing instruction at program counter:");
113 log_println("General purpose registers:");
115 for (i = 0; i < 16; i++) {
116 log_println("\tr%d:\t0x%08X\t%d", i, mc->gregs[i], mc->gregs[i]);
119 log_println("Floating point registers:");
121 for (i = 0; i < 16; i++) {
122 freg.fr.d = mc->fpregs.fprs[i].d;
123 log_println("\tf%d\t0x%016llX\t(double)%e\t(float)%f", i, freg.l, freg.fr.d, freg.fr.f);
126 log_println("Dumping the current stacktrace:");
127 stacktrace_print_current();
130 /* md_signal_handler_sigsegv ***************************************************
132 NullPointerException signal handler for hardware null pointer
135 *******************************************************************************/
137 void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
151 _uc = (ucontext_t *) _p;
152 _mc = &_uc->uc_mcontext;
154 xpc = (u1 *)_mc->psw.addr;
156 /* Check opcodes and verify it is a null pointer exception */
158 switch (N_RX_GET_OPC(xpc)) {
161 case OPC_CL: /* array size check on NULL array */
162 base = N_RX_GET_BASE(xpc);
165 } else if (_mc->gregs[base] == 0) {
178 md_dump_context(xpc, _mc);
180 vm_abort("%s: segmentation fault at %p, aborting.", __FUNCTION__, xpc);
183 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
184 sp = (u1 *)_mc->gregs[REG_SP];
186 type = TRAP_NullPointerException;
189 /* Handle the trap. */
191 p = trap_handle(type, val, pv, sp, ra, xpc, _p);
194 _mc->gregs[REG_ITMP3_XPTR] = (uintptr_t) p;
195 _mc->gregs[REG_ITMP1_XPC] = (uintptr_t) xpc;
196 _mc->psw.addr = (uintptr_t) asm_handle_exception;
199 _mc->psw.addr = (uintptr_t) xpc;
203 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p)
216 _uc = (ucontext_t *) _p;
217 _mc = &_uc->uc_mcontext;
218 xpc = ra = siginfo->si_addr;
220 /* Our trap instruction has the format: { 0x02, one_byte_of_data }. */
222 if ((siginfo->si_code == ILL_ILLOPC) && (N_RR_GET_OPC(xpc) == OPC_ILL)) {
224 /* bits 7-4 contain a register holding a value */
225 reg = N_ILL_GET_REG(xpc);
227 /* bits 3-0 designate the exception type */
228 type = N_ILL_GET_TYPE(xpc);
230 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
231 sp = (u1 *)_mc->gregs[REG_SP];
232 val = (ptrint)_mc->gregs[reg];
234 if (TRAP_COMPILER == type) {
235 /* The PV from the compiler stub is equal to the XPC. */
239 /* The return address in is REG_RA */
241 ra = (u1 *)_mc->gregs[REG_RA];
246 /* Handle the trap. */
248 p = trap_handle(type, val, pv, sp, ra, xpc, _p);
250 if (TRAP_COMPILER == type) {
252 _mc->gregs[REG_ITMP3_XPTR] = (uintptr_t) builtin_retrieve_exception();
253 _mc->gregs[REG_ITMP1_XPC] = (uintptr_t) ra - 2;
254 _mc->gregs[REG_PV] = (uintptr_t) md_codegen_get_pv_from_pc(ra);
255 _mc->psw.addr = (uintptr_t) asm_handle_exception;
257 _mc->gregs[REG_PV] = (uintptr_t) p;
258 _mc->psw.addr = (uintptr_t) p;
262 _mc->gregs[REG_ITMP3_XPTR] = (uintptr_t) p;
263 _mc->gregs[REG_ITMP1_XPC] = (uintptr_t) xpc;
264 _mc->psw.addr = (uintptr_t) asm_handle_exception;
267 _mc->psw.addr = (uintptr_t) xpc;
272 md_dump_context(xpc, _mc);
274 vm_abort("%s: illegal instruction at %p, aborting.", __FUNCTION__, xpc);
278 /* md_signal_handler_sigfpe ****************************************************
280 ArithmeticException signal handler for hardware divide by zero
283 *******************************************************************************/
285 void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
299 _uc = (ucontext_t *) _p;
300 _mc = &_uc->uc_mcontext;
302 /* Instruction that raised signal */
303 xpc = siginfo->si_addr;
307 if (N_RR_GET_OPC(xpc) == OPC_DR) { /* DR */
309 r1 = N_RR_GET_REG1(xpc);
310 r2 = N_RR_GET_REG2(xpc);
313 (_mc->gregs[r1] == 0xFFFFFFFF) &&
314 (_mc->gregs[r1 + 1] == 0x80000000) &&
315 (_mc->gregs[r2] == 0xFFFFFFFF)
317 /* handle special case 0x80000000 / 0xFFFFFFFF that fails on hardware */
318 /* next instruction */
319 pc = (u1 *)_mc->psw.addr;
323 _mc->gregs[r1 + 1] = 0x80000000;
324 /* continue at next instruction */
325 _mc->psw.addr = (ptrint) pc;
329 else if (_mc->gregs[r2] == 0) {
332 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
333 sp = (u1 *)_mc->gregs[REG_SP];
336 type = TRAP_ArithmeticException;
339 /* Handle the trap. */
341 p = trap_handle(type, val, pv, sp, ra, xpc, _p);
343 _mc->gregs[REG_ITMP3_XPTR] = (uintptr_t) p;
344 _mc->gregs[REG_ITMP1_XPC] = (uintptr_t) xpc;
345 _mc->psw.addr = (uintptr_t) asm_handle_exception;
351 /* Could not handle signal */
354 md_dump_context(xpc, _mc);
356 vm_abort("%s: floating point exception at %p, aborting.", __FUNCTION__, xpc);
360 /* md_signal_handler_sigusr2 ***************************************************
362 Signal handler for profiling sampling.
364 *******************************************************************************/
366 #if defined(ENABLE_THREADS)
367 void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
376 _uc = (ucontext_t *) _p;
377 _mc = &_uc->uc_mcontext;
379 /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
380 different to the ones in <ucontext.h>. */
382 pc = (u1 *) _mc->psw.addr;
389 #if defined(ENABLE_THREADS)
390 void md_critical_section_restart(ucontext_t *_uc)
396 _mc = &_uc->uc_mcontext;
398 pc = (u1 *)_mc->psw.addr;
400 npc = critical_find_restart_point(pc);
403 log_println("%s: pc=%p, npc=%p", __FUNCTION__, pc, npc);
404 _mc->psw.addr = (ptrint) npc;
410 /* md_jit_method_patch_address *************************************************
412 Gets the patch address of the currently compiled method. The offset
413 is extracted from the load instruction(s) before the jump and added
414 to the right base address (PV or REG_METHODPTR).
416 INVOKESTATIC/SPECIAL:
418 0x7748d7b2: a7 18 ff d4 lhi %r1,-44
420 0x7748d7b6: 58 d1 d0 00 l %r13,0(%r1,%r13)
422 0x7748d7ba: 0d ed basr %r14,%r13
427 0x7748d82a: 58 c0 20 00 l %r12,0(%r2)
429 0x7748d82e: 58 d0 c0 00 l %r13,0(%r12)
431 0x7748d832: 0d ed basr %r14,%r13
437 last 2 instructions the same as in invokevirtual
439 *******************************************************************************/
441 void *md_jit_method_patch_address(void* pv, void *ra, void *mptr)
446 void *pa; /* patch address */
448 /* go back to the load before the call instruction */
450 pc = ((uint8_t *) ra) - SZ_BCR - SZ_L;
452 /* get the base register of the load */
454 base = N_RX_GET_BASE(pc);
455 index = N_RX_GET_INDEX(pc);
457 /* check for the different calls */
461 /* INVOKESTATIC/SPECIAL */
465 /* the offset is in the load instruction */
466 offset = N_RX_GET_DISP(pc) + N_PV_OFFSET;
469 /* the offset is in the immediate load before the load */
470 offset = N_RI_GET_IMM(pc - SZ_L);
476 /* add the offset to the procedure vector */
478 pa = ((uint8_t *) pv) + offset;
483 /* INVOKEVIRTUAL/INTERFACE */
485 offset = N_RX_GET_DISP(pc);
487 /* return NULL if no mptr was specified (used for replacement) */
492 /* add offset to method pointer */
494 pa = (uint8_t *)mptr + offset;
498 /* catch any problems */
499 vm_abort("md_jit_method_patch_address");
507 /* md_patch_replacement_point **************************************************
509 Patch the given replacement point.
511 *******************************************************************************/
512 #if defined(ENABLE_REPLACEMENT)
513 void md_patch_replacement_point(u1 *pc, u1 *savedmcode, bool revert)
519 void md_handle_exception(int32_t *regs, int64_t *fregs, int32_t *out) {
537 xptr = *(uint8_t **)(regs + REG_ITMP3_XPTR);
538 xpc = *(uint8_t **)(regs + REG_ITMP1_XPC);
539 sp = *(uint8_t **)(regs + REG_SP);
542 /* initialize number of calle saved int regs to restore to 0 */
545 /* initialize number of calle saved flt regs to restore to 0 */
552 pv = methodtree_find(xpc);
554 handler = exceptions_handle_exception((java_object_t *)xptr, xpc, pv, sp);
556 if (handler == NULL) {
558 /* exception was not handled
559 * get values of calee saved registers and remove stack frame
562 /* read stuff from data segment */
564 framesize = *(int32_t *)(pv + FrameSize);
566 intsave = *(int32_t *)(pv + IntSave);
567 if (intsave > out[0]) {
571 fltsave = *(int32_t *)(pv + FltSave);
572 if (fltsave > out[1]) {
576 /* pointer to register save area */
578 savearea = (int64_t *)(sp + framesize - 8);
582 ra = *(uint8_t **)(sp + framesize - 8);
584 /* restore saved registers */
586 for (i = 0; i < intsave; ++i) {
588 reg = abi_registers_integer_saved[INT_SAV_CNT - 1 - i];
589 regs[reg] = *(int32_t *)(savearea);
592 for (i = 0; i < fltsave; ++i) {
594 reg = abi_registers_float_saved[FLT_SAV_CNT - 1 - i];
595 fregs[reg] = *savearea;
598 /* remove stack frame */
602 /* new xpc is call before return address */
609 } while (handler == NULL);
611 /* write new values for registers */
613 *(uint8_t **)(regs + REG_ITMP3_XPTR) = xptr;
614 *(uint8_t **)(regs + REG_ITMP1_XPC) = xpc;
615 *(uint8_t **)(regs + REG_SP) = sp;
616 *(uint8_t **)(regs + REG_PV) = pv - 0XFFC;
618 /* maybe leaf flag */
620 out[2] = (loops == 1);
624 * These are local overrides for various environment variables in Emacs.
625 * Please do not remove this and leave it at the end of the file, where
626 * Emacs will automagically detect them.
627 * ---------------------------------------------------------------------
630 * indent-tabs-mode: t
634 * vim:noexpandtab:sw=4:ts=4: