bba9eab4d5250a96a89aeca75634343a10510de3
[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 8343 2007-08-17 21:39:32Z michi $
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/llni.h"
38 #include "native/native.h"
39
40 #include "native/include/gnu_classpath_Pointer.h"
41 #include "native/include/java_lang_Class.h"
42 #include "native/include/java_lang_StackTraceElement.h"
43 #include "native/include/java_lang_Throwable.h"
44
45 #include "native/include/java_lang_VMThrowable.h"
46
47 #include "native/vm/java_lang_Class.h"
48
49 #include "vm/builtin.h"
50 #include "vm/exceptions.h"
51 #include "vm/stringlocal.h"
52
53 #include "vm/jit/stacktrace.h"
54
55 #include "vmcore/class.h"
56 #include "vmcore/loader.h"
57
58
59 /* native methods implemented by this file ************************************/
60
61 static JNINativeMethod methods[] = {
62         { "fillInStackTrace", "(Ljava/lang/Throwable;)Ljava/lang/VMThrowable;",        (void *) (ptrint) &Java_java_lang_VMThrowable_fillInStackTrace },
63         { "getStackTrace",    "(Ljava/lang/Throwable;)[Ljava/lang/StackTraceElement;", (void *) (ptrint) &Java_java_lang_VMThrowable_getStackTrace    },
64 };
65
66
67 /* _Jv_java_lang_VMThrowable_init **********************************************
68
69    Register native functions.
70
71 *******************************************************************************/
72
73 void _Jv_java_lang_VMThrowable_init(void)
74 {
75         utf *u;
76
77         u = utf_new_char("java/lang/VMThrowable");
78
79         native_method_register(u, methods, NATIVE_METHODS_COUNT);
80 }
81
82
83 /*
84  * Class:     java/lang/VMThrowable
85  * Method:    fillInStackTrace
86  * Signature: (Ljava/lang/Throwable;)Ljava/lang/VMThrowable;
87  */
88 JNIEXPORT java_lang_VMThrowable* JNICALL Java_java_lang_VMThrowable_fillInStackTrace(JNIEnv *env, jclass clazz, java_lang_Throwable *t)
89 {
90         java_lang_VMThrowable *o;
91         stacktracecontainer   *stc;
92
93         o = (java_lang_VMThrowable *)
94                 native_new_and_init(class_java_lang_VMThrowable);
95
96         if (o == NULL)
97                 return NULL;
98
99         stc = stacktrace_fillInStackTrace();
100
101         if (stc == NULL)
102                 return NULL;
103
104         LLNI_field_set_ref(o, vmData, (gnu_classpath_Pointer *) stc);
105
106         return o;
107 }
108
109
110 /*
111  * Class:     java/lang/VMThrowable
112  * Method:    getStackTrace
113  * Signature: (Ljava/lang/Throwable;)[Ljava/lang/StackTraceElement;
114  */
115 JNIEXPORT java_handle_objectarray_t* JNICALL Java_java_lang_VMThrowable_getStackTrace(JNIEnv *env, java_lang_VMThrowable *this, java_lang_Throwable *t)
116 {
117         stacktracecontainer         *stc;
118         stacktracebuffer            *stb;
119         stacktrace_entry            *ste;
120         stacktrace_entry            *tmpste;
121         s4                           size;
122         s4                           i;
123         classinfo                   *c;
124         bool                         inexceptionclass;
125         bool                         leftexceptionclass;
126
127         methodinfo                  *m;
128         java_handle_objectarray_t   *oa;
129         s4                           oalength;
130         java_lang_StackTraceElement *o;
131         java_lang_String            *filename;
132         s4                           linenumber;
133         java_lang_String            *declaringclass;
134
135         /* get the stacktrace buffer from the VMThrowable object */
136
137         /*XXX stc = (stacktracecontainer *) this->vmData;*/
138         LLNI_field_get_ref(this, vmData, stc);
139         stb = &(stc->stb);
140
141         /* get the class of the Throwable object */
142
143         LLNI_class_get(t, c);
144
145         assert(stb != NULL);
146
147         size = stb->used;
148
149         assert(size >= 2);
150
151         /* skip first 2 elements in stacktrace buffer:                            */
152         /*   0: VMThrowable.fillInStackTrace                                      */
153         /*   1: Throwable.fillInStackTrace                                        */
154
155         ste = &(stb->entries[2]);
156         size -= 2;
157
158         if ((size > 0) && (ste->method != 0)) {
159                 /* not a builtin native wrapper*/
160
161                 if ((ste->method->class->name == utf_java_lang_Throwable) &&
162                         (ste->method->name == utf_init)) {
163                         /* We assume that we are within the initializer of the
164                            exception object, the exception object itself should
165                            not appear in the stack trace, so we skip till we reach
166                            the first function, which is not an init function. */
167
168                         inexceptionclass = false;
169                         leftexceptionclass = false;
170
171                         while (size > 0) {
172                                 /* check if we are in the exception class */
173
174                                 if (ste->method->class == c)
175                                         inexceptionclass = true;
176
177                                 /* check if we left the exception class */
178
179                                 if (inexceptionclass && (ste->method->class != c))
180                                         leftexceptionclass = true;
181
182                                 /* Found exception start point if we left the
183                                    initalizers or we left the exception class. */
184
185                                 if ((ste->method->name != utf_init) || leftexceptionclass)
186                                         break;
187
188                                 /* go to next stacktrace element */
189
190                                 ste++;
191                                 size--;
192                         }
193                 }
194         }
195
196
197         /* now fill the stacktrace into java objects */
198
199         m = class_findmethod(class_java_lang_StackTraceElement,
200                                                  utf_init,
201                                                  utf_new_char("(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;Z)V"));
202
203         if (m == NULL)
204                 return NULL;
205
206         /* count entries with a method name */
207
208         for (oalength = 0, i = size, tmpste = ste; i > 0; i--, tmpste++)
209                 if (tmpste->method)
210                         oalength++;
211
212         /* create the stacktrace element array */
213
214         oa = builtin_anewarray(oalength, class_java_lang_StackTraceElement);
215
216         if (oa == NULL)
217                 return NULL;
218
219         for (i = 0; size > 0; size--, ste++, i++) {
220                 /* skip entries without a method name */
221
222                 if (ste->method == NULL) {
223                         i--;
224                         continue;
225                 }
226
227                 /* allocate a new stacktrace element */
228
229                 o = (java_lang_StackTraceElement *)
230                         builtin_new(class_java_lang_StackTraceElement);
231
232                 if (o == NULL)
233                         return NULL;
234
235                 /* get filename */
236
237                 if (!(ste->method->flags & ACC_NATIVE)) {
238                         if (ste->method->class->sourcefile)
239                                 filename = (java_lang_String *) javastring_new(ste->method->class->sourcefile);
240                         else
241                                 filename = NULL;
242                 }
243                 else
244                         filename = NULL;
245
246                 /* get line number */
247
248                 if (ste->method->flags & ACC_NATIVE)
249                         linenumber = -1;
250                 else
251                         linenumber = (ste->linenumber == 0) ? -1 : ste->linenumber;
252
253                 /* get declaring class name */
254
255                 declaringclass =
256                         _Jv_java_lang_Class_getName(LLNI_classinfo_wrap(ste->method->class));
257
258                 /* fill the java.lang.StackTraceElement element */
259
260                 LLNI_field_set_ref(o, fileName      , filename);
261                 LLNI_field_set_val(o, lineNumber    , linenumber);
262                 LLNI_field_set_ref(o, declaringClass, declaringclass);
263                 LLNI_field_set_ref(o, methodName    , (java_lang_String *) javastring_new(ste->method->name));
264                 LLNI_field_set_val(o, isNative      , (ste->method->flags & ACC_NATIVE) ? 1 : 0);
265
266                 LLNI_objectarray_element_set(oa, i, o);
267         }
268
269         return oa;
270 }
271
272
273 /*
274  * These are local overrides for various environment variables in Emacs.
275  * Please do not remove this and leave it at the end of the file, where
276  * Emacs will automagically detect them.
277  * ---------------------------------------------------------------------
278  * Local variables:
279  * mode: c
280  * indent-tabs-mode: t
281  * c-basic-offset: 4
282  * tab-width: 4
283  * End:
284  */