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"
60 #define OOPS() assert(0);
62 /* prototypes *****************************************************************/
64 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p);
66 void md_dump_context(u1 *pc, mcontext_t *mc);
68 /* md_init *********************************************************************
70 Do some machine dependent initialization.
72 *******************************************************************************/
78 /* md_dump_context ************************************************************
80 Logs the machine context
82 *******************************************************************************/
84 void md_dump_context(u1 *pc, mcontext_t *mc) {
94 log_println("Dumping context.");
96 log_println("Program counter: 0x%08X", pc);
98 pv = codegen_get_pv_from_pc_nocheck(pc);
100 log_println("No java method found at location.");
102 m = (*(codeinfo **)(pv + CodeinfoPointer))->m;
104 "Java method: class %s, method %s, descriptor %s.",
105 m->class->name->text, m->name->text, m->descriptor->text
109 #if defined(ENABLE_DISASSEMBLER)
110 log_println("Printing instruction at program counter:");
114 log_println("General purpose registers:");
116 for (i = 0; i < 16; i++) {
117 log_println("\tr%d:\t0x%08X\t%d", i, mc->gregs[i], mc->gregs[i]);
120 log_println("Floating point registers:");
122 for (i = 0; i < 16; i++) {
123 freg.fr.d = mc->fpregs.fprs[i].d;
124 log_println("\tf%d\t0x%016llX\t(double)%e\t(float)%f", i, freg.l, freg.fr.d, freg.fr.f);
127 #if defined(ENABLE_THREADS)
128 log_println("Dumping the current stacktrace:");
129 threads_print_stacktrace();
134 /* md_signal_handler_sigsegv ***************************************************
136 NullPointerException signal handler for hardware null pointer
139 *******************************************************************************/
141 void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
155 _uc = (ucontext_t *) _p;
156 _mc = &_uc->uc_mcontext;
158 xpc = (u1 *)_mc->psw.addr;
160 /* Check opcodes and verify it is a null pointer exception */
165 case 0x55: /* CL (array size check on NULL array) */
166 base = (xpc[2] >> 4) & 0xF;
169 } else if (_mc->gregs[base] == 0) {
182 md_dump_context(xpc, _mc);
184 vm_abort("%s: segmentation fault at %p, aborting.", __FUNCTION__, xpc);
187 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
188 sp = (u1 *)_mc->gregs[REG_SP];
190 type = EXCEPTION_HARDWARE_NULLPOINTER;
193 /* Handle the type. */
195 p = signal_handle(type, val, pv, sp, ra, xpc, _p);
198 _mc->gregs[REG_ITMP3_XPTR] = (intptr_t) p;
199 _mc->gregs[REG_ITMP1_XPC] = (intptr_t) xpc;
200 _mc->psw.addr = (intptr_t) asm_handle_exception;
203 _mc->psw.addr = (intptr_t) xpc;
207 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p)
220 _uc = (ucontext_t *) _p;
221 _mc = &_uc->uc_mcontext;
222 xpc = ra = siginfo->si_addr;
224 /* Our trap instruction has the format: { 0x02, one_byte_of_data }. */
226 if ((siginfo->si_code == ILL_ILLOPC) && (xpc[0] == 0x02)) {
228 /* bits 7-4 contain a register holding a value */
229 reg = (xpc[1] >> 4) & 0xF;
231 /* bits 3-0 designate the exception type */
234 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
235 sp = (u1 *)_mc->gregs[REG_SP];
236 val = (ptrint)_mc->gregs[reg];
238 /* Handle the type. */
240 p = signal_handle(type, val, pv, sp, ra, xpc, _p);
243 _mc->gregs[REG_ITMP3_XPTR] = (intptr_t) p;
244 _mc->gregs[REG_ITMP1_XPC] = (intptr_t) xpc;
245 _mc->psw.addr = (intptr_t) asm_handle_exception;
248 _mc->psw.addr = (intptr_t) xpc;
252 md_dump_context(xpc, _mc);
254 vm_abort("%s: illegal instruction at %p, aborting.", __FUNCTION__, xpc);
258 /* md_signal_handler_sigfpe ****************************************************
260 ArithmeticException signal handler for hardware divide by zero
263 *******************************************************************************/
265 void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
279 _uc = (ucontext_t *) _p;
280 _mc = &_uc->uc_mcontext;
282 /* Instruction that raised signal */
283 xpc = siginfo->si_addr;
287 if (xpc[0] == 0x1D) { /* DR */
289 r1 = (xpc[1] >> 4) & 0xF;
293 (_mc->gregs[r1] == 0xFFFFFFFF) &&
294 (_mc->gregs[r1 + 1] == 0x80000000) &&
295 (_mc->gregs[r2] == 0xFFFFFFFF)
297 /* handle special case 0x80000000 / 0xFFFFFFFF that fails on hardware */
298 /* next instruction */
299 pc = (u1 *)_mc->psw.addr;
303 _mc->gregs[r1 + 1] = 0x80000000;
304 /* continue at next instruction */
305 _mc->psw.addr = (ptrint) pc;
309 else if (_mc->gregs[r2] == 0) {
312 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
313 sp = (u1 *)_mc->gregs[REG_SP];
316 type = EXCEPTION_HARDWARE_ARITHMETIC;
319 /* Handle the type. */
321 p = signal_handle(type, val, pv, sp, ra, xpc, _p);
323 _mc->gregs[REG_ITMP3_XPTR] = (intptr_t) p;
324 _mc->gregs[REG_ITMP1_XPC] = (intptr_t) xpc;
325 _mc->psw.addr = (intptr_t) asm_handle_exception;
331 /* Could not handle signal */
334 md_dump_context(xpc, _mc);
336 vm_abort("%s: floating point exception at %p, aborting.", __FUNCTION__, xpc);
340 /* md_signal_handler_sigusr2 ***************************************************
342 Signal handler for profiling sampling.
344 *******************************************************************************/
346 #if defined(ENABLE_THREADS)
347 void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
356 _uc = (ucontext_t *) _p;
357 _mc = &_uc->uc_mcontext;
359 /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
360 different to the ones in <ucontext.h>. */
362 pc = (u1 *) _mc->psw.addr;
369 #if defined(ENABLE_THREADS)
370 void md_critical_section_restart(ucontext_t *_uc)
376 _mc = &_uc->uc_mcontext;
378 pc = (u1 *)_mc->psw.addr;
380 npc = critical_find_restart_point(pc);
383 log_println("%s: pc=%p, npc=%p", __FUNCTION__, pc, npc);
384 _mc->psw.addr = (ptrint) npc;
390 /* md_codegen_patch_branch *****************************************************
392 Back-patches a branch instruction.
394 *******************************************************************************/
396 void md_codegen_patch_branch(codegendata *cd, s4 branchmpc, s4 targetmpc)
400 s4 disp; /* branch displacement */
402 /* calculate the patch position */
404 mcodeptr = (s4 *) (cd->mcodebase + branchmpc);
406 /* Calculate the branch displacement. */
408 disp = targetmpc - branchmpc;
409 disp += 4; /* size of branch */
410 disp /= 2; /* specified in halfwords */
412 ASSERT_VALID_BRANCH(disp);
414 /* patch the branch instruction before the mcodeptr */
416 mcodeptr[-1] |= (disp & 0xFFFF);
420 /* md_stacktrace_get_returnaddress *********************************************
422 Returns the return address of the current stackframe, specified by
423 the passed stack pointer and the stack frame size.
425 *******************************************************************************/
427 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
431 /* on S390 the return address is located on the top of the stackframe */
433 ra = *((u1 **) (sp + framesize - 8));
439 /* md_jit_method_patch_address *************************************************
441 Gets the patch address of the currently compiled method. The offset
442 is extracted from the load instruction(s) before the jump and added
443 to the right base address (PV or REG_METHODPTR).
445 INVOKESTATIC/SPECIAL:
447 0x7748d7b2: a7 18 ff d4 lhi %r1,-44
449 0x7748d7b6: 58 d1 d0 00 l %r13,0(%r1,%r13)
451 0x7748d7ba: 0d ed basr %r14,%r13
456 0x7748d82a: 58 c0 20 00 l %r12,0(%r2)
458 0x7748d82e: 58 d0 c0 00 l %r13,0(%r12)
460 0x7748d832: 0d ed basr %r14,%r13
466 last 2 instructions the same as in invokevirtual
468 *******************************************************************************/
470 void *md_jit_method_patch_address(void* pv, void *ra, void *mptr)
475 void *pa; /* patch address */
477 /* go back to the load before the call instruction */
479 pc = ((uint8_t *) ra) - 2 /* sizeof bcr */ - 4 /* sizeof l */;
481 /* get the base register of the load */
486 /* check for the different calls */
490 /* INVOKESTATIC/SPECIAL */
495 /* the offset is in the load instruction */
496 offset = ((*(uint16_t *) (pc + 2)) & 0xFFF) + N_PV_OFFSET;
499 /* the offset is in the immediate load before the load */
500 offset = *((int16_t *) (pc - 2));
506 /* add the offset to the procedure vector */
508 pa = ((uint8_t *) pv) + offset;
513 /* INVOKEVIRTUAL/INTERFACE */
515 offset = *((uint16_t *) (pc + 2)) & 0xFFF;
517 /* return NULL if no mptr was specified (used for replacement) */
522 /* add offset to method pointer */
528 /* catch any problems */
529 vm_abort("md_jit_method_patch_address");
537 /* md_codegen_get_pv_from_pc ***************************************************
539 On this architecture just a wrapper function to
540 codegen_get_pv_from_pc.
542 *******************************************************************************/
544 u1 *md_codegen_get_pv_from_pc(u1 *ra)
548 /* Get the start address of the function which contains this
549 address from the method table. */
551 pv = codegen_get_pv_from_pc(ra);
557 /* md_cacheflush ***************************************************************
559 Calls the system's function to flush the instruction and data
562 *******************************************************************************/
564 void md_cacheflush(u1 *addr, s4 nbytes)
570 /* md_icacheflush **************************************************************
572 Calls the system's function to flush the instruction cache.
574 *******************************************************************************/
576 void md_icacheflush(u1 *addr, s4 nbytes)
582 /* md_dcacheflush **************************************************************
584 Calls the system's function to flush the data cache.
586 *******************************************************************************/
588 void md_dcacheflush(u1 *addr, s4 nbytes)
594 /* md_patch_replacement_point **************************************************
596 Patch the given replacement point.
598 *******************************************************************************/
599 #if defined(ENABLE_REPLACEMENT)
600 void md_patch_replacement_point(u1 *pc, u1 *savedmcode, bool revert)
606 void md_handle_exception(int32_t *regs, int64_t *fregs, int32_t *out) {
624 xptr = *(uint8_t **)(regs + REG_ITMP3_XPTR);
625 xpc = *(uint8_t **)(regs + REG_ITMP1_XPC);
626 sp = *(uint8_t **)(regs + REG_SP);
629 /* initialize number of calle saved int regs to restore to 0 */
632 /* initialize number of calle saved flt regs to restore to 0 */
639 pv = codegen_get_pv_from_pc(xpc);
641 handler = exceptions_handle_exception(xptr, xpc, pv, sp);
643 if (handler == NULL) {
645 /* exception was not handled
646 * get values of calee saved registers and remove stack frame
649 /* read stuff from data segment */
651 framesize = *(int32_t *)(pv + FrameSize);
653 intsave = *(int32_t *)(pv + IntSave);
654 if (intsave > out[0]) {
658 fltsave = *(int32_t *)(pv + FltSave);
659 if (fltsave > out[1]) {
663 /* pointer to register save area */
665 savearea = (int64_t *)(sp + framesize - 8);
669 ra = *(uint8_t **)(sp + framesize - 8);
671 /* restore saved registers */
673 for (i = 0; i < intsave; ++i) {
675 reg = abi_registers_integer_saved[INT_SAV_CNT - 1 - i];
676 regs[reg] = *(int32_t *)(savearea);
679 for (i = 0; i < fltsave; ++i) {
681 reg = abi_registers_float_saved[FLT_SAV_CNT - 1 - i];
682 fregs[reg] = *savearea;
685 /* remove stack frame */
689 /* new xpc is call before return address */
696 } while (handler == NULL);
698 /* write new values for registers */
700 *(uint8_t **)(regs + REG_ITMP3_XPTR) = xptr;
701 *(uint8_t **)(regs + REG_ITMP1_XPC) = xpc;
702 *(uint8_t **)(regs + REG_SP) = sp;
703 *(uint8_t **)(regs + REG_PV) = pv - 0XFFC;
705 /* maybe leaf flag */
707 out[2] = (loops == 1);
711 * These are local overrides for various environment variables in Emacs.
712 * Please do not remove this and leave it at the end of the file, where
713 * Emacs will automagically detect them.
714 * ---------------------------------------------------------------------
717 * indent-tabs-mode: t
721 * vim:noexpandtab:sw=4:ts=4: