almost all stacktraces do now really work.
[cacao.git] / src / native / vm / VMThrowable.c
1 /* nat/VMThrowable.c - java/lang/Throwable
2
3    Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
4    R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
5    M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
6    P. Tomsich, J. Wenninger
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., 59 Temple Place - Suite 330, Boston, MA
23    02111-1307, USA.
24
25    Contact: cacao@complang.tuwien.ac.at
26
27    Authors: Joseph Wenninger
28
29    $Id: VMThrowable.c 1683 2004-12-05 21:33:36Z jowenn $
30
31 */
32
33 #include "native/jni.h"
34 #include "native/native.h"
35 #include "native/include/java_lang_Class.h"
36 #include "native/include/java_lang_Throwable.h"
37 #include "native/include/java_lang_VMClass.h"
38 #include "native/include/java_lang_VMThrowable.h"
39 #include "vm/builtin.h"
40 #include "vm/loader.h"
41 #include "vm/tables.h"
42 #include "vm/jit/asmpart.h"
43
44
45 /*
46  * Class:     java/lang/VMThrowable
47  * Method:    fillInStackTrace
48  * Signature: (Ljava/lang/Throwable;)Ljava/lang/VMThrowable;
49  */
50 JNIEXPORT java_lang_VMThrowable* JNICALL Java_java_lang_VMThrowable_fillInStackTrace(JNIEnv *env, jclass clazz, java_lang_Throwable *par1)
51 {
52         classinfo *class_java_lang_VMThrowable = NULL;
53         java_lang_VMThrowable *vmthrow;
54
55         if (!class_java_lang_VMThrowable)
56                 class_java_lang_VMThrowable = class_new(utf_new_char("java/lang/VMThrowable"));
57
58         if (class_java_lang_VMThrowable == NULL)
59                 panic("Needed class java.lang.VMThrowable missing");
60
61         vmthrow = (java_lang_VMThrowable *) native_new_and_init(class_java_lang_VMThrowable);
62
63         if (vmthrow == NULL)
64                 panic("Needed instance of class  java.lang.VMThrowable could not be created");
65
66 #if defined(__I386__) || defined(__ALPHA__)
67         cacao_stacktrace_NormalTrace(&(vmthrow->vmData));
68 #endif
69         return vmthrow;
70 }
71
72
73 static
74 java_objectarray* generateStackTraceArray(JNIEnv *env,stacktraceelement *el,long size)
75 {
76         long resultPos;
77         methodinfo *m;
78         classinfo *c;
79         java_objectarray *oa;
80
81         c = class_new(utf_new_char("java/lang/StackTraceElement"));
82
83         if (!c->loaded)
84                 class_load(c);
85
86         if (!c->linked)
87                 class_link(c);
88
89         m = class_findmethod(c,
90                                                  utf_new_char("<init>"),
91                                                  utf_new_char("(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;Z)V"));
92
93         if (!m)
94                 panic("java.lang.StackTraceElement misses needed constructor"); 
95
96         oa = builtin_anewarray(size, c);
97
98         if (!oa)
99                 return 0;
100
101 /*      printf("Should return an array with %ld element(s)\n",size);*/
102         /*pos--;*/
103         
104         for(resultPos=0;size>0;size--,el++,resultPos++) {
105                 java_objectheader *element;
106
107                 if (el->method==0) {
108                         resultPos--;
109                         continue;
110                 }
111
112                 element=builtin_new(c);
113                 if (!element) {
114                         panic("Memory for stack trace element could not be allocated");
115                 }
116 #ifdef __GNUC__
117 #warning call constructor once jni is fixed to allow more than three parameters
118 #endif
119 #if 0
120                 (*env)->CallVoidMethod(env,element,m,
121                         javastring_new(el->method->class->sourcefile),
122                         source[size].linenumber,
123                         javastring_new(el->method->class->name),
124                         javastring_new(el->method->name),
125                         el->method->flags & ACC_NATIVE);
126 #else
127                 if (!(el->method->flags & ACC_NATIVE))setfield_critical(c,element,"fileName",          
128                 "Ljava/lang/String;",  jobject, 
129                 (jobject) javastring_new(el->method->class->sourcefile));
130 /*              setfield_critical(c,element,"className",          "Ljava/lang/String;",  jobject,  */
131 /*              (jobject) javastring_new(el->method->class->name)); */
132                 setfield_critical(c,element,"declaringClass",          "Ljava/lang/String;",  jobject, 
133                 (jobject) Java_java_lang_VMClass_getName(env, NULL, (java_lang_Class *) el->method->class));
134                 setfield_critical(c,element,"methodName",          "Ljava/lang/String;",  jobject, 
135                 (jobject) javastring_new(el->method->name));
136                 setfield_critical(c,element,"lineNumber",          "I",  jint, 
137                 (jint) ((el->method->flags & ACC_NATIVE) ? -1:(el->linenumber)));
138                 setfield_critical(c,element,"isNative",          "Z",  jboolean, 
139                 (jboolean) ((el->method->flags & ACC_NATIVE) ? 1:0));
140
141
142 #endif                  
143
144                 oa->data[resultPos]=element;
145         }
146
147         return oa;
148
149 }
150
151
152 /*
153  * Class:     java/lang/VMThrowable
154  * Method:    getStackTrace
155  * Signature: (Ljava/lang/Throwable;)[Ljava/lang/StackTraceElement;
156  */
157 JNIEXPORT java_objectarray* JNICALL Java_java_lang_VMThrowable_getStackTrace(JNIEnv *env, java_lang_VMThrowable *this, java_lang_Throwable *par1)
158 {
159 #if defined(__I386__) || defined(__ALPHA__)
160         stackTraceBuffer *buf=(stackTraceBuffer*)this->vmData;
161         u8 size;
162         stacktraceelement *el;
163         classinfo  *excClass=par1->header.vftbl->class;
164         utf*  init=utf_new_char("<init>");
165         utf*  throwable=utf_new_char("java/lang/Throwable");
166         long destElementCount;
167         stacktraceelement *tmpEl;
168
169         if (!buf) panic("Invalid java.lang.VMThrowable.vmData field in java.lang.VMThrowable.getStackTrace native code");
170         
171         size=buf->full;
172         if (size<=2) panic("Invalid java.lang.VMThrowable.vmData field in java.lang.VMThrowable.getStackTrace native code (length<=2)");
173         size -=2;
174         el=&(buf->start[2]); /* element 0==VMThrowable.fillInStackTrace native call, 1==Throwable.fillInStackTrace*/
175         if (el->method!=0) { /* => not a builtin native wrapper*/
176                 if ((el->method->class->name==throwable) && (el->method->name == init) ){
177                         /* We assume that we are within the initializer of the exception object, the exception object itself should not appear
178                                 in the stack trace, so we skip till we reach the first function, which is not an init function or till we reach the exception object class*/
179                         for (; (size>0) && (el->method->name==init) && (el->method->class!=excClass); el++, size--) {
180                                 /* just loop*/
181                         }
182                         size --;
183                         el++;
184                         if (size<1) {
185                                 log_text("Invalid stacktrace for VMThrowable.getStackTrace()");
186                         }
187                 }
188         }
189
190         
191         for (destElementCount = 0, tmpEl=el; size>0; size--,tmpEl++) {
192                 if (tmpEl->method!=0) destElementCount++;
193         }
194
195         return generateStackTraceArray(env,el,destElementCount);
196 #else
197         return 0;
198 #endif
199 }
200
201
202 /*
203  * These are local overrides for various environment variables in Emacs.
204  * Please do not remove this and leave it at the end of the file, where
205  * Emacs will automagically detect them.
206  * ---------------------------------------------------------------------
207  * Local variables:
208  * mode: c
209  * indent-tabs-mode: t
210  * c-basic-offset: 4
211  * tab-width: 4
212  * End:
213  */