* Removed all Id tags.
[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 */
26
27
28 #include "config.h"
29
30 #include <assert.h>
31
32 #include "vm/types.h"
33
34 #include "native/jni.h"
35 #include "native/llni.h"
36 #include "native/native.h"
37
38 #include "native/include/gnu_classpath_Pointer.h"
39 #include "native/include/java_lang_Class.h"
40 #include "native/include/java_lang_StackTraceElement.h"
41 #include "native/include/java_lang_Throwable.h"
42
43 #include "native/include/java_lang_VMThrowable.h"
44
45 #include "native/vm/java_lang_Class.h"
46
47 #include "vm/builtin.h"
48 #include "vm/exceptions.h"
49 #include "vm/stringlocal.h"
50
51 #include "vm/jit/stacktrace.h"
52
53 #include "vmcore/class.h"
54 #include "vmcore/loader.h"
55
56
57 /* native methods implemented by this file ************************************/
58
59 static JNINativeMethod methods[] = {
60         { "fillInStackTrace", "(Ljava/lang/Throwable;)Ljava/lang/VMThrowable;",        (void *) (ptrint) &Java_java_lang_VMThrowable_fillInStackTrace },
61         { "getStackTrace",    "(Ljava/lang/Throwable;)[Ljava/lang/StackTraceElement;", (void *) (ptrint) &Java_java_lang_VMThrowable_getStackTrace    },
62 };
63
64
65 /* _Jv_java_lang_VMThrowable_init **********************************************
66
67    Register native functions.
68
69 *******************************************************************************/
70
71 void _Jv_java_lang_VMThrowable_init(void)
72 {
73         utf *u;
74
75         u = utf_new_char("java/lang/VMThrowable");
76
77         native_method_register(u, methods, NATIVE_METHODS_COUNT);
78 }
79
80
81 /*
82  * Class:     java/lang/VMThrowable
83  * Method:    fillInStackTrace
84  * Signature: (Ljava/lang/Throwable;)Ljava/lang/VMThrowable;
85  */
86 JNIEXPORT java_lang_VMThrowable* JNICALL Java_java_lang_VMThrowable_fillInStackTrace(JNIEnv *env, jclass clazz, java_lang_Throwable *t)
87 {
88         java_lang_VMThrowable *o;
89         stacktracecontainer   *stc;
90
91         o = (java_lang_VMThrowable *)
92                 native_new_and_init(class_java_lang_VMThrowable);
93
94         if (o == NULL)
95                 return NULL;
96
97         stc = stacktrace_fillInStackTrace();
98
99         if (stc == NULL)
100                 return NULL;
101
102         LLNI_field_set_ref(o, vmData, (gnu_classpath_Pointer *) stc);
103
104         return o;
105 }
106
107
108 /*
109  * Class:     java/lang/VMThrowable
110  * Method:    getStackTrace
111  * Signature: (Ljava/lang/Throwable;)[Ljava/lang/StackTraceElement;
112  */
113 JNIEXPORT java_handle_objectarray_t* JNICALL Java_java_lang_VMThrowable_getStackTrace(JNIEnv *env, java_lang_VMThrowable *this, java_lang_Throwable *t)
114 {
115         stacktracecontainer         *stc;
116         stacktracebuffer            *stb;
117         stacktrace_entry            *ste;
118         stacktrace_entry            *tmpste;
119         s4                           size;
120         s4                           i;
121         classinfo                   *c;
122         bool                         inexceptionclass;
123         bool                         leftexceptionclass;
124
125         methodinfo                  *m;
126         java_handle_objectarray_t   *oa;
127         s4                           oalength;
128         java_lang_StackTraceElement *o;
129         java_lang_String            *filename;
130         s4                           linenumber;
131         java_lang_String            *declaringclass;
132
133         /* get the stacktrace buffer from the VMThrowable object */
134
135         /*XXX stc = (stacktracecontainer *) this->vmData;*/
136         LLNI_field_get_ref(this, vmData, stc);
137         stb = &(stc->stb);
138
139         /* get the class of the Throwable object */
140
141         LLNI_class_get(t, c);
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(LLNI_classinfo_wrap(ste->method->class));
255
256                 /* fill the java.lang.StackTraceElement element */
257
258                 LLNI_field_set_ref(o, fileName      , filename);
259                 LLNI_field_set_val(o, lineNumber    , linenumber);
260                 LLNI_field_set_ref(o, declaringClass, declaringclass);
261                 LLNI_field_set_ref(o, methodName    , (java_lang_String *) javastring_new(ste->method->name));
262                 LLNI_field_set_val(o, isNative      , (ste->method->flags & ACC_NATIVE) ? 1 : 0);
263
264                 LLNI_objectarray_element_set(oa, i, 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  */