1 /* src/vm/jit/x86_64/md.c - machine dependent x86_64 Linux functions
3 Copyright (C) 1996-2005, 2006 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
25 Contact: cacao@cacaojvm.org
27 Authors: Christian Thalinger
29 Changes: Edwin Steiner
31 $Id: md.c 8251 2007-08-01 15:26:59Z pm $
43 #include "vm/jit/s390/md-abi.h"
45 #if defined(ENABLE_THREADS)
46 # include "threads/threads-common.h"
47 # include "threads/native/threads.h"
50 #include "vm/exceptions.h"
51 #include "vm/signallocal.h"
52 #include "vm/jit/asmpart.h"
53 #include "vm/jit/methodheader.h"
54 #include "vm/jit/stacktrace.h"
56 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
57 #include "vmcore/options.h" /* XXX debug */
58 #include "vm/jit/disass.h" /* XXX debug */
61 #include "vm/jit/codegen-common.h"
62 #include "vm/jit/s390/codegen.h"
65 #define OOPS() assert(0);
67 /* prototypes *****************************************************************/
69 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p);
71 void md_dump_context(u1 *pc, mcontext_t *mc);
73 /* md_init *********************************************************************
75 Do some machine dependent initialization.
77 *******************************************************************************/
83 /* md_dump_context ************************************************************
85 Logs the machine context
87 *******************************************************************************/
89 void md_dump_context(u1 *pc, mcontext_t *mc) {
99 log_println("Dumping context.");
101 log_println("Program counter: 0x%08X", pc);
103 pv = codegen_get_pv_from_pc_nocheck(pc);
105 log_println("No java method found at location.");
107 m = ((codeinfo *)(pv + CodeinfoPointer))->m;
109 "Java method: class %s, method %s, descriptor %s.",
110 utf_bytes(m->class->name), utf_bytes(m->name), utf_bytes(m->descriptor)
114 #if defined(ENABLE_DISASSEMBLER)
115 log_println("Printing instruction at program counter:");
119 log_println("General purpose registers:");
121 for (i = 0; i < 16; i++) {
122 log_println("\tr%d:\t0x%08X\t%d", i, mc->gregs[i], mc->gregs[i]);
125 log_println("Floating point registers:");
127 for (i = 0; i < 16; i++) {
128 freg.fr.d = mc->fpregs.fprs[i].d;
129 log_println("\tf%d\t0x%016llX\t(double)%e\t(float)%f", i, freg.l, freg.fr.d, freg.fr.f);
132 #if defined(ENABLE_THREADS)
133 log_println("Dumping the current stacktrace:");
134 threads_print_stacktrace();
139 /* md_signal_handler_sigsegv ***************************************************
141 NullPointerException signal handler for hardware null pointer
144 *******************************************************************************/
146 void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
157 java_objectheader *e;
161 _uc = (ucontext_t *) _p;
162 _mc = &_uc->uc_mcontext;
164 xpc = (u1 *)_mc->psw.addr;
166 /* Check opcodes and verify it is a null pointer exception */
171 case 0x55: /* CL (array size check on NULL array) */
172 base = (xpc[2] >> 4) & 0xF;
175 } else if (_mc->gregs[base] == 0) {
185 md_dump_context(xpc, _mc);
187 vm_abort("%s: segmentation fault at %p, aborting.", __FUNCTION__, xpc);
190 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
191 sp = (u1 *)_mc->gregs[REG_SP];
193 type = EXCEPTION_HARDWARE_NULLPOINTER;
196 /* create stackframeinfo */
198 stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
200 /* generate appropriate exception */
202 e = exceptions_new_hardware_exception(xpc, type, val);
204 /* remove stackframeinfo */
206 stacktrace_remove_stackframeinfo(&sfi);
209 _mc->gregs[REG_ITMP2_XPC] = (ptrint) xpc;
210 _mc->gregs[REG_ITMP1_XPTR] = (ptrint) e;
211 _mc->psw.addr = (ptrint) asm_handle_exception;
217 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p) {
227 java_objectheader *e;
230 _uc = (ucontext_t *) _p;
231 _mc = &_uc->uc_mcontext;
232 xpc = ra = siginfo->si_addr;
234 /* Our trap instruction has the format: { 0x02, one_byte_of_data }. */
236 if ((siginfo->si_code == ILL_ILLOPC) && (xpc[0] == 0x02)) {
238 /* bits 7-4 contain a register holding a value */
239 reg = (xpc[1] >> 4) & 0xF;
241 /* bits 3-0 designate the exception type */
244 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
245 sp = (u1 *)_mc->gregs[REG_SP];
246 val = (ptrint)_mc->gregs[reg];
248 /* create stackframeinfo */
250 stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
252 /* generate appropriate exception */
254 e = exceptions_new_hardware_exception(xpc, type, val);
256 /* remove stackframeinfo */
258 stacktrace_remove_stackframeinfo(&sfi);
261 _mc->gregs[REG_ITMP1_XPTR] = (ptrint)e;
262 _mc->gregs[REG_ITMP2_XPC] = (ptrint)xpc;
263 _mc->psw.addr = (ptrint) asm_handle_exception;
269 md_dump_context(xpc, _mc);
271 vm_abort("%s: illegal instruction at %p, aborting.", __FUNCTION__, xpc);
275 /* md_signal_handler_sigfpe ****************************************************
277 ArithmeticException signal handler for hardware divide by zero
280 *******************************************************************************/
282 void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
295 java_objectheader *e;
297 _uc = (ucontext_t *) _p;
298 _mc = &_uc->uc_mcontext;
300 /* Instruction that raised signal */
301 xpc = siginfo->si_addr;
305 if (xpc[0] == 0x1D) { /* DR */
307 r1 = (xpc[1] >> 4) & 0xF;
311 (_mc->gregs[r1] == 0xFFFFFFFF) &&
312 (_mc->gregs[r1 + 1] == 0x80000000) &&
313 (_mc->gregs[r2] == 0xFFFFFFFF)
315 /* handle special case */
316 /* next instruction */
317 pc = (u1 *)_mc->psw.addr;
321 _mc->gregs[r1 + 1] = 0x80000000;
322 /* continue at next instruction */
323 _mc->psw.addr = (ptrint) pc;
326 } else if (_mc->gregs[r2] == 0) {
329 pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
330 sp = (u1 *)_mc->gregs[REG_SP];
333 type = EXCEPTION_HARDWARE_ARITHMETIC;
336 /* create stackframeinfo */
338 stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
340 /* generate appropriate exception */
342 e = exceptions_new_hardware_exception(xpc, type, val);
344 /* remove stackframeinfo */
346 stacktrace_remove_stackframeinfo(&sfi);
348 _mc->gregs[REG_ITMP1_XPTR] = (ptrint)e;
349 _mc->gregs[REG_ITMP2_XPC] = (ptrint)xpc;
350 _mc->psw.addr = (ptrint) 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_codegen_patch_branch *****************************************************
417 Back-patches a branch instruction.
419 *******************************************************************************/
421 void md_codegen_patch_branch(codegendata *cd, s4 branchmpc, s4 targetmpc)
425 s4 disp; /* branch displacement */
427 /* calculate the patch position */
429 mcodeptr = (s4 *) (cd->mcodebase + branchmpc);
431 /* Calculate the branch displacement. */
433 disp = targetmpc - branchmpc;
434 disp += 4; /* size of branch */
435 disp /= 2; /* specified in halfwords */
437 ASSERT_VALID_BRANCH(disp);
439 /* patch the branch instruction before the mcodeptr */
441 mcodeptr[-1] |= (disp & 0xFFFF);
445 /* md_stacktrace_get_returnaddress *********************************************
447 Returns the return address of the current stackframe, specified by
448 the passed stack pointer and the stack frame size.
450 *******************************************************************************/
452 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
456 /* on S390 the return address is located on the top of the stackframe */
458 ra = *((u1 **) (sp + framesize - SIZEOF_VOID_P));
464 /* md_get_method_patch_address *************************************************
466 Gets the patch address of the currently compiled method. The offset
467 is extracted from the load instruction(s) before the jump and added
468 to the right base address (PV or REG_METHODPTR).
470 INVOKESTATIC/SPECIAL:
472 0x7748d7b2: a7 18 ff d4 lhi %r1,-44
474 0x7748d7b6: 58 d1 d0 00 l %r13,0(%r1,%r13)
476 0x7748d7ba: 0d ed basr %r14,%r13
481 0x7748d82a: 58 c0 20 00 l %r12,0(%r2)
483 0x7748d82e: 58 d0 c0 00 l %r13,0(%r12)
485 0x7748d832: 0d ed basr %r14,%r13
491 last 2 instructions the same as in invokevirtual
493 *******************************************************************************/
495 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
499 u1 *pa; /* patch address */
501 /* go back to the load before the call instruction */
503 ra = ra - 2 /* sizeof bcr */ - 4 /* sizeof l */;
505 /* get the base register of the load */
510 /* check for the different calls */
514 /* INVOKESTATIC/SPECIAL */
519 /* the offset is in the load instruction */
520 offset = ((*(u2 *)(ra + 2)) & 0xFFF) + N_PV_OFFSET;
523 /* the offset is in the immediate load before the load */
524 offset = *((s2 *) (ra - 2));
530 /* add the offset to the procedure vector */
532 pa = sfi->pv + offset;
538 /* INVOKEVIRTUAL/INTERFACE */
540 offset = *((u2 *)(ra + 2)) & 0xFFF;
542 /* return NULL if no mptr was specified (used for replacement) */
547 /* add offset to method pointer */
552 /* catch any problems */
561 /* md_codegen_get_pv_from_pc ***************************************************
563 On this architecture just a wrapper function to
564 codegen_get_pv_from_pc.
566 *******************************************************************************/
568 u1 *md_codegen_get_pv_from_pc(u1 *ra)
572 /* Get the start address of the function which contains this
573 address from the method table. */
575 pv = codegen_get_pv_from_pc(ra);
581 /* md_cacheflush ***************************************************************
583 Calls the system's function to flush the instruction and data
586 *******************************************************************************/
588 void md_cacheflush(u1 *addr, s4 nbytes)
594 /* md_icacheflush **************************************************************
596 Calls the system's function to flush the instruction cache.
598 *******************************************************************************/
600 void md_icacheflush(u1 *addr, s4 nbytes)
606 /* md_dcacheflush **************************************************************
608 Calls the system's function to flush the data cache.
610 *******************************************************************************/
612 void md_dcacheflush(u1 *addr, s4 nbytes)
618 /* md_patch_replacement_point **************************************************
620 Patch the given replacement point.
622 *******************************************************************************/
623 #if defined(ENABLE_REPLACEMENT)
624 void md_patch_replacement_point(codeinfo *code, s4 index, rplpoint *rp, u1 *savedmcode)
631 * These are local overrides for various environment variables in Emacs.
632 * Please do not remove this and leave it at the end of the file, where
633 * Emacs will automagically detect them.
634 * ---------------------------------------------------------------------
637 * indent-tabs-mode: t
641 * vim:noexpandtab:sw=4:ts=4: