1 /* src/vm/jit/s390/md.c - machine dependent s390 Linux functions
3 Copyright (C) 2006, 2007 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
8 This file is part of CACAO.
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.
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.
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
37 #include "vm/jit/s390/md-abi.h"
39 #if defined(ENABLE_THREADS)
40 # include "threads/threads-common.h"
41 # include "threads/native/threads.h"
44 #include "vm/exceptions.h"
45 #include "vm/signallocal.h"
46 #include "vm/jit/asmpart.h"
47 #include "vm/jit/abi.h"
48 #include "vm/jit/methodheader.h"
49 #include "vm/jit/stacktrace.h"
51 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
52 #include "vmcore/options.h" /* XXX debug */
53 #include "vm/jit/disass.h" /* XXX debug */
56 #include "vm/jit/codegen-common.h"
57 #include "vm/jit/s390/codegen.h"
61 /* prototypes *****************************************************************/
63 u1 *exceptions_handle_exception(java_object_t *xptro, u1 *xpc, u1 *pv, u1 *sp);
65 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p);
67 void md_dump_context(u1 *pc, mcontext_t *mc);
69 /* md_init *********************************************************************
71 Do some machine dependent initialization.
73 *******************************************************************************/
79 /* md_dump_context ************************************************************
81 Logs the machine context
83 *******************************************************************************/
85 void md_dump_context(u1 *pc, mcontext_t *mc) {
95 log_println("Dumping context.");
97 log_println("Program counter: 0x%08X", pc);
99 pv = codegen_get_pv_from_pc_nocheck(pc);
101 log_println("No java method found at location.");
103 m = (*(codeinfo **)(pv + CodeinfoPointer))->m;
105 "Java method: class %s, method %s, descriptor %s.",
106 m->class->name->text, m->name->text, m->descriptor->text
110 #if defined(ENABLE_DISASSEMBLER)
111 log_println("Printing instruction at program counter:");
115 log_println("General purpose registers:");
117 for (i = 0; i < 16; i++) {
118 log_println("\tr%d:\t0x%08X\t%d", i, mc->gregs[i], mc->gregs[i]);
121 log_println("Floating point registers:");
123 for (i = 0; i < 16; i++) {
124 freg.fr.d = mc->fpregs.fprs[i].d;
125 log_println("\tf%d\t0x%016llX\t(double)%e\t(float)%f", i, freg.l, freg.fr.d, freg.fr.f);
128 #if defined(ENABLE_THREADS)
129 log_println("Dumping the current stacktrace:");
130 threads_print_stacktrace();
135 /* md_signal_handler_sigsegv ***************************************************
137 NullPointerException signal handler for hardware null pointer
140 *******************************************************************************/
142 void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
156 _uc = (ucontext_t *) _p;
157 _mc = &_uc->uc_mcontext;
159 xpc = (u1 *)_mc->psw.addr;
161 /* Check opcodes and verify it is a null pointer exception */
163 switch (N_RX_GET_OPC(xpc)) {
166 case OPC_CL: /* array size check on NULL array */
167 base = N_RX_GET_BASE(xpc);
170 } else if (_mc->gregs[base] == 0) {
183 md_dump_context(xpc, _mc);
185 vm_abort("%s: segmentation fault at %p, aborting.", __FUNCTION__, xpc);
188 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
189 sp = (u1 *)_mc->gregs[REG_SP];
191 type = EXCEPTION_HARDWARE_NULLPOINTER;
194 /* Handle the type. */
196 p = signal_handle(type, val, pv, sp, ra, xpc, _p);
199 _mc->gregs[REG_ITMP3_XPTR] = (intptr_t) p;
200 _mc->gregs[REG_ITMP1_XPC] = (intptr_t) xpc;
201 _mc->psw.addr = (intptr_t) asm_handle_exception;
204 _mc->psw.addr = (intptr_t) xpc;
208 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p)
221 _uc = (ucontext_t *) _p;
222 _mc = &_uc->uc_mcontext;
223 xpc = ra = siginfo->si_addr;
225 /* Our trap instruction has the format: { 0x02, one_byte_of_data }. */
227 if ((siginfo->si_code == ILL_ILLOPC) && (N_RR_GET_OPC(xpc) == OPC_ILL)) {
229 /* bits 7-4 contain a register holding a value */
230 reg = N_ILL_GET_REG(xpc);
232 /* bits 3-0 designate the exception type */
233 type = N_ILL_GET_TYPE(xpc);
235 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
236 sp = (u1 *)_mc->gregs[REG_SP];
237 val = (ptrint)_mc->gregs[reg];
239 if (EXCEPTION_HARDWARE_COMPILER == type) {
240 /* The PV from the compiler stub is equal to the XPC. */
244 /* The return address in is REG_RA */
246 ra = (u1 *)_mc->gregs[REG_RA];
251 /* Handle the type. */
253 p = signal_handle(type, val, pv, sp, ra, xpc, _p);
255 if (EXCEPTION_HARDWARE_COMPILER == type) {
257 _mc->gregs[REG_ITMP3_XPTR] = (intptr_t) builtin_retrieve_exception();
258 _mc->gregs[REG_ITMP1_XPC] = (intptr_t) ra - 2;
259 _mc->gregs[REG_PV] = (intptr_t) md_codegen_get_pv_from_pc(ra);
260 _mc->psw.addr = (intptr_t) asm_handle_exception;
262 _mc->gregs[REG_PV] = (intptr_t) p;
263 _mc->psw.addr = (intptr_t) p;
267 _mc->gregs[REG_ITMP3_XPTR] = (intptr_t) p;
268 _mc->gregs[REG_ITMP1_XPC] = (intptr_t) xpc;
269 _mc->psw.addr = (intptr_t) asm_handle_exception;
272 _mc->psw.addr = (intptr_t) xpc;
277 md_dump_context(xpc, _mc);
279 vm_abort("%s: illegal instruction at %p, aborting.", __FUNCTION__, xpc);
283 /* md_signal_handler_sigfpe ****************************************************
285 ArithmeticException signal handler for hardware divide by zero
288 *******************************************************************************/
290 void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
304 _uc = (ucontext_t *) _p;
305 _mc = &_uc->uc_mcontext;
307 /* Instruction that raised signal */
308 xpc = siginfo->si_addr;
312 if (N_RR_GET_OPC(xpc) == OPC_DR) { /* DR */
314 r1 = N_RR_GET_REG1(xpc);
315 r2 = N_RR_GET_REG2(xpc);
318 (_mc->gregs[r1] == 0xFFFFFFFF) &&
319 (_mc->gregs[r1 + 1] == 0x80000000) &&
320 (_mc->gregs[r2] == 0xFFFFFFFF)
322 /* handle special case 0x80000000 / 0xFFFFFFFF that fails on hardware */
323 /* next instruction */
324 pc = (u1 *)_mc->psw.addr;
328 _mc->gregs[r1 + 1] = 0x80000000;
329 /* continue at next instruction */
330 _mc->psw.addr = (ptrint) pc;
334 else if (_mc->gregs[r2] == 0) {
337 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
338 sp = (u1 *)_mc->gregs[REG_SP];
341 type = EXCEPTION_HARDWARE_ARITHMETIC;
344 /* Handle the type. */
346 p = signal_handle(type, val, pv, sp, ra, xpc, _p);
348 _mc->gregs[REG_ITMP3_XPTR] = (intptr_t) p;
349 _mc->gregs[REG_ITMP1_XPC] = (intptr_t) xpc;
350 _mc->psw.addr = (intptr_t) asm_handle_exception;
356 /* Could not handle signal */
359 md_dump_context(xpc, _mc);
361 vm_abort("%s: floating point exception at %p, aborting.", __FUNCTION__, xpc);
365 /* md_signal_handler_sigusr2 ***************************************************
367 Signal handler for profiling sampling.
369 *******************************************************************************/
371 #if defined(ENABLE_THREADS)
372 void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
381 _uc = (ucontext_t *) _p;
382 _mc = &_uc->uc_mcontext;
384 /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
385 different to the ones in <ucontext.h>. */
387 pc = (u1 *) _mc->psw.addr;
394 #if defined(ENABLE_THREADS)
395 void md_critical_section_restart(ucontext_t *_uc)
401 _mc = &_uc->uc_mcontext;
403 pc = (u1 *)_mc->psw.addr;
405 npc = critical_find_restart_point(pc);
408 log_println("%s: pc=%p, npc=%p", __FUNCTION__, pc, npc);
409 _mc->psw.addr = (ptrint) npc;
415 /* md_stacktrace_get_returnaddress *********************************************
417 Returns the return address of the current stackframe, specified by
418 the passed stack pointer and the stack frame size.
420 *******************************************************************************/
422 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
426 /* on S390 the return address is located on the top of the stackframe */
428 ra = *((u1 **) (sp + framesize - 8));
434 /* md_jit_method_patch_address *************************************************
436 Gets the patch address of the currently compiled method. The offset
437 is extracted from the load instruction(s) before the jump and added
438 to the right base address (PV or REG_METHODPTR).
440 INVOKESTATIC/SPECIAL:
442 0x7748d7b2: a7 18 ff d4 lhi %r1,-44
444 0x7748d7b6: 58 d1 d0 00 l %r13,0(%r1,%r13)
446 0x7748d7ba: 0d ed basr %r14,%r13
451 0x7748d82a: 58 c0 20 00 l %r12,0(%r2)
453 0x7748d82e: 58 d0 c0 00 l %r13,0(%r12)
455 0x7748d832: 0d ed basr %r14,%r13
461 last 2 instructions the same as in invokevirtual
463 *******************************************************************************/
465 void *md_jit_method_patch_address(void* pv, void *ra, void *mptr)
470 void *pa; /* patch address */
472 /* go back to the load before the call instruction */
474 pc = ((uint8_t *) ra) - SZ_BCR - SZ_L;
476 /* get the base register of the load */
478 base = N_RX_GET_BASE(pc);
479 index = N_RX_GET_INDEX(pc);
481 /* check for the different calls */
485 /* INVOKESTATIC/SPECIAL */
489 /* the offset is in the load instruction */
490 offset = N_RX_GET_DISP(pc) + N_PV_OFFSET;
493 /* the offset is in the immediate load before the load */
494 offset = N_RI_GET_IMM(pc - SZ_L);
500 /* add the offset to the procedure vector */
502 pa = ((uint8_t *) pv) + offset;
507 /* INVOKEVIRTUAL/INTERFACE */
509 offset = N_RX_GET_DISP(pc);
511 /* return NULL if no mptr was specified (used for replacement) */
516 /* add offset to method pointer */
518 pa = (uint8_t *)mptr + offset;
522 /* catch any problems */
523 vm_abort("md_jit_method_patch_address");
531 /* md_codegen_get_pv_from_pc ***************************************************
533 On this architecture just a wrapper function to
534 codegen_get_pv_from_pc.
536 *******************************************************************************/
538 u1 *md_codegen_get_pv_from_pc(u1 *ra)
542 /* Get the start address of the function which contains this
543 address from the method table. */
545 pv = codegen_get_pv_from_pc(ra);
551 /* md_cacheflush ***************************************************************
553 Calls the system's function to flush the instruction and data
556 *******************************************************************************/
558 void md_cacheflush(u1 *addr, s4 nbytes)
564 /* md_icacheflush **************************************************************
566 Calls the system's function to flush the instruction cache.
568 *******************************************************************************/
570 void md_icacheflush(u1 *addr, s4 nbytes)
576 /* md_dcacheflush **************************************************************
578 Calls the system's function to flush the data cache.
580 *******************************************************************************/
582 void md_dcacheflush(u1 *addr, s4 nbytes)
588 /* md_patch_replacement_point **************************************************
590 Patch the given replacement point.
592 *******************************************************************************/
593 #if defined(ENABLE_REPLACEMENT)
594 void md_patch_replacement_point(u1 *pc, u1 *savedmcode, bool revert)
600 void md_handle_exception(int32_t *regs, int64_t *fregs, int32_t *out) {
618 xptr = *(uint8_t **)(regs + REG_ITMP3_XPTR);
619 xpc = *(uint8_t **)(regs + REG_ITMP1_XPC);
620 sp = *(uint8_t **)(regs + REG_SP);
623 /* initialize number of calle saved int regs to restore to 0 */
626 /* initialize number of calle saved flt regs to restore to 0 */
633 pv = codegen_get_pv_from_pc(xpc);
635 handler = exceptions_handle_exception((java_object_t *)xptr, xpc, pv, sp);
637 if (handler == NULL) {
639 /* exception was not handled
640 * get values of calee saved registers and remove stack frame
643 /* read stuff from data segment */
645 framesize = *(int32_t *)(pv + FrameSize);
647 intsave = *(int32_t *)(pv + IntSave);
648 if (intsave > out[0]) {
652 fltsave = *(int32_t *)(pv + FltSave);
653 if (fltsave > out[1]) {
657 /* pointer to register save area */
659 savearea = (int64_t *)(sp + framesize - 8);
663 ra = *(uint8_t **)(sp + framesize - 8);
665 /* restore saved registers */
667 for (i = 0; i < intsave; ++i) {
669 reg = abi_registers_integer_saved[INT_SAV_CNT - 1 - i];
670 regs[reg] = *(int32_t *)(savearea);
673 for (i = 0; i < fltsave; ++i) {
675 reg = abi_registers_float_saved[FLT_SAV_CNT - 1 - i];
676 fregs[reg] = *savearea;
679 /* remove stack frame */
683 /* new xpc is call before return address */
690 } while (handler == NULL);
692 /* write new values for registers */
694 *(uint8_t **)(regs + REG_ITMP3_XPTR) = xptr;
695 *(uint8_t **)(regs + REG_ITMP1_XPC) = xpc;
696 *(uint8_t **)(regs + REG_SP) = sp;
697 *(uint8_t **)(regs + REG_PV) = pv - 0XFFC;
699 /* maybe leaf flag */
701 out[2] = (loops == 1);
705 * These are local overrides for various environment variables in Emacs.
706 * Please do not remove this and leave it at the end of the file, where
707 * Emacs will automagically detect them.
708 * ---------------------------------------------------------------------
711 * indent-tabs-mode: t
715 * vim:noexpandtab:sw=4:ts=4: