Added asm_calljavafunction2int and asm_calljavafunction2float to prevent
[cacao.git] / src / vm / jit / stacktrace.c
1 /* vm/jit/stacktrace.c
2
3    Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
4    R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
5    C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
6    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., 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: stacktrace.c 1774 2004-12-20 20:16:57Z jowenn $
30
31 */
32
33
34 #include <stdlib.h>
35 #include <string.h>
36
37 #include "asmoffsets.h"
38 #include "mm/boehm.h"
39 #include "native/native.h"
40 #include "vm/global.h"                   /* required here for native includes */
41 #include "native/include/java_lang_ClassLoader.h"
42 #include "toolbox/logging.h"
43 #include "vm/builtin.h"
44 #include "vm/tables.h"
45 #include "vm/jit/codegen.inc.h"
46
47
48 #undef JWDEBUG
49 /*JoWenn: simplify collectors (trace doesn't contain internal methods)*/
50
51 extern classinfo *class_java_lang_Class;
52 extern classinfo *class_java_lang_SecurityManager;
53
54 /* the line number is only u2, but to avoid alignment problems it is made the same size as a native
55         pointer. In the structures where this is used, values of -1 or -2 have a special meainging, so
56         if java bytecode is ever extended to support more than 65535 lines/file, this could will have to
57         be changed.*/
58
59 #ifdef _ALPHA_
60         #define LineNumber u8
61 #else
62         #define LineNumber u4
63 #endif
64
65 typedef struct lineNumberTableEntry {
66 /* The special value of -1 means that a inlined function starts, a value of -2 means that an inlined function ends*/
67         LineNumber lineNr;
68         void *pc;
69 } lineNumberTableEntry;
70
71 typedef struct lineNumberTableEntryInlineBegin {
72 /*this should have the same layout and size as the lineNumberTableEntry*/
73         LineNumber lineNrOuter;
74         methodinfo *method;
75 } lineNumberTableEntryInlineBegin;
76
77
78 typedef void(*CacaoStackTraceCollector)(void **,stackTraceBuffer*);
79
80 #define BLOCK_INITIALSIZE 40
81 #define BLOCK_SIZEINCREMENT 40
82
83 static void addEntry(stackTraceBuffer* buffer,methodinfo*method ,LineNumber line) {
84         if (buffer->size>buffer->full) {
85                 stacktraceelement *tmp=&(buffer->start[buffer->full]);
86                 tmp->method=method;
87                 tmp->linenumber=line;
88                 buffer->full = buffer->full + 1;
89 #ifdef JWDEBUG
90                 log_text("addEntry (stacktrace):");
91                 if (method) utf_display(method->name); else printf("Native");
92                 if (method) {printf("\n");utf_display(method->class->name);}
93                 printf("\nLine:%ld\n",line);
94 #endif
95         } else {
96                 stacktraceelement *newBuffer=(stacktraceelement*)
97                         malloc((buffer->size+BLOCK_SIZEINCREMENT)*sizeof(stacktraceelement));
98                 if (newBuffer==0) panic("OOM during stacktrace creation");
99                 memcpy(newBuffer,buffer->start,buffer->size*sizeof(stacktraceelement));
100                 if (buffer->needsFree) free(buffer->start);
101                 buffer->start=newBuffer;
102                 buffer->size=buffer->size+BLOCK_SIZEINCREMENT;
103                 buffer->needsFree=1;
104                 addEntry(buffer,method,line);
105         }
106 }
107
108 static int fillInStackTrace_methodRecursive(stackTraceBuffer *buffer,methodinfo 
109                 *method,lineNumberTableEntry *startEntry, lineNumberTableEntry **entry, size_t *entriesAhead,void *adress) {
110
111         size_t ahead=*entriesAhead;
112         lineNumberTableEntry *ent=*entry;
113         lineNumberTableEntryInlineBegin *ilStart;
114
115         for (;ahead>0;ahead--,ent++) {
116                 if (adress>=ent->pc) {
117                         switch (ent->lineNr) {
118                                 case -1: /*begin of inlined method */
119                                         ilStart=(lineNumberTableEntryInlineBegin*)(++ent);
120                                         ent ++;
121                                         ahead--; ahead--;
122                                         if (fillInStackTrace_methodRecursive(buffer,ilStart->method,ent,&ent,&ahead,adress)) {
123                                                 addEntry(buffer,method,ilStart->lineNrOuter);
124                                                 return 1;
125                                         }
126                                         break;
127                                 case -2: /*end of inlined method*/
128                                         *entry=ent;
129                                         *entriesAhead=ahead;
130                                         return 0;
131                                         break;
132                                 default:
133                                         if (adress==ent->pc) {
134                                                 addEntry(buffer,method,ent->lineNr);
135                                                 return 1;
136                                         }
137                                         break;
138                         }
139                 } else {
140                         if (adress>startEntry->pc) {
141                                 ent--;
142                                 addEntry(buffer,method,ent->lineNr);
143                                 return 1;       
144                         } else panic("trace point before method");
145                 }
146         }
147         ent--;
148         addEntry(buffer,method,ent->lineNr);
149         return 1;
150         
151 }
152
153 static void fillInStackTrace_method(stackTraceBuffer *buffer,methodinfo *method,char *dataSeg, void* adress) {
154         size_t lineNumberTableSize=(*((size_t*)(dataSeg+LineNumberTableSize)));
155
156
157         if ( lineNumberTableSize == 0) {
158                 /*right now this happens only on 
159                 i386,if the native stub causes an exception in a <clinit> invocation (jowenn)*/
160                 addEntry(buffer,method,0);
161                 return;
162         } else {
163                 lineNumberTableEntry *ent; /*=(lineNumberTableEntry*) ((*((char**)(dataSeg+LineNumberTableStart))) - (sizeof(lineNumberTableEntry)-sizeof(void*)));*/
164                 void **calc;
165                 lineNumberTableEntry *startEntry;
166
167                 /*              printf("dataSeg: %p\n",dataSeg);*/
168                 calc=dataSeg+LineNumberTableStart;
169                 /*              printf("position of line number table start reference in data segment: %p\n",calc);
170                                 printf("line number table start as found in table: %p\n",*calc);*/
171                 ent=(lineNumberTableEntry *) (((char*)(*calc) - (sizeof(lineNumberTableEntry)-sizeof(void*))));
172                 /*              printf("line number table start as calculated: %p\n",ent);*/
173                 ent-=(lineNumberTableSize-1);
174                 startEntry=ent;
175                 /*              printf("line number table real start (bottom end) as calculated(2): %p\n",startEntry);*/
176
177                 if (!fillInStackTrace_methodRecursive(buffer,method,startEntry,&ent,&lineNumberTableSize,adress)) {
178                         panic("Trace point not found in suspected method");
179                 }
180         }
181 }
182
183
184 void  cacao_stacktrace_fillInStackTrace(void **target,CacaoStackTraceCollector coll)
185 {
186
187         stacktraceelement primaryBlock[BLOCK_INITIALSIZE*sizeof(stacktraceelement)]; 
188                 /*In most cases this should be enough -> one malloc less. I don't think temporary data should be
189                 allocated with the GC, only the result*/
190         stackTraceBuffer buffer;
191         buffer.needsFree=0;
192         buffer.start=primaryBlock;
193         buffer.size=BLOCK_INITIALSIZE*sizeof(stacktraceelement);
194         buffer.full=0;
195
196
197         {
198                 struct native_stackframeinfo *info=(*(((void**)(builtin_asm_get_stackframeinfo()))));
199                 if (!info) {
200                         log_text("info ==0");
201                         *target=0;
202                         return;
203                 } else {
204                         char *dataseg; /*make it byte addressable*/
205                         methodinfo *currentMethod=0;
206                         void *returnAdress;
207                         char* stackPtr;
208
209 /*                      utf_display(info->method->class->name);
210                         utf_display(info->method->name);*/
211                         
212                         while ((currentMethod!=0) ||  (info!=0)) {
213                                 if (currentMethod==0) { /*some builtin native */
214                                         currentMethod=info->method;
215                                         returnAdress=info->returnToFromNative;
216                                         /*log_text("native");*/
217                                         if (currentMethod) {
218                                                 /*utf_display(currentMethod->class->name);
219                                                 utf_display(currentMethod->name);*/
220                                                 addEntry(&buffer,currentMethod,0);
221                                         }
222 #if defined(__ALPHA__)
223                                         if (info->savedpv!=0)
224                                                 dataseg=info->savedpv;
225                                         else
226                                                 dataseg=codegen_findmethod(returnAdress);
227 #elif defined(__I386__)
228                                         dataseg=codegen_findmethod(returnAdress);
229 #endif
230                                         currentMethod=(*((methodinfo**)(dataseg+MethodPointer)));
231                                         if (info->beginOfJavaStackframe==0)
232                                                 stackPtr=((char*)info)+sizeof(native_stackframeinfo);
233                                         else
234 #if defined(__ALPHA__)
235                                                 stackPtr=(char*)(info->beginOfJavaStackframe);
236 #elif defined(__I386__)
237                                                 stackPtr=(char*)(info->beginOfJavaStackframe)+sizeof(void*);
238 #endif
239                                         info=info->oldThreadspecificHeadValue;
240                                 } else { /*method created by jit*/
241                                         u4 frameSize;
242                                         /*log_text("JIT");*/
243 #if defined (__ALPHA__)
244                                         if (currentMethod->isleafmethod) {
245 #ifdef JWDEBUG
246                                                 printf("class.method:%s.%s\n",currentMethod->class->name->text,currentMethod->name->text);
247 #endif
248                                                 panic("How could that happen ??? A leaf method in the middle of a stacktrace ??");
249                                         }
250 #endif
251                                         /*utf_display(currentMethod->class->name);
252                                         utf_display(currentMethod->name);*/
253                                         fillInStackTrace_method(&buffer,currentMethod,dataseg,returnAdress);
254                                         frameSize=*((u4*)(dataseg+FrameSize));
255 #if defined(__ALPHA__)
256                                         /* cacao saves the return adress as the first element of the stack frame on alphas*/
257                                         dataseg=codegen_findmethod(*((void**)(stackPtr+frameSize-sizeof(void*))));
258                                         returnAdress=(*((void**)(stackPtr+frameSize-sizeof(void*))));
259 #elif defined(__I386__)
260                                         /* on i386 the return adress is the first element before the stack frme*/
261                                         returnAdress=(*((void**)(stackPtr+frameSize)));
262                                         dataseg=codegen_findmethod(*((void**)(stackPtr+frameSize)));
263 #endif
264 /*                                      printf ("threadrootmethod %p\n",builtin_asm_get_threadrootmethod());
265                                         if (currentMethod==builtin_asm_get_threadrootmethod()) break;*/
266                                         currentMethod=(*((methodinfo**)(dataseg+MethodPointer)));
267 #if defined(__ALPHA__)
268                                         stackPtr+=frameSize;
269 #elif defined(__I386__)
270                                         stackPtr+=frameSize+sizeof(void*);
271 #endif
272                                 }
273                         }
274                         
275                         if (coll) coll(target,&buffer);
276                         if (buffer.needsFree) free(buffer.start);
277                         return;
278                 }
279                 /*log_text("\n=========================================================");*/
280         }
281         *target=0;
282
283 }
284
285
286 static
287 void stackTraceCollector(void **target, stackTraceBuffer *buffer) {
288         stackTraceBuffer *dest=*target=heap_allocate(sizeof(stackTraceBuffer)+buffer->full*sizeof(stacktraceelement),true,0);
289         memcpy(*target,buffer,sizeof(stackTraceBuffer));
290         memcpy(dest+1,buffer->start,buffer->full*sizeof(stacktraceelement));
291
292         dest->needsFree=0;
293         dest->size=dest->full;
294         dest->start=dest+1;
295
296         /*
297         if (buffer->full>0) {
298                 printf("SOURCE BUFFER:%s\n",buffer->start[0].method->name->text);
299                 printf("DEST BUFFER:%s\n",dest->start[0].method->name->text);
300         } else printf("Buffer is empty\n");
301         */
302 }
303
304
305 void  cacao_stacktrace_NormalTrace(void **target) {
306         cacao_stacktrace_fillInStackTrace(target,&stackTraceCollector);
307 }
308
309
310
311 static
312 void classContextCollector(void **target, stackTraceBuffer *buffer) {
313         java_objectarray *tmpArray;
314         int i;
315         stacktraceelement *current;
316         stacktraceelement *start;
317         classinfo *c;
318         size_t size;
319         size_t targetSize;
320
321         size=buffer->full;
322         targetSize=0;
323         for (i=0;i<size;i++)
324                 if (buffer->start[i].method!=0) targetSize++;
325         start=buffer->start;
326         start++;
327         targetSize--;
328         if (!class_java_lang_Class)
329                 class_java_lang_Class = class_new(utf_new_char("java/lang/Class"));
330
331         if (!class_java_lang_SecurityManager)
332                 class_java_lang_SecurityManager =
333                         class_new(utf_new_char("java/lang/SecurityManager"));
334
335         if (targetSize > 0) {
336                 if ((start->method) && (start->method->class== class_java_lang_SecurityManager)) {
337                         targetSize--;
338                         start++;
339                 }
340         }
341
342         tmpArray =
343                 builtin_newarray(targetSize, class_array_of(class_java_lang_Class)->vftbl);
344
345         for(i = 0, current = start; i < targetSize; i++, current++) {
346                 if (current->method==0) { i--; continue;}
347                 /*printf("adding item to class context array:%s\n",current->method->class->name->text);
348                 printf("method for class: :%s\n",current->method->name->text);*/
349                 use_class_as_object(current->method->class);
350                 tmpArray->data[i] = (java_objectheader *) current->method->class;
351         }
352
353         *target=tmpArray;
354 }
355
356
357
358 java_objectarray *cacao_createClassContextArray() {
359         java_objectarray *array=0;
360         cacao_stacktrace_fillInStackTrace(&array,&classContextCollector);
361         return array;
362         
363 }
364
365
366 static
367 void classLoaderCollector(void **target, stackTraceBuffer *buffer) {
368         int i;
369         stacktraceelement *current;
370         stacktraceelement *start;
371         methodinfo *m;
372         classinfo *privilegedAction;
373         size_t size;
374
375         size = buffer->full;
376
377
378         if (!class_java_lang_SecurityManager)
379                 class_java_lang_SecurityManager =
380                         class_new(utf_new_char("java/lang/SecurityManager"));
381
382         if (size > 1) {
383                 size--;
384                 start=&(buffer->start[1]);
385                 if (start == class_java_lang_SecurityManager) {
386                         size--;
387                         start--;
388                 }
389         } else {
390                 start=0;
391                 size=0;
392         }
393         privilegedAction=class_new(utf_new_char("java/security/PrivilegedAction"));
394
395         for(i=0, current = start; i < size; i++, current++) {
396                 m=start->method;
397                 if (!m) continue;
398
399                 if (m->class == privilegedAction) {
400                         *target=NULL;
401                         return;
402                 }
403
404                 if (m->class->classloader) {
405                         *target= (java_lang_ClassLoader *) m->class->classloader;
406                         return;
407                 }
408         }
409
410         *target=NULL;
411 }
412
413 java_objectheader *cacao_currentClassLoader() {
414         java_objectheader *header=0;
415         cacao_stacktrace_fillInStackTrace(&header,&classLoaderCollector);
416         return header;
417 }
418
419
420 static
421 void callingMethodCollector(void **target, stackTraceBuffer *buffer) {  
422         if (buffer->full >2) (*target)=buffer->start[2].method;
423         else (*target=0);
424 }
425
426 methodinfo *cacao_callingMethod() {
427         methodinfo *method;
428         cacao_stacktrace_fillInStackTrace(&method,&callingMethodCollector);
429         return method;
430 }
431
432 /*
433  * These are local overrides for various environment variables in Emacs.
434  * Please do not remove this and leave it at the end of the file, where
435  * Emacs will automagically detect them.
436  * ---------------------------------------------------------------------
437  * Local variables:
438  * mode: c
439  * indent-tabs-mode: t
440  * c-basic-offset: 4
441  * tab-width: 4
442  * End:
443  */