jamvm

view src/excep.c @ 401:3ca4c2fbbd7f

Handle difference between StackTraceElement constructors.

2008-08-04 Andrew John Hughes <gnu_andrew@member.fsf.org>

* configure.ac: Credit CACAO for
--with-java-runtime-library macro.
* src/excep.c,
* src/symbol.h:
Handle differing signature of StackTraceElement
constructor.
author andrew
date Tue Aug 05 05:16:11 2008 +0100 (2008-08-05)
parents ef6fa16d00f7
children 24373fc1d951
line source
1 /*
2 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008
3 * Robert Lougher <rob@lougher.org.uk>.
4 *
5 * This file is part of JamVM.
6 *
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.
11 *
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.
16 *
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.
20 */
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include "jam.h"
25 #include "lock.h"
26 #include "symbol.h"
27 #include "excep.h"
29 static Class *ste_class, *ste_array_class, *throw_class, *vmthrow_class;
30 static MethodBlock *vmthrow_init_mb;
31 static int backtrace_offset;
32 static int inited = FALSE;
34 static Class *exceptions[MAX_EXCEPTION_ENUM];
36 static int exception_symbols[] = {
37 EXCEPTIONS_DO(SYMBOL_NAME_ENUM)
38 };
40 void initialiseException() {
41 FieldBlock *bcktrce;
42 int i;
44 ste_class = findSystemClass0(SYMBOL(java_lang_StackTraceElement));
45 ste_array_class = findArrayClass(SYMBOL(array_java_lang_StackTraceElement));
46 vmthrow_class = findSystemClass0(SYMBOL(java_lang_VMThrowable));
47 throw_class = findSystemClass0(SYMBOL(java_lang_Throwable));
48 bcktrce = findField(vmthrow_class, SYMBOL(backtrace), SYMBOL(sig_java_lang_Object));
49 /* VMDIFF
50 GNU Classpath variant uses additional package-private constructor which allows
51 isNative to be specified, and changes the ordering.
52 */
53 vmthrow_init_mb = findMethod(ste_class, SYMBOL(object_init),
54 #ifdef WITH_JAVA_RUNTIME_LIBRARY_CLASSPATH
55 SYMBOL(_java_lang_String_I_java_lang_String_java_lang_String_Z__V));
56 #elif WITH_JAVA_RUNTIME_LIBRARY_OPENJDK
57 SYMBOL(_java_lang_String_java_lang_String_java_lang_String_I__V));
58 #endif
59 if((bcktrce == NULL) || (vmthrow_init_mb == NULL)) {
60 jam_fprintf(stderr, "Error initialising VM (initialiseException)\n");
61 exitVM(1);
62 }
64 CLASS_CB(vmthrow_class)->flags |= VMTHROWABLE;
65 backtrace_offset = bcktrce->offset;
67 registerStaticClassRef(&ste_class);
68 registerStaticClassRef(&ste_array_class);
69 registerStaticClassRef(&vmthrow_class);
70 registerStaticClassRef(&throw_class);
72 /* Load and register the exceptions used within the VM.
73 These are preloaded to speed up access. The VM will
74 abort if any can't be loaded */
76 for(i = 0; i < MAX_EXCEPTION_ENUM; i++) {
77 exceptions[i] = findSystemClass0(symbol_values[exception_symbols[i]]);
78 registerStaticClassRef(&exceptions[i]);
79 }
81 inited = TRUE;
82 }
84 Object *exceptionOccurred() {
85 return getExecEnv()->exception;
86 }
88 void setException(Object *exp) {
89 getExecEnv()->exception = exp;
90 }
92 void clearException() {
93 ExecEnv *ee = getExecEnv();
95 if(ee->overflow) {
96 ee->overflow = FALSE;
97 ee->stack_end -= STACK_RED_ZONE_SIZE;
98 }
99 ee->exception = NULL;
100 }
102 void signalChainedExceptionClass(Class *exception, char *message, Object *cause) {
103 Object *exp = allocObject(exception);
104 Object *str = message == NULL ? NULL : Cstr2String(message);
105 MethodBlock *init = lookupMethod(exception, SYMBOL(object_init),
106 SYMBOL(_java_lang_String__V));
107 if(exp && init) {
108 executeMethod(exp, init, str);
110 if(cause && !exceptionOccurred()) {
111 MethodBlock *mb = lookupMethod(exception, SYMBOL(initCause),
112 SYMBOL(_java_lang_Throwable__java_lang_Throwable));
113 if(mb)
114 executeMethod(exp, mb, cause);
115 }
116 setException(exp);
117 }
118 }
120 void signalChainedExceptionName(char *excep_name, char *message, Object *cause) {
121 if(!inited) {
122 jam_fprintf(stderr, "Exception occurred while VM initialising.\n");
123 if(message)
124 jam_fprintf(stderr, "%s: %s\n", excep_name, message);
125 else
126 jam_fprintf(stderr, "%s\n", excep_name);
127 exit(1);
128 } else {
129 Class *exception = findSystemClass(excep_name);
131 if(!exceptionOccurred())
132 signalChainedExceptionClass(exception, message, cause);
133 }
134 }
136 void signalChainedExceptionEnum(int excep_enum, char *message, Object *cause) {
137 if(!inited) {
138 char *excep_name = symbol_values[exception_symbols[excep_enum]];
140 jam_fprintf(stderr, "Exception occurred while VM initialising.\n");
141 if(message)
142 jam_fprintf(stderr, "%s: %s\n", excep_name, message);
143 else
144 jam_fprintf(stderr, "%s\n", excep_name);
145 exit(1);
146 }
148 signalChainedExceptionClass(exceptions[excep_enum], message, cause);
149 }
151 void printException() {
152 ExecEnv *ee = getExecEnv();
153 Object *exception = ee->exception;
155 if(exception != NULL) {
156 MethodBlock *mb = lookupMethod(exception->class, SYMBOL(printStackTrace),
157 SYMBOL(___V));
158 clearException();
159 executeMethod(exception, mb);
161 /* If we're really low on memory we might have been able to throw
162 * OutOfMemory, but then been unable to print any part of it! In
163 * this case the VM just seems to stop... */
164 if(ee->exception) {
165 jam_fprintf(stderr, "Exception occurred while printing exception (%s)...\n",
166 CLASS_CB(ee->exception->class)->name);
167 jam_fprintf(stderr, "Original exception was %s\n", CLASS_CB(exception->class)->name);
168 }
169 }
170 }
172 CodePntr findCatchBlockInMethod(MethodBlock *mb, Class *exception, CodePntr pc_pntr) {
173 ExceptionTableEntry *table = mb->exception_table;
174 int size = mb->exception_table_size;
175 int pc = pc_pntr - ((CodePntr)mb->code);
176 int i;
178 for(i = 0; i < size; i++)
179 if((pc >= table[i].start_pc) && (pc < table[i].end_pc)) {
181 /* If the catch_type is 0 it's a finally block, which matches
182 any exception. Otherwise, the thrown exception class must
183 be an instance of the caught exception class to catch it */
185 if(table[i].catch_type != 0) {
186 Class *caught_class = resolveClass(mb->class, table[i].catch_type, FALSE);
187 if(caught_class == NULL) {
188 clearException();
189 continue;
190 }
191 if(!isInstanceOf(caught_class, exception))
192 continue;
193 }
194 return ((CodePntr)mb->code) + table[i].handler_pc;
195 }
197 return NULL;
198 }
200 CodePntr findCatchBlock(Class *exception) {
201 Frame *frame = getExecEnv()->last_frame;
202 CodePntr handler_pc = NULL;
204 while(((handler_pc = findCatchBlockInMethod(frame->mb, exception, frame->last_pc)) == NULL)
205 && (frame->prev->mb != NULL)) {
207 if(frame->mb->access_flags & ACC_SYNCHRONIZED) {
208 Object *sync_ob = frame->mb->access_flags & ACC_STATIC ?
209 (Object*)frame->mb->class : (Object*)frame->lvars[0];
210 objectUnlock(sync_ob);
211 }
212 frame = frame->prev;
213 }
215 getExecEnv()->last_frame = frame;
217 return handler_pc;
218 }
220 int mapPC2LineNo(MethodBlock *mb, CodePntr pc_pntr) {
221 int pc = pc_pntr - (CodePntr) mb->code;
222 int i;
224 if(mb->line_no_table_size > 0) {
225 for(i = mb->line_no_table_size-1; i && pc < mb->line_no_table[i].start_pc; i--);
226 return mb->line_no_table[i].line_no;
227 }
229 return -1;
230 }
232 Object *setStackTrace0(ExecEnv *ee, int max_depth) {
233 Frame *bottom, *last = ee->last_frame;
234 Object *array, *vmthrwble;
235 uintptr_t *data;
236 int depth = 0;
238 if(last->prev == NULL) {
239 if((array = allocTypeArray(sizeof(uintptr_t) == 4 ? T_INT : T_LONG, 0)) == NULL)
240 return NULL;
241 goto out2;
242 }
244 for(; last->mb != NULL && isInstanceOf(vmthrow_class, last->mb->class);
245 last = last->prev);
247 for(; last->mb != NULL && isInstanceOf(throw_class, last->mb->class);
248 last = last->prev);
250 bottom = last;
251 do {
252 for(; last->mb != NULL; last = last->prev, depth++)
253 if(depth == max_depth)
254 goto out;
255 } while((last = last->prev)->prev != NULL);
257 out:
258 if((array = allocTypeArray(sizeof(uintptr_t) == 4 ? T_INT : T_LONG, depth*2)) == NULL)
259 return NULL;
261 data = ARRAY_DATA(array);
262 depth = 0;
263 do {
264 for(; bottom->mb != NULL; bottom = bottom->prev) {
265 if(depth == max_depth)
266 goto out2;
268 data[depth++] = (uintptr_t)bottom->mb;
269 data[depth++] = (uintptr_t)bottom->last_pc;
270 }
271 } while((bottom = bottom->prev)->prev != NULL);
273 out2:
274 if((vmthrwble = allocObject(vmthrow_class)))
275 INST_DATA(vmthrwble)[backtrace_offset] = (uintptr_t)array;
277 return vmthrwble;
278 }
280 Object *convertStackTrace(Object *vmthrwble) {
281 Object *array, *ste_array;
282 int depth, i, j;
283 uintptr_t *src;
284 Object **dest;
286 if((array = (Object *)INST_DATA(vmthrwble)[backtrace_offset]) == NULL)
287 return NULL;
289 src = ARRAY_DATA(array);
290 depth = ARRAY_LEN(array);
292 if((ste_array = allocArray(ste_array_class, depth/2, sizeof(Object*))) == NULL)
293 return NULL;
295 dest = ARRAY_DATA(ste_array);
297 for(i = 0, j = 0; i < depth; j++) {
298 MethodBlock *mb = (MethodBlock*)src[i++];
299 CodePntr pc = (CodePntr)src[i++];
300 ClassBlock *cb = CLASS_CB(mb->class);
301 char *dot_name = slash2dots(cb->name);
303 int isNative = mb->access_flags & ACC_NATIVE ? TRUE : FALSE;
304 Object *filename = isNative ? NULL : (cb->source_file_name ?
305 createString(cb->source_file_name) : NULL);
306 Object *classname = createString(dot_name);
307 Object *methodname = createString(mb->name);
308 Object *ste = allocObject(ste_class);
309 sysFree(dot_name);
311 if(exceptionOccurred())
312 return NULL;
314 /* VMDIFF: Arguments vary between libraries
315 Note: OpenJDK simply uses -2 to indicate a native method. */
316 #ifdef WITH_JAVA_RUNTIME_LIBRARY_CLASSPATH
317 executeMethod(ste, vmthrow_init_mb, filename, isNative ? -1 : mapPC2LineNo(mb, pc),
318 classname, methodname, isNative);
319 #elif WITH_JAVA_RUNTIME_LIBRARY_OPENJDK
320 executeMethod(ste, vmthrow_init_mb, classname, methodname, filename,
321 isNative ? -1 : mapPC2LineNo(mb, pc));
322 #endif
324 if(exceptionOccurred())
325 return NULL;
327 dest[j] = ste;
328 }
330 return ste_array;
331 }
333 /* GC support for marking classes referenced by a VMThrowable.
334 In rare circumstances a stack backtrace may hold the only
335 reference to a class */
337 void markVMThrowable(Object *vmthrwble, int mark, int mark_soft_refs) {
338 Object *array;
340 if((array = (Object *)INST_DATA(vmthrwble)[backtrace_offset]) != NULL) {
341 uintptr_t *src = ARRAY_DATA(array);
342 int i, depth = ARRAY_LEN(array);
344 for(i = 0; i < depth; i += 2) {
345 MethodBlock *mb = (MethodBlock*)src[i];
346 markObject(mb->class, mark, mark_soft_refs);
347 }
348 }
349 }