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"
47 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
48 #include "vmcore/options.h" /* XXX debug */
49 #include "vm/jit/disass.h" /* XXX debug */
52 #include "vm/jit/codegen-common.h"
53 #include "vm/jit/s390/codegen.h"
54 #include "vm/jit/s390/md.h"
57 /* prototypes *****************************************************************/
59 u1 *exceptions_handle_exception(java_object_t *xptro, u1 *xpc, u1 *pv, u1 *sp);
61 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p);
63 void md_dump_context(u1 *pc, mcontext_t *mc);
65 /* md_init *********************************************************************
67 Do some machine dependent initialization.
69 *******************************************************************************/
75 /* md_dump_context ************************************************************
77 Logs the machine context
79 *******************************************************************************/
81 void md_dump_context(u1 *pc, mcontext_t *mc) {
91 log_println("Dumping context.");
93 log_println("Program counter: 0x%08X", pc);
95 pv = methodtree_find_nocheck(pc);
98 log_println("No java method found at location.");
100 m = (*(codeinfo **)(pv + CodeinfoPointer))->m;
102 "Java method: class %s, method %s, descriptor %s.",
103 m->class->name->text, m->name->text, m->descriptor->text
107 #if defined(ENABLE_DISASSEMBLER)
108 log_println("Printing instruction at program counter:");
112 log_println("General purpose registers:");
114 for (i = 0; i < 16; i++) {
115 log_println("\tr%d:\t0x%08X\t%d", i, mc->gregs[i], mc->gregs[i]);
118 log_println("Floating point registers:");
120 for (i = 0; i < 16; i++) {
121 freg.fr.d = mc->fpregs.fprs[i].d;
122 log_println("\tf%d\t0x%016llX\t(double)%e\t(float)%f", i, freg.l, freg.fr.d, freg.fr.f);
125 log_println("Dumping the current stacktrace:");
126 stacktrace_print_current();
129 /* md_signal_handler_sigsegv ***************************************************
131 NullPointerException signal handler for hardware null pointer
134 *******************************************************************************/
136 void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
150 _uc = (ucontext_t *) _p;
151 _mc = &_uc->uc_mcontext;
153 xpc = (u1 *)_mc->psw.addr;
155 /* Check opcodes and verify it is a null pointer exception */
157 switch (N_RX_GET_OPC(xpc)) {
160 case OPC_CL: /* array size check on NULL array */
161 base = N_RX_GET_BASE(xpc);
164 } else if (_mc->gregs[base] == 0) {
177 md_dump_context(xpc, _mc);
179 vm_abort("%s: segmentation fault at %p, aborting.", __FUNCTION__, xpc);
182 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
183 sp = (u1 *)_mc->gregs[REG_SP];
185 type = EXCEPTION_HARDWARE_NULLPOINTER;
188 /* Handle the type. */
190 p = signal_handle(type, val, pv, sp, ra, xpc, _p);
193 _mc->gregs[REG_ITMP3_XPTR] = (intptr_t) p;
194 _mc->gregs[REG_ITMP1_XPC] = (intptr_t) xpc;
195 _mc->psw.addr = (intptr_t) asm_handle_exception;
198 _mc->psw.addr = (intptr_t) xpc;
202 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p)
215 _uc = (ucontext_t *) _p;
216 _mc = &_uc->uc_mcontext;
217 xpc = ra = siginfo->si_addr;
219 /* Our trap instruction has the format: { 0x02, one_byte_of_data }. */
221 if ((siginfo->si_code == ILL_ILLOPC) && (N_RR_GET_OPC(xpc) == OPC_ILL)) {
223 /* bits 7-4 contain a register holding a value */
224 reg = N_ILL_GET_REG(xpc);
226 /* bits 3-0 designate the exception type */
227 type = N_ILL_GET_TYPE(xpc);
229 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
230 sp = (u1 *)_mc->gregs[REG_SP];
231 val = (ptrint)_mc->gregs[reg];
233 if (EXCEPTION_HARDWARE_COMPILER == type) {
234 /* The PV from the compiler stub is equal to the XPC. */
238 /* The return address in is REG_RA */
240 ra = (u1 *)_mc->gregs[REG_RA];
245 /* Handle the type. */
247 p = signal_handle(type, val, pv, sp, ra, xpc, _p);
249 if (EXCEPTION_HARDWARE_COMPILER == type) {
251 _mc->gregs[REG_ITMP3_XPTR] = (intptr_t) builtin_retrieve_exception();
252 _mc->gregs[REG_ITMP1_XPC] = (intptr_t) ra - 2;
253 _mc->gregs[REG_PV] = (intptr_t) md_codegen_get_pv_from_pc(ra);
254 _mc->psw.addr = (intptr_t) asm_handle_exception;
256 _mc->gregs[REG_PV] = (intptr_t) p;
257 _mc->psw.addr = (intptr_t) p;
261 _mc->gregs[REG_ITMP3_XPTR] = (intptr_t) p;
262 _mc->gregs[REG_ITMP1_XPC] = (intptr_t) xpc;
263 _mc->psw.addr = (intptr_t) asm_handle_exception;
266 _mc->psw.addr = (intptr_t) xpc;
271 md_dump_context(xpc, _mc);
273 vm_abort("%s: illegal instruction at %p, aborting.", __FUNCTION__, xpc);
277 /* md_signal_handler_sigfpe ****************************************************
279 ArithmeticException signal handler for hardware divide by zero
282 *******************************************************************************/
284 void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
298 _uc = (ucontext_t *) _p;
299 _mc = &_uc->uc_mcontext;
301 /* Instruction that raised signal */
302 xpc = siginfo->si_addr;
306 if (N_RR_GET_OPC(xpc) == OPC_DR) { /* DR */
308 r1 = N_RR_GET_REG1(xpc);
309 r2 = N_RR_GET_REG2(xpc);
312 (_mc->gregs[r1] == 0xFFFFFFFF) &&
313 (_mc->gregs[r1 + 1] == 0x80000000) &&
314 (_mc->gregs[r2] == 0xFFFFFFFF)
316 /* handle special case 0x80000000 / 0xFFFFFFFF that fails on hardware */
317 /* next instruction */
318 pc = (u1 *)_mc->psw.addr;
322 _mc->gregs[r1 + 1] = 0x80000000;
323 /* continue at next instruction */
324 _mc->psw.addr = (ptrint) pc;
328 else if (_mc->gregs[r2] == 0) {
331 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
332 sp = (u1 *)_mc->gregs[REG_SP];
335 type = EXCEPTION_HARDWARE_ARITHMETIC;
338 /* Handle the type. */
340 p = signal_handle(type, val, pv, sp, ra, xpc, _p);
342 _mc->gregs[REG_ITMP3_XPTR] = (intptr_t) p;
343 _mc->gregs[REG_ITMP1_XPC] = (intptr_t) xpc;
344 _mc->psw.addr = (intptr_t) asm_handle_exception;
350 /* Could not handle signal */
353 md_dump_context(xpc, _mc);
355 vm_abort("%s: floating point exception at %p, aborting.", __FUNCTION__, xpc);
359 /* md_signal_handler_sigusr2 ***************************************************
361 Signal handler for profiling sampling.
363 *******************************************************************************/
365 #if defined(ENABLE_THREADS)
366 void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
375 _uc = (ucontext_t *) _p;
376 _mc = &_uc->uc_mcontext;
378 /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
379 different to the ones in <ucontext.h>. */
381 pc = (u1 *) _mc->psw.addr;
388 #if defined(ENABLE_THREADS)
389 void md_critical_section_restart(ucontext_t *_uc)
395 _mc = &_uc->uc_mcontext;
397 pc = (u1 *)_mc->psw.addr;
399 npc = critical_find_restart_point(pc);
402 log_println("%s: pc=%p, npc=%p", __FUNCTION__, pc, npc);
403 _mc->psw.addr = (ptrint) npc;
409 /* md_jit_method_patch_address *************************************************
411 Gets the patch address of the currently compiled method. The offset
412 is extracted from the load instruction(s) before the jump and added
413 to the right base address (PV or REG_METHODPTR).
415 INVOKESTATIC/SPECIAL:
417 0x7748d7b2: a7 18 ff d4 lhi %r1,-44
419 0x7748d7b6: 58 d1 d0 00 l %r13,0(%r1,%r13)
421 0x7748d7ba: 0d ed basr %r14,%r13
426 0x7748d82a: 58 c0 20 00 l %r12,0(%r2)
428 0x7748d82e: 58 d0 c0 00 l %r13,0(%r12)
430 0x7748d832: 0d ed basr %r14,%r13
436 last 2 instructions the same as in invokevirtual
438 *******************************************************************************/
440 void *md_jit_method_patch_address(void* pv, void *ra, void *mptr)
445 void *pa; /* patch address */
447 /* go back to the load before the call instruction */
449 pc = ((uint8_t *) ra) - SZ_BCR - SZ_L;
451 /* get the base register of the load */
453 base = N_RX_GET_BASE(pc);
454 index = N_RX_GET_INDEX(pc);
456 /* check for the different calls */
460 /* INVOKESTATIC/SPECIAL */
464 /* the offset is in the load instruction */
465 offset = N_RX_GET_DISP(pc) + N_PV_OFFSET;
468 /* the offset is in the immediate load before the load */
469 offset = N_RI_GET_IMM(pc - SZ_L);
475 /* add the offset to the procedure vector */
477 pa = ((uint8_t *) pv) + offset;
482 /* INVOKEVIRTUAL/INTERFACE */
484 offset = N_RX_GET_DISP(pc);
486 /* return NULL if no mptr was specified (used for replacement) */
491 /* add offset to method pointer */
493 pa = (uint8_t *)mptr + offset;
497 /* catch any problems */
498 vm_abort("md_jit_method_patch_address");
506 /* md_patch_replacement_point **************************************************
508 Patch the given replacement point.
510 *******************************************************************************/
511 #if defined(ENABLE_REPLACEMENT)
512 void md_patch_replacement_point(u1 *pc, u1 *savedmcode, bool revert)
518 void md_handle_exception(int32_t *regs, int64_t *fregs, int32_t *out) {
536 xptr = *(uint8_t **)(regs + REG_ITMP3_XPTR);
537 xpc = *(uint8_t **)(regs + REG_ITMP1_XPC);
538 sp = *(uint8_t **)(regs + REG_SP);
541 /* initialize number of calle saved int regs to restore to 0 */
544 /* initialize number of calle saved flt regs to restore to 0 */
551 pv = methodtree_find(xpc);
553 handler = exceptions_handle_exception((java_object_t *)xptr, xpc, pv, sp);
555 if (handler == NULL) {
557 /* exception was not handled
558 * get values of calee saved registers and remove stack frame
561 /* read stuff from data segment */
563 framesize = *(int32_t *)(pv + FrameSize);
565 intsave = *(int32_t *)(pv + IntSave);
566 if (intsave > out[0]) {
570 fltsave = *(int32_t *)(pv + FltSave);
571 if (fltsave > out[1]) {
575 /* pointer to register save area */
577 savearea = (int64_t *)(sp + framesize - 8);
581 ra = *(uint8_t **)(sp + framesize - 8);
583 /* restore saved registers */
585 for (i = 0; i < intsave; ++i) {
587 reg = abi_registers_integer_saved[INT_SAV_CNT - 1 - i];
588 regs[reg] = *(int32_t *)(savearea);
591 for (i = 0; i < fltsave; ++i) {
593 reg = abi_registers_float_saved[FLT_SAV_CNT - 1 - i];
594 fregs[reg] = *savearea;
597 /* remove stack frame */
601 /* new xpc is call before return address */
608 } while (handler == NULL);
610 /* write new values for registers */
612 *(uint8_t **)(regs + REG_ITMP3_XPTR) = xptr;
613 *(uint8_t **)(regs + REG_ITMP1_XPC) = xpc;
614 *(uint8_t **)(regs + REG_SP) = sp;
615 *(uint8_t **)(regs + REG_PV) = pv - 0XFFC;
617 /* maybe leaf flag */
619 out[2] = (loops == 1);
623 * These are local overrides for various environment variables in Emacs.
624 * Please do not remove this and leave it at the end of the file, where
625 * Emacs will automagically detect them.
626 * ---------------------------------------------------------------------
629 * indent-tabs-mode: t
633 * vim:noexpandtab:sw=4:ts=4: