* src/vm/jit/trap.c (trap_handle): Update executionstates PC register in case
[cacao.git] / src / vm / jit / trap.c
1 /* src/vm/jit/trap.c - 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.h"
36
37 #include "native/llni.h"
38
39 #include "toolbox/logging.h"
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
57 /**
58  * Mmap the first memory page to support hardware exceptions and check
59  * the maximum hardware trap displacement on the architectures where
60  * it is required (TRAP_INSTRUCTION_IS_LOAD defined to 1).
61  */
62 void trap_init(void)
63 {
64 #if !(defined(__ARM__) && defined(__LINUX__))
65         /* On arm-linux the first memory page can't be mmap'ed, as it
66            contains the exception vectors. */
67
68         int pagesize;
69
70         /* mmap a memory page at address 0x0, so our hardware-exceptions
71            work. */
72
73         pagesize = os_getpagesize();
74
75         (void) os_mmap_anonymous(NULL, pagesize, PROT_NONE, MAP_PRIVATE | MAP_FIXED);
76 #endif
77
78         TRACESUBSYSTEMINITIALIZATION("trap_init");
79
80 #if !defined(TRAP_INSTRUCTION_IS_LOAD)
81 # error TRAP_INSTRUCTION_IS_LOAD is not defined in your md-trap.h
82 #endif
83
84 #if TRAP_INSTRUCTION_IS_LOAD == 1
85         /* Check if we get into trouble with our hardware-exceptions. */
86
87         if (TRAP_END > OFFSET(java_bytearray_t, data))
88                 vm_abort("trap_init: maximum hardware trap displacement is greater than the array-data offset: %d > %d", TRAP_END, OFFSET(java_bytearray_t, data));
89 #endif
90 }
91
92
93 /**
94  * Handles the signal which is generated by trap instructions, caught
95  * by a signal handler and calls the correct function.
96  *
97  * @param type trap number
98  * @param 
99  */
100 void* trap_handle(int type, intptr_t val, void *pv, void *sp, void *ra, void *xpc, void *context)
101 {
102         executionstate_t  es;
103         stackframeinfo_t  sfi;
104         int32_t           index;
105         java_handle_t    *o;
106         methodinfo       *m;
107         java_handle_t    *p;
108
109 #if !defined(NDEBUG)
110         if (opt_TraceTraps)
111                 log_println("[signal_handle: trap %d]", type);
112 #endif
113         
114 #if defined(ENABLE_VMLOG)
115         vmlog_cacao_signl_type(type);
116 #endif
117
118         /* Prevent compiler warnings. */
119
120         o = NULL;
121         m = NULL;
122
123 #if defined(__ALPHA__) || defined(__ARM__) || defined(__I386__) || defined(__POWERPC__) || defined(__POWERPC64__) || defined(__X86_64__)
124 # if !defined(NDEBUG)
125         /* Perform a sanity check on our execution state functions. */
126
127         executionstate_sanity_check(context);
128 # endif
129
130         /* Read execution state from current context. */
131
132         es.code = NULL;
133         md_executionstate_read(&es, context);
134 #endif
135
136         /* wrap the value into a handle if it is a reference */
137         /* BEFORE: creating stackframeinfo */
138
139         switch (type) {
140         case TRAP_ClassCastException:
141                 o = LLNI_WRAP((java_object_t *) val);
142                 break;
143
144         case TRAP_COMPILER:
145                 /* In this case the passed PV points to the compiler stub.  We
146                    get the methodinfo pointer here and set PV to NULL so
147                    stacktrace_stackframeinfo_add determines the PV for the
148                    parent Java method. */
149
150                 m  = code_get_methodinfo_for_pv(pv);
151                 pv = NULL;
152                 break;
153
154         default:
155                 /* do nothing */
156                 break;
157         }
158
159         /* Fill and add a stackframeinfo. */
160
161         stacktrace_stackframeinfo_add(&sfi, pv, sp, ra, xpc);
162
163         switch (type) {
164         case TRAP_NullPointerException:
165                 p = exceptions_new_nullpointerexception();
166                 break;
167
168         case TRAP_ArithmeticException:
169                 p = exceptions_new_arithmeticexception();
170                 break;
171
172         case TRAP_ArrayIndexOutOfBoundsException:
173                 index = (s4) val;
174                 p = exceptions_new_arrayindexoutofboundsexception(index);
175                 break;
176
177         case TRAP_ArrayStoreException:
178                 p = exceptions_new_arraystoreexception();
179                 break;
180
181         case TRAP_ClassCastException:
182                 p = exceptions_new_classcastexception(o);
183                 break;
184
185         case TRAP_CHECK_EXCEPTION:
186                 p = exceptions_fillinstacktrace();
187                 break;
188
189         case TRAP_PATCHER:
190 #if defined(ENABLE_REPLACEMENT)
191                 if (replace_me_wrapper(xpc, context)) {
192                         p = NULL;
193                         break;
194                 }
195 #endif
196                 p = patcher_handler(xpc);
197                 break;
198
199         case TRAP_COMPILER:
200                 p = jit_compile_handle(m, sfi.pv, ra, (void *) val);
201                 break;
202
203 #if defined(ENABLE_REPLACEMENT)
204         case TRAP_COUNTDOWN:
205 #if defined(__I386__)
206                 replace_me_wrapper((char*)xpc - 13, context);
207 #endif
208                 p = NULL;
209                 break;
210 #endif
211
212         default:
213                 /* Let's try to get a backtrace. */
214
215                 (void) methodtree_find(xpc);
216
217                 /* If that does not work, print more debug info. */
218
219                 log_println("signal_handle: unknown hardware exception type %d", type);
220
221 #if SIZEOF_VOID_P == 8
222                 log_println("PC=0x%016lx", xpc);
223 #else
224                 log_println("PC=0x%08x", xpc);
225 #endif
226
227 #if defined(ENABLE_DISASSEMBLER)
228                 log_println("machine instruction at PC:");
229                 disassinstr(xpc);
230 #endif
231
232                 vm_abort("Exiting...");
233
234                 /* keep compiler happy */
235
236                 p = NULL;
237         }
238
239         /* Remove stackframeinfo. */
240
241         stacktrace_stackframeinfo_remove(&sfi);
242
243 #if defined(__ALPHA__) || defined(__ARM__) || defined(__I386__) || defined(__POWERPC__) || defined(__POWERPC64__) || defined(__X86_64__)
244         /* Update execution state and set registers. */
245         /* AFTER: removing stackframeinfo */
246
247         switch (type) {
248         case TRAP_COMPILER:
249                 // The normal case for a compiler trap is to jump directly to
250                 // the newly compiled method.
251
252                 if (p != NULL) {
253                         es.pc = (uint8_t *) (uintptr_t) p;
254                         es.pv = (uint8_t *) (uintptr_t) p;
255                         break;
256                 }
257
258                 // In case of an exception during JIT compilation, we fetch
259                 // the exception here and proceed with exception handling.
260
261                 java_handle_t *e = exceptions_get_and_clear_exception();
262                 assert(e != NULL);
263
264                 // Get and set the PV from the parent Java method.
265
266                 es.pv = md_codegen_get_pv_from_pc(ra);
267
268                 // XXX: Make the code below a fall-through to default case!
269
270                 es.intregs[REG_ITMP1_XPTR] = (uintptr_t) LLNI_DIRECT(e);
271                 es.intregs[REG_ITMP2_XPC]  = (uintptr_t) xpc;
272                 es.pc                      = (uint8_t *) (uintptr_t) asm_handle_exception;
273                 break;
274
275         case TRAP_PATCHER:
276                 // The normal case for a patcher trap is to continue execution at
277                 // the trap instruction. On some archs the PC may point after the
278                 // trap instruction, so we reset it here.
279
280                 if (p == NULL) {
281                         es.pc = (uint8_t *) (uintptr_t) xpc;
282                         break;
283                 }
284
285                 /* fall-through */
286
287         default:
288                 if (p != NULL) {
289                         es.intregs[REG_ITMP1_XPTR] = (uintptr_t) LLNI_DIRECT(p);
290                         es.intregs[REG_ITMP2_XPC]  = (uintptr_t) xpc;
291                         es.pc                      = (uint8_t *) (uintptr_t) asm_handle_exception;
292                 }
293         }
294
295         /* Write back execution state to current context. */
296
297         md_executionstate_write(&es, context);
298 #endif
299
300         /* unwrap and return the exception object */
301         /* AFTER: removing stackframeinfo */
302
303         if (type == TRAP_COMPILER)
304                 return p;
305         else
306                 return LLNI_UNWRAP(p);
307 }
308
309
310 /*
311  * These are local overrides for various environment variables in Emacs.
312  * Please do not remove this and leave it at the end of the file, where
313  * Emacs will automagically detect them.
314  * ---------------------------------------------------------------------
315  * Local variables:
316  * mode: c
317  * indent-tabs-mode: t
318  * c-basic-offset: 4
319  * tab-width: 4
320  * End:
321  */