Merge from mainline (gomp-merge-2005-02-26).
[official-gcc.git] / libjava / gnu / gcj / runtime / natStackTrace.cc
blobd9f3355c04600c89255c1e93ad2e3a1fd10c320c
1 // natStackTrace.cc - native helper methods for Throwable
3 /* Copyright (C) 2000, 2002, 2003 Free Software Foundation, Inc
5 This file is part of libgcj.
7 This software is copyrighted work licensed under the terms of the
8 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
9 details. */
11 /**
12 * @author Andrew Haley <aph@cygnus.com>
13 * @author Mark Wielaard <mark@klomp.org>
15 * Native helper methods for VM specific Throwable support.
18 #include <config.h>
19 #include <platform.h>
21 #include <string.h>
23 #include <jvm.h>
24 #include <gcj/cni.h>
25 #include <gnu/gcj/RawData.h>
26 #include <java/lang/Object.h>
27 #include <java-threads.h>
28 #include <gnu/gcj/runtime/MethodRef.h>
29 #include <gnu/gcj/runtime/StackTrace.h>
30 #include <java/lang/Thread.h>
31 #include <java-interp.h>
32 #include <java/util/IdentityHashMap.h>
33 #include <java/lang/ArrayIndexOutOfBoundsException.h>
35 #include <sys/types.h>
37 #include <stdlib.h>
39 #include <unistd.h>
41 #ifdef HAVE_EXECINFO_H
42 #include <execinfo.h>
43 #endif
45 #include <unwind.h>
48 #ifdef INTERPRETER
49 extern "C" void *_Unwind_FindEnclosingFunction (void *pc)
50 __attribute__((pure));
51 #endif // INTERPRETER
53 // Fill in this stack trace with MAXLEN elements starting at offset.
54 void
55 gnu::gcj::runtime::StackTrace::fillInStackTrace (jint maxlen, jint offset)
57 #ifdef HAVE_BACKTRACE
58 offset += 1;
59 void *_p[maxlen + offset];
60 len = backtrace (_p, maxlen + offset) - offset;
61 void **p = _p + offset;
62 _Jv_frame_info *frame;
63 if (len > 0)
65 #ifdef INTERPRETER
66 extern void *const _Jv_StartOfInterpreter;
67 extern void * _Jv_EndOfInterpreter;
69 java::lang::Thread *thread = java::lang::Thread::currentThread();
70 _Jv_MethodChain *interp_frame
71 = (thread ? reinterpret_cast<_Jv_MethodChain *> (thread->interp_frame)
72 : NULL);
73 #endif // INTERPRETER
75 frame = (_Jv_frame_info *) _Jv_Malloc (len * sizeof (_Jv_frame_info));
76 for (int n = 0; n < len; n++)
78 void *pc = p[n];
79 frame[n].addr = pc;
81 #ifdef INTERPRETER
82 frame[n].interp = 0;
84 // If _Jv_StartOfInterpreter is NULL either we've never
85 // entered the intepreter or _Unwind_FindEnclosingFunction
86 // is broken.
87 if (__builtin_expect (_Jv_StartOfInterpreter != NULL, false))
89 // _Jv_StartOfInterpreter marks the very first
90 // instruction in the interpreter, but
91 // _Jv_EndOfInterpreter is an upper bound. If PC is
92 // less than _Jv_EndOfInterpreter it might be in the
93 // interpreter: we call _Unwind_FindEnclosingFunction to
94 // find out.
95 if (pc >= _Jv_StartOfInterpreter
96 && (pc < _Jv_EndOfInterpreter
97 || _Jv_EndOfInterpreter == NULL))
99 if (_Unwind_FindEnclosingFunction (pc)
100 == _Jv_StartOfInterpreter)
102 frame[n].interp = (void *) interp_frame->self;
103 interp_frame = interp_frame->next;
105 else
107 // We've found an address that we know is not within
108 // the interpreter. We use that to refine our upper
109 // bound on where the interpreter ends.
110 _Jv_EndOfInterpreter = pc;
114 #endif // INTERPRETER
118 else
119 frame = NULL;
121 addrs = reinterpret_cast<gnu::gcj::RawData *> (frame);
122 #else // HAVE_BACKTRACE
123 (void)maxlen;
124 (void)offset;
125 #endif // HAVE_BACKTRACE
128 /* Obtain the next power-of-2 of some integer. */
129 static inline jint
130 nextpowerof2 (jint n)
132 n |= (n >> 1);
133 n |= (n >> 2);
134 n |= (n >> 4);
135 n |= (n >> 8);
136 n |= (n >> 16);
137 return n+1;
140 #define GET_FRAME(N) \
141 ({ \
142 if ((N) >= len) \
143 fillInStackTrace (nextpowerof2 (N), 1); \
144 if ((N) < 0 || (N) >= len) \
145 throw new ::java::lang::ArrayIndexOutOfBoundsException (); \
147 _Jv_frame_info *frame = (_Jv_frame_info *)addrs; \
148 &frame[N]; \
151 gnu::gcj::runtime::MethodRef *
152 gnu::gcj::runtime::StackTrace::getCompiledMethodRef (gnu::gcj::RawData *addr)
154 void *p = _Unwind_FindEnclosingFunction (addr);
155 return gnu::gcj::runtime::StackTrace
156 ::methodAtAddress ((gnu::gcj::RawData *)p);
159 java::lang::Class *
160 gnu::gcj::runtime::StackTrace::getClass (gnu::gcj::RawData *p)
162 gnu::gcj::runtime::MethodRef *ref = getCompiledMethodRef (p);
163 if (ref)
164 return ref->klass;
165 else
166 return NULL;
169 java::lang::Class *
170 gnu::gcj::runtime::StackTrace::classAt (jint n)
172 _Jv_frame_info *frame = GET_FRAME (n);
174 #ifdef INTERPRETER
175 if (frame->interp)
177 _Jv_InterpMethod *meth
178 = reinterpret_cast<_Jv_InterpMethod *> (frame->interp);
179 return meth->defining_class;
181 #endif // INTERPRETER
183 return getClass ((gnu::gcj::RawData *)frame->addr);
186 java::lang::String*
187 gnu::gcj::runtime::StackTrace::methodAt (jint n)
189 _Jv_frame_info *frame = GET_FRAME (n);
190 _Jv_Method *meth = NULL;
192 #ifdef INTERPRETER
193 if (frame->interp)
195 meth
196 = reinterpret_cast<_Jv_InterpMethod *> (frame->interp)
197 ->get_method();
199 #endif // INTERPRETER
201 if (! meth)
203 gnu::gcj::runtime::MethodRef *ref
204 = getCompiledMethodRef ((gnu::gcj::RawData *)frame->addr);
205 if (ref)
206 meth = (_Jv_Method *)ref->method;
209 return meth
210 ? _Jv_NewStringUtf8Const (meth->name)
211 : NULL ;
214 void
215 gnu::gcj::runtime::StackTrace::update(void)
217 jclass klass;
219 while ((klass = _Jv_PopClass ()))
221 for (int i=0; i<klass->method_count; i++)
223 JvSynchronize sync (map);
224 _Jv_Method *meth = &(klass->methods[i]);
225 if (meth->ncode) // i.e. if p is not abstract
227 gnu::gcj::runtime::MethodRef *ref
228 = new gnu::gcj::runtime::MethodRef
229 ((gnu::gcj::RawData *)meth, klass);
230 map->put ((java::lang::Object*)(meth->ncode), ref);
236 void
237 gnu::gcj::runtime::StackTrace::finalize(void)
239 if (addrs != NULL)
240 _Jv_Free (addrs);