Fix LDC, LDC_W, and INSTANCEOF opcodes, more debugging
[jamvm-avr32-jem.git] / src / excep.c
blobeb5f068ae7244bee04cc27dcbe96b2c0166809f6
1 /*
2 * Copyright (C) 2003, 2004, 2005, 2006, 2007
3 * Robert Lougher <rob@lougher.org.uk>.
5 * This file is part of JamVM.
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2,
10 * or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include "jam.h"
25 #include "lock.h"
27 static Class *ste_class, *ste_array_class, *throw_class, *vmthrow_class;
28 static MethodBlock *vmthrow_init_mb;
29 static int backtrace_offset;
30 static int inited = FALSE;
32 void initialiseException() {
33 if(!inited) {
34 FieldBlock *bcktrce;
36 ste_class = findSystemClass("java/lang/StackTraceElement");
37 ste_array_class = findArrayClass("[Ljava/lang/StackTraceElement;");
38 vmthrow_class = findSystemClass("java/lang/VMThrowable");
39 throw_class = findSystemClass("java/lang/Throwable");
40 bcktrce = findField(vmthrow_class, "backtrace", "Ljava/lang/Object;");
41 vmthrow_init_mb = findMethod(ste_class, "<init>",
42 "(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;Z)V");
44 if((bcktrce == NULL) || (vmthrow_init_mb == NULL)) {
45 jam_fprintf(stderr, "Error initialising VM (initialiseException)\n");
46 exitVM(1);
48 CLASS_CB(vmthrow_class)->flags |= VMTHROWABLE;
49 backtrace_offset = bcktrce->offset;
51 registerStaticClassRef(&ste_class);
52 registerStaticClassRef(&ste_array_class);
53 registerStaticClassRef(&vmthrow_class);
54 registerStaticClassRef(&throw_class);
56 inited = TRUE;
60 Object *exceptionOccurred() {
61 return getExecEnv()->exception;
64 void signalChainedException(char *excep_name, char *message, Object *cause) {
65 if(VMInitialising()) {
66 jam_fprintf(stderr, "Exception occurred while VM initialising.\n");
67 if(message)
68 jam_fprintf(stderr, "%s: %s\n", excep_name, message);
69 else
70 jam_fprintf(stderr, "%s\n", excep_name);
71 exitVM(1);
72 } else {
73 Class *exception = findSystemClass(excep_name);
75 if(!exceptionOccurred()) {
76 Object *exp = allocObject(exception);
77 Object *str = message == NULL ? NULL : Cstr2String(message);
78 MethodBlock *init = lookupMethod(exception,
79 "<init>", "(Ljava/lang/String;)V");
80 if(exp && init) {
81 executeMethod(exp, init, str);
83 if(cause && !exceptionOccurred()) {
84 MethodBlock *mb = lookupMethod(exception, "initCause",
85 "(Ljava/lang/Throwable;)Ljava/lang/Throwable;");
86 if(mb)
87 executeMethod(exp, mb, cause);
90 getExecEnv()->exception = exp;
96 void setException(Object *exp) {
97 getExecEnv()->exception = exp;
100 void clearException() {
101 ExecEnv *ee = getExecEnv();
103 if(ee->overflow) {
104 ee->overflow = FALSE;
105 ee->stack_end -= STACK_RED_ZONE_SIZE;
107 ee->exception = NULL;
110 void printException() {
111 ExecEnv *ee = getExecEnv();
112 Object *exception = ee->exception;
114 if(exception != NULL) {
115 MethodBlock *mb = lookupMethod(exception->class, "printStackTrace", "()V");
116 clearException();
117 executeMethod(exception, mb);
119 /* If we're really low on memory we might have been able to throw
120 * OutOfMemory, but then been unable to print any part of it! In
121 * this case the VM just seems to stop... */
122 if(ee->exception) {
123 jam_fprintf(stderr, "Exception occured while printing exception (%s)...\n",
124 CLASS_CB(ee->exception->class)->name);
125 jam_fprintf(stderr, "Original exception was %s\n", CLASS_CB(exception->class)->name);
130 CodePntr findCatchBlockInMethod(MethodBlock *mb, Class *exception, CodePntr pc_pntr) {
131 ExceptionTableEntry *table = mb->exception_table;
132 int size = mb->exception_table_size;
133 #ifdef JEM
134 int pc = (char*)pc_pntr - ((char*)mb->code);
135 #else
136 int pc = pc_pntr - ((CodePntr)mb->code);
137 #endif
138 int i;
140 for(i = 0; i < size; i++)
141 if((pc >= table[i].start_pc) && (pc < table[i].end_pc)) {
143 /* If the catch_type is 0 it's a finally block, which matches
144 any exception. Otherwise, the thrown exception class must
145 be an instance of the caught exception class to catch it */
147 if(table[i].catch_type != 0) {
148 Class *caught_class = resolveClass(mb->class, table[i].catch_type, FALSE);
149 if(caught_class == NULL) {
150 clearException();
151 continue;
153 if(!isInstanceOf(caught_class, exception))
154 continue;
156 #ifdef JEM
157 return (CodePntr)(((char*)mb->code) + table[i].handler_pc);
158 #else
159 return ((CodePntr)mb->code) + table[i].handler_pc;
160 #endif
163 return NULL;
166 CodePntr findCatchBlock(Class *exception) {
167 Frame *frame = getExecEnv()->last_frame;
168 CodePntr handler_pc = NULL;
170 while(((handler_pc = findCatchBlockInMethod(frame->mb, exception, frame->last_pc)) == NULL)
171 && (frame->prev->mb != NULL)) {
173 if(frame->mb->access_flags & ACC_SYNCHRONIZED) {
174 #ifndef JEM
175 Object *sync_ob = frame->mb->access_flags & ACC_STATIC ?
176 (Object*)frame->mb->class : (Object*)frame->lvars[0];
177 #else
178 Object *sync_ob = frame->mb->access_flags & ACC_STATIC ?
179 (Object*)frame->mb->class : (Object*)*(frame->lvars_jem - 1);
180 #endif
181 objectUnlock(sync_ob);
183 frame = frame->prev;
186 getExecEnv()->last_frame = frame;
188 return handler_pc;
191 int mapPC2LineNo(MethodBlock *mb, CodePntr pc_pntr) {
192 int pc = pc_pntr - (CodePntr) mb->code;
193 int i;
195 if(mb->line_no_table_size > 0) {
196 for(i = mb->line_no_table_size-1; i && pc < mb->line_no_table[i].start_pc; i--);
197 return mb->line_no_table[i].line_no;
200 return -1;
203 Object *setStackTrace0(ExecEnv *ee, int max_depth) {
204 Frame *bottom, *last = ee->last_frame;
205 Object *array, *vmthrwble;
206 uintptr_t *data;
207 int depth = 0;
209 if(!inited)
210 initialiseException();
212 if(last->prev == NULL) {
213 if((array = allocTypeArray(sizeof(uintptr_t) == 4 ? T_INT : T_LONG, 0)) == NULL)
214 return NULL;
215 goto out2;
218 for(; last->mb != NULL && isInstanceOf(vmthrow_class, last->mb->class);
219 last = last->prev);
221 for(; last->mb != NULL && isInstanceOf(throw_class, last->mb->class);
222 last = last->prev);
224 bottom = last;
225 do {
226 for(; last->mb != NULL; last = last->prev, depth++)
227 if(depth == max_depth)
228 goto out;
229 } while((last = last->prev)->prev != NULL);
231 out:
232 if((array = allocTypeArray(sizeof(uintptr_t) == 4 ? T_INT : T_LONG, depth*2)) == NULL)
233 return NULL;
235 data = ARRAY_DATA(array);
236 depth = 0;
237 do {
238 for(; bottom->mb != NULL; bottom = bottom->prev) {
239 if(depth == max_depth)
240 goto out2;
242 data[depth++] = (uintptr_t)bottom->mb;
243 data[depth++] = (uintptr_t)bottom->last_pc;
245 } while((bottom = bottom->prev)->prev != NULL);
247 out2:
248 if((vmthrwble = allocObject(vmthrow_class))) {
249 #if JAM_ON_STACK
250 INST_DATA(vmthrwble)[backtrace_offset] = (uintptr_t)array;
251 #else
252 INST_DATA(vmthrwble)[backtrace_offset] = (uintptr_t)ARRAY_DATA(array);
253 #endif
256 return vmthrwble;
259 Object *convertStackTrace(Object *vmthrwble) {
260 Object *array, *ste_array;
261 int depth, i, j;
262 uintptr_t *src;
263 Object **dest;
265 if(!inited)
266 initialiseException();
268 if((array = (Object *)INST_DATA(vmthrwble)[backtrace_offset]) == NULL)
269 return NULL;
271 #if !JAM_ON_STACK
272 array = JAM_ARRAY(array);
273 #endif
275 src = ARRAY_DATA(array);
276 depth = ARRAY_LEN(array);
278 if((ste_array = allocArray(ste_array_class, depth/2, sizeof(Object*))) == NULL)
279 return NULL;
281 dest = ARRAY_DATA(ste_array);
283 for(i = 0, j = 0; i < depth; j++) {
284 MethodBlock *mb = (MethodBlock*)src[i++];
285 CodePntr pc = (CodePntr)src[i++];
286 ClassBlock *cb = CLASS_CB(mb->class);
287 char *dot_name = slash2dots(cb->name);
289 int isNative = mb->access_flags & ACC_NATIVE ? TRUE : FALSE;
290 Object *filename = isNative ? NULL : (cb->source_file_name ?
291 createString(cb->source_file_name) : NULL);
292 Object *classname = createString(dot_name);
293 Object *methodname = createString(mb->name);
294 Object *ste = allocObject(ste_class);
295 sysFree(dot_name);
297 if(exceptionOccurred())
298 return NULL;
300 executeMethod(ste, vmthrow_init_mb, filename, isNative ? -1 : mapPC2LineNo(mb, pc),
301 classname, methodname, isNative);
303 if(exceptionOccurred())
304 return NULL;
306 #if JAM_ON_STACK
307 dest[j] = ste;
308 #else
309 dest[j] = INST_DATA(ste);
310 #endif
313 return ste_array;
316 /* GC support for marking classes referenced by a VMThrowable.
317 In rare circumstances a stack backtrace may hold the only
318 reference to a class */
320 void markVMThrowable(Object *vmthrwble, int mark, int mark_soft_refs) {
321 Object *array;
323 if((array = (Object *)INST_DATA(vmthrwble)[backtrace_offset]) != NULL) {
324 uintptr_t *src;
325 int i, depth;
327 #if !JAM_ON_STACK
328 array = JAM_ARRAY(array);
329 #endif
330 src = ARRAY_DATA(array);
331 depth = ARRAY_LEN(array);
333 for(i = 0; i < depth; i += 2) {
334 MethodBlock *mb = (MethodBlock*)src[i];
335 markObject(mb->class, mark, mark_soft_refs);