1 /* src/vm/jit/s390/md.c - machine dependent s390 Linux functions
3 Copyright (C) 2006, 2007, 2008, 2010
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.hpp"
39 #include "vm/exceptions.hpp"
40 #include "vm/signallocal.hpp"
42 #include "vm/jit/abi.h"
43 #include "vm/jit/executionstate.h"
44 #include "vm/jit/methodheader.h"
45 #include "vm/jit/methodtree.h"
46 #include "vm/jit/stacktrace.hpp"
47 #include "vm/jit/trap.hpp"
49 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
50 #include "vm/options.h" /* XXX debug */
53 #include "vm/jit/codegen-common.hpp"
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();
131 * NullPointerException signal handler for hardware null pointer check.
133 void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
135 ucontext_t* _uc = (ucontext_t *) _p;
136 mcontext_t* _mc = &_uc->uc_mcontext;
138 void* xpc = (u1 *) _mc->psw.addr;
141 trap_handle(TRAP_SIGSEGV, xpc, _p);
145 * Illegal Instruction signal handler for hardware exception checks.
147 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p)
149 ucontext_t* _uc = (ucontext_t *) _p;
150 mcontext_t* _mc = &_uc->uc_mcontext;
152 void* xpc = siginfo->si_addr;
155 trap_handle(TRAP_SIGILL, xpc, _p);
158 /* md_signal_handler_sigfpe ****************************************************
160 ArithmeticException signal handler for hardware divide by zero
163 *******************************************************************************/
165 void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
167 ucontext_t* _uc = (ucontext_t *) _p;
168 mcontext_t* _mc = &_uc->uc_mcontext;
170 void* xpc = siginfo->si_addr;
172 if (N_RR_GET_OPC(xpc) == OPC_DR) { /* DR */
174 int r1 = N_RR_GET_REG1(xpc);
175 int r2 = N_RR_GET_REG2(xpc);
178 (_mc->gregs[r1] == 0xFFFFFFFF) &&
179 (_mc->gregs[r1 + 1] == 0x80000000) &&
180 (_mc->gregs[r2] == 0xFFFFFFFF)
182 /* handle special case 0x80000000 / 0xFFFFFFFF that fails on hardware */
183 /* next instruction */
184 u1 *pc = (u1 *)_mc->psw.addr;
188 _mc->gregs[r1 + 1] = 0x80000000;
189 /* continue at next instruction */
190 _mc->psw.addr = (ptrint) pc;
197 trap_handle(TRAP_SIGFPE, xpc, _p);
201 /* md_signal_handler_sigusr2 ***************************************************
203 Signal handler for profiling sampling.
205 *******************************************************************************/
207 #if defined(ENABLE_THREADS)
208 void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
217 _uc = (ucontext_t *) _p;
218 _mc = &_uc->uc_mcontext;
220 /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
221 different to the ones in <ucontext.h>. */
223 pc = (u1 *) _mc->psw.addr;
231 * Read the given context into an executionstate.
233 * @param es execution state
234 * @param context machine context
236 void md_executionstate_read(executionstate_t* es, void* context)
242 _uc = (ucontext_t *) context;
243 _mc = &_uc->uc_mcontext;
245 /* read special registers */
246 es->pc = (u1 *) _mc->psw.addr;
247 es->sp = (u1 *) _mc->gregs[REG_SP];
248 es->pv = (u1 *) _mc->gregs[REG_PV] - N_PV_OFFSET;
249 es->ra = (u1 *) _mc->gregs[REG_RA];
251 /* read integer registers */
252 for (i = 0; i < INT_REG_CNT; i++)
253 es->intregs[i] = _mc->gregs[i];
255 /* read float registers */
256 /* Do not use the assignment operator '=', as the type of
257 * the _mc->sc_fpregs[i] can cause invalid conversions. */
259 assert(sizeof(_mc->fpregs.fprs) == sizeof(es->fltregs));
260 os_memcpy(&es->fltregs, &_mc->fpregs.fprs, sizeof(_mc->fpregs.fprs));
265 * Write the given executionstate back to the context.
267 * @param es execution state
268 * @param context machine context
270 void md_executionstate_write(executionstate_t* es, void* context)
276 _uc = (ucontext_t *) context;
277 _mc = &_uc->uc_mcontext;
279 /* write integer registers */
280 for (i = 0; i < INT_REG_CNT; i++)
281 _mc->gregs[i] = es->intregs[i];
283 /* write float registers */
284 /* Do not use the assignment operator '=', as the type of
285 * the _mc->sc_fpregs[i] can cause invalid conversions. */
287 assert(sizeof(_mc->fpregs.fprs) == sizeof(es->fltregs));
288 os_memcpy(&_mc->fpregs.fprs, &es->fltregs, sizeof(_mc->fpregs.fprs));
290 /* write special registers */
291 _mc->psw.addr = (ptrint) es->pc;
292 _mc->gregs[REG_SP] = (ptrint) es->sp;
293 _mc->gregs[REG_PV] = (ptrint) es->pv + N_PV_OFFSET;
294 _mc->gregs[REG_RA] = (ptrint) es->ra;
298 /* md_jit_method_patch_address *************************************************
300 Gets the patch address of the currently compiled method. The offset
301 is extracted from the load instruction(s) before the jump and added
302 to the right base address (PV or REG_METHODPTR).
304 INVOKESTATIC/SPECIAL:
306 0x7748d7b2: a7 18 ff d4 lhi %r1,-44
308 0x7748d7b6: 58 d1 d0 00 l %r13,0(%r1,%r13)
310 0x7748d7ba: 0d ed basr %r14,%r13
315 0x7748d82a: 58 c0 20 00 l %r12,0(%r2)
317 0x7748d82e: 58 d0 c0 00 l %r13,0(%r12)
319 0x7748d832: 0d ed basr %r14,%r13
325 last 2 instructions the same as in invokevirtual
327 *******************************************************************************/
329 void *md_jit_method_patch_address(void* pv, void *ra, void *mptr)
334 void *pa; /* patch address */
336 /* go back to the load before the call instruction */
338 pc = ((uint8_t *) ra) - SZ_BCR - SZ_L;
340 /* get the base register of the load */
342 base = N_RX_GET_BASE(pc);
343 index = N_RX_GET_INDEX(pc);
345 /* check for the different calls */
349 /* INVOKESTATIC/SPECIAL */
353 /* the offset is in the load instruction */
354 offset = N_RX_GET_DISP(pc) + N_PV_OFFSET;
357 /* the offset is in the immediate load before the load */
358 offset = N_RI_GET_IMM(pc - SZ_L);
364 /* add the offset to the procedure vector */
366 pa = ((uint8_t *) pv) + offset;
371 /* INVOKEVIRTUAL/INTERFACE */
373 offset = N_RX_GET_DISP(pc);
375 /* return NULL if no mptr was specified (used for replacement) */
380 /* add offset to method pointer */
382 pa = (uint8_t *)mptr + offset;
386 /* catch any problems */
387 vm_abort("md_jit_method_patch_address");
396 * Decode the trap instruction at the given PC.
398 * @param trp information about trap to be filled
399 * @param sig signal number
400 * @param xpc exception PC
401 * @param es execution state of the machine
402 * @return true if trap was decoded successfully, false otherwise.
404 bool md_trap_decode(trapinfo_t* trp, int sig, void* xpc, executionstate_t* es)
408 if (N_RR_GET_OPC(xpc) == OPC_ILL) {
409 int32_t reg = N_ILL_GET_REG(xpc);
410 trp->type = N_ILL_GET_TYPE(xpc);
411 trp->value = es->intregs[reg];
420 switch (N_RX_GET_OPC(xpc)) {
423 case OPC_CL: /* array size check on NULL array */
424 base = N_RX_GET_BASE(xpc);
427 } else if (es->intregs[base] == 0) {
438 // Check for implicit NullPointerException.
440 trp->type = TRAP_NullPointerException;
450 if (N_RR_GET_OPC(xpc) == OPC_DR) {
451 int r2 = N_RR_GET_REG2(xpc);
452 if (es->intregs[r2] == 0) {
453 trp->type = TRAP_ArithmeticException;
469 /* md_patch_replacement_point **************************************************
471 Patch the given replacement point.
473 *******************************************************************************/
474 #if defined(ENABLE_REPLACEMENT)
475 void md_patch_replacement_point(u1 *pc, u1 *savedmcode, bool revert)
481 void md_handle_exception(int32_t *regs, int64_t *fregs, int32_t *out) {
499 xptr = *(uint8_t **)(regs + REG_ITMP1_XPTR);
500 xpc = *(uint8_t **)(regs + REG_ITMP2_XPC);
501 sp = *(uint8_t **)(regs + REG_SP);
504 /* initialize number of calle saved int regs to restore to 0 */
507 /* initialize number of calle saved flt regs to restore to 0 */
514 pv = methodtree_find(xpc);
516 handler = exceptions_handle_exception((java_object_t *)xptr, xpc, pv, sp);
518 if (handler == NULL) {
520 /* exception was not handled
521 * get values of calee saved registers and remove stack frame
524 /* read stuff from data segment */
526 framesize = *(int32_t *)(pv + FrameSize);
528 intsave = *(int32_t *)(pv + IntSave);
529 if (intsave > out[0]) {
533 fltsave = *(int32_t *)(pv + FltSave);
534 if (fltsave > out[1]) {
538 /* pointer to register save area */
540 savearea = (int64_t *)(sp + framesize - 8);
544 ra = *(uint8_t **)(sp + framesize - 8);
546 /* restore saved registers */
548 for (i = 0; i < intsave; ++i) {
550 reg = abi_registers_integer_saved[INT_SAV_CNT - 1 - i];
551 regs[reg] = *(int32_t *)(savearea);
554 for (i = 0; i < fltsave; ++i) {
556 reg = abi_registers_float_saved[FLT_SAV_CNT - 1 - i];
557 fregs[reg] = *savearea;
560 /* remove stack frame */
564 /* new xpc is call before return address */
571 } while (handler == NULL);
573 /* write new values for registers */
575 *(uint8_t **)(regs + REG_ITMP1_XPTR) = xptr;
576 *(uint8_t **)(regs + REG_ITMP2_XPC) = xpc;
577 *(uint8_t **)(regs + REG_SP) = sp;
578 *(uint8_t **)(regs + REG_PV) = pv - 0XFFC;
580 /* maybe leaf flag */
582 out[2] = (loops == 1);
586 * These are local overrides for various environment variables in Emacs.
587 * Please do not remove this and leave it at the end of the file, where
588 * Emacs will automagically detect them.
589 * ---------------------------------------------------------------------
592 * indent-tabs-mode: t
596 * vim:noexpandtab:sw=4:ts=4: