* src/vm/jit/trap.cpp (trap_handle): Enhanced debug output of trap tracer.
[cacao.git] / src / vm / jit / trap.cpp
1 /* src/vm/jit/trap.cpp - hardware traps
2
3    Copyright (C) 2008
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5
6    This file is part of CACAO.
7
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.
12
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.
17
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
21    02110-1301, USA.
22
23 */
24
25
26 #include "config.h"
27
28 #include <stdint.h>
29
30 /* Include machine dependent trap stuff. */
31
32 #include "md.h"
33 #include "md-trap.h"
34
35 #include "mm/memory.hpp"
36
37 #include "native/llni.h"
38
39 #include "toolbox/logging.hpp"
40
41 #include "vm/exceptions.hpp"
42 #include "vm/options.h"
43 #include "vm/os.hpp"
44 #include "vm/vm.hpp"
45
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"
55
56 #ifdef __cplusplus
57 extern "C" {
58 #endif
59
60 /**
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).
64  */
65 void trap_init(void)
66 {
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. */
70
71         int pagesize;
72
73         /* mmap a memory page at address 0x0, so our hardware-exceptions
74            work. */
75
76         pagesize = os::getpagesize();
77
78         (void) os::mmap_anonymous(NULL, pagesize, PROT_NONE, MAP_PRIVATE | MAP_FIXED);
79 #endif
80
81         TRACESUBSYSTEMINITIALIZATION("trap_init");
82
83 #if !defined(TRAP_INSTRUCTION_IS_LOAD)
84 # error TRAP_INSTRUCTION_IS_LOAD is not defined in your md-trap.h
85 #endif
86
87 #if TRAP_INSTRUCTION_IS_LOAD == 1
88         /* Check if we get into trouble with our hardware-exceptions. */
89
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));
92 #endif
93 }
94
95
96 /**
97  * Handles the signal which is generated by trap instructions, caught
98  * by a signal handler and calls the correct function.
99  *
100  * @param type trap number
101  * @param 
102  */
103 void* trap_handle(int type, intptr_t val, void *pv, void *sp, void *ra, void *xpc, void *context)
104 {
105         executionstate_t es;
106         stackframeinfo_t sfi;
107
108 #if !defined(NDEBUG)
109         if (opt_TraceTraps)
110                 log_println("[trap_handle: type=%d, val=%p, pv=%p, sp=%p, ra=%p, xpc=%p]", type, val, pv, sp, ra, xpc);
111 #endif
112         
113 #if defined(ENABLE_VMLOG)
114         vmlog_cacao_signl_type(type);
115 #endif
116
117         /* Prevent compiler warnings. */
118
119         java_handle_t* o = NULL;
120         methodinfo*    m = NULL;
121
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. */
125
126         executionstate_sanity_check(context);
127 # endif
128
129         /* Read execution state from current context. */
130
131         es.code = NULL;
132         md_executionstate_read(&es, context);
133
134 //# define TRAPS_VERBOSE
135 # if !defined(NDEBUG) && defined(TRAPS_VERBOSE)
136         /* Dump contents of execution state */
137
138         if (opt_TraceTraps) {
139                 log_println("[trap_handle: dumping execution state BEFORE ...]");
140                 executionstate_println(&es);
141         }
142 # endif
143 #endif
144
145         /* Do some preparations before we enter the nativeworld. */
146         /* BEFORE: creating stackframeinfo */
147
148         switch (type) {
149         case TRAP_ClassCastException:
150                 /* Wrap the value into a handle, as it is a reference. */
151
152                 o = LLNI_WRAP((java_object_t *) val);
153                 break;
154
155         case TRAP_COMPILER:
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. */
160
161                 m  = code_get_methodinfo_for_pv(pv);
162                 pv = NULL;
163                 break;
164
165         default:
166                 /* do nothing */
167                 break;
168         }
169
170         /* Fill and add a stackframeinfo. */
171
172         stacktrace_stackframeinfo_add(&sfi, pv, sp, ra, xpc);
173
174         /* Get resulting exception (or pointer to compiled method). */
175
176         int32_t        index;
177         java_handle_t* p;
178         void*          entry;
179
180         switch (type) {
181         case TRAP_NullPointerException:
182                 p = exceptions_new_nullpointerexception();
183                 break;
184
185         case TRAP_ArithmeticException:
186                 p = exceptions_new_arithmeticexception();
187                 break;
188
189         case TRAP_ArrayIndexOutOfBoundsException:
190                 index = (int32_t) val;
191                 p = exceptions_new_arrayindexoutofboundsexception(index);
192                 break;
193
194         case TRAP_ArrayStoreException:
195                 p = exceptions_new_arraystoreexception();
196                 break;
197
198         case TRAP_ClassCastException:
199                 p = exceptions_new_classcastexception(o);
200                 break;
201
202         case TRAP_CHECK_EXCEPTION:
203                 p = exceptions_fillinstacktrace();
204                 break;
205
206         case TRAP_PATCHER:
207 #if defined(ENABLE_REPLACEMENT)
208                 if (replace_me_wrapper((uint8_t*) xpc, context)) {
209                         p = NULL;
210                         break;
211                 }
212 #endif
213                 p = patcher_handler((uint8_t*) xpc);
214                 break;
215
216         case TRAP_COMPILER:
217                 entry = jit_compile_handle(m, sfi.pv, ra, (void*) val);
218                 p = NULL;
219                 break;
220
221 #if defined(ENABLE_REPLACEMENT)
222         case TRAP_COUNTDOWN:
223 # if defined(__I386__)
224                 replace_me_wrapper((char*)xpc - 13, context);
225 # endif
226                 p = NULL;
227                 break;
228 #endif
229
230         default:
231                 /* Let's try to get a backtrace. */
232
233                 (void) methodtree_find(xpc);
234
235                 /* If that does not work, print more debug info. */
236
237                 log_println("signal_handle: unknown hardware exception type %d", type);
238
239 #if SIZEOF_VOID_P == 8
240                 log_println("PC=0x%016lx", xpc);
241 #else
242                 log_println("PC=0x%08x", xpc);
243 #endif
244
245 #if defined(ENABLE_DISASSEMBLER)
246                 log_println("machine instruction at PC:");
247                 disassinstr((uint8_t*) xpc);
248 #endif
249
250                 vm_abort("Exiting...");
251
252                 /* keep compiler happy */
253
254                 p = NULL;
255         }
256
257         /* Remove stackframeinfo. */
258
259         stacktrace_stackframeinfo_remove(&sfi);
260
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 */
264
265         switch (type) {
266         case TRAP_COMPILER:
267                 // The normal case for a compiler trap is to jump directly to
268                 // the newly compiled method.
269
270                 if (entry != NULL) {
271                         es.pc = (uint8_t *) (uintptr_t) entry;
272                         es.pv = (uint8_t *) (uintptr_t) entry;
273                         break;
274                 }
275
276                 // In case of an exception during JIT compilation, we fetch
277                 // the exception here and proceed with exception handling.
278
279                 p = exceptions_get_and_clear_exception();
280                 assert(p != NULL);
281
282                 // Get and set the PV from the parent Java method.
283
284                 es.pv = (uint8_t *) md_codegen_get_pv_from_pc(ra);
285
286                 // Now fall-through to default exception handling.
287
288                 goto trap_handle_exception;
289
290         case TRAP_PATCHER:
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.
294
295                 if (p == NULL) {
296                         es.pc = (uint8_t *) (uintptr_t) xpc;
297                         break;
298                 }
299
300                 // Fall-through to default exception handling.
301
302         trap_handle_exception:
303         default:
304                 if (p != NULL) {
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;
308                 }
309         }
310
311         /* Write back execution state to current context. */
312
313         md_executionstate_write(&es, context);
314
315 # if !defined(NDEBUG) && defined(TRAPS_VERBOSE)
316         /* Dump contents of execution state */
317
318         if (opt_TraceTraps) {
319                 log_println("[trap_handle: dumping execution state AFTER ...]");
320                 executionstate_println(&es);
321         }
322 # endif
323 #endif
324
325         /* Unwrap and return the exception object. */
326         /* AFTER: removing stackframeinfo */
327
328         if (type == TRAP_COMPILER)
329                 return entry;
330         else
331                 return LLNI_UNWRAP(p);
332 }
333
334 #ifdef __cplusplus
335 }
336 #endif
337
338
339 /*
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  * ---------------------------------------------------------------------
344  * Local variables:
345  * mode: c++
346  * indent-tabs-mode: t
347  * c-basic-offset: 4
348  * tab-width: 4
349  * End:
350  */