1 /* src/vm/jit/trap.cpp - hardware traps
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
30 /* Include machine dependent trap stuff. */
35 #include "mm/memory.hpp"
37 #include "native/llni.h"
39 #include "toolbox/logging.hpp"
41 #include "vm/exceptions.hpp"
42 #include "vm/options.h"
46 #include "vm/jit/asmpart.h"
47 #include "vm/jit/code.hpp"
48 #include "vm/jit/disass.h"
49 #include "vm/jit/executionstate.h"
50 #include "vm/jit/jit.hpp"
51 #include "vm/jit/methodtree.h"
52 #include "vm/jit/patcher-common.hpp"
53 #include "vm/jit/replace.hpp"
54 #include "vm/jit/stacktrace.hpp"
61 * Mmap the first memory page to support hardware exceptions and check
62 * the maximum hardware trap displacement on the architectures where
63 * it is required (TRAP_INSTRUCTION_IS_LOAD defined to 1).
67 #if !(defined(__ARM__) && defined(__LINUX__))
68 /* On arm-linux the first memory page can't be mmap'ed, as it
69 contains the exception vectors. */
73 /* mmap a memory page at address 0x0, so our hardware-exceptions
76 pagesize = os::getpagesize();
78 (void) os::mmap_anonymous(NULL, pagesize, PROT_NONE, MAP_PRIVATE | MAP_FIXED);
81 TRACESUBSYSTEMINITIALIZATION("trap_init");
83 #if !defined(TRAP_INSTRUCTION_IS_LOAD)
84 # error TRAP_INSTRUCTION_IS_LOAD is not defined in your md-trap.h
87 #if TRAP_INSTRUCTION_IS_LOAD == 1
88 /* Check if we get into trouble with our hardware-exceptions. */
90 if (TRAP_END > OFFSET(java_bytearray_t, data))
91 vm_abort("trap_init: maximum hardware trap displacement is greater than the array-data offset: %d > %d", TRAP_END, OFFSET(java_bytearray_t, data));
97 * Handles the signal which is generated by trap instructions, caught
98 * by a signal handler and calls the correct function.
100 * @param type trap number
103 void* trap_handle(int type, intptr_t val, void *pv, void *sp, void *ra, void *xpc, void *context)
106 stackframeinfo_t sfi;
110 log_println("[trap_handle: type=%d, val=%p, pv=%p, sp=%p, ra=%p, xpc=%p]", type, val, pv, sp, ra, xpc);
113 #if defined(ENABLE_VMLOG)
114 vmlog_cacao_signl_type(type);
117 /* Prevent compiler warnings. */
119 java_handle_t* o = NULL;
120 methodinfo* m = NULL;
122 #if defined(__ALPHA__) || defined(__ARM__) || defined(__I386__) || defined(__POWERPC__) || defined(__POWERPC64__) || defined(__X86_64__)
123 # if !defined(NDEBUG)
124 /* Perform a sanity check on our execution state functions. */
126 executionstate_sanity_check(context);
129 /* Read execution state from current context. */
132 md_executionstate_read(&es, context);
134 //# define TRAPS_VERBOSE
135 # if !defined(NDEBUG) && defined(TRAPS_VERBOSE)
136 /* Dump contents of execution state */
138 if (opt_TraceTraps) {
139 log_println("[trap_handle: dumping execution state BEFORE ...]");
140 executionstate_println(&es);
145 /* Do some preparations before we enter the nativeworld. */
146 /* BEFORE: creating stackframeinfo */
149 case TRAP_ClassCastException:
150 /* Wrap the value into a handle, as it is a reference. */
152 o = LLNI_WRAP((java_object_t *) val);
156 /* In this case the passed PV points to the compiler stub. We
157 get the methodinfo pointer here and set PV to NULL so
158 stacktrace_stackframeinfo_add determines the PV for the
159 parent Java method. */
161 m = code_get_methodinfo_for_pv(pv);
170 /* Fill and add a stackframeinfo. */
172 stacktrace_stackframeinfo_add(&sfi, pv, sp, ra, xpc);
174 /* Get resulting exception (or pointer to compiled method). */
181 case TRAP_NullPointerException:
182 p = exceptions_new_nullpointerexception();
185 case TRAP_ArithmeticException:
186 p = exceptions_new_arithmeticexception();
189 case TRAP_ArrayIndexOutOfBoundsException:
190 index = (int32_t) val;
191 p = exceptions_new_arrayindexoutofboundsexception(index);
194 case TRAP_ArrayStoreException:
195 p = exceptions_new_arraystoreexception();
198 case TRAP_ClassCastException:
199 p = exceptions_new_classcastexception(o);
202 case TRAP_CHECK_EXCEPTION:
203 p = exceptions_fillinstacktrace();
207 #if defined(ENABLE_REPLACEMENT)
208 if (replace_me_wrapper((uint8_t*) xpc, context)) {
213 p = patcher_handler((uint8_t*) xpc);
217 entry = jit_compile_handle(m, sfi.pv, ra, (void*) val);
221 #if defined(ENABLE_REPLACEMENT)
223 # if defined(__I386__)
224 replace_me_wrapper((char*)xpc - 13, context);
231 /* Let's try to get a backtrace. */
233 (void) methodtree_find(xpc);
235 /* If that does not work, print more debug info. */
237 log_println("signal_handle: unknown hardware exception type %d", type);
239 #if SIZEOF_VOID_P == 8
240 log_println("PC=0x%016lx", xpc);
242 log_println("PC=0x%08x", xpc);
245 #if defined(ENABLE_DISASSEMBLER)
246 log_println("machine instruction at PC:");
247 disassinstr((uint8_t*) xpc);
250 vm_abort("Exiting...");
252 /* keep compiler happy */
257 /* Remove stackframeinfo. */
259 stacktrace_stackframeinfo_remove(&sfi);
261 #if defined(__ALPHA__) || defined(__ARM__) || defined(__I386__) || defined(__POWERPC__) || defined(__POWERPC64__) || defined(__X86_64__)
262 /* Update execution state and set registers. */
263 /* AFTER: removing stackframeinfo */
267 // The normal case for a compiler trap is to jump directly to
268 // the newly compiled method.
271 es.pc = (uint8_t *) (uintptr_t) entry;
272 es.pv = (uint8_t *) (uintptr_t) entry;
276 // In case of an exception during JIT compilation, we fetch
277 // the exception here and proceed with exception handling.
279 p = exceptions_get_and_clear_exception();
282 // Get and set the PV from the parent Java method.
284 es.pv = (uint8_t *) md_codegen_get_pv_from_pc(ra);
286 // Now fall-through to default exception handling.
288 goto trap_handle_exception;
291 // The normal case for a patcher trap is to continue execution at
292 // the trap instruction. On some archs the PC may point after the
293 // trap instruction, so we reset it here.
296 es.pc = (uint8_t *) (uintptr_t) xpc;
300 // Fall-through to default exception handling.
302 trap_handle_exception:
305 es.intregs[REG_ITMP1_XPTR] = (uintptr_t) LLNI_DIRECT(p);
306 es.intregs[REG_ITMP2_XPC] = (uintptr_t) xpc;
307 es.pc = (uint8_t *) (uintptr_t) asm_handle_exception;
311 /* Write back execution state to current context. */
313 md_executionstate_write(&es, context);
315 # if !defined(NDEBUG) && defined(TRAPS_VERBOSE)
316 /* Dump contents of execution state */
318 if (opt_TraceTraps) {
319 log_println("[trap_handle: dumping execution state AFTER ...]");
320 executionstate_println(&es);
325 /* Unwrap and return the exception object. */
326 /* AFTER: removing stackframeinfo */
328 if (type == TRAP_COMPILER)
331 return LLNI_UNWRAP(p);
340 * These are local overrides for various environment variables in Emacs.
341 * Please do not remove this and leave it at the end of the file, where
342 * Emacs will automagically detect them.
343 * ---------------------------------------------------------------------
346 * indent-tabs-mode: t