jamvm

view src/excep.c @ 402:24373fc1d951

Add additional tracing support.

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

* .hgignore: Updated with autogen.sh output.
* configure.ac: Add new trace options.
* src/class.c,
* src/excep.c,
* src/natives.c,
* src/resolve.c: Add trace support.
* src/jam.h,
* src/dll.c,
* src/os/linux/os.c: Add support for reporting
the linking error using dlerror.
author andrew
date Tue Aug 05 05:46:09 2008 +0100 (2008-08-05)
parents 3ca4c2fbbd7f
children
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 /* Trace exception handling */
30 #ifdef TRACEEXCEP
31 #define TRACE(fmt, ...) jam_printf(fmt, ## __VA_ARGS__)
32 #define TRACE(fmt, ...)
33 #endif
35 static Class *ste_class, *ste_array_class, *throw_class, *vmthrow_class;
36 static MethodBlock *vmthrow_init_mb;
37 static int backtrace_offset;
38 static int inited = FALSE;
40 static Class *exceptions[MAX_EXCEPTION_ENUM];
42 static int exception_symbols[] = {
43 EXCEPTIONS_DO(SYMBOL_NAME_ENUM)
44 };
46 void initialiseException() {
47 FieldBlock *bcktrce;
48 int i;
50 ste_class = findSystemClass0(SYMBOL(java_lang_StackTraceElement));
51 ste_array_class = findArrayClass(SYMBOL(array_java_lang_StackTraceElement));
52 vmthrow_class = findSystemClass0(SYMBOL(java_lang_VMThrowable));
53 throw_class = findSystemClass0(SYMBOL(java_lang_Throwable));
54 bcktrce = findField(vmthrow_class, SYMBOL(backtrace), SYMBOL(sig_java_lang_Object));
55 /* VMDIFF
56 GNU Classpath variant uses additional package-private constructor which allows
57 isNative to be specified, and changes the ordering.
58 */
59 vmthrow_init_mb = findMethod(ste_class, SYMBOL(object_init),
60 #ifdef WITH_JAVA_RUNTIME_LIBRARY_CLASSPATH
61 SYMBOL(_java_lang_String_I_java_lang_String_java_lang_String_Z__V));
62 #elif WITH_JAVA_RUNTIME_LIBRARY_OPENJDK
63 SYMBOL(_java_lang_String_java_lang_String_java_lang_String_I__V));
64 #endif
65 if((bcktrce == NULL) || (vmthrow_init_mb == NULL)) {
66 jam_fprintf(stderr, "Error initialising VM (initialiseException)\n");
67 exitVM(1);
68 }
70 CLASS_CB(vmthrow_class)->flags |= VMTHROWABLE;
71 backtrace_offset = bcktrce->offset;
73 registerStaticClassRef(&ste_class);
74 registerStaticClassRef(&ste_array_class);
75 registerStaticClassRef(&vmthrow_class);
76 registerStaticClassRef(&throw_class);
78 /* Load and register the exceptions used within the VM.
79 These are preloaded to speed up access. The VM will
80 abort if any can't be loaded */
82 for(i = 0; i < MAX_EXCEPTION_ENUM; i++) {
83 exceptions[i] = findSystemClass0(symbol_values[exception_symbols[i]]);
84 registerStaticClassRef(&exceptions[i]);
85 }
87 inited = TRUE;
88 }
90 Object *exceptionOccurred() {
91 return getExecEnv()->exception;
92 }
94 void setException(Object *exp) {
95 getExecEnv()->exception = exp;
96 }
98 void clearException() {
99 ExecEnv *ee = getExecEnv();
101 if(ee->overflow) {
102 ee->overflow = FALSE;
103 ee->stack_end -= STACK_RED_ZONE_SIZE;
104 }
105 ee->exception = NULL;
106 }
108 void signalChainedExceptionClass(Class *exception, char *message, Object *cause) {
109 Object *exp = allocObject(exception);
110 Object *str = message == NULL ? NULL : Cstr2String(message);
111 MethodBlock *init = lookupMethod(exception, SYMBOL(object_init),
112 SYMBOL(_java_lang_String__V));
113 if(exp && init) {
114 executeMethod(exp, init, str);
116 if(cause && !exceptionOccurred()) {
117 MethodBlock *mb = lookupMethod(exception, SYMBOL(initCause),
118 SYMBOL(_java_lang_Throwable__java_lang_Throwable));
119 if(mb)
120 executeMethod(exp, mb, cause);
121 }
122 setException(exp);
123 }
124 }
126 void signalChainedExceptionName(char *excep_name, char *message, Object *cause) {
127 if(!inited) {
128 jam_fprintf(stderr, "Exception occurred while VM initialising.\n");
129 if(message)
130 jam_fprintf(stderr, "%s: %s\n", excep_name, message);
131 else
132 jam_fprintf(stderr, "%s\n", excep_name);
133 exit(1);
134 } else {
135 Class *exception = findSystemClass(excep_name);
137 if(!exceptionOccurred())
138 signalChainedExceptionClass(exception, message, cause);
139 }
140 }
142 void signalChainedExceptionEnum(int excep_enum, char *message, Object *cause) {
143 TRACE("<EXCEP: Exception with message %s and cause %s>\n", message,
144 cause ? CLASS_CB(cause->class)->name : "unknown");
145 if(!inited) {
146 char *excep_name = symbol_values[exception_symbols[excep_enum]];
148 jam_fprintf(stderr, "Exception occurred while VM initialising.\n");
149 if(message)
150 jam_fprintf(stderr, "%s: %s\n", excep_name, message);
151 else
152 jam_fprintf(stderr, "%s\n", excep_name);
153 exit(1);
154 }
156 signalChainedExceptionClass(exceptions[excep_enum], message, cause);
157 }
159 void printException() {
160 ExecEnv *ee = getExecEnv();
161 Object *exception = ee->exception;
163 if(exception != NULL) {
164 MethodBlock *mb = lookupMethod(exception->class, SYMBOL(printStackTrace),
165 SYMBOL(___V));
166 clearException();
167 executeMethod(exception, mb);
169 /* If we're really low on memory we might have been able to throw
170 * OutOfMemory, but then been unable to print any part of it! In
171 * this case the VM just seems to stop... */
172 if(ee->exception) {
173 jam_fprintf(stderr, "Exception occurred while printing exception (%s)...\n",
174 CLASS_CB(ee->exception->class)->name);
175 jam_fprintf(stderr, "Original exception was %s\n", CLASS_CB(exception->class)->name);
176 }
177 }
178 }
180 CodePntr findCatchBlockInMethod(MethodBlock *mb, Class *exception, CodePntr pc_pntr) {
181 ExceptionTableEntry *table = mb->exception_table;
182 int size = mb->exception_table_size;
183 int pc = pc_pntr - ((CodePntr)mb->code);
184 int i;
186 for(i = 0; i < size; i++)
187 if((pc >= table[i].start_pc) && (pc < table[i].end_pc)) {
189 /* If the catch_type is 0 it's a finally block, which matches
190 any exception. Otherwise, the thrown exception class must
191 be an instance of the caught exception class to catch it */
193 if(table[i].catch_type != 0) {
194 Class *caught_class = resolveClass(mb->class, table[i].catch_type, FALSE);
195 if(caught_class == NULL) {
196 clearException();
197 continue;
198 }
199 if(!isInstanceOf(caught_class, exception))
200 continue;
201 }
202 return ((CodePntr)mb->code) + table[i].handler_pc;
203 }
205 return NULL;
206 }
208 CodePntr findCatchBlock(Class *exception) {
209 Frame *frame = getExecEnv()->last_frame;
210 CodePntr handler_pc = NULL;
212 while(((handler_pc = findCatchBlockInMethod(frame->mb, exception, frame->last_pc)) == NULL)
213 && (frame->prev->mb != NULL)) {
215 if(frame->mb->access_flags & ACC_SYNCHRONIZED) {
216 Object *sync_ob = frame->mb->access_flags & ACC_STATIC ?
217 (Object*)frame->mb->class : (Object*)frame->lvars[0];
218 objectUnlock(sync_ob);
219 }
220 frame = frame->prev;
221 }
223 getExecEnv()->last_frame = frame;
225 return handler_pc;
226 }
228 int mapPC2LineNo(MethodBlock *mb, CodePntr pc_pntr) {
229 int pc = pc_pntr - (CodePntr) mb->code;
230 int i;
232 if(mb->line_no_table_size > 0) {
233 for(i = mb->line_no_table_size-1; i && pc < mb->line_no_table[i].start_pc; i--);
234 return mb->line_no_table[i].line_no;
235 }
237 return -1;
238 }
240 Object *setStackTrace0(ExecEnv *ee, int max_depth) {
241 Frame *bottom, *last = ee->last_frame;
242 Object *array, *vmthrwble;
243 uintptr_t *data;
244 int depth = 0;
246 if(last->prev == NULL) {
247 if((array = allocTypeArray(sizeof(uintptr_t) == 4 ? T_INT : T_LONG, 0)) == NULL)
248 return NULL;
249 goto out2;
250 }
252 for(; last->mb != NULL && isInstanceOf(vmthrow_class, last->mb->class);
253 last = last->prev);
255 for(; last->mb != NULL && isInstanceOf(throw_class, last->mb->class);
256 last = last->prev);
258 bottom = last;
259 do {
260 for(; last->mb != NULL; last = last->prev, depth++)
261 if(depth == max_depth)
262 goto out;
263 } while((last = last->prev)->prev != NULL);
265 out:
266 if((array = allocTypeArray(sizeof(uintptr_t) == 4 ? T_INT : T_LONG, depth*2)) == NULL)
267 return NULL;
269 data = ARRAY_DATA(array);
270 depth = 0;
271 do {
272 for(; bottom->mb != NULL; bottom = bottom->prev) {
273 if(depth == max_depth)
274 goto out2;
276 data[depth++] = (uintptr_t)bottom->mb;
277 data[depth++] = (uintptr_t)bottom->last_pc;
278 }
279 } while((bottom = bottom->prev)->prev != NULL);
281 out2:
282 if((vmthrwble = allocObject(vmthrow_class)))
283 INST_DATA(vmthrwble)[backtrace_offset] = (uintptr_t)array;
285 return vmthrwble;
286 }
288 Object *convertStackTrace(Object *vmthrwble) {
289 Object *array, *ste_array;
290 int depth, i, j;
291 uintptr_t *src;
292 Object **dest;
294 if((array = (Object *)INST_DATA(vmthrwble)[backtrace_offset]) == NULL)
295 return NULL;
297 src = ARRAY_DATA(array);
298 depth = ARRAY_LEN(array);
300 if((ste_array = allocArray(ste_array_class, depth/2, sizeof(Object*))) == NULL)
301 return NULL;
303 dest = ARRAY_DATA(ste_array);
305 for(i = 0, j = 0; i < depth; j++) {
306 MethodBlock *mb = (MethodBlock*)src[i++];
307 CodePntr pc = (CodePntr)src[i++];
308 ClassBlock *cb = CLASS_CB(mb->class);
309 char *dot_name = slash2dots(cb->name);
311 int isNative = mb->access_flags & ACC_NATIVE ? TRUE : FALSE;
312 Object *filename = isNative ? NULL : (cb->source_file_name ?
313 createString(cb->source_file_name) : NULL);
314 Object *classname = createString(dot_name);
315 Object *methodname = createString(mb->name);
316 Object *ste = allocObject(ste_class);
317 sysFree(dot_name);
319 if(exceptionOccurred())
320 return NULL;
322 /* VMDIFF: Arguments vary between libraries
323 Note: OpenJDK simply uses -2 to indicate a native method. */
324 #ifdef WITH_JAVA_RUNTIME_LIBRARY_CLASSPATH
325 executeMethod(ste, vmthrow_init_mb, filename, isNative ? -1 : mapPC2LineNo(mb, pc),
326 classname, methodname, isNative);
327 #elif WITH_JAVA_RUNTIME_LIBRARY_OPENJDK
328 executeMethod(ste, vmthrow_init_mb, classname, methodname, filename,
329 isNative ? -1 : mapPC2LineNo(mb, pc));
330 #endif
332 if(exceptionOccurred())
333 return NULL;
335 dest[j] = ste;
336 }
338 return ste_array;
339 }
341 /* GC support for marking classes referenced by a VMThrowable.
342 In rare circumstances a stack backtrace may hold the only
343 reference to a class */
345 void markVMThrowable(Object *vmthrwble, int mark, int mark_soft_refs) {
346 Object *array;
348 if((array = (Object *)INST_DATA(vmthrwble)[backtrace_offset]) != NULL) {
349 uintptr_t *src = ARRAY_DATA(array);
350 int i, depth = ARRAY_LEN(array);
352 for(i = 0; i < depth; i += 2) {
353 MethodBlock *mb = (MethodBlock*)src[i];
354 markObject(mb->class, mark, mark_soft_refs);
355 }
356 }
357 }