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"
42 #include "vm/jit/asmpart.h"
43 #include "vm/jit/abi.h"
44 #include "vm/jit/executionstate.h"
45 #include "vm/jit/methodheader.h"
46 #include "vm/jit/methodtree.h"
47 #include "vm/jit/stacktrace.h"
48 #include "vm/jit/trap.h"
50 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
51 #include "vmcore/options.h" /* XXX debug */
52 #include "vm/jit/disass.h" /* XXX debug */
55 #include "vm/jit/codegen-common.h"
56 #include "vm/jit/s390/codegen.h"
57 #include "vm/jit/s390/md.h"
60 /* prototypes *****************************************************************/
62 u1 *exceptions_handle_exception(java_object_t *xptro, u1 *xpc, u1 *pv, u1 *sp);
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 = methodtree_find_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->clazz->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 log_println("Dumping the current stacktrace:");
129 stacktrace_print_current();
132 /* md_signal_handler_sigsegv ***************************************************
134 NullPointerException signal handler for hardware null pointer
137 *******************************************************************************/
139 void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
153 _uc = (ucontext_t *) _p;
154 _mc = &_uc->uc_mcontext;
156 xpc = (u1 *)_mc->psw.addr;
158 /* Check opcodes and verify it is a null pointer exception */
160 switch (N_RX_GET_OPC(xpc)) {
163 case OPC_CL: /* array size check on NULL array */
164 base = N_RX_GET_BASE(xpc);
167 } else if (_mc->gregs[base] == 0) {
180 md_dump_context(xpc, _mc);
182 vm_abort("%s: segmentation fault at %p, aborting.", __FUNCTION__, xpc);
185 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
186 sp = (u1 *)_mc->gregs[REG_SP];
188 type = TRAP_NullPointerException;
191 /* Handle the trap. */
193 p = trap_handle(type, val, pv, sp, ra, xpc, _p);
196 _mc->gregs[REG_ITMP3_XPTR] = (uintptr_t) p;
197 _mc->gregs[REG_ITMP1_XPC] = (uintptr_t) xpc;
198 _mc->psw.addr = (uintptr_t) asm_handle_exception;
201 _mc->psw.addr = (uintptr_t) xpc;
205 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p)
218 _uc = (ucontext_t *) _p;
219 _mc = &_uc->uc_mcontext;
220 xpc = ra = siginfo->si_addr;
222 /* Our trap instruction has the format: { 0x02, one_byte_of_data }. */
224 if ((siginfo->si_code == ILL_ILLOPC) && (N_RR_GET_OPC(xpc) == OPC_ILL)) {
226 /* bits 7-4 contain a register holding a value */
227 reg = N_ILL_GET_REG(xpc);
229 /* bits 3-0 designate the exception type */
230 type = N_ILL_GET_TYPE(xpc);
232 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
233 sp = (u1 *)_mc->gregs[REG_SP];
234 val = (ptrint)_mc->gregs[reg];
236 if (TRAP_COMPILER == type) {
237 /* The PV from the compiler stub is equal to the XPC. */
241 /* The return address in is REG_RA */
243 ra = (u1 *)_mc->gregs[REG_RA];
248 /* Handle the trap. */
250 p = trap_handle(type, val, pv, sp, ra, xpc, _p);
252 if (TRAP_COMPILER == type) {
254 _mc->gregs[REG_ITMP3_XPTR] = (uintptr_t) builtin_retrieve_exception();
255 _mc->gregs[REG_ITMP1_XPC] = (uintptr_t) ra - 2;
256 _mc->gregs[REG_PV] = (uintptr_t) md_codegen_get_pv_from_pc(ra);
257 _mc->psw.addr = (uintptr_t) asm_handle_exception;
259 _mc->gregs[REG_PV] = (uintptr_t) p;
260 _mc->psw.addr = (uintptr_t) p;
264 _mc->gregs[REG_ITMP3_XPTR] = (uintptr_t) p;
265 _mc->gregs[REG_ITMP1_XPC] = (uintptr_t) xpc;
266 _mc->psw.addr = (uintptr_t) asm_handle_exception;
269 _mc->psw.addr = (uintptr_t) xpc;
274 md_dump_context(xpc, _mc);
276 vm_abort("%s: illegal instruction at %p, aborting.", __FUNCTION__, xpc);
280 /* md_signal_handler_sigfpe ****************************************************
282 ArithmeticException signal handler for hardware divide by zero
285 *******************************************************************************/
287 void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
301 _uc = (ucontext_t *) _p;
302 _mc = &_uc->uc_mcontext;
304 /* Instruction that raised signal */
305 xpc = siginfo->si_addr;
309 if (N_RR_GET_OPC(xpc) == OPC_DR) { /* DR */
311 r1 = N_RR_GET_REG1(xpc);
312 r2 = N_RR_GET_REG2(xpc);
315 (_mc->gregs[r1] == 0xFFFFFFFF) &&
316 (_mc->gregs[r1 + 1] == 0x80000000) &&
317 (_mc->gregs[r2] == 0xFFFFFFFF)
319 /* handle special case 0x80000000 / 0xFFFFFFFF that fails on hardware */
320 /* next instruction */
321 pc = (u1 *)_mc->psw.addr;
325 _mc->gregs[r1 + 1] = 0x80000000;
326 /* continue at next instruction */
327 _mc->psw.addr = (ptrint) pc;
331 else if (_mc->gregs[r2] == 0) {
334 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
335 sp = (u1 *)_mc->gregs[REG_SP];
338 type = TRAP_ArithmeticException;
341 /* Handle the trap. */
343 p = trap_handle(type, val, pv, sp, ra, xpc, _p);
345 _mc->gregs[REG_ITMP3_XPTR] = (uintptr_t) p;
346 _mc->gregs[REG_ITMP1_XPC] = (uintptr_t) xpc;
347 _mc->psw.addr = (uintptr_t) asm_handle_exception;
353 /* Could not handle signal */
356 md_dump_context(xpc, _mc);
358 vm_abort("%s: floating point exception at %p, aborting.", __FUNCTION__, xpc);
362 /* md_signal_handler_sigusr2 ***************************************************
364 Signal handler for profiling sampling.
366 *******************************************************************************/
368 #if defined(ENABLE_THREADS)
369 void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
378 _uc = (ucontext_t *) _p;
379 _mc = &_uc->uc_mcontext;
381 /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
382 different to the ones in <ucontext.h>. */
384 pc = (u1 *) _mc->psw.addr;
392 * Read the given context into an executionstate.
394 * @param es execution state
395 * @param context machine context
397 void md_executionstate_read(executionstate_t* es, void* context)
399 vm_abort("md_executionstate_read: IMPLEMENT ME!");
404 * Write the given executionstate back to the context.
406 * @param es execution state
407 * @param context machine context
409 void md_executionstate_write(executionstate_t* es, void* context)
411 vm_abort("md_executionstate_write: IMPLEMENT ME!");
415 /* md_jit_method_patch_address *************************************************
417 Gets the patch address of the currently compiled method. The offset
418 is extracted from the load instruction(s) before the jump and added
419 to the right base address (PV or REG_METHODPTR).
421 INVOKESTATIC/SPECIAL:
423 0x7748d7b2: a7 18 ff d4 lhi %r1,-44
425 0x7748d7b6: 58 d1 d0 00 l %r13,0(%r1,%r13)
427 0x7748d7ba: 0d ed basr %r14,%r13
432 0x7748d82a: 58 c0 20 00 l %r12,0(%r2)
434 0x7748d82e: 58 d0 c0 00 l %r13,0(%r12)
436 0x7748d832: 0d ed basr %r14,%r13
442 last 2 instructions the same as in invokevirtual
444 *******************************************************************************/
446 void *md_jit_method_patch_address(void* pv, void *ra, void *mptr)
451 void *pa; /* patch address */
453 /* go back to the load before the call instruction */
455 pc = ((uint8_t *) ra) - SZ_BCR - SZ_L;
457 /* get the base register of the load */
459 base = N_RX_GET_BASE(pc);
460 index = N_RX_GET_INDEX(pc);
462 /* check for the different calls */
466 /* INVOKESTATIC/SPECIAL */
470 /* the offset is in the load instruction */
471 offset = N_RX_GET_DISP(pc) + N_PV_OFFSET;
474 /* the offset is in the immediate load before the load */
475 offset = N_RI_GET_IMM(pc - SZ_L);
481 /* add the offset to the procedure vector */
483 pa = ((uint8_t *) pv) + offset;
488 /* INVOKEVIRTUAL/INTERFACE */
490 offset = N_RX_GET_DISP(pc);
492 /* return NULL if no mptr was specified (used for replacement) */
497 /* add offset to method pointer */
499 pa = (uint8_t *)mptr + offset;
503 /* catch any problems */
504 vm_abort("md_jit_method_patch_address");
512 /* md_patch_replacement_point **************************************************
514 Patch the given replacement point.
516 *******************************************************************************/
517 #if defined(ENABLE_REPLACEMENT)
518 void md_patch_replacement_point(u1 *pc, u1 *savedmcode, bool revert)
524 void md_handle_exception(int32_t *regs, int64_t *fregs, int32_t *out) {
542 xptr = *(uint8_t **)(regs + REG_ITMP3_XPTR);
543 xpc = *(uint8_t **)(regs + REG_ITMP1_XPC);
544 sp = *(uint8_t **)(regs + REG_SP);
547 /* initialize number of calle saved int regs to restore to 0 */
550 /* initialize number of calle saved flt regs to restore to 0 */
557 pv = methodtree_find(xpc);
559 handler = exceptions_handle_exception((java_object_t *)xptr, xpc, pv, sp);
561 if (handler == NULL) {
563 /* exception was not handled
564 * get values of calee saved registers and remove stack frame
567 /* read stuff from data segment */
569 framesize = *(int32_t *)(pv + FrameSize);
571 intsave = *(int32_t *)(pv + IntSave);
572 if (intsave > out[0]) {
576 fltsave = *(int32_t *)(pv + FltSave);
577 if (fltsave > out[1]) {
581 /* pointer to register save area */
583 savearea = (int64_t *)(sp + framesize - 8);
587 ra = *(uint8_t **)(sp + framesize - 8);
589 /* restore saved registers */
591 for (i = 0; i < intsave; ++i) {
593 reg = abi_registers_integer_saved[INT_SAV_CNT - 1 - i];
594 regs[reg] = *(int32_t *)(savearea);
597 for (i = 0; i < fltsave; ++i) {
599 reg = abi_registers_float_saved[FLT_SAV_CNT - 1 - i];
600 fregs[reg] = *savearea;
603 /* remove stack frame */
607 /* new xpc is call before return address */
614 } while (handler == NULL);
616 /* write new values for registers */
618 *(uint8_t **)(regs + REG_ITMP3_XPTR) = xptr;
619 *(uint8_t **)(regs + REG_ITMP1_XPC) = xpc;
620 *(uint8_t **)(regs + REG_SP) = sp;
621 *(uint8_t **)(regs + REG_PV) = pv - 0XFFC;
623 /* maybe leaf flag */
625 out[2] = (loops == 1);
629 * These are local overrides for various environment variables in Emacs.
630 * Please do not remove this and leave it at the end of the file, where
631 * Emacs will automagically detect them.
632 * ---------------------------------------------------------------------
635 * indent-tabs-mode: t
639 * vim:noexpandtab:sw=4:ts=4: