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.
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() {
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");
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
);
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");
68 jam_fprintf(stderr
, "%s: %s\n", excep_name
, message
);
70 jam_fprintf(stderr
, "%s\n", excep_name
);
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");
81 executeMethod(exp
, init
, str
);
83 if(cause
&& !exceptionOccurred()) {
84 MethodBlock
*mb
= lookupMethod(exception
, "initCause",
85 "(Ljava/lang/Throwable;)Ljava/lang/Throwable;");
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();
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");
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... */
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
;
134 int pc
= (char*)pc_pntr
- ((char*)mb
->code
);
136 int pc
= pc_pntr
- ((CodePntr
)mb
->code
);
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
) {
153 if(!isInstanceOf(caught_class
, exception
))
157 return (CodePntr
)(((char*)mb
->code
) + table
[i
].handler_pc
);
159 return ((CodePntr
)mb
->code
) + table
[i
].handler_pc
;
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
) {
175 Object
*sync_ob
= frame
->mb
->access_flags
& ACC_STATIC
?
176 (Object
*)frame
->mb
->class : (Object
*)frame
->lvars
[0];
178 Object
*sync_ob
= frame
->mb
->access_flags
& ACC_STATIC
?
179 (Object
*)frame
->mb
->class : (Object
*)*(frame
->lvars_jem
- 1);
181 objectUnlock(sync_ob
);
186 getExecEnv()->last_frame
= frame
;
191 int mapPC2LineNo(MethodBlock
*mb
, CodePntr pc_pntr
) {
192 int pc
= pc_pntr
- (CodePntr
) mb
->code
;
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
;
203 Object
*setStackTrace0(ExecEnv
*ee
, int max_depth
) {
204 Frame
*bottom
, *last
= ee
->last_frame
;
205 Object
*array
, *vmthrwble
;
210 initialiseException();
212 if(last
->prev
== NULL
) {
213 if((array
= allocTypeArray(sizeof(uintptr_t) == 4 ? T_INT
: T_LONG
, 0)) == NULL
)
218 for(; last
->mb
!= NULL
&& isInstanceOf(vmthrow_class
, last
->mb
->class);
221 for(; last
->mb
!= NULL
&& isInstanceOf(throw_class
, last
->mb
->class);
226 for(; last
->mb
!= NULL
; last
= last
->prev
, depth
++)
227 if(depth
== max_depth
)
229 } while((last
= last
->prev
)->prev
!= NULL
);
232 if((array
= allocTypeArray(sizeof(uintptr_t) == 4 ? T_INT
: T_LONG
, depth
*2)) == NULL
)
235 data
= ARRAY_DATA(array
);
238 for(; bottom
->mb
!= NULL
; bottom
= bottom
->prev
) {
239 if(depth
== max_depth
)
242 data
[depth
++] = (uintptr_t)bottom
->mb
;
243 data
[depth
++] = (uintptr_t)bottom
->last_pc
;
245 } while((bottom
= bottom
->prev
)->prev
!= NULL
);
248 if((vmthrwble
= allocObject(vmthrow_class
))) {
250 INST_DATA(vmthrwble
)[backtrace_offset
] = (uintptr_t)array
;
252 INST_DATA(vmthrwble
)[backtrace_offset
] = (uintptr_t)ARRAY_DATA(array
);
259 Object
*convertStackTrace(Object
*vmthrwble
) {
260 Object
*array
, *ste_array
;
266 initialiseException();
268 if((array
= (Object
*)INST_DATA(vmthrwble
)[backtrace_offset
]) == NULL
)
272 array
= JAM_ARRAY(array
);
275 src
= ARRAY_DATA(array
);
276 depth
= ARRAY_LEN(array
);
278 if((ste_array
= allocArray(ste_array_class
, depth
/2, sizeof(Object
*))) == 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
);
297 if(exceptionOccurred())
300 executeMethod(ste
, vmthrow_init_mb
, filename
, isNative
? -1 : mapPC2LineNo(mb
, pc
),
301 classname
, methodname
, isNative
);
303 if(exceptionOccurred())
309 dest
[j
] = INST_DATA(ste
);
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
) {
323 if((array
= (Object
*)INST_DATA(vmthrwble
)[backtrace_offset
]) != NULL
) {
328 array
= JAM_ARRAY(array
);
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
);