* Updated header: Added 2006. Changed address of FSF. Changed email
[cacao.git] / src / native / vm / VMThrowable.c
1 /* src/native/vm/VMThrowable.c - java/lang/VMThrowable
2
3    Copyright (C) 1996-2005, 2006 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    Contact: cacao@cacaojvm.org
26
27    Authors: Joseph Wenninger
28
29    Changes: Christian Thalinger
30
31    $Id: VMThrowable.c 4357 2006-01-22 23:33:38Z twisti $
32
33 */
34
35
36 #include <assert.h>
37
38 #include "config.h"
39 #include "vm/types.h"
40
41 #include "native/jni.h"
42 #include "native/native.h"
43 #include "native/include/java_lang_Class.h"
44 #include "native/include/java_lang_StackTraceElement.h"
45 #include "native/include/java_lang_Throwable.h"
46 #include "native/include/java_lang_VMClass.h"
47 #include "native/include/java_lang_VMThrowable.h"
48 #include "vm/builtin.h"
49 #include "vm/class.h"
50 #include "vm/exceptions.h"
51 #include "vm/loader.h"
52 #include "vm/stringlocal.h"
53 #include "vm/jit/stacktrace.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 *par1)
62 {
63         java_lang_VMThrowable *vmthrow;
64
65         vmthrow = (java_lang_VMThrowable *)
66                 native_new_and_init(class_java_lang_VMThrowable);
67
68         if (!vmthrow) {
69                 log_text("Needed instance of class  java.lang.VMThrowable could not be created");
70                 assert(0);
71         }
72
73 #if defined(__ALPHA__) || defined(__ARM__) || defined(__I386__) || defined(__MIPS__) || defined(__POWERPC__) || defined(__X86_64__)
74         if (!cacao_stacktrace_NormalTrace((void **) &(vmthrow->vmData)))
75                 return NULL;
76 #endif
77
78         return vmthrow;
79 }
80
81
82 /*
83  * Class:     java/lang/VMThrowable
84  * Method:    getStackTrace
85  * Signature: (Ljava/lang/Throwable;)[Ljava/lang/StackTraceElement;
86  */
87 JNIEXPORT java_objectarray* JNICALL Java_java_lang_VMThrowable_getStackTrace(JNIEnv *env, java_lang_VMThrowable *this, java_lang_Throwable *t)
88 {
89 #if defined(__ALPHA__) || defined(__ARM__) || defined(__I386__) || defined(__MIPS__) || defined(__POWERPC__) || defined(__X86_64__)
90         stackTraceBuffer            *buf;
91         stacktraceelement           *elem;
92         stacktraceelement           *tmpelem;
93         s4                           size;
94         s4                           i;
95         classinfo                   *c;
96         bool                         inexceptionclass;
97         bool                         leftexceptionclass;
98
99         methodinfo                  *m;
100         java_objectarray            *oa;
101         s4                           oalength;
102         java_lang_StackTraceElement *ste;
103         java_lang_String            *filename;
104         s4                           linenumber;
105         java_lang_String            *declaringclass;
106
107         buf = (stackTraceBuffer *) this->vmData;
108         c = t->header.vftbl->class;
109
110         if (!buf) {
111                 log_text("Invalid java.lang.VMThrowable.vmData field in java.lang.VMThrowable.getStackTrace native code");
112                 assert(0);
113         }
114         
115         size = buf->full;
116
117         if (size < 2) {
118                 log_text("Invalid java.lang.VMThrowable.vmData field in java.lang.VMThrowable.getStackTrace native code (length<2)");
119                 assert(0);
120         }
121
122         /* skip first 2 elements in stacktrace buffer:                            */
123         /*   0: VMThrowable.fillInStackTrace                                      */
124         /*   1: Throwable.fillInStackTrace                                        */
125
126         elem = &(buf->start[2]);
127         size -= 2;
128
129         if (size && elem->method != 0) {
130                 /* not a builtin native wrapper*/
131
132                 if ((elem->method->class->name == utf_java_lang_Throwable) &&
133                         (elem->method->name == utf_init)) {
134                         /* We assume that we are within the initializer of the exception  */
135                         /* object, the exception object itself should not appear in the   */
136                         /* stack trace, so we skip till we reach the first function,      */
137                         /* which is not an init function.                                 */
138
139                         inexceptionclass = false;
140                         leftexceptionclass = false;
141
142                         while (size > 0) {
143                                 /* check if we are in the exception class */
144
145                                 if (elem->method->class == c)
146                                         inexceptionclass = true;
147
148                                 /* check if we left the exception class */
149
150                                 if (inexceptionclass && (elem->method->class != c))
151                                         leftexceptionclass = true;
152
153                                 /* found exception start point if we left the initalizers or  */
154                                 /* we left the exception class                                */
155
156                                 if ((elem->method->name != utf_init) || leftexceptionclass)
157                                         break;
158
159                                 elem++;
160                                 size--;
161                         }
162                 }
163         }
164
165
166         /* now fill the stacktrace into java objects */
167
168         m = class_findmethod(class_java_lang_StackTraceElement,
169                                                  utf_init,
170                                                  utf_new_char("(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;Z)V"));
171
172         if (!m)
173                 return NULL;
174
175         /* count entries with a method name */
176
177         for (oalength = 0, i = size, tmpelem = elem; i > 0; i--, tmpelem++)
178                 if (tmpelem->method)
179                         oalength++;
180
181         /* create the stacktrace element array */
182
183         oa = builtin_anewarray(oalength, class_java_lang_StackTraceElement);
184
185         if (!oa)
186                 return NULL;
187
188         for (i = 0; size > 0; size--, elem++, i++) {
189                 if (elem->method == NULL) {
190                         i--;
191                         continue;
192                 }
193
194                 /* allocate a new stacktrace element */
195
196                 ste = (java_lang_StackTraceElement *)
197                         builtin_new(class_java_lang_StackTraceElement);
198
199                 if (!ste)
200                         return NULL;
201
202                 /* get filename */
203
204                 if (!(elem->method->flags & ACC_NATIVE)) {
205                         if (elem->method->class->sourcefile)
206                                 filename = javastring_new(elem->method->class->sourcefile);
207                         else
208                                 filename = NULL;
209
210                 } else {
211                         filename = NULL;
212                 }
213
214                 /* get line number */
215
216                 if (elem->method->flags & ACC_NATIVE)
217                         linenumber = -1;
218                 else
219                         linenumber = (elem->linenumber == 0) ? -1 : elem->linenumber;
220
221                 /* get declaring class name */
222
223                 declaringclass = Java_java_lang_VMClass_getName(env, NULL, (java_lang_Class *) elem->method->class);
224
225
226                 /* fill the stacktrace element */
227
228                 ste->fileName       = filename;
229                 ste->lineNumber     = linenumber;
230                 ste->declaringClass = declaringclass;
231                 ste->methodName     = javastring_new(elem->method->name);
232                 ste->isNative       = (elem->method->flags & ACC_NATIVE) ? 1 : 0;
233
234                 oa->data[i] = (java_objectheader *) ste;
235         }
236
237         return oa;
238 #else
239         return NULL;
240 #endif
241 }
242
243
244 /*
245  * These are local overrides for various environment variables in Emacs.
246  * Please do not remove this and leave it at the end of the file, where
247  * Emacs will automagically detect them.
248  * ---------------------------------------------------------------------
249  * Local variables:
250  * mode: c
251  * indent-tabs-mode: t
252  * c-basic-offset: 4
253  * tab-width: 4
254  * End:
255  */