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 8068 2007-06-12 15:50:35Z 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)
156 java_objectheader *e;
160 _uc = (ucontext_t *) _p;
161 _mc = &_uc->uc_mcontext;
163 xpc = (u1 *)_mc->psw.addr;
165 /* Check opcodes and verify it is a null pointer exception */
170 base = (xpc[2] >> 4) & 0xF;
173 } 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];
189 sp = (u1 *)_mc->gregs[REG_SP];
191 type = EXCEPTION_HARDWARE_NULLPOINTER;
194 e = exceptions_new_hardware_exception(pv, sp, ra, xpc, type, val);
196 _mc->gregs[REG_ITMP2_XPC] = (ptrint) xpc;
197 _mc->gregs[REG_ITMP1_XPTR] = (ptrint) e;
198 _mc->psw.addr = (ptrint) asm_handle_exception;
201 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p) {
210 java_objectheader *e;
213 _uc = (ucontext_t *) _p;
214 _mc = &_uc->uc_mcontext;
215 xpc = ra = siginfo->si_addr;
217 /* Our trap instruction has the format: { 0x02, one_byte_of_data }. */
219 if ((siginfo->si_code == ILL_ILLOPC) && (xpc[0] == 0x02)) {
221 /* bits 7-4 contain a register holding a value */
222 reg = (xpc[1] >> 4) & 0xF;
224 /* bits 3-0 designate the exception type */
227 pv = (u1 *)_mc->gregs[REG_PV];
228 sp = (u1 *)_mc->gregs[REG_SP];
229 val = (ptrint)_mc->gregs[reg];
231 e = exceptions_new_hardware_exception(pv, sp, ra, xpc, type, val);
233 _mc->gregs[REG_ITMP1_XPTR] = (ptrint)e;
234 _mc->gregs[REG_ITMP2_XPC] = (ptrint)xpc;
235 _mc->psw.addr = (ptrint) asm_handle_exception;
239 md_dump_context(xpc, _mc);
241 vm_abort("%s: illegal instruction at %p, aborting.", __FUNCTION__, xpc);
245 /* md_signal_handler_sigfpe ****************************************************
247 ArithmeticException signal handler for hardware divide by zero
250 *******************************************************************************/
252 void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
264 java_objectheader *e;
266 _uc = (ucontext_t *) _p;
267 _mc = &_uc->uc_mcontext;
269 /* Instruction that raised signal */
270 xpc = siginfo->si_addr;
274 if (xpc[0] == 0x1D) { /* DR */
276 r1 = (xpc[1] >> 4) & 0xF;
280 (_mc->gregs[r1] == 0xFFFFFFFF) &&
281 (_mc->gregs[r1 + 1] == 0x80000000) &&
282 (_mc->gregs[r2] == 0xFFFFFFFF)
284 /* handle special case */
285 /* next instruction */
286 pc = (u1 *)_mc->psw.addr;
290 _mc->gregs[r1 + 1] = 0x80000000;
291 /* continue at next instruction */
292 _mc->psw.addr = (ptrint) pc;
295 } else if (_mc->gregs[r2] == 0) {
298 pv = (u1 *)_mc->gregs[REG_PV];
299 sp = (u1 *)_mc->gregs[REG_SP];
302 type = EXCEPTION_HARDWARE_ARITHMETIC;
305 e = exceptions_new_hardware_exception(pv, sp, ra, xpc, type, val);
307 _mc->gregs[REG_ITMP1_XPTR] = (ptrint)e;
308 _mc->gregs[REG_ITMP2_XPC] = (ptrint)xpc;
309 _mc->psw.addr = (ptrint) asm_handle_exception;
315 /* Could not handle signal */
318 md_dump_context(xpc, _mc);
320 vm_abort("%s: floating point exception at %p, aborting.", __FUNCTION__, xpc);
324 /* md_signal_handler_sigusr2 ***************************************************
326 Signal handler for profiling sampling.
328 *******************************************************************************/
330 #if defined(ENABLE_THREADS)
331 void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
340 _uc = (ucontext_t *) _p;
341 _mc = &_uc->uc_mcontext;
343 /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
344 different to the ones in <ucontext.h>. */
346 pc = (u1 *) _mc->psw.addr;
353 #if defined(ENABLE_THREADS)
354 void md_critical_section_restart(ucontext_t *_uc)
360 _mc = &_uc->uc_mcontext;
362 pc = (u1 *)_mc->psw.addr;
364 npc = critical_find_restart_point(pc);
367 log_println("%s: pc=%p, npc=%p", __FUNCTION__, pc, npc);
368 _mc->psw.addr = (ptrint) npc;
374 /* md_codegen_patch_branch *****************************************************
376 Back-patches a branch instruction.
378 *******************************************************************************/
380 void md_codegen_patch_branch(codegendata *cd, s4 branchmpc, s4 targetmpc)
384 s4 disp; /* branch displacement */
386 /* calculate the patch position */
388 mcodeptr = (s4 *) (cd->mcodebase + branchmpc);
390 /* Calculate the branch displacement. */
392 disp = targetmpc - branchmpc;
393 disp += 4; /* size of branch */
394 disp /= 2; /* specified in halfwords */
396 ASSERT_VALID_BRANCH(disp);
398 /* patch the branch instruction before the mcodeptr */
400 mcodeptr[-1] |= (disp & 0xFFFF);
404 /* md_stacktrace_get_returnaddress *********************************************
406 Returns the return address of the current stackframe, specified by
407 the passed stack pointer and the stack frame size.
409 *******************************************************************************/
411 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
415 /* on S390 the return address is located on the top of the stackframe */
417 ra = *((u1 **) (sp + framesize - SIZEOF_VOID_P));
423 /* md_get_method_patch_address *************************************************
425 Gets the patch address of the currently compiled method. The offset
426 is extracted from the load instruction(s) before the jump and added
427 to the right base address (PV or REG_METHODPTR).
429 INVOKESTATIC/SPECIAL:
431 0x7748d7b2: a7 18 ff d4 lhi %r1,-44
433 0x7748d7b6: 58 d1 d0 00 l %r13,0(%r1,%r13)
435 0x7748d7ba: 0d ed basr %r14,%r13
440 0x7748d82a: 58 c0 20 00 l %r12,0(%r2)
442 0x7748d82e: 58 d0 c0 00 l %r13,0(%r12)
444 0x7748d832: 0d ed basr %r14,%r13
450 last 2 instructions the same as in invokevirtual
452 *******************************************************************************/
454 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
458 u1 *pa; /* patch address */
460 /* go back to the load before the call instruction */
462 ra = ra - 2 /* sizeof bcr */ - 4 /* sizeof l */;
464 /* get the base register of the load */
468 /* check for the different calls */
470 if (base == 0xd) { /* pv relative */
471 /* INVOKESTATIC/SPECIAL */
473 /* the offset is in the load before the load */
475 offset = *((s2 *) (ra - 2));
477 /* add the offset to the procedure vector */
479 pa = sfi->pv + offset;
481 else if (base == 0xc) { /* mptr relative */
482 /* INVOKEVIRTUAL/INTERFACE */
484 offset = *((u2 *)(ra + 2)) & 0xFFF;
486 /* add offset to method pointer */
491 /* catch any problems */
499 /* md_codegen_get_pv_from_pc ***************************************************
501 On this architecture just a wrapper function to
502 codegen_get_pv_from_pc.
504 *******************************************************************************/
506 u1 *md_codegen_get_pv_from_pc(u1 *ra)
510 /* Get the start address of the function which contains this
511 address from the method table. */
513 pv = codegen_get_pv_from_pc(ra);
519 /* md_cacheflush ***************************************************************
521 Calls the system's function to flush the instruction and data
524 *******************************************************************************/
526 void md_cacheflush(u1 *addr, s4 nbytes)
532 /* md_icacheflush **************************************************************
534 Calls the system's function to flush the instruction cache.
536 *******************************************************************************/
538 void md_icacheflush(u1 *addr, s4 nbytes)
544 /* md_dcacheflush **************************************************************
546 Calls the system's function to flush the data cache.
548 *******************************************************************************/
550 void md_dcacheflush(u1 *addr, s4 nbytes)
556 /* md_patch_replacement_point **************************************************
558 Patch the given replacement point.
560 *******************************************************************************/
562 void md_patch_replacement_point(rplpoint *rp)
566 /* XXX this is probably unsafe! */
568 /* save the current machine code */
569 mcode = *(u8*)rp->pc;
571 /* write spinning instruction */
572 *(u2*)(rp->pc) = 0xebfe;
575 rp->pc[4] = (rp->mcode >> 32);
577 /* write first word */
578 *(u4*)(rp->pc) = (u4) rp->mcode;
580 /* store saved mcode */
583 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
591 /* XXX if required asm_cacheflush(rp->pc,8); */
595 * These are local overrides for various environment variables in Emacs.
596 * Please do not remove this and leave it at the end of the file, where
597 * Emacs will automagically detect them.
598 * ---------------------------------------------------------------------
601 * indent-tabs-mode: t
605 * vim:noexpandtab:sw=4:ts=4: