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