Merged revisions 7797-7917 via svnmerge from
[cacao.git] / src / native / vm / gnu / java_lang_VMThrowable.c
1 /* src/native/vm/gnu/java_lang_VMThrowable.c
2
3    Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
4    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6    J. Wenninger, Institut f. Computersprachen - TU Wien
7
8    This file is part of CACAO.
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2, or (at
13    your option) any later version.
14
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23    02110-1301, USA.
24
25    $Id: java_lang_VMThrowable.c 7910 2007-05-16 08:02:52Z twisti $
26
27 */
28
29
30 #include "config.h"
31
32 #include <assert.h>
33
34 #include "vm/types.h"
35
36 #include "native/jni.h"
37 #include "native/native.h"
38
39 #include "native/include/gnu_classpath_Pointer.h"
40 #include "native/include/java_lang_Class.h"
41 #include "native/include/java_lang_StackTraceElement.h"
42 #include "native/include/java_lang_Throwable.h"
43
44 #include "native/include/java_lang_VMThrowable.h"
45
46 #include "native/vm/java_lang_Class.h"
47
48 #include "vm/builtin.h"
49 #include "vm/exceptions.h"
50 #include "vm/stringlocal.h"
51
52 #include "vm/jit/stacktrace.h"
53
54 #include "vmcore/class.h"
55 #include "vmcore/loader.h"
56
57
58 /* native methods implemented by this file ************************************/
59
60 static JNINativeMethod methods[] = {
61         { "fillInStackTrace", "(Ljava/lang/Throwable;)Ljava/lang/VMThrowable;",        (void *) (ptrint) &Java_java_lang_VMThrowable_fillInStackTrace },
62         { "getStackTrace",    "(Ljava/lang/Throwable;)[Ljava/lang/StackTraceElement;", (void *) (ptrint) &Java_java_lang_VMThrowable_getStackTrace    },
63 };
64
65
66 /* _Jv_java_lang_VMThrowable_init **********************************************
67
68    Register native functions.
69
70 *******************************************************************************/
71
72 void _Jv_java_lang_VMThrowable_init(void)
73 {
74         utf *u;
75
76         u = utf_new_char("java/lang/VMThrowable");
77
78         native_method_register(u, methods, NATIVE_METHODS_COUNT);
79 }
80
81
82 /*
83  * Class:     java/lang/VMThrowable
84  * Method:    fillInStackTrace
85  * Signature: (Ljava/lang/Throwable;)Ljava/lang/VMThrowable;
86  */
87 JNIEXPORT java_lang_VMThrowable* JNICALL Java_java_lang_VMThrowable_fillInStackTrace(JNIEnv *env, jclass clazz, java_lang_Throwable *t)
88 {
89         java_lang_VMThrowable *o;
90         stacktracecontainer   *stc;
91
92         o = (java_lang_VMThrowable *)
93                 native_new_and_init(class_java_lang_VMThrowable);
94
95         if (o == NULL)
96                 return NULL;
97
98         stc = stacktrace_fillInStackTrace();
99
100         if (stc == NULL)
101                 return NULL;
102
103         o->vmData = (gnu_classpath_Pointer *) stc;
104
105         return o;
106 }
107
108
109 /*
110  * Class:     java/lang/VMThrowable
111  * Method:    getStackTrace
112  * Signature: (Ljava/lang/Throwable;)[Ljava/lang/StackTraceElement;
113  */
114 JNIEXPORT java_objectarray* JNICALL Java_java_lang_VMThrowable_getStackTrace(JNIEnv *env, java_lang_VMThrowable *this, java_lang_Throwable *t)
115 {
116         stacktracecontainer         *stc;
117         stacktracebuffer            *stb;
118         stacktrace_entry            *ste;
119         stacktrace_entry            *tmpste;
120         s4                           size;
121         s4                           i;
122         classinfo                   *c;
123         bool                         inexceptionclass;
124         bool                         leftexceptionclass;
125
126         methodinfo                  *m;
127         java_objectarray            *oa;
128         s4                           oalength;
129         java_lang_StackTraceElement *o;
130         java_lang_String            *filename;
131         s4                           linenumber;
132         java_lang_String            *declaringclass;
133
134         /* get the stacktrace buffer from the VMThrowable object */
135
136         stc = (stacktracecontainer *) this->vmData;
137         stb = &(stc->stb);
138
139         /* get the class of the Throwable object */
140
141         c = t->header.vftbl->class;
142
143         assert(stb != NULL);
144
145         size = stb->used;
146
147         assert(size >= 2);
148
149         /* skip first 2 elements in stacktrace buffer:                            */
150         /*   0: VMThrowable.fillInStackTrace                                      */
151         /*   1: Throwable.fillInStackTrace                                        */
152
153         ste = &(stb->entries[2]);
154         size -= 2;
155
156         if ((size > 0) && (ste->method != 0)) {
157                 /* not a builtin native wrapper*/
158
159                 if ((ste->method->class->name == utf_java_lang_Throwable) &&
160                         (ste->method->name == utf_init)) {
161                         /* We assume that we are within the initializer of the
162                            exception object, the exception object itself should
163                            not appear in the stack trace, so we skip till we reach
164                            the first function, which is not an init function. */
165
166                         inexceptionclass = false;
167                         leftexceptionclass = false;
168
169                         while (size > 0) {
170                                 /* check if we are in the exception class */
171
172                                 if (ste->method->class == c)
173                                         inexceptionclass = true;
174
175                                 /* check if we left the exception class */
176
177                                 if (inexceptionclass && (ste->method->class != c))
178                                         leftexceptionclass = true;
179
180                                 /* Found exception start point if we left the
181                                    initalizers or we left the exception class. */
182
183                                 if ((ste->method->name != utf_init) || leftexceptionclass)
184                                         break;
185
186                                 /* go to next stacktrace element */
187
188                                 ste++;
189                                 size--;
190                         }
191                 }
192         }
193
194
195         /* now fill the stacktrace into java objects */
196
197         m = class_findmethod(class_java_lang_StackTraceElement,
198                                                  utf_init,
199                                                  utf_new_char("(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;Z)V"));
200
201         if (m == NULL)
202                 return NULL;
203
204         /* count entries with a method name */
205
206         for (oalength = 0, i = size, tmpste = ste; i > 0; i--, tmpste++)
207                 if (tmpste->method)
208                         oalength++;
209
210         /* create the stacktrace element array */
211
212         oa = builtin_anewarray(oalength, class_java_lang_StackTraceElement);
213
214         if (oa == NULL)
215                 return NULL;
216
217         for (i = 0; size > 0; size--, ste++, i++) {
218                 /* skip entries without a method name */
219
220                 if (ste->method == NULL) {
221                         i--;
222                         continue;
223                 }
224
225                 /* allocate a new stacktrace element */
226
227                 o = (java_lang_StackTraceElement *)
228                         builtin_new(class_java_lang_StackTraceElement);
229
230                 if (o == NULL)
231                         return NULL;
232
233                 /* get filename */
234
235                 if (!(ste->method->flags & ACC_NATIVE)) {
236                         if (ste->method->class->sourcefile)
237                                 filename = (java_lang_String *) javastring_new(ste->method->class->sourcefile);
238                         else
239                                 filename = NULL;
240                 }
241                 else
242                         filename = NULL;
243
244                 /* get line number */
245
246                 if (ste->method->flags & ACC_NATIVE)
247                         linenumber = -1;
248                 else
249                         linenumber = (ste->linenumber == 0) ? -1 : ste->linenumber;
250
251                 /* get declaring class name */
252
253                 declaringclass =
254                         _Jv_java_lang_Class_getName((java_lang_Class *) ste->method->class);
255
256                 /* fill the java.lang.StackTraceElement element */
257
258                 o->fileName       = filename;
259                 o->lineNumber     = linenumber;
260                 o->declaringClass = declaringclass;
261                 o->methodName     = (java_lang_String *) javastring_new(ste->method->name);
262                 o->isNative       = (ste->method->flags & ACC_NATIVE) ? 1 : 0;
263
264                 oa->data[i] = (java_objectheader *) o;
265         }
266
267         return oa;
268 }
269
270
271 /*
272  * These are local overrides for various environment variables in Emacs.
273  * Please do not remove this and leave it at the end of the file, where
274  * Emacs will automagically detect them.
275  * ---------------------------------------------------------------------
276  * Local variables:
277  * mode: c
278  * indent-tabs-mode: t
279  * c-basic-offset: 4
280  * tab-width: 4
281  * End:
282  */