summaryrefslogtreecommitdiff
path: root/libjava
diff options
context:
space:
mode:
authorbryce <bryce@138bc75d-0d04-0410-961f-82ee72b054a4>2005-03-10 19:02:21 +0000
committerbryce <bryce@138bc75d-0d04-0410-961f-82ee72b054a4>2005-03-10 19:02:21 +0000
commit04c95bc933562928623c859240c17a70f2a1311c (patch)
tree7b6e8c5a43f4dcb0d8d4ac926f4562a978e11786 /libjava
parent5bd3d8171f767d4995706ea87092c5dc688fff21 (diff)
downloadgcc-04c95bc933562928623c859240c17a70f2a1311c.tar.gz
2005-03-10 Bryce McKinlay <mckinlay@redhat.com>
New Stack Trace infrastructure. * Makefile.am (libgcj0_convenience_la_SOURCES): Add stacktrace.cc. (gnu/gcj/runtime/StackTrace.lo): Removed. (ordinary_java_source_files): Remove obsolete files. (nat_source_files): Remove obsolete files. Add natVMThrowable.cc. * configure.host (fallback_backtrace_h): Set backtrace header for mingw and cygwin targets. * configure.ac: Make symlink for fallback backtrace headers. * Makefile.in, configure: Rebuilt. * defineclass.cc (_Jv_ClassReader::read_one_code_attribute): Read 'LineNumberTable' attribute. (_Jv_ClassReader::read_one_class_attribute): Read 'SourceFile' attribute. (_Jv_ClassReader::handleCodeAttribute): Initialize method line table fields. * exception.cc: Remove unused include. * interpret.cc (DIRECT_THREADED, insn_slot): Moved to java-interp.h. (SAVE_PC): New macro. Save current PC in the interpreter frame. (NULLCHECK, NULLARRAYCHECK): Use SAVE_PC. (_Jv_InterpMethod::compile): Translate bytecode PC values in the line table to direct threaded instruction values. (_Jv_StartOfInterpreter, _Jv_EndOfInterpreter): Removed. (_Jv_InterpMethod::run): No longer member function. All callers updated. Remove _Unwind calls. Call SAVE_PC whenever a call is made or where an instruction could throw. (_Jv_InterpMethod::get_source_line): New. Look up source line numbers in line_table. * prims.cc (catch_segv): Construct exception after MAKE_THROW_FRAME. (catch_fpe): Likewise. * stacktrace.cc: New file. Stack trace code now here. * gnu/gcj/runtime/MethodRef.java: * gnu/gcj/runtime/NameFinder.java: Mostly reimplemented. Now simply calls addr2line to look up PC addresses in a given binary or shared library. * gnu/gcj/runtime/StackTrace.java, gnu/gcj/runtime/natNameFinder.cc, gnu/gcj/runtime/natStackTrace.cc: Removed. * gnu/java/lang/MainThread.java (call_main): Add comment warning that this function name is specially recognised by the stack trace code and shouldn't be changed. * include/java-interp.h (DIRECT_THREADED, insn_slot): Moved here. (struct _Jv_LineTableEntry, line_table, line_table_len): New. (_Jv_InterpMethod::run): Update declaration. (_Jv_StackTrace_): New friend. NameFinder and StackTrace no longer friends. (_Jv_InterpFrame): Renamed from _Jv_MethodChain. Add PC field. * include/java-stack.h: New file. Declarations for stack tracing. * include/jvm.h (_Jv_Frame_info): Removed. * java/lang/Class.h: Update friend declarations. * java/lang/VMClassLoader.java (getSystemClassLoader): Simplify exception message. * java/lang/VMThrowable.java (fillInStackTrace): Now native. (getStackTrace): Now native. (data): New RawDataManaged field. * java/lang/natClass.cc: Update includes. (forName): Use _Jv_StackTrace::GetCallingClass for calling-classloader check. (getClassLoader): Likewise. * java/lang/natRuntime.cc: Update includes. (_load): Use _Jv_StackTrace::GetFirstNonSystemClassLoader. * java/lang/natVMSecurityManager.cc: Update includes. (getClassContext): Use _Jv_StackTrace::GetClassContext. * java/lang/natVMThrowable.cc: New file. Native methods for VMThrowable. * java/lang/reflect/natArray.cc: Update includes. (newInstance): Use _Jv_StackTrace::GetCallingClass to implement accessibility check. * java/lang/reflect/natConstructor.cc: Update includes. (newInstance): Use _Jv_StackTrace::GetCallingClass to implement accessibility check. * java/lang/reflect/natField.cc: Update includes. (getAddr): Use _Jv_StackTrace::GetCallingClass to implement accessibility check. * java/lang/reflect/natMethod.cc: Update includes. (invoke): Use _Jv_StackTrace::GetCallingClass to implement accessibility check. * java/util/natResourceBundle.cc: Update includes. (getCallingClassLoader): Use _Jv_StackTrace::GetCallingClass. * java/util/logging/natLogger.cc: Update includes. Use _Jv_StackTrace::GetCallerInfo to get call-site info. * sysdep/generic/backtrace.h: Fallback backtrace code. Stub implementation. * sysdep/i386/backtrace.h: New. Fallback backtrace code. i386 implementation. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@96253 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libjava')
-rw-r--r--libjava/ChangeLog86
-rw-r--r--libjava/Makefile.am17
-rw-r--r--libjava/Makefile.in71
-rwxr-xr-xlibjava/configure3
-rw-r--r--libjava/configure.ac1
-rw-r--r--libjava/configure.host10
-rw-r--r--libjava/defineclass.cc58
-rw-r--r--libjava/exception.cc1
-rw-r--r--libjava/gnu/classpath/Configuration.java.in2
-rw-r--r--libjava/gnu/gcj/runtime/NameFinder.java522
-rw-r--r--libjava/gnu/java/lang/MainThread.java2
-rw-r--r--libjava/include/java-interp.h76
-rw-r--r--libjava/include/java-stack.h49
-rw-r--r--libjava/include/jvm.h14
-rw-r--r--libjava/interpret.cc159
-rw-r--r--libjava/java/lang/Class.h7
-rw-r--r--libjava/java/lang/VMClassLoader.java8
-rw-r--r--libjava/java/lang/VMThrowable.java44
-rw-r--r--libjava/java/lang/natClass.cc37
-rw-r--r--libjava/java/lang/natRuntime.cc25
-rw-r--r--libjava/java/lang/natVMSecurityManager.cc33
-rw-r--r--libjava/java/lang/natVMThrowable.cc45
-rw-r--r--libjava/java/lang/reflect/natArray.cc18
-rw-r--r--libjava/java/lang/reflect/natConstructor.cc16
-rw-r--r--libjava/java/lang/reflect/natField.cc14
-rw-r--r--libjava/java/lang/reflect/natMethod.cc16
-rw-r--r--libjava/java/util/logging/natLogger.cc26
-rw-r--r--libjava/java/util/natResourceBundle.cc27
-rw-r--r--libjava/prims.cc8
-rw-r--r--libjava/stacktrace.cc527
-rw-r--r--libjava/sysdep/generic/backtrace.h22
-rw-r--r--libjava/sysdep/i386/backtrace.h42
32 files changed, 1164 insertions, 822 deletions
diff --git a/libjava/ChangeLog b/libjava/ChangeLog
index b74f0edd7bd..b92bf687e69 100644
--- a/libjava/ChangeLog
+++ b/libjava/ChangeLog
@@ -1,3 +1,89 @@
+2005-03-10 Bryce McKinlay <mckinlay@redhat.com>
+
+ New Stack Trace infrastructure.
+ * Makefile.am (libgcj0_convenience_la_SOURCES): Add stacktrace.cc.
+ (gnu/gcj/runtime/StackTrace.lo): Removed.
+ (ordinary_java_source_files): Remove obsolete files.
+ (nat_source_files): Remove obsolete files. Add natVMThrowable.cc.
+ * configure.host (fallback_backtrace_h): Set backtrace header
+ for mingw and cygwin targets.
+ * configure.ac: Make symlink for fallback backtrace headers.
+ * Makefile.in, configure: Rebuilt.
+ * defineclass.cc (_Jv_ClassReader::read_one_code_attribute):
+ Read 'LineNumberTable' attribute.
+ (_Jv_ClassReader::read_one_class_attribute): Read 'SourceFile'
+ attribute.
+ (_Jv_ClassReader::handleCodeAttribute): Initialize method line
+ table fields.
+ * exception.cc: Remove unused include.
+ * interpret.cc (DIRECT_THREADED, insn_slot): Moved to java-interp.h.
+ (SAVE_PC): New macro. Save current PC in the interpreter frame.
+ (NULLCHECK, NULLARRAYCHECK): Use SAVE_PC.
+ (_Jv_InterpMethod::compile): Translate bytecode PC values in the line
+ table to direct threaded instruction values.
+ (_Jv_StartOfInterpreter, _Jv_EndOfInterpreter): Removed.
+ (_Jv_InterpMethod::run): No longer member function. All
+ callers updated. Remove _Unwind calls. Call SAVE_PC whenever a call
+ is made or where an instruction could throw.
+ (_Jv_InterpMethod::get_source_line): New. Look up source line numbers
+ in line_table.
+ * prims.cc (catch_segv): Construct exception after MAKE_THROW_FRAME.
+ (catch_fpe): Likewise.
+ * stacktrace.cc: New file. Stack trace code now here.
+ * gnu/gcj/runtime/MethodRef.java:
+ * gnu/gcj/runtime/NameFinder.java: Mostly reimplemented. Now simply
+ calls addr2line to look up PC addresses in a given binary or shared
+ library.
+ * gnu/gcj/runtime/StackTrace.java, gnu/gcj/runtime/natNameFinder.cc,
+ gnu/gcj/runtime/natStackTrace.cc: Removed.
+ * gnu/java/lang/MainThread.java (call_main): Add comment warning that
+ this function name is specially recognised by the stack trace code
+ and shouldn't be changed.
+ * include/java-interp.h (DIRECT_THREADED, insn_slot): Moved here.
+ (struct _Jv_LineTableEntry, line_table, line_table_len): New.
+ (_Jv_InterpMethod::run): Update declaration.
+ (_Jv_StackTrace_): New friend. NameFinder and StackTrace no longer
+ friends.
+ (_Jv_InterpFrame): Renamed from _Jv_MethodChain. Add PC field.
+ * include/java-stack.h: New file. Declarations for stack tracing.
+ * include/jvm.h (_Jv_Frame_info): Removed.
+ * java/lang/Class.h: Update friend declarations.
+ * java/lang/VMClassLoader.java (getSystemClassLoader): Simplify
+ exception message.
+ * java/lang/VMThrowable.java (fillInStackTrace): Now native.
+ (getStackTrace): Now native.
+ (data): New RawDataManaged field.
+ * java/lang/natClass.cc: Update includes.
+ (forName): Use _Jv_StackTrace::GetCallingClass for
+ calling-classloader check.
+ (getClassLoader): Likewise.
+ * java/lang/natRuntime.cc: Update includes.
+ (_load): Use _Jv_StackTrace::GetFirstNonSystemClassLoader.
+ * java/lang/natVMSecurityManager.cc: Update includes.
+ (getClassContext): Use _Jv_StackTrace::GetClassContext.
+ * java/lang/natVMThrowable.cc: New file. Native methods for
+ VMThrowable.
+ * java/lang/reflect/natArray.cc: Update includes.
+ (newInstance): Use _Jv_StackTrace::GetCallingClass to implement
+ accessibility check.
+ * java/lang/reflect/natConstructor.cc: Update includes.
+ (newInstance): Use _Jv_StackTrace::GetCallingClass to implement
+ accessibility check.
+ * java/lang/reflect/natField.cc: Update includes.
+ (getAddr): Use _Jv_StackTrace::GetCallingClass to implement
+ accessibility check.
+ * java/lang/reflect/natMethod.cc: Update includes.
+ (invoke): Use _Jv_StackTrace::GetCallingClass to implement
+ accessibility check.
+ * java/util/natResourceBundle.cc: Update includes.
+ (getCallingClassLoader): Use _Jv_StackTrace::GetCallingClass.
+ * java/util/logging/natLogger.cc: Update includes. Use
+ _Jv_StackTrace::GetCallerInfo to get call-site info.
+ * sysdep/generic/backtrace.h: Fallback backtrace code. Stub
+ implementation.
+ * sysdep/i386/backtrace.h: New. Fallback backtrace code. i386
+ implementation.
+
2005-03-10 Ranjit Mathew <rmathew@hotmail.com>
* testsuite/libjava.compile/PR20312.java: New file.
diff --git a/libjava/Makefile.am b/libjava/Makefile.am
index cd6f0b3aa64..920b05bd9af 100644
--- a/libjava/Makefile.am
+++ b/libjava/Makefile.am
@@ -217,7 +217,7 @@ libgij_la_LDFLAGS = -rpath $(toolexeclibdir) \
# convenience library suddenly invokes the --whole-archive path instead.
# This allows the build to succeed for targets that allocate multiple got
# subsections in the linker, such as Alpha and MIPS.
-libgcj0_convenience_la_SOURCES = prims.cc jni.cc exception.cc \
+libgcj0_convenience_la_SOURCES = prims.cc jni.cc exception.cc stacktrace.cc \
link.cc defineclass.cc interpret.cc verify.cc \
$(nat_source_files) $(math_c_source_files) $(java_source_files) \
$(gnu_xml_source_files) $(built_java_source_files) \
@@ -588,20 +588,12 @@ clean-nat:
SUFFIXES = .class .java .h .properties
-## Note: we omit StackTrace here, since it has an explicit rule a bit
-## later, and GNU make will warn in this case.
-$(filter-out gnu/gcj/runtime/StackTrace.lo, $(javao_files)) $(xlib_javao_files): %.lo: %.java
+$(javao_files) $(xlib_javao_files): %.lo: %.java
$(LTGCJCOMPILE) -o $@ -c $<
$(gtk_awt_peer_sources:.java=.lo) $(gnu_xml_source_files:.java=.lo): %.lo: %.java
$(LTGCJCOMPILE) -fjni -o $@ -c $<
-## A special case. The sibcall optimization can change the number of
-## frames on the stack, and StackTrace makes assumptions about this
-## number.
-gnu/gcj/runtime/StackTrace.lo: gnu/gcj/runtime/StackTrace.java
- $(LTGCJCOMPILE) -fno-optimize-sibling-calls -o $@ -c $<
-
## Pass the list of object files to libtool in a temporary file to
## avoid tripping platform command line length limits.
libgcj.la: $(libgcj_la_OBJECTS) $(libgcj_la_DEPENDENCIES)
@@ -2911,12 +2903,10 @@ gnu/gcj/io/SimpleSHSStream.java \
gnu/gcj/runtime/FileDeleter.java \
gnu/gcj/runtime/FinalizerThread.java \
gnu/gcj/runtime/JNIWeakRef.java \
-gnu/gcj/runtime/MethodRef.java \
gnu/gcj/runtime/NameFinder.java \
gnu/gcj/runtime/PersistentByteMap.java \
gnu/gcj/runtime/SharedLibHelper.java \
gnu/gcj/runtime/SharedLibLoader.java \
-gnu/gcj/runtime/StackTrace.java \
gnu/gcj/runtime/StringBuffer.java \
gnu/gcj/runtime/SystemClassLoader.java \
gnu/gcj/runtime/VMClassLoader.java \
@@ -3676,9 +3666,7 @@ gnu/gcj/convert/natOutput_SJIS.cc \
gnu/gcj/io/natSimpleSHSStream.cc \
gnu/gcj/io/shs.cc \
gnu/gcj/runtime/natFinalizerThread.cc \
-gnu/gcj/runtime/natNameFinder.cc \
gnu/gcj/runtime/natSharedLibLoader.cc \
-gnu/gcj/runtime/natStackTrace.cc \
gnu/gcj/runtime/natStringBuffer.cc \
gnu/gcj/runtime/natVMClassLoader.cc \
gnu/gcj/util/natDebug.cc \
@@ -3708,6 +3696,7 @@ java/lang/natSystem.cc \
java/lang/natThread.cc \
java/lang/natVMClassLoader.cc \
java/lang/natVMSecurityManager.cc \
+java/lang/natVMThrowable.cc \
java/lang/ref/natReference.cc \
java/lang/reflect/natArray.cc \
java/lang/reflect/natConstructor.cc \
diff --git a/libjava/Makefile.in b/libjava/Makefile.in
index 4e114c7dc97..4be41130c88 100644
--- a/libjava/Makefile.in
+++ b/libjava/Makefile.in
@@ -84,7 +84,8 @@ CONFIG_CLEAN_FILES = libgcj.pc libgcj.spec libgcj-test.spec \
gnu/java/net/natPlainSocketImpl.cc \
gnu/java/net/natPlainDatagramSocketImpl.cc \
gnu/java/nio/natPipeImpl.cc gnu/java/nio/natSelectorImpl.cc \
- gnu/java/nio/channels/natFileChannelImpl.cc sysdep/locks.h
+ gnu/java/nio/channels/natFileChannelImpl.cc sysdep/locks.h \
+ sysdep/backtrace.h
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
@@ -331,7 +332,7 @@ am_libgcj_la_OBJECTS =
libgcj_la_OBJECTS = $(am_libgcj_la_OBJECTS)
libgcj0_convenience_la_LIBADD =
am__libgcj0_convenience_la_SOURCES_DIST = prims.cc jni.cc exception.cc \
- link.cc defineclass.cc interpret.cc verify.cc \
+ stacktrace.cc link.cc defineclass.cc interpret.cc verify.cc \
gnu/gcj/natCore.cc gnu/gcj/convert/JIS0208_to_Unicode.cc \
gnu/gcj/convert/JIS0212_to_Unicode.cc \
gnu/gcj/convert/Unicode_to_JIS.cc gnu/gcj/convert/natIconv.cc \
@@ -341,9 +342,7 @@ am__libgcj0_convenience_la_SOURCES_DIST = prims.cc jni.cc exception.cc \
gnu/gcj/convert/natOutput_SJIS.cc \
gnu/gcj/io/natSimpleSHSStream.cc gnu/gcj/io/shs.cc \
gnu/gcj/runtime/natFinalizerThread.cc \
- gnu/gcj/runtime/natNameFinder.cc \
gnu/gcj/runtime/natSharedLibLoader.cc \
- gnu/gcj/runtime/natStackTrace.cc \
gnu/gcj/runtime/natStringBuffer.cc \
gnu/gcj/runtime/natVMClassLoader.cc gnu/gcj/util/natDebug.cc \
gnu/java/lang/natMainThread.cc \
@@ -362,7 +361,7 @@ am__libgcj0_convenience_la_SOURCES_DIST = prims.cc jni.cc exception.cc \
java/lang/natString.cc java/lang/natStringBuffer.cc \
java/lang/natSystem.cc java/lang/natThread.cc \
java/lang/natVMClassLoader.cc \
- java/lang/natVMSecurityManager.cc \
+ java/lang/natVMSecurityManager.cc java/lang/natVMThrowable.cc \
java/lang/ref/natReference.cc java/lang/reflect/natArray.cc \
java/lang/reflect/natConstructor.cc \
java/lang/reflect/natField.cc java/lang/reflect/natMethod.cc \
@@ -555,12 +554,11 @@ am__libgcj0_convenience_la_SOURCES_DIST = prims.cc jni.cc exception.cc \
gnu/gcj/io/MimeTypes.java gnu/gcj/io/SimpleSHSStream.java \
gnu/gcj/runtime/FileDeleter.java \
gnu/gcj/runtime/FinalizerThread.java \
- gnu/gcj/runtime/JNIWeakRef.java gnu/gcj/runtime/MethodRef.java \
+ gnu/gcj/runtime/JNIWeakRef.java \
gnu/gcj/runtime/NameFinder.java \
gnu/gcj/runtime/PersistentByteMap.java \
gnu/gcj/runtime/SharedLibHelper.java \
gnu/gcj/runtime/SharedLibLoader.java \
- gnu/gcj/runtime/StackTrace.java \
gnu/gcj/runtime/StringBuffer.java \
gnu/gcj/runtime/SystemClassLoader.java \
gnu/gcj/runtime/VMClassLoader.java gnu/gcj/util/Debug.java \
@@ -2615,9 +2613,7 @@ am__objects_6 = gnu/gcj/natCore.lo \
gnu/gcj/convert/natOutput_SJIS.lo \
gnu/gcj/io/natSimpleSHSStream.lo gnu/gcj/io/shs.lo \
gnu/gcj/runtime/natFinalizerThread.lo \
- gnu/gcj/runtime/natNameFinder.lo \
gnu/gcj/runtime/natSharedLibLoader.lo \
- gnu/gcj/runtime/natStackTrace.lo \
gnu/gcj/runtime/natStringBuffer.lo \
gnu/gcj/runtime/natVMClassLoader.lo gnu/gcj/util/natDebug.lo \
gnu/java/lang/natMainThread.lo \
@@ -2636,7 +2632,7 @@ am__objects_6 = gnu/gcj/natCore.lo \
java/lang/natString.lo java/lang/natStringBuffer.lo \
java/lang/natSystem.lo java/lang/natThread.lo \
java/lang/natVMClassLoader.lo \
- java/lang/natVMSecurityManager.lo \
+ java/lang/natVMSecurityManager.lo java/lang/natVMThrowable.lo \
java/lang/ref/natReference.lo java/lang/reflect/natArray.lo \
java/lang/reflect/natConstructor.lo \
java/lang/reflect/natField.lo java/lang/reflect/natMethod.lo \
@@ -3996,12 +3992,11 @@ am__objects_15 = $(am__objects_9) gnu/classpath/ServiceFactory.lo \
gnu/gcj/io/DefaultMimeTypes.lo gnu/gcj/io/MimeTypes.lo \
gnu/gcj/io/SimpleSHSStream.lo gnu/gcj/runtime/FileDeleter.lo \
gnu/gcj/runtime/FinalizerThread.lo \
- gnu/gcj/runtime/JNIWeakRef.lo gnu/gcj/runtime/MethodRef.lo \
- gnu/gcj/runtime/NameFinder.lo \
+ gnu/gcj/runtime/JNIWeakRef.lo gnu/gcj/runtime/NameFinder.lo \
gnu/gcj/runtime/PersistentByteMap.lo \
gnu/gcj/runtime/SharedLibHelper.lo \
gnu/gcj/runtime/SharedLibLoader.lo \
- gnu/gcj/runtime/StackTrace.lo gnu/gcj/runtime/StringBuffer.lo \
+ gnu/gcj/runtime/StringBuffer.lo \
gnu/gcj/runtime/SystemClassLoader.lo \
gnu/gcj/runtime/VMClassLoader.lo gnu/gcj/util/Debug.lo \
gnu/java/io/ASN1ParsingException.lo \
@@ -4746,12 +4741,12 @@ am__objects_18 = java/lang/ConcreteProcess.lo \
@USING_WIN32_THREADS_TRUE@am__objects_27 = win32-threads.lo
@USING_NO_THREADS_TRUE@am__objects_28 = no-threads.lo
am_libgcj0_convenience_la_OBJECTS = prims.lo jni.lo exception.lo \
- link.lo defineclass.lo interpret.lo verify.lo $(am__objects_6) \
- $(am__objects_7) $(am__objects_16) $(am__objects_17) \
- $(am__objects_18) $(am__objects_19) $(am__objects_20) \
- $(am__objects_21) $(am__objects_22) $(am__objects_23) \
- $(am__objects_24) $(am__objects_25) $(am__objects_26) \
- $(am__objects_27) $(am__objects_28)
+ stacktrace.lo link.lo defineclass.lo interpret.lo verify.lo \
+ $(am__objects_6) $(am__objects_7) $(am__objects_16) \
+ $(am__objects_17) $(am__objects_18) $(am__objects_19) \
+ $(am__objects_20) $(am__objects_21) $(am__objects_22) \
+ $(am__objects_23) $(am__objects_24) $(am__objects_25) \
+ $(am__objects_26) $(am__objects_27) $(am__objects_28)
libgcj0_convenience_la_OBJECTS = $(am_libgcj0_convenience_la_OBJECTS)
am_libgij_la_OBJECTS = gij.lo
libgij_la_OBJECTS = $(am_libgij_la_OBJECTS)
@@ -5163,7 +5158,7 @@ libgij_la_LDFLAGS = -rpath $(toolexeclibdir) \
# convenience library suddenly invokes the --whole-archive path instead.
# This allows the build to succeed for targets that allocate multiple got
# subsections in the linker, such as Alpha and MIPS.
-libgcj0_convenience_la_SOURCES = prims.cc jni.cc exception.cc \
+libgcj0_convenience_la_SOURCES = prims.cc jni.cc exception.cc stacktrace.cc \
link.cc defineclass.cc interpret.cc verify.cc \
$(nat_source_files) $(math_c_source_files) $(java_source_files) \
$(gnu_xml_source_files) $(built_java_source_files) \
@@ -7306,12 +7301,10 @@ gnu/gcj/io/SimpleSHSStream.java \
gnu/gcj/runtime/FileDeleter.java \
gnu/gcj/runtime/FinalizerThread.java \
gnu/gcj/runtime/JNIWeakRef.java \
-gnu/gcj/runtime/MethodRef.java \
gnu/gcj/runtime/NameFinder.java \
gnu/gcj/runtime/PersistentByteMap.java \
gnu/gcj/runtime/SharedLibHelper.java \
gnu/gcj/runtime/SharedLibLoader.java \
-gnu/gcj/runtime/StackTrace.java \
gnu/gcj/runtime/StringBuffer.java \
gnu/gcj/runtime/SystemClassLoader.java \
gnu/gcj/runtime/VMClassLoader.java \
@@ -8066,9 +8059,7 @@ gnu/gcj/convert/natOutput_SJIS.cc \
gnu/gcj/io/natSimpleSHSStream.cc \
gnu/gcj/io/shs.cc \
gnu/gcj/runtime/natFinalizerThread.cc \
-gnu/gcj/runtime/natNameFinder.cc \
gnu/gcj/runtime/natSharedLibLoader.cc \
-gnu/gcj/runtime/natStackTrace.cc \
gnu/gcj/runtime/natStringBuffer.cc \
gnu/gcj/runtime/natVMClassLoader.cc \
gnu/gcj/util/natDebug.cc \
@@ -8098,6 +8089,7 @@ java/lang/natSystem.cc \
java/lang/natThread.cc \
java/lang/natVMClassLoader.cc \
java/lang/natVMSecurityManager.cc \
+java/lang/natVMThrowable.cc \
java/lang/ref/natReference.cc \
java/lang/reflect/natArray.cc \
java/lang/reflect/natConstructor.cc \
@@ -8783,13 +8775,9 @@ gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp):
gnu/gcj/runtime/natFinalizerThread.lo: \
gnu/gcj/runtime/$(am__dirstamp) \
gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp)
-gnu/gcj/runtime/natNameFinder.lo: gnu/gcj/runtime/$(am__dirstamp) \
- gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp)
gnu/gcj/runtime/natSharedLibLoader.lo: \
gnu/gcj/runtime/$(am__dirstamp) \
gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp)
-gnu/gcj/runtime/natStackTrace.lo: gnu/gcj/runtime/$(am__dirstamp) \
- gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp)
gnu/gcj/runtime/natStringBuffer.lo: gnu/gcj/runtime/$(am__dirstamp) \
gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp)
gnu/gcj/runtime/natVMClassLoader.lo: gnu/gcj/runtime/$(am__dirstamp) \
@@ -8899,6 +8887,8 @@ java/lang/natVMClassLoader.lo: java/lang/$(am__dirstamp) \
java/lang/$(DEPDIR)/$(am__dirstamp)
java/lang/natVMSecurityManager.lo: java/lang/$(am__dirstamp) \
java/lang/$(DEPDIR)/$(am__dirstamp)
+java/lang/natVMThrowable.lo: java/lang/$(am__dirstamp) \
+ java/lang/$(DEPDIR)/$(am__dirstamp)
java/lang/ref/$(am__dirstamp):
@$(mkdir_p) java/lang/ref
@: > java/lang/ref/$(am__dirstamp)
@@ -9612,8 +9602,6 @@ gnu/gcj/runtime/FinalizerThread.lo: gnu/gcj/runtime/$(am__dirstamp) \
gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp)
gnu/gcj/runtime/JNIWeakRef.lo: gnu/gcj/runtime/$(am__dirstamp) \
gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp)
-gnu/gcj/runtime/MethodRef.lo: gnu/gcj/runtime/$(am__dirstamp) \
- gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp)
gnu/gcj/runtime/NameFinder.lo: gnu/gcj/runtime/$(am__dirstamp) \
gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp)
gnu/gcj/runtime/PersistentByteMap.lo: gnu/gcj/runtime/$(am__dirstamp) \
@@ -9622,8 +9610,6 @@ gnu/gcj/runtime/SharedLibHelper.lo: gnu/gcj/runtime/$(am__dirstamp) \
gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp)
gnu/gcj/runtime/SharedLibLoader.lo: gnu/gcj/runtime/$(am__dirstamp) \
gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp)
-gnu/gcj/runtime/StackTrace.lo: gnu/gcj/runtime/$(am__dirstamp) \
- gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp)
gnu/gcj/runtime/StringBuffer.lo: gnu/gcj/runtime/$(am__dirstamp) \
gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp)
gnu/gcj/runtime/SystemClassLoader.lo: gnu/gcj/runtime/$(am__dirstamp) \
@@ -16363,8 +16349,6 @@ mostlyclean-compile:
-rm -f gnu/gcj/runtime/FinalizerThread.lo
-rm -f gnu/gcj/runtime/JNIWeakRef.$(OBJEXT)
-rm -f gnu/gcj/runtime/JNIWeakRef.lo
- -rm -f gnu/gcj/runtime/MethodRef.$(OBJEXT)
- -rm -f gnu/gcj/runtime/MethodRef.lo
-rm -f gnu/gcj/runtime/NameFinder.$(OBJEXT)
-rm -f gnu/gcj/runtime/NameFinder.lo
-rm -f gnu/gcj/runtime/PersistentByteMap.$(OBJEXT)
@@ -16373,8 +16357,6 @@ mostlyclean-compile:
-rm -f gnu/gcj/runtime/SharedLibHelper.lo
-rm -f gnu/gcj/runtime/SharedLibLoader.$(OBJEXT)
-rm -f gnu/gcj/runtime/SharedLibLoader.lo
- -rm -f gnu/gcj/runtime/StackTrace.$(OBJEXT)
- -rm -f gnu/gcj/runtime/StackTrace.lo
-rm -f gnu/gcj/runtime/StringBuffer.$(OBJEXT)
-rm -f gnu/gcj/runtime/StringBuffer.lo
-rm -f gnu/gcj/runtime/SystemClassLoader.$(OBJEXT)
@@ -16383,12 +16365,8 @@ mostlyclean-compile:
-rm -f gnu/gcj/runtime/VMClassLoader.lo
-rm -f gnu/gcj/runtime/natFinalizerThread.$(OBJEXT)
-rm -f gnu/gcj/runtime/natFinalizerThread.lo
- -rm -f gnu/gcj/runtime/natNameFinder.$(OBJEXT)
- -rm -f gnu/gcj/runtime/natNameFinder.lo
-rm -f gnu/gcj/runtime/natSharedLibLoader.$(OBJEXT)
-rm -f gnu/gcj/runtime/natSharedLibLoader.lo
- -rm -f gnu/gcj/runtime/natStackTrace.$(OBJEXT)
- -rm -f gnu/gcj/runtime/natStackTrace.lo
-rm -f gnu/gcj/runtime/natStringBuffer.$(OBJEXT)
-rm -f gnu/gcj/runtime/natStringBuffer.lo
-rm -f gnu/gcj/runtime/natVMClassLoader.$(OBJEXT)
@@ -19002,6 +18980,8 @@ mostlyclean-compile:
-rm -f java/lang/natVMClassLoader.lo
-rm -f java/lang/natVMSecurityManager.$(OBJEXT)
-rm -f java/lang/natVMSecurityManager.lo
+ -rm -f java/lang/natVMThrowable.$(OBJEXT)
+ -rm -f java/lang/natVMThrowable.lo
-rm -f java/lang/ref/PhantomReference.$(OBJEXT)
-rm -f java/lang/ref/PhantomReference.lo
-rm -f java/lang/ref/Reference.$(OBJEXT)
@@ -21926,6 +21906,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/posix-threads.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/posix.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/prims.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stacktrace.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/verify.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/win32-threads.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/win32.Plo@am__quote@
@@ -21992,19 +21973,15 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/FileDeleter.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/FinalizerThread.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/JNIWeakRef.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/MethodRef.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/NameFinder.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/PersistentByteMap.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/SharedLibHelper.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/SharedLibLoader.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/StackTrace.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/StringBuffer.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/SystemClassLoader.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/VMClassLoader.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/natFinalizerThread.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/natNameFinder.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/natSharedLibLoader.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/natStackTrace.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/natStringBuffer.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/natVMClassLoader.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/tools/gcj_dbtool/$(DEPDIR)/Main.Po@am__quote@
@@ -23312,6 +23289,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@java/lang/$(DEPDIR)/natThread.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@java/lang/$(DEPDIR)/natVMClassLoader.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@java/lang/$(DEPDIR)/natVMSecurityManager.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@java/lang/$(DEPDIR)/natVMThrowable.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@java/lang/$(DEPDIR)/s_atan.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@java/lang/$(DEPDIR)/s_ceil.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@java/lang/$(DEPDIR)/s_copysign.Plo@am__quote@
@@ -26677,15 +26655,12 @@ distclean-local:
clean-nat:
rm -f $(nat_files) $(xlib_nat_files)
-$(filter-out gnu/gcj/runtime/StackTrace.lo, $(javao_files)) $(xlib_javao_files): %.lo: %.java
+$(javao_files) $(xlib_javao_files): %.lo: %.java
$(LTGCJCOMPILE) -o $@ -c $<
$(gtk_awt_peer_sources:.java=.lo) $(gnu_xml_source_files:.java=.lo): %.lo: %.java
$(LTGCJCOMPILE) -fjni -o $@ -c $<
-gnu/gcj/runtime/StackTrace.lo: gnu/gcj/runtime/StackTrace.java
- $(LTGCJCOMPILE) -fno-optimize-sibling-calls -o $@ -c $<
-
libgcj.la: $(libgcj_la_OBJECTS) $(libgcj_la_DEPENDENCIES)
@echo Creating list of files to link...
@: $(call write_entries_to_file,$(libgcj_la_OBJECTS),libgcj.objectlist)
diff --git a/libjava/configure b/libjava/configure
index f8fb203b9f9..980f4a4e567 100755
--- a/libjava/configure
+++ b/libjava/configure
@@ -8454,6 +8454,8 @@ fi
if test -d sysdep; then true; else mkdir sysdep; fi
ac_config_links="$ac_config_links sysdep/locks.h:sysdep/$sysdeps_dir/locks.h"
+ ac_config_links="$ac_config_links sysdep/backtrace.h:$fallback_backtrace_h"
+
HASH_SYNC_SPEC=
# Hash synchronization is only useful with posix threads right now.
@@ -16482,6 +16484,7 @@ do
"include/java-gc.h" ) CONFIG_LINKS="$CONFIG_LINKS include/java-gc.h:include/$GCHDR" ;;
"include/java-threads.h" ) CONFIG_LINKS="$CONFIG_LINKS include/java-threads.h:include/$THREADH" ;;
"sysdep/locks.h" ) CONFIG_LINKS="$CONFIG_LINKS sysdep/locks.h:sysdep/$sysdeps_dir/locks.h" ;;
+ "sysdep/backtrace.h" ) CONFIG_LINKS="$CONFIG_LINKS sysdep/backtrace.h:$fallback_backtrace_h" ;;
"include/java-signal.h" ) CONFIG_LINKS="$CONFIG_LINKS include/java-signal.h:$SIGNAL_HANDLER" ;;
"include/java-signal-aux.h" ) CONFIG_LINKS="$CONFIG_LINKS include/java-signal-aux.h:$SIGNAL_HANDLER_AUX" ;;
"depfiles" ) CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
diff --git a/libjava/configure.ac b/libjava/configure.ac
index 6fcfe6d1436..2e40268038a 100644
--- a/libjava/configure.ac
+++ b/libjava/configure.ac
@@ -710,6 +710,7 @@ AM_CONDITIONAL(USING_NO_THREADS, test "$THREADS" = none)
if test -d sysdep; then true; else mkdir sysdep; fi
AC_CONFIG_LINKS(sysdep/locks.h:sysdep/$sysdeps_dir/locks.h)
+AC_CONFIG_LINKS(sysdep/backtrace.h:$fallback_backtrace_h)
HASH_SYNC_SPEC=
# Hash synchronization is only useful with posix threads right now.
diff --git a/libjava/configure.host b/libjava/configure.host
index 583b4e2e015..4d4c6e311bf 100644
--- a/libjava/configure.host
+++ b/libjava/configure.host
@@ -30,6 +30,8 @@
# from a signal handler.
# disable_dladdr Set to "yes" if dladdr should not be used
# (i.e it is broken).
+# fallback_backtrace_h Header to use for fallback backtrace implementation
+# (only for targets that don't support DWARF2 unwind)
libgcj_flags=
libgcj_cflags=
@@ -42,6 +44,7 @@ sysdeps_dir=generic
slow_pthread_self=
can_unwind_signal=no
disable_dladdr=
+fallback_backtrace_h=sysdep/generic/backtrace.h
case "${target_optspace}:${host}" in
yes:*)
@@ -258,6 +261,13 @@ EOF
;;
esac
+case "${host}" in
+ *-cygwin* | *-mingw*)
+ fallback_backtrace_h=sysdep/i386/backtrace.h
+ ;;
+esac
+
+
libgcj_cflags="${libgcj_cflags} ${libgcj_flags}"
libgcj_cxxflags="${libgcj_cxxflags} ${libgcj_flags}"
libgcj_javaflags="${libgcj_javaflags} ${libgcj_flags}"
diff --git a/libjava/defineclass.cc b/libjava/defineclass.cc
index 382b321f591..111b1fb2ca2 100644
--- a/libjava/defineclass.cc
+++ b/libjava/defineclass.cc
@@ -229,6 +229,7 @@ struct _Jv_ClassReader {
len = length;
pos = 0;
def = klass;
+
def->size_in_bytes = -1;
def->vtable_method_count = -1;
def->engine = &_Jv_soleInterpreterEngine;
@@ -613,26 +614,54 @@ void _Jv_ClassReader::read_one_method_attribute (int method_index)
}
}
-void _Jv_ClassReader::read_one_code_attribute (int /*method*/)
+void _Jv_ClassReader::read_one_code_attribute (int method_index)
{
- /* ignore for now, ... later we may want to pick up
- line number information, for debugging purposes;
- in fact, the whole debugger issue is open! */
-
- /* int name = */ read2u ();
+ int name = read2u ();
int length = read4 ();
- skip (length);
-
+ if (is_attribute_name (name, "LineNumberTable"))
+ {
+ _Jv_InterpMethod *method = reinterpret_cast<_Jv_InterpMethod *>
+ (def_interp->interpreted_methods[method_index]);
+ if (method->line_table != NULL)
+ throw_class_format_error ("Method already has LineNumberTable");
+
+ int table_len = read2u ();
+ _Jv_LineTableEntry* table
+ = (_Jv_LineTableEntry *) JvAllocBytes (table_len
+ * sizeof (_Jv_LineTableEntry));
+ for (int i = 0; i < table_len; i++)
+ {
+ table[i].bytecode_pc = read2u ();
+ table[i].line = read2u ();
+ }
+ method->line_table_len = table_len;
+ method->line_table = table;
+ }
+ else
+ {
+ /* ignore unknown code attributes */
+ skip (length);
+ }
}
void _Jv_ClassReader::read_one_class_attribute ()
{
- /* we also ignore the class attributes, ...
- some day we'll add inner-classes support. */
-
- /* int name = */ read2u ();
+ int name = read2u ();
int length = read4 ();
- skip (length);
+ if (is_attribute_name (name, "SourceFile"))
+ {
+ int source_index = read2u ();
+ check_tag (source_index, JV_CONSTANT_Utf8);
+ prepare_pool_entry (source_index, JV_CONSTANT_Utf8);
+ def_interp->source_file_name = _Jv_NewStringUtf8Const
+ (def->constants.data[source_index].utf8);
+ }
+ else
+ {
+ /* Currently, we ignore most class attributes.
+ FIXME: Add inner-classes attributes support. */
+ skip (length);
+ }
}
@@ -1279,6 +1308,9 @@ void _Jv_ClassReader::handleCodeAttribute
method->defining_class = def;
method->self = &def->methods[method_index];
method->prepared = NULL;
+ method->line_table_len = 0;
+ method->line_table = NULL;
+
// grab the byte code!
memcpy ((void*) method->bytecode (),
diff --git a/libjava/exception.cc b/libjava/exception.cc
index 088d48268e3..ef7292c3bf7 100644
--- a/libjava/exception.cc
+++ b/libjava/exception.cc
@@ -15,7 +15,6 @@ details. */
#include <java/lang/Class.h>
#include <java/lang/NullPointerException.h>
-#include <gnu/gcj/runtime/StackTrace.h>
#include <gnu/gcj/runtime/MethodRef.h>
#include <gnu/gcj/RawData.h>
#include <gcj/cni.h>
diff --git a/libjava/gnu/classpath/Configuration.java.in b/libjava/gnu/classpath/Configuration.java.in
index 5a4b97e8032..68d9a478261 100644
--- a/libjava/gnu/classpath/Configuration.java.in
+++ b/libjava/gnu/classpath/Configuration.java.in
@@ -52,7 +52,7 @@ public interface Configuration
// For libgcj we never load the JNI libraries.
boolean INIT_LOAD_LIBRARY = false;
- // For libgcj we have native methods for proxy support....
+ // For libgcj we have native methods for dynamic proxy support....
boolean HAVE_NATIVE_GET_PROXY_DATA = false;
boolean HAVE_NATIVE_GET_PROXY_CLASS = false;
boolean HAVE_NATIVE_GENERATE_PROXY_CLASS = false;
diff --git a/libjava/gnu/gcj/runtime/NameFinder.java b/libjava/gnu/gcj/runtime/NameFinder.java
index b14bbf93327..5469f08168d 100644
--- a/libjava/gnu/gcj/runtime/NameFinder.java
+++ b/libjava/gnu/gcj/runtime/NameFinder.java
@@ -9,6 +9,7 @@ details. */
package gnu.gcj.runtime;
+import gnu.classpath.Configuration;
import gnu.gcj.RawData;
import java.lang.StringBuffer;
@@ -19,456 +20,156 @@ import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.IOException;
import java.io.File;
+import java.util.Iterator;
+import java.util.HashMap;
+
/**
- * Helper class that translates addresses (represented as longs) to a
- * StackTraceElement array.
+ * Lookup addresses (represented as longs) to find source & line number info.
*
- * There are a couple of system properties that can be set to manipulate the
- * result (all default to true):
+ * The following system property is available (defaults to true):
* <li>
- * <ul><code>gnu.gcj.runtime.NameFinder.demangle</code>
- * Whether names should be demangled.</ul>
- * <ul><code>gnu.gcj.runtime.NameFinder.sanitize</code></ul>
- * Whether calls to initialize exceptions and starting the runtime system
- * should be removed from the stack trace. Only done when names are
- * demangled.</ul>
- * <ul><code>gnu.gcj.runtime.NameFinder.remove_unknown</code>
- * Whether calls to unknown functions (class and method names are unknown)
- * should be removed from the stack trace. Only done when the stack is
- * sanitized.</ul>
- * <ul><code>gnu.gcj.runtime.NameFinder.remove_internal</code>
- * Whether runtime internal calls (methods in the internal _Jv_* classes
- * and functions starting with 'ffi_') should be removed from the stack
- * trace. Only done when the stack is sanitized.</ul>
* <ul><code>gnu.gcj.runtime.NameFinder.use_addr2line</code>
- * Whether an external process (addr2line or addr2name.awk) should be used
- * as fallback to convert the addresses to function names when the runtime
- * is unable to do it through <code>dladdr</code>.</ul>
+ * Whether an external process, addr2line, should be used to look up
+ * source file and line number info. Throwable.printStackTrace() will
+ * be faster if this property is set to 'false'.
+ * </ul>
* </li>
*
* <code>close()</code> should be called to get rid of all resources.
*
* This class is used from <code>java.lang.VMThrowable</code>.
*
- * Currently the <code>lookup(long[])</code> method is not thread safe.
- * It can easily be made thread safe by synchronizing access to all external
- * processes when used.
- *
* @author Mark Wielaard (mark@klomp.org)
*/
public class NameFinder
{
- // Set these to false when not needed.
- private static final boolean demangle
- = Boolean.valueOf(System.getProperty
- ("gnu.gcj.runtime.NameFinder.demangle", "true")
- ).booleanValue();
- private static final boolean sanitize
- = Boolean.valueOf(System.getProperty
- ("gnu.gcj.runtime.NameFinder.sanitize", "true")
- ).booleanValue();
- private static final boolean remove_unknown
- = Boolean.valueOf(System.getProperty
- ("gnu.gcj.runtime.NameFinder.remove_unknown", "true")
- ).booleanValue();
-
- // The remove_interpreter name is an old 3.3/3.4 (deprecated) synonym.
- private static final boolean remove_internal
- = (Boolean.valueOf(System.getProperty
- ("gnu.gcj.runtime.NameFinder.remove_internal", "true")
- ).booleanValue()
- ||
- Boolean.valueOf(System.getProperty
- ("gnu.gcj.runtime.NameFinder.remove_interpreter", "true")
- ).booleanValue()
- );
-
- private static final boolean use_addr2line
- = Boolean.valueOf(System.getProperty
- ("gnu.gcj.runtime.NameFinder.use_addr2line", "true")
- ).booleanValue();
-
- /**
- * The name of the currently running executable.
- */
- private final String executable;
-
- /**
- * Process used for demangling names.
- */
- private Process cppfilt;
-
- private BufferedWriter cppfiltOut;
- private BufferedReader cppfiltIn;
-
/**
- * Process used for translating addresses to function/file names.
+ * The name of the binary to look up.
*/
- private Process addr2line;
+ private String binaryFile;
+ private String sourceFile;
+ private int lineNum;
+ private HashMap procs = new HashMap();
- private BufferedWriter addr2lineOut;
- private BufferedReader addr2lineIn;
-
- /**
- * Flag set if using addr2name.awk instead of addr2line from binutils.
- */
- private boolean usingAddr2name = false;
+ private static final boolean use_addr2line
+ = Boolean.valueOf(System.getProperty
+ ("gnu.gcj.runtime.NameFinder.use_addr2line", "true")
+ ).booleanValue();
- /**
- * Creates a new NameFinder. Call close to get rid of any resources
- * created while using the <code>lookup</code> methods.
- */
- public NameFinder()
+ class Addr2Line
{
- executable = getExecutable();
- Runtime runtime = Runtime.getRuntime();
- if (demangle)
+ Process proc;
+ BufferedWriter out;
+ BufferedReader in;
+
+ Addr2Line(String binaryFile)
{
try
- {
- String[] exec = new String[] {"c++filt", "-s", "java"};
- cppfilt = runtime.exec(exec);
- cppfiltIn = new BufferedReader
- (new InputStreamReader(cppfilt.getInputStream()));
- cppfiltOut = new BufferedWriter
- (new OutputStreamWriter(cppfilt.getOutputStream()));
- }
+ {
+ String[] exec = new String[] {"addr2line", "-e", binaryFile};
+ Runtime runtime = Runtime.getRuntime();
+ proc = runtime.exec(exec);
+ }
catch (IOException ioe)
- {
- if (cppfilt != null)
- cppfilt.destroy();
- cppfilt = null;
- }
- }
-
- if (use_addr2line)
{
- try
- {
- String[] exec = new String[] {"addr2line", "-f", "-e", executable};
- addr2line = runtime.exec(exec);
- }
- catch (IOException ioe)
- {
- try
- {
- String[] exec = new String[] {"addr2name.awk", executable};
- addr2line = runtime.exec(exec);
- usingAddr2name = true;
- }
- catch (IOException ioe2) { addr2line = null; }
- }
-
- if (addr2line != null)
- {
- addr2lineIn = new BufferedReader
- (new InputStreamReader(addr2line.getInputStream()));
- addr2lineOut = new BufferedWriter
- (new OutputStreamWriter(addr2line.getOutputStream()));
- }
}
- }
-
- /**
- * Returns the name of the currently running process.
- */
- native private static String getExecutable();
-
- /**
- * Tries to use dladdr to create the nth StackTraceElement from the given
- * addresses. Returns null on failure.
- */
- native private StackTraceElement dladdrLookup(RawData addrs, int n);
-
- /**
- * Returns the nth element from the stack as a hex encoded String.
- */
- native private String getAddrAsString(RawData addrs, int n);
-
- /**
- * Returns the label that is exported for the given method name.
- */
- native private String getExternalLabel(String name);
-
- /**
- * If nth element of stack is an interpreted frame, return the
- * element representing the method being interpreted.
- */
- native private StackTraceElement lookupInterp(RawData addrs, int n);
- /**
- * Creates the nth StackTraceElement from the given native stacktrace.
- */
- private StackTraceElement lookup(RawData addrs, int n)
- {
- StackTraceElement result;
-
- result = lookupInterp(addrs, n);
- if (result == null)
- result = dladdrLookup(addrs, n);
- if (result == null)
+ if (proc != null)
{
- String name = null;
- String file = null;
-
- String hex = getAddrAsString(addrs, n);
-
- if (addr2line != null)
- {
- try
- {
- addr2lineOut.write(hex);
- addr2lineOut.newLine();
- addr2lineOut.flush();
- name = addr2lineIn.readLine();
- file = addr2lineIn.readLine();
-
- // addr2line uses symbolic debugging information instead
- // of the actually exported labels as addr2name.awk does.
- // This name might need some modification, depending on
- // the system, to make it a label like that returned
- // by addr2name.awk or dladdr.
- if (! usingAddr2name)
- if (name != null && ! "??".equals (name))
- name = getExternalLabel (name);
- }
- catch (IOException ioe) { addr2line = null; }
- }
-
- if (name == null || "??".equals(name))
- name = hex;
-
- result = createStackTraceElement(name, file);
+ in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
+ out = new BufferedWriter(new OutputStreamWriter(proc.getOutputStream()));
+ }
+ }
+
+ void close()
+ {
+ try
+ {
+ in.close();
+ out.close();
}
+ catch (IOException x) {}
- return result;
+ proc.destroy();
+ }
}
/**
- * Given an Throwable and a native stacktrace returns an array of
- * StackTraceElement containing class, method, file and linenumbers.
+ * Create a new NameFinder to lookup names in binaryFile. Call close to get rid of any
+ * resources created while using the <code>lookup</code> methods.
*/
- public StackTraceElement[] lookup(Throwable t, StackTrace trace)
+ public NameFinder()
{
- RawData addrs = trace.stackTraceAddrs();
- int length = trace.length();
-
- StackTraceElement[] elements = new StackTraceElement[length];
- for (int i=0; i < length; i++)
- elements[i] = lookup(addrs, i);
-
- if (demangle && sanitize)
- return sanitizeStack(elements, t);
- else
- return elements;
}
-
/**
- * Removes calls to initialize exceptions and the runtime system from
- * the stack trace including stack frames of which nothing usefull is known.
- * Throw away the top of the stack till we find the constructor(s)
- * of this Throwable or at least the contructors of java.lang.Throwable
- * or the actual fillInStackTrace call.
- * Also throw away from the top everything before and including a runtime
- * _Jv_Throw call.
+ * Returns the source file name if lookup() was successful. If the source file could not be
+ * determined, the binary name will be returned instead.
*/
- private static StackTraceElement[] sanitizeStack(StackTraceElement[] elements,
- Throwable t)
+ public String getSourceFile()
{
- StackTraceElement[] stack;
-
- String className = t.getClass().getName();
- String consName;
- int lastDot = className.lastIndexOf('.');
- if (lastDot == -1)
- consName = className + '(';
+ String file;
+ if (sourceFile != null)
+ file = sourceFile;
else
- consName = className.substring(lastDot + 1) + '(';
-
- int unknown = 0;
- int internal = 0;
- int last_throw = -1;
- int length = elements.length;
- int end = length-1;
- for (int i = 0; i < length; i++)
- {
- String CName = elements[i].getClassName();
- String MName = elements[i].getMethodName();
- if ((CName == null && MName != null && MName.startsWith("_Jv_Throw"))
- ||
- (CName != null
- && (CName.equals(className)
- || CName.equals("java.lang.Throwable")
- || CName.equals("java.lang.VMThrowable"))
- && MName != null
- && (MName.startsWith(consName)
- || MName.startsWith("Throwable(")
- || MName.startsWith("fillInStackTrace("))))
- {
- last_throw = i;
- // Reset counting of unknown and internal frames.
- unknown = 0;
- internal = 0;
- }
- else if (remove_unknown && CName == null
- && (MName == null || MName.startsWith("0x")))
- unknown++;
- else if (remove_internal
- && ((CName == null
- && MName != null && MName.startsWith("ffi_"))
- || (CName != null && CName.startsWith("_Jv_"))
- || (CName == null && MName != null
- && MName.startsWith("_Jv_"))))
- internal++;
- else if (("java.lang.Thread".equals(CName)
- || "gnu.java.lang.MainThread".equals(CName))
- && "run()".equals(MName))
- {
- end = i;
- break;
- }
- }
- int begin = last_throw+1;
-
- // Now filter out everything at the start and the end that is not part
- // of the "normal" user program including any elements that are internal
- // calls or have no usefull information whatsoever.
- // Unless that means we filter out all info.
- int nr_elements = end - begin - unknown - internal + 1;
- if ((begin > 0 || end < length-1 || unknown > 0 || internal > 0)
- && nr_elements > 0)
- {
- stack = new StackTraceElement[nr_elements];
- int pos =0;
- for (int i=begin; i<=end; i++)
- {
- String MName = elements[i].getMethodName();
- String CName = elements[i].getClassName();
- if (remove_unknown && CName == null
- && (MName == null || MName.startsWith("0x")))
- ; // Skip unknown frame
- else if (remove_internal
- && ((CName == null
- && MName != null && MName.startsWith("ffi_"))
- || (CName != null && CName.startsWith("_Jv_"))
- || (CName == null && MName != null
- && MName.startsWith("_Jv_"))))
- ; // Skip internal runtime frame
- else
- {
- // Null Class or Method name in elements are not allowed.
- if (MName == null || CName == null)
- {
- MName = MName == null ? "" : MName;
- CName = CName == null ? "" : CName;
- stack[pos] = newElement(elements[i].getFileName(),
- elements[i].getLineNumber(),
- CName, MName,
- elements[i].isNativeMethod());
- }
- else
- stack[pos] = elements[i];
- pos++;
- }
- }
- }
- else
- stack = elements;
-
- return stack;
+ file = binaryFile;
+
+ return file.substring(file.lastIndexOf(File.separator) + 1, file.length());
}
/**
- * Native helper method to create a StackTraceElement. Needed to work
- * around normal Java access restrictions.
- */
- native static private StackTraceElement newElement(String fileName,
- int lineNumber,
- String className,
- String methName,
- boolean isNative);
-
- /**
- * Creates a StackTraceElement given a string and a filename.
- * Splits the given string into the class and method part.
- * The string name will be a demangled to a fully qualified java method
- * string. The string file will be decomposed into a file name and possibly
- * a line number. The name should never be null, but the file may be if it
- * is unknown.
- */
- private StackTraceElement createStackTraceElement(String name, String file)
+ * If lookup() was successful, returns the line number of addr. If the line number could not
+ * be determined, -1 is returned.
+ */
+ public int getLineNum()
{
- if (!demangle)
- return newElement(file, -1, null, name, false);
-
- String s = demangleName(name);
- String methodName = s;
- String className = null;
- int bracket = s.indexOf('(');
- if (bracket > 0)
+ return lineNum;
+ }
+
+ public void lookup (String file, long addr)
+ {
+ binaryFile = file;
+ sourceFile = null;
+ lineNum = -1;
+
+ if (! use_addr2line)
+ return;
+ Addr2Line addr2line = (Addr2Line) procs.get(file);
+ if (addr2line == null)
{
- int dot = s.lastIndexOf('.', bracket);
- if (dot > 0)
- {
- className = s.substring(0, dot);
- methodName = s.substring(dot+1, s.length());
- }
+ addr2line = new Addr2Line(file);
+ procs.put(file, addr2line);
}
-
- String fileName = file;
- int line = -1;
- if (fileName != null)
+
+ if (addr2line.proc == null)
+ return;
+
+ String hexAddr = "0x" + Long.toHexString(addr);
+ String name;
+
+ try
{
- int colon = file.lastIndexOf(':');
- if (colon > 0)
- {
- fileName = file.substring(0, colon);
- try
- {
- line = Integer.parseInt(file.substring(colon+1, file.length()));
- }
- catch (NumberFormatException nfe) { /* ignore */ }
- }
+ addr2line.out.write(hexAddr);
+ addr2line.out.newLine();
+ addr2line.out.flush();
+ String result = addr2line.in.readLine();
- if (line == 0)
- line =-1;
-
- if ("".equals(fileName) || "??".equals(fileName))
- fileName = null;
- else if (fileName != null)
- {
- try
- {
- fileName = new File(fileName).getCanonicalPath();
- }
- catch (IOException ioe) { /* ignore */ }
- }
- }
-
- return newElement(fileName, line, className, methodName, false);
- }
-
- /**
- * Demangles the given String if possible. Returns the demangled String or
- * the original string if demangling is impossible.
- */
- private String demangleName(String s)
- {
- if (cppfilt != null)
- {
- try
+ if (result.indexOf("??") == -1)
{
- cppfiltOut.write(s);
- cppfiltOut.newLine();
- cppfiltOut.flush();
- return cppfiltIn.readLine();
+ int split = result.lastIndexOf(':');
+ sourceFile = result.substring(0, split);
+ String lineNumStr = result.substring(split + 1, result.length());
+ lineNum = Integer.parseInt (lineNumStr);
}
- catch (IOException ioe) { cppfilt.destroy(); cppfilt = null; }
- }
-
- return s;
+ }
+ catch (IOException ioe)
+ {
+ addr2line = null;
+ }
+ catch (NumberFormatException x)
+ {
+ }
}
/**
@@ -508,7 +209,7 @@ public class NameFinder
// Demangle the type arguments
int arrayDepth = 0;
char c = (index < length) ? m.charAt(index) : ')';
- while (c != ')')
+ while (c != ')')
{
String type;
switch(c)
@@ -581,18 +282,11 @@ public class NameFinder
*/
public void close()
{
- if (cppfilt != null)
- cppfilt.destroy();
-
- if (addr2line != null)
- addr2line.destroy();
- }
-
- /**
- * Calls close to get rid of all resources.
- */
- protected void finalize()
- {
- close();
+ Iterator itr = procs.values().iterator();
+ while (itr.hasNext())
+ {
+ Addr2Line proc = (Addr2Line) itr.next();
+ proc.close();
+ }
}
}
diff --git a/libjava/gnu/java/lang/MainThread.java b/libjava/gnu/java/lang/MainThread.java
index 14a00ca8d9b..44c20ff94d2 100644
--- a/libjava/gnu/java/lang/MainThread.java
+++ b/libjava/gnu/java/lang/MainThread.java
@@ -127,5 +127,7 @@ final class MainThread extends Thread
return mainName;
}
+ // Note: this function name is known to the stack tracing code.
+ // You shouldn't change this without also updating stacktrace.cc.
private native void call_main();
}
diff --git a/libjava/include/java-interp.h b/libjava/include/java-interp.h
index 4126c2f44cd..569286116ee 100644
--- a/libjava/include/java-interp.h
+++ b/libjava/include/java-interp.h
@@ -23,6 +23,11 @@ details. */
#include <java/lang/ClassLoader.h>
#include <java/lang/reflect/Modifier.h>
+// Define this to get the direct-threaded interpreter. If undefined,
+// we revert to a basic bytecode interpreter. The former is faster
+// but uses more memory.
+#define DIRECT_THREADED
+
extern "C" {
#include <ffi.h>
}
@@ -95,6 +100,41 @@ public:
}
};
+// The type of the PC depends on whether we're doing direct threading
+// or a more ordinary bytecode interpreter.
+#ifdef DIRECT_THREADED
+// Slot in the "compiled" form of the bytecode.
+union insn_slot
+{
+ // Address of code.
+ void *insn;
+ // An integer value used by an instruction.
+ jint int_val;
+ // A pointer value used by an instruction.
+ void *datum;
+};
+
+typedef insn_slot *pc_t;
+#else
+typedef unsigned char *pc_t;
+#endif
+
+
+// This structure holds the bytecode pc and corresponding source code
+// line number. An array (plus length field) of this structure is put
+// in each _Jv_InterpMethod and used to resolve the (internal) program
+// counter of the interpreted method to an actual java source file
+// line.
+struct _Jv_LineTableEntry
+{
+ union
+ {
+ pc_t pc;
+ int bytecode_pc;
+ };
+ int line;
+};
+
class _Jv_InterpMethod : public _Jv_MethodBase
{
_Jv_ushort max_stack;
@@ -103,6 +143,10 @@ class _Jv_InterpMethod : public _Jv_MethodBase
_Jv_ushort exc_count;
+ // Length of the line_table - when this is zero then line_table is NULL.
+ int line_table_len;
+ _Jv_LineTableEntry *line_table;
+
void *prepared;
unsigned char* bytecode ()
@@ -135,17 +179,19 @@ class _Jv_InterpMethod : public _Jv_MethodBase
static void run_class (ffi_cif*, void*, ffi_raw*, void*);
static void run_synch_class (ffi_cif*, void*, ffi_raw*, void*);
- void run (void*, ffi_raw *);
+ static void run (void*, ffi_raw *, _Jv_InterpMethod *);
+
+ // Returns source file line number for given PC value, or -1 if line
+ // number info is unavailable.
+ int get_source_line(pc_t mpc);
public:
static void dump_object(jobject o);
friend class _Jv_ClassReader;
friend class _Jv_BytecodeVerifier;
- friend class gnu::gcj::runtime::NameFinder;
- friend class gnu::gcj::runtime::StackTrace;
+ friend class _Jv_StackTrace;
friend class _Jv_InterpreterEngine;
-
#ifdef JV_MARKOBJ_DECL
friend JV_MARKOBJ_DECL;
@@ -155,11 +201,14 @@ class _Jv_InterpMethod : public _Jv_MethodBase
class _Jv_InterpClass
{
_Jv_MethodBase **interpreted_methods;
- _Jv_ushort *field_initializers;
+ _Jv_ushort *field_initializers;
+ jstring source_file_name;
friend class _Jv_ClassReader;
friend class _Jv_InterpMethod;
+ friend class _Jv_StackTrace;
friend class _Jv_InterpreterEngine;
+
friend void _Jv_InitField (jobject, jclass, int);
#ifdef JV_MARKOBJ_DECL
friend JV_MARKOBJ_DECL;
@@ -219,23 +268,24 @@ public:
}
};
-// A structure of this type is used to link together interpreter
-// invocations on the stack.
-struct _Jv_MethodChain
+// The interpreted call stack, represented by a linked list of frames.
+struct _Jv_InterpFrame
{
- const _Jv_InterpMethod *self;
- _Jv_MethodChain **ptr;
- _Jv_MethodChain *next;
+ _Jv_InterpMethod *self;
+ _Jv_InterpFrame **ptr;
+ _Jv_InterpFrame *next;
+ pc_t pc;
- _Jv_MethodChain (const _Jv_InterpMethod *s, _Jv_MethodChain **n)
+ _Jv_InterpFrame (_Jv_InterpMethod *s, _Jv_InterpFrame **n)
{
self = s;
ptr = n;
next = *n;
*n = this;
+ pc = NULL;
}
- ~_Jv_MethodChain ()
+ ~_Jv_InterpFrame ()
{
*ptr = next;
}
diff --git a/libjava/include/java-stack.h b/libjava/include/java-stack.h
index 6c3103ce056..2d914cb9ba7 100644
--- a/libjava/include/java-stack.h
+++ b/libjava/include/java-stack.h
@@ -1,6 +1,6 @@
// java-stack.h - Definitions for unwinding & inspecting the call stack.
-/* Copyright (C) 2003 Free Software Foundation
+/* Copyright (C) 2005 Free Software Foundation
This file is part of libgcj.
@@ -21,10 +21,12 @@ details. */
#include <java/lang/Class.h>
#include <java/lang/StackTraceElement.h>
#include <java/lang/Throwable.h>
+#include <java/lang/Thread.h>
#include <gnu/gcj/runtime/NameFinder.h>
using namespace gnu::gcj::runtime;
+using namespace java::lang;
enum _Jv_FrameType
{
@@ -51,13 +53,44 @@ struct _Jv_StackFrame
#ifdef INTERPRETER
_Jv_InterpFrameInfo interp;
#endif
- void *ip;
+ struct {
+ void *ip;
+ void *start_ip;
+ };
};
// _Jv_FrameInfo info; /* Frame-type specific data. */
jclass klass;
_Jv_Method *meth;
};
+typedef struct _Jv_UnwindState;
+typedef _Unwind_Reason_Code (*_Jv_TraceFn) (_Jv_UnwindState *);
+
+struct _Jv_UnwindState
+{
+ jint length; // length of FRAMES
+ jint pos; // current position in FRAMES
+ _Jv_StackFrame *frames; // array of stack frame data to be filled.
+ _Jv_InterpFrame *interp_frame; // current frame in the interpreter stack.
+ _Jv_TraceFn trace_function; // function to call back after each frame
+ // is enumerated. May be NULL.
+ void *trace_data; // additional state data for trace_function.
+
+ _Jv_UnwindState (jint ln)
+ {
+ length = ln;
+ pos = 0;
+ frames = NULL;
+ Thread *thread = Thread::currentThread();
+ // Check for NULL currentThread(), in case an exception is created
+ // very early during the runtime startup.
+ if (thread)
+ interp_frame = (_Jv_InterpFrame *) thread->interp_frame;
+ trace_function = NULL;
+ trace_data = NULL;
+ }
+};
+
class _Jv_StackTrace
{
private:
@@ -65,20 +98,28 @@ private:
_Jv_StackFrame frames[];
static void UpdateNCodeMap ();
- static jclass ClassForIP (void *ip, void **ncode);
+ static jclass ClassForFrame (_Jv_StackFrame *frame);
static void FillInFrameInfo (_Jv_StackFrame *frame);
static void getLineNumberForFrame(_Jv_StackFrame *frame, NameFinder *finder,
jstring *sourceFileName, jint *lineNum);
static _Unwind_Reason_Code UnwindTraceFn (struct _Unwind_Context *context,
void *state_ptr);
+
+ static _Unwind_Reason_Code calling_class_trace_fn (_Jv_UnwindState *state);
+ static _Unwind_Reason_Code non_system_trace_fn (_Jv_UnwindState *state);
public:
static _Jv_StackTrace *GetStackTrace (void);
static JArray< ::java::lang::StackTraceElement *>*
GetStackTraceElements (_Jv_StackTrace *trace,
java::lang::Throwable *throwable);
- static jclass GetCallingClass (void);
+ static jclass GetCallingClass (jclass);
+ static void GetCallerInfo (jclass checkClass, jclass *, _Jv_Method **);
+ static JArray<jclass> *GetClassContext (jclass checkClass);
+ static ClassLoader *GetFirstNonSystemClassLoader (void);
+
};
+
#endif /* __JV_STACKTRACE_H__ */
diff --git a/libjava/include/jvm.h b/libjava/include/jvm.h
index 7668703f54c..4dfdb4d3767 100644
--- a/libjava/include/jvm.h
+++ b/libjava/include/jvm.h
@@ -120,20 +120,6 @@ union _Jv_value
jobject object_value;
};
-// An instance of this type is used to represent a single frame in a
-// backtrace. If the interpreter has been built, we also include
-// information about the interpreted method.
-struct _Jv_frame_info
-{
- // PC value.
- void *addr;
-#ifdef INTERPRETER
- // Actually a _Jv_InterpMethod, but we don't want to include
- // java-interp.h everywhere.
- void *interp;
-#endif // INTERPRETER
-};
-
/* Extract a character from a Java-style Utf8 string.
* PTR points to the current character.
* LIMIT points to the end of the Utf8 string.
diff --git a/libjava/interpret.cc b/libjava/interpret.cc
index 4c547b35dd6..a2bcbb84084 100644
--- a/libjava/interpret.cc
+++ b/libjava/interpret.cc
@@ -13,11 +13,6 @@ details. */
#include <config.h>
#include <platform.h>
-// Define this to get the direct-threaded interpreter. If undefined,
-// we revert to a basic bytecode interpreter. The former is faster
-// but uses more memory.
-#define DIRECT_THREADED
-
#pragma implementation "java-interp.h"
#include <jvm.h>
@@ -83,26 +78,6 @@ void _Jv_InitInterpreter() {}
extern "C" double __ieee754_fmod (double,double);
-// This represents a single slot in the "compiled" form of the
-// bytecode.
-union insn_slot
-{
- // Address of code.
- void *insn;
- // An integer value used by an instruction.
- jint int_val;
- // A pointer value used by an instruction.
- void *datum;
-};
-
-// The type of the PC depends on whether we're doing direct threading
-// or a more ordinary bytecode interpreter.
-#ifdef DIRECT_THREADED
-typedef insn_slot *pc_t;
-#else
-typedef unsigned char *pc_t;
-#endif
-
static inline void dupx (_Jv_word *sp, int n, int x)
{
// first "slide" n+x elements n to the right
@@ -117,7 +92,6 @@ static inline void dupx (_Jv_word *sp, int n, int x)
{
sp[top-(n+x)-i] = sp[top-i];
}
-
}
// Used to convert from floating types to integral types.
@@ -248,15 +222,16 @@ static jint get4(unsigned char* loc) {
| (((jint)(loc[3])) << 0);
}
+#define SAVE_PC() frame_desc.pc = pc
#ifdef HANDLE_SEGV
-#define NULLCHECK(X)
-#define NULLARRAYCHECK(X)
+#define NULLCHECK(X) SAVE_PC()
+#define NULLARRAYCHECK(X) SAVE_PC()
#else
#define NULLCHECK(X) \
- do { if ((X)==NULL) throw_null_pointer_exception (); } while (0)
+ do { SAVE_PC(); if ((X)==NULL) throw_null_pointer_exception (); } while (0)
#define NULLARRAYCHECK(X) \
- do { if ((X)==NULL) { throw_null_pointer_exception (); } } while (0)
+ do { SAVE_PC(); if ((X)==NULL) { throw_null_pointer_exception (); } } while (0)
#endif
#define ARRAYBOUNDSCHECK(array, index) \
@@ -274,7 +249,7 @@ _Jv_InterpMethod::run_normal (ffi_cif *,
void* __this)
{
_Jv_InterpMethod *_this = (_Jv_InterpMethod *) __this;
- _this->run (ret, args);
+ run (ret, args, _this);
}
void
@@ -288,7 +263,7 @@ _Jv_InterpMethod::run_synch_object (ffi_cif *,
jobject rcv = (jobject) args[0].ptr;
JvSynchronize mutex (rcv);
- _this->run (ret, args);
+ run (ret, args, _this);
}
void
@@ -299,7 +274,7 @@ _Jv_InterpMethod::run_class (ffi_cif *,
{
_Jv_InterpMethod *_this = (_Jv_InterpMethod *) __this;
_Jv_InitClass (_this->defining_class);
- _this->run (ret, args);
+ run (ret, args, _this);
}
void
@@ -314,7 +289,7 @@ _Jv_InterpMethod::run_synch_class (ffi_cif *,
_Jv_InitClass (sync);
JvSynchronize mutex (sync);
- _this->run (ret, args);
+ run (ret, args, _this);
}
#ifdef DIRECT_THREADED
@@ -783,29 +758,23 @@ _Jv_InterpMethod::compile (const void * const *insn_targets)
exc[i].handler_type.p = handler;
}
+ // Translate entries in the LineNumberTable from bytecode PC's to direct
+ // threaded interpreter instruction values.
+ for (int i = 0; i < line_table_len; i++)
+ {
+ int byte_pc = line_table[i].bytecode_pc;
+ line_table[i].pc = &insns[pc_mapping[byte_pc]];
+ }
+
prepared = insns;
}
#endif /* DIRECT_THREADED */
-// These exist so that the stack-tracing code can find the boundaries
-// of the interpreter.
-void *_Jv_StartOfInterpreter;
-void *_Jv_EndOfInterpreter;
-extern "C" void *_Unwind_FindEnclosingFunction (void *pc);
-
void
-_Jv_InterpMethod::run (void *retp, ffi_raw *args)
+_Jv_InterpMethod::run (void *retp, ffi_raw *args, _Jv_InterpMethod *meth)
{
using namespace java::lang::reflect;
- // Record the address of the start of this member function in
- // _Jv_StartOfInterpreter. Such a write to a global variable
- // without acquiring a lock is correct iff reads and writes of words
- // in memory are atomic, but Java requires that anyway.
- foo:
- if (_Jv_StartOfInterpreter == NULL)
- _Jv_StartOfInterpreter = _Unwind_FindEnclosingFunction (&&foo);
-
// FRAME_DESC registers this particular invocation as the top-most
// interpreter frame. This lets the stack tracing code (for
// Throwable) print information about the method being interpreted
@@ -813,20 +782,20 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
// destructor so it cleans up automatically when the interpreter
// returns.
java::lang::Thread *thread = java::lang::Thread::currentThread();
- _Jv_MethodChain frame_desc (this,
- (_Jv_MethodChain **) &thread->interp_frame);
+ _Jv_InterpFrame frame_desc (meth,
+ (_Jv_InterpFrame **) &thread->interp_frame);
- _Jv_word stack[max_stack];
+ _Jv_word stack[meth->max_stack];
_Jv_word *sp = stack;
- _Jv_word locals[max_locals];
+ _Jv_word locals[meth->max_locals];
/* Go straight at it! the ffi raw format matches the internal
stack representation exactly. At least, that's the idea.
*/
- memcpy ((void*) locals, (void*) args, args_raw_size);
+ memcpy ((void*) locals, (void*) args, meth->args_raw_size);
- _Jv_word *pool_data = defining_class->constants.data;
+ _Jv_word *pool_data = meth->defining_class->constants.data;
/* These three are temporaries for common code used by several
instructions. */
@@ -1068,14 +1037,14 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
#define AMPAMP(label) &&label
// Compile if we must. NOTE: Double-check locking.
- if (prepared == NULL)
+ if (meth->prepared == NULL)
{
_Jv_MutexLock (&compile_mutex);
- if (prepared == NULL)
- compile (insn_target);
+ if (meth->prepared == NULL)
+ meth->compile (insn_target);
_Jv_MutexUnlock (&compile_mutex);
}
- pc = (insn_slot *) prepared;
+ pc = (insn_slot *) meth->prepared;
#else
@@ -1132,7 +1101,8 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
* the corresponding bit JV_CONSTANT_ResolvedFlag in the tag
* directly. For now, I don't think it is worth it. */
- rmeth = (_Jv_Linker::resolve_pool_entry (defining_class,
+ SAVE_PC();
+ rmeth = (_Jv_Linker::resolve_pool_entry (meth->defining_class,
index)).rmethod;
sp -= rmeth->stack_item_count;
@@ -1140,7 +1110,10 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
// working if the method is final. So instead we do an
// explicit test.
if (! sp[0].o)
- throw new java::lang::NullPointerException;
+ {
+ //printf("invokevirtual pc = %p/%i\n", pc, meth->get_pc_val(pc));
+ throw new java::lang::NullPointerException;
+ }
if (rmeth->vtable_index == -1)
{
@@ -1173,7 +1146,10 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
// working if the method is final. So instead we do an
// explicit test.
if (! sp[0].o)
- throw new java::lang::NullPointerException;
+ {
+ SAVE_PC();
+ throw new java::lang::NullPointerException;
+ }
if (rmeth->vtable_index == -1)
{
@@ -1193,6 +1169,8 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
perform_invoke:
{
+ SAVE_PC();
+
/* here goes the magic again... */
ffi_cif *cif = &rmeth->cif;
ffi_raw *raw = (ffi_raw*) sp;
@@ -2423,7 +2401,8 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
insn_getstatic:
{
jint fieldref_index = GET2U ();
- _Jv_Linker::resolve_pool_entry (defining_class, fieldref_index);
+ SAVE_PC(); // Constant pool resolution could throw.
+ _Jv_Linker::resolve_pool_entry (meth->defining_class, fieldref_index);
_Jv_Field *field = pool_data[fieldref_index].field;
if ((field->flags & Modifier::STATIC) == 0)
@@ -2510,7 +2489,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
insn_getfield:
{
jint fieldref_index = GET2U ();
- _Jv_Linker::resolve_pool_entry (defining_class, fieldref_index);
+ _Jv_Linker::resolve_pool_entry (meth->defining_class, fieldref_index);
_Jv_Field *field = pool_data[fieldref_index].field;
if ((field->flags & Modifier::STATIC) != 0)
@@ -2626,7 +2605,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
insn_putstatic:
{
jint fieldref_index = GET2U ();
- _Jv_Linker::resolve_pool_entry (defining_class, fieldref_index);
+ _Jv_Linker::resolve_pool_entry (meth->defining_class, fieldref_index);
_Jv_Field *field = pool_data[fieldref_index].field;
jclass type = field->type;
@@ -2713,7 +2692,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
insn_putfield:
{
jint fieldref_index = GET2U ();
- _Jv_Linker::resolve_pool_entry (defining_class, fieldref_index);
+ _Jv_Linker::resolve_pool_entry (meth->defining_class, fieldref_index);
_Jv_Field *field = pool_data[fieldref_index].field;
jclass type = field->type;
@@ -2839,7 +2818,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
{
int index = GET2U ();
- rmeth = (_Jv_Linker::resolve_pool_entry (defining_class,
+ rmeth = (_Jv_Linker::resolve_pool_entry (meth->defining_class,
index)).rmethod;
sp -= rmeth->stack_item_count;
@@ -2847,7 +2826,10 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
// We don't use NULLCHECK here because we can't rely on that
// working for <init>. So instead we do an explicit test.
if (! sp[0].o)
- throw new java::lang::NullPointerException;
+ {
+ SAVE_PC();
+ throw new java::lang::NullPointerException;
+ }
fun = (void (*)()) rmeth->method->ncode;
@@ -2868,7 +2850,10 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
// We don't use NULLCHECK here because we can't rely on that
// working for <init>. So instead we do an explicit test.
if (! sp[0].o)
- throw new java::lang::NullPointerException;
+ {
+ SAVE_PC();
+ throw new java::lang::NullPointerException;
+ }
fun = (void (*)()) rmeth->method->ncode;
}
goto perform_invoke;
@@ -2878,7 +2863,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
{
int index = GET2U ();
- rmeth = (_Jv_Linker::resolve_pool_entry (defining_class,
+ rmeth = (_Jv_Linker::resolve_pool_entry (meth->defining_class,
index)).rmethod;
sp -= rmeth->stack_item_count;
@@ -2908,7 +2893,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
{
int index = GET2U ();
- rmeth = (_Jv_Linker::resolve_pool_entry (defining_class,
+ rmeth = (_Jv_Linker::resolve_pool_entry (meth->defining_class,
index)).rmethod;
sp -= rmeth->stack_item_count;
@@ -2952,7 +2937,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
insn_new:
{
int index = GET2U ();
- jclass klass = (_Jv_Linker::resolve_pool_entry (defining_class,
+ jclass klass = (_Jv_Linker::resolve_pool_entry (meth->defining_class,
index)).clazz;
jobject res = _Jv_AllocObject (klass);
PUSHA (res);
@@ -2986,7 +2971,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
insn_anewarray:
{
int index = GET2U ();
- jclass klass = (_Jv_Linker::resolve_pool_entry (defining_class,
+ jclass klass = (_Jv_Linker::resolve_pool_entry (meth->defining_class,
index)).clazz;
int size = POPI();
jobject result = _Jv_NewObjectArray (size, klass, 0);
@@ -3027,9 +3012,10 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
insn_checkcast:
{
+ SAVE_PC();
jobject value = POPA();
jint index = GET2U ();
- jclass to = (_Jv_Linker::resolve_pool_entry (defining_class,
+ jclass to = (_Jv_Linker::resolve_pool_entry (meth->defining_class,
index)).clazz;
if (value != NULL && ! to->isInstance (value))
@@ -3047,6 +3033,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
#ifdef DIRECT_THREADED
checkcast_resolved:
{
+ SAVE_PC();
jobject value = POPA ();
jclass to = (jclass) AVAL ();
if (value != NULL && ! to->isInstance (value))
@@ -3058,9 +3045,10 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
insn_instanceof:
{
+ SAVE_PC();
jobject value = POPA();
jint index = GET2U ();
- jclass to = (_Jv_Linker::resolve_pool_entry (defining_class,
+ jclass to = (_Jv_Linker::resolve_pool_entry (meth->defining_class,
index)).clazz;
PUSHI (to->isInstance (value));
@@ -3123,7 +3111,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
int dim = GET1U ();
jclass type
- = (_Jv_Linker::resolve_pool_entry (defining_class,
+ = (_Jv_Linker::resolve_pool_entry (meth->defining_class,
kind_index)).clazz;
jint *sizes = (jint*) __builtin_alloca (sizeof (jint)*dim);
@@ -3212,10 +3200,10 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
#else
int logical_pc = pc - 1 - bytecode ();
#endif
- _Jv_InterpException *exc = exceptions ();
+ _Jv_InterpException *exc = meth->exceptions ();
jclass exc_class = ex->getClass ();
- for (int i = 0; i < exc_count; i++)
+ for (int i = 0; i < meth->exc_count; i++)
{
if (PCVAL (exc[i].start_pc) <= logical_pc
&& logical_pc < PCVAL (exc[i].end_pc))
@@ -3272,6 +3260,21 @@ throw_null_pointer_exception ()
}
#endif
+/* Look up source code line number for given bytecode (or direct threaded
+ interpreter) PC. */
+int
+_Jv_InterpMethod::get_source_line(pc_t mpc)
+{
+ int line = line_table_len > 0 ? line_table[0].line : -1;
+ for (int i = 1; i < line_table_len; i++)
+ if (line_table[i].pc > mpc)
+ break;
+ else
+ line = line_table[i].line;
+
+ return line;
+}
+
/** Do static initialization for fields with a constant initializer */
void
_Jv_InitField (jobject obj, jclass klass, int index)
diff --git a/libjava/java/lang/Class.h b/libjava/java/lang/Class.h
index d7b21e76b05..46feff6280c 100644
--- a/libjava/java/lang/Class.h
+++ b/libjava/java/lang/Class.h
@@ -21,7 +21,6 @@ details. */
#include <java/lang/reflect/Modifier.h>
#include <java/security/ProtectionDomain.h>
#include <java/lang/Package.h>
-#include <gnu/gcj/runtime/StackTrace.h>
// We declare these here to avoid including gcj/cni.h.
extern "C" void _Jv_InitClass (jclass klass);
@@ -238,13 +237,13 @@ jclass _Jv_GetArrayClass (jclass klass, java::lang::ClassLoader *loader);
jboolean _Jv_IsInterpretedClass (jclass);
void _Jv_InitField (jobject, jclass, int);
-class _Jv_ClassReader;
+class _Jv_ClassReader;
class _Jv_InterpClass;
class _Jv_InterpMethod;
#endif
+class _Jv_StackTrace;
class _Jv_BytecodeVerifier;
-class gnu::gcj::runtime::StackTrace;
class java::io::VMObjectStreamClass;
void _Jv_sharedlib_register_hook (jclass klass);
@@ -473,6 +472,7 @@ private:
friend class ::_Jv_ClassReader;
friend class ::_Jv_InterpClass;
friend class ::_Jv_InterpMethod;
+ friend class ::_Jv_StackTrace;
#endif
#ifdef JV_MARKOBJ_DECL
@@ -480,7 +480,6 @@ private:
#endif
friend class ::_Jv_BytecodeVerifier;
- friend class gnu::gcj::runtime::StackTrace;
friend class java::io::VMObjectStreamClass;
friend class ::_Jv_Linker;
diff --git a/libjava/java/lang/VMClassLoader.java b/libjava/java/lang/VMClassLoader.java
index e21bb649542..c0739ba7e7c 100644
--- a/libjava/java/lang/VMClassLoader.java
+++ b/libjava/java/lang/VMClassLoader.java
@@ -304,12 +304,10 @@ final class VMClassLoader
default_sys
= (ClassLoader) c.newInstance(new Object[] { default_sys });
}
- catch (Exception e)
+ catch (Exception ex)
{
- System.err.println("Requested system classloader "
- + loader + " failed, using "
- + "gnu.gcj.runtime.VMClassLoader");
- e.printStackTrace();
+ throw new Error("Failed to load requested system classloader "
+ + loader, ex);
}
}
return default_sys;
diff --git a/libjava/java/lang/VMThrowable.java b/libjava/java/lang/VMThrowable.java
index 102916a5d7c..f3b079a566e 100644
--- a/libjava/java/lang/VMThrowable.java
+++ b/libjava/java/lang/VMThrowable.java
@@ -1,5 +1,5 @@
/* java.lang.VMThrowable -- VM support methods for Throwable.
- Copyright (C) 1998, 1999, 2002, 2004 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2002, 2004, 2005 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -37,8 +37,7 @@ exception statement from your version. */
package java.lang;
-import gnu.gcj.runtime.NameFinder;
-import gnu.gcj.runtime.StackTrace;
+import gnu.gcj.RawDataManaged;
/**
* VM dependent state and support methods Throwable.
@@ -51,10 +50,8 @@ import gnu.gcj.runtime.StackTrace;
*/
final class VMThrowable
{
- private gnu.gcj.runtime.StackTrace trace;
-
/**
- * Private contructor, create VMThrowables with fillInStackTrace();
+ * Private contructor, create VMThrowables with StackTrace();
*/
private VMThrowable() { }
@@ -67,20 +64,7 @@ final class VMThrowable
* @return a new VMThrowable containing the current execution stack trace.
* @see Throwable#fillInStackTrace()
*/
- static VMThrowable fillInStackTrace(Throwable t)
- {
- VMThrowable state = null;
-
- /* FIXME: size of the stack trace is limited to 128 elements.
- It's undoubtedly sensible to limit the stack trace, but 128 is
- rather arbitrary. It may be better to configure this. */
- if (trace_enabled)
- {
- state = new VMThrowable ();
- state.trace = new gnu.gcj.runtime.StackTrace(128);
- }
- return state;
- }
+ static native VMThrowable fillInStackTrace(Throwable t);
/**
* Returns an <code>StackTraceElement</code> array based on the execution
@@ -90,21 +74,11 @@ final class VMThrowable
* @return a non-null but possible zero length array of StackTraceElement.
* @see Throwable#getStackTrace()
*/
- StackTraceElement[] getStackTrace(Throwable t)
- {
- StackTraceElement[] result;
- if (trace != null)
- {
- NameFinder nameFinder = new NameFinder();
- result = nameFinder.lookup(t, trace);
- nameFinder.close();
- }
- else
- result = new StackTraceElement[0];
-
- return result;
- }
-
+ native StackTraceElement[] getStackTrace(Throwable t);
+
// Setting this flag to false prevents fillInStackTrace() from running.
static boolean trace_enabled = true;
+
+ // Native stack data.
+ private RawDataManaged data;
}
diff --git a/libjava/java/lang/natClass.cc b/libjava/java/lang/natClass.cc
index f29f6674764..25343e38b05 100644
--- a/libjava/java/lang/natClass.cc
+++ b/libjava/java/lang/natClass.cc
@@ -53,7 +53,6 @@ details. */
#include <java/lang/SecurityManager.h>
#include <java/lang/StringBuffer.h>
#include <java/lang/VMClassLoader.h>
-#include <gnu/gcj/runtime/StackTrace.h>
#include <gcj/method.h>
#include <gnu/gcj/runtime/MethodRef.h>
#include <gnu/gcj/RawData.h>
@@ -62,6 +61,7 @@ details. */
#include <java-cpool.h>
#include <java-interp.h>
#include <java-assert.h>
+#include <java-stack.h>
#include <execution.h>
@@ -101,20 +101,10 @@ jclass
java::lang::Class::forName (jstring className)
{
java::lang::ClassLoader *loader = NULL;
- gnu::gcj::runtime::StackTrace *t
- = new gnu::gcj::runtime::StackTrace(4);
- java::lang::Class *klass = NULL;
- try
- {
- for (int i = 1; !klass; i++)
- {
- klass = t->classAt (i);
- }
- loader = klass->getClassLoaderInternal();
- }
- catch (::java::lang::ArrayIndexOutOfBoundsException *e)
- {
- }
+
+ jclass caller = _Jv_StackTrace::GetCallingClass (&Class::class$);
+ if (caller)
+ loader = caller->getClassLoaderInternal();
return forName (className, true, loader);
}
@@ -125,21 +115,10 @@ java::lang::Class::getClassLoader (void)
java::lang::SecurityManager *s = java::lang::System::getSecurityManager();
if (s != NULL)
{
- gnu::gcj::runtime::StackTrace *t
- = new gnu::gcj::runtime::StackTrace(4);
- Class *caller = NULL;
+ jclass caller = _Jv_StackTrace::GetCallingClass (&Class::class$);
ClassLoader *caller_loader = NULL;
- try
- {
- for (int i = 1; !caller; i++)
- {
- caller = t->classAt (i);
- }
- caller_loader = caller->getClassLoaderInternal();
- }
- catch (::java::lang::ArrayIndexOutOfBoundsException *e)
- {
- }
+ if (caller)
+ caller_loader = caller->getClassLoaderInternal();
// If the caller has a non-null class loader, and that loader
// is not this class' loader or an ancestor thereof, then do a
diff --git a/libjava/java/lang/natRuntime.cc b/libjava/java/lang/natRuntime.cc
index 97a69b27f28..d013878834d 100644
--- a/libjava/java/lang/natRuntime.cc
+++ b/libjava/java/lang/natRuntime.cc
@@ -16,6 +16,7 @@ details. */
#include <gcj/cni.h>
#include <jvm.h>
#include <java-props.h>
+#include <java-stack.h>
#include <java/lang/Long.h>
#include <java/lang/Runtime.h>
#include <java/lang/UnknownError.h>
@@ -29,8 +30,6 @@ details. */
#include <java/lang/Process.h>
#include <java/lang/ConcreteProcess.h>
#include <java/lang/ClassLoader.h>
-#include <gnu/gcj/runtime/StackTrace.h>
-#include <java/lang/ArrayIndexOutOfBoundsException.h>
#include <jni.h>
@@ -164,27 +163,7 @@ java::lang::Runtime::_load (jstring path, jboolean do_search)
if (do_search)
{
ClassLoader *sys = ClassLoader::systemClassLoader;
- ClassLoader *look = NULL;
- gnu::gcj::runtime::StackTrace *t = new gnu::gcj::runtime::StackTrace(10);
- try
- {
- for (int i = 0; i < 10; ++i)
- {
- jclass klass = t->classAt(i);
- if (klass != NULL)
- {
- ClassLoader *loader = klass->getClassLoaderInternal();
- if (loader != NULL && loader != sys)
- {
- look = loader;
- break;
- }
- }
- }
- }
- catch (::java::lang::ArrayIndexOutOfBoundsException *e)
- {
- }
+ ClassLoader *look = _Jv_StackTrace::GetFirstNonSystemClassLoader ();
if (look != NULL)
{
diff --git a/libjava/java/lang/natVMSecurityManager.cc b/libjava/java/lang/natVMSecurityManager.cc
index 8fd2875aedc..d55b7a54c3a 100644
--- a/libjava/java/lang/natVMSecurityManager.cc
+++ b/libjava/java/lang/natVMSecurityManager.cc
@@ -12,43 +12,18 @@ details. */
#include <gcj/cni.h>
#include <jvm.h>
+#include <java-stack.h>
+
#include <java/lang/VMSecurityManager.h>
#include <java/lang/SecurityManager.h>
#include <java/lang/ClassLoader.h>
#include <java/lang/Class.h>
-#include <gnu/gcj/runtime/StackTrace.h>
JArray<jclass> *
java::lang::VMSecurityManager::getClassContext ()
{
- JArray<jclass> *result = NULL;
- gnu::gcj::runtime::StackTrace *t = new gnu::gcj::runtime::StackTrace();
- if (t)
- {
- int maxlen = t->length();
-
- int len = 0;
- for (int i=0; i<maxlen; i++)
- {
- jclass klass = t->classAt(i);
- if (klass != NULL && klass != &java::lang::VMSecurityManager::class$
- && klass != &java::lang::SecurityManager::class$)
- ++len;
- }
-
- result =
- (JArray<jclass> *) _Jv_NewObjectArray (len, &java::lang::Class::class$,
- NULL);
-
- len = 0;
- for (int i=0; i<maxlen; i++)
- {
- jclass klass = t->classAt(i);
- if (klass != NULL && klass != &java::lang::VMSecurityManager::class$
- && klass != &java::lang::SecurityManager::class$)
- elements(result)[len++] = klass;
- }
- }
+ JArray<jclass> *result =
+ _Jv_StackTrace::GetClassContext (&SecurityManager::class$);
return result;
}
diff --git a/libjava/java/lang/natVMThrowable.cc b/libjava/java/lang/natVMThrowable.cc
new file mode 100644
index 00000000000..6db1a1fd56d
--- /dev/null
+++ b/libjava/java/lang/natVMThrowable.cc
@@ -0,0 +1,45 @@
+// natVMThrowable.cc - Native part of VMThrowable class.
+
+/* Copyright (C) 2003 Free Software Foundation
+
+ This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
+details. */
+
+#include <config.h>
+
+#include <stdlib.h>
+
+#include <gcj/cni.h>
+#include <jvm.h>
+#include <java-stack.h>
+
+#include <java/lang/Throwable.h>
+#include <java/lang/VMThrowable.h>
+
+using namespace gnu::gcj;
+
+java::lang::VMThrowable *
+java::lang::VMThrowable::fillInStackTrace (java::lang::Throwable *)
+{
+ using namespace java::lang;
+
+ // Don't trace stack during initialization of the runtime.
+ if (! trace_enabled)
+ return NULL;
+
+ _Jv_StackTrace *trace = _Jv_StackTrace::GetStackTrace ();
+ VMThrowable *vmthrowable = new VMThrowable ();
+ vmthrowable->data = (RawDataManaged *) trace;
+ return vmthrowable;
+}
+
+
+JArray< ::java::lang::StackTraceElement *> *
+java::lang::VMThrowable::getStackTrace (java::lang::Throwable *throwable)
+{
+ _Jv_StackTrace *trace = reinterpret_cast <_Jv_StackTrace *> (data);
+ return _Jv_StackTrace::GetStackTraceElements (trace, throwable);
+}
diff --git a/libjava/java/lang/reflect/natArray.cc b/libjava/java/lang/reflect/natArray.cc
index ce76b9c92d4..b7bc8beff88 100644
--- a/libjava/java/lang/reflect/natArray.cc
+++ b/libjava/java/lang/reflect/natArray.cc
@@ -14,6 +14,7 @@ details. */
#include <jvm.h>
#include <gcj/cni.h>
+#include <java-stack.h>
#include <java/lang/reflect/Array.h>
#include <java/lang/ArrayIndexOutOfBoundsException.h>
#include <java/lang/IllegalArgumentException.h>
@@ -54,21 +55,10 @@ java::lang::reflect::Array::newInstance (jclass componentType,
if (ndims == 1)
return newInstance (componentType, dims[0]);
- gnu::gcj::runtime::StackTrace *t
- = new gnu::gcj::runtime::StackTrace(4);
- Class *caller = NULL;
+ Class *caller = _Jv_StackTrace::GetCallingClass (&Array::class$);
ClassLoader *caller_loader = NULL;
- try
- {
- for (int i = 1; !caller; i++)
- {
- caller = t->classAt (i);
- }
- caller_loader = caller->getClassLoaderInternal();
- }
- catch (::java::lang::ArrayIndexOutOfBoundsException *e)
- {
- }
+ if (caller)
+ caller_loader = caller->getClassLoaderInternal();
jclass arrayType = componentType;
for (int i = 0; i < ndims; i++)
diff --git a/libjava/java/lang/reflect/natConstructor.cc b/libjava/java/lang/reflect/natConstructor.cc
index 3697332d1ef..f4d95905bfc 100644
--- a/libjava/java/lang/reflect/natConstructor.cc
+++ b/libjava/java/lang/reflect/natConstructor.cc
@@ -12,6 +12,7 @@ details. */
#include <gcj/cni.h>
#include <jvm.h>
+#include <java-stack.h>
#include <java/lang/ArrayIndexOutOfBoundsException.h>
#include <java/lang/IllegalAccessException.h>
@@ -55,20 +56,7 @@ java::lang::reflect::Constructor::newInstance (jobjectArray args)
// Check accessibility, if required.
if (! (Modifier::isPublic (meth->accflags) || this->isAccessible()))
{
- gnu::gcj::runtime::StackTrace *t
- = new gnu::gcj::runtime::StackTrace(4);
- Class *caller = NULL;
- try
- {
- for (int i = 1; !caller; i++)
- {
- caller = t->classAt (i);
- }
- }
- catch (::java::lang::ArrayIndexOutOfBoundsException *e)
- {
- }
-
+ Class *caller = _Jv_StackTrace::GetCallingClass (&Constructor::class$);
if (! _Jv_CheckAccess(caller, declaringClass, meth->accflags))
throw new IllegalAccessException;
}
diff --git a/libjava/java/lang/reflect/natField.cc b/libjava/java/lang/reflect/natField.cc
index 9a8107b795d..33a5717f4b3 100644
--- a/libjava/java/lang/reflect/natField.cc
+++ b/libjava/java/lang/reflect/natField.cc
@@ -13,6 +13,7 @@ details. */
#include <stdlib.h>
#include <jvm.h>
+#include <java-stack.h>
#include <java/lang/reflect/Field.h>
#include <java/lang/reflect/Modifier.h>
#include <java/lang/ArrayIndexOutOfBoundsException.h>
@@ -78,18 +79,7 @@ getAddr (java::lang::reflect::Field* field, jclass caller, jobject obj,
// Check accessibility, if required.
if (! (Modifier::isPublic (flags) || field->isAccessible()))
{
- gnu::gcj::runtime::StackTrace *t
- = new gnu::gcj::runtime::StackTrace(7);
- try
- {
- // We want to skip all the frames on the stack from this class.
- for (int i = 1; !caller || caller == &Field::class$; i++)
- caller = t->classAt (i);
- }
- catch (::java::lang::ArrayIndexOutOfBoundsException *e)
- {
- }
-
+ caller = _Jv_StackTrace::GetCallingClass (&Field::class$);
if (! _Jv_CheckAccess (caller, field->getDeclaringClass(), flags))
throw new java::lang::IllegalAccessException;
}
diff --git a/libjava/java/lang/reflect/natMethod.cc b/libjava/java/lang/reflect/natMethod.cc
index 27c26e19ac7..4329443146c 100644
--- a/libjava/java/lang/reflect/natMethod.cc
+++ b/libjava/java/lang/reflect/natMethod.cc
@@ -13,6 +13,7 @@ details. */
#include <gcj/cni.h>
#include <jvm.h>
#include <jni.h>
+#include <java-stack.h>
#include <java/lang/reflect/Method.h>
#include <java/lang/reflect/Constructor.h>
@@ -168,20 +169,7 @@ java::lang::reflect::Method::invoke (jobject obj, jobjectArray args)
// Check accessibility, if required.
if (! (Modifier::isPublic (meth->accflags) || this->isAccessible()))
{
- gnu::gcj::runtime::StackTrace *t
- = new gnu::gcj::runtime::StackTrace(4);
- Class *caller = NULL;
- try
- {
- for (int i = 1; !caller; i++)
- {
- caller = t->classAt (i);
- }
- }
- catch (::java::lang::ArrayIndexOutOfBoundsException *e)
- {
- }
-
+ Class *caller = _Jv_StackTrace::GetCallingClass (&Method::class$);
if (! _Jv_CheckAccess(caller, declaringClass, meth->accflags))
throw new IllegalAccessException;
}
diff --git a/libjava/java/util/logging/natLogger.cc b/libjava/java/util/logging/natLogger.cc
index 15d1ab70efd..e92c487c66f 100644
--- a/libjava/java/util/logging/natLogger.cc
+++ b/libjava/java/util/logging/natLogger.cc
@@ -17,7 +17,7 @@ details. */
#include <gcj/cni.h>
#include <jvm.h>
-
+#include <java-stack.h>
#include <java/lang/Object.h>
#include <java/lang/Class.h>
@@ -25,31 +25,19 @@ details. */
#include <java/lang/StackTraceElement.h>
#include <java/lang/ArrayIndexOutOfBoundsException.h>
+using namespace java::util::logging;
+
java::lang::StackTraceElement*
java::util::logging::Logger::getCallerStackFrame ()
{
- gnu::gcj::runtime::StackTrace *t
- = new gnu::gcj::runtime::StackTrace(4);
- java::lang::Class *klass = NULL;
- int i = 2;
- try
- {
- // skip until this class
- while ((klass = t->classAt (i)) != getClass())
- i++;
- // skip the stackentries of this class
- while ((klass = t->classAt (i)) == getClass() || klass == NULL)
- i++;
- }
- catch (::java::lang::ArrayIndexOutOfBoundsException *e)
- {
- // FIXME: RuntimeError
- }
+ jclass klass = NULL;
+ _Jv_Method *meth = NULL;
+ _Jv_StackTrace::GetCallerInfo (&Logger::class$, &klass, &meth);
java::lang::StackTraceElement *e
= new java::lang::StackTraceElement
(JvNewStringUTF (""), 0,
- klass->getName(), t->methodAt(i), false);
+ klass->getName(), _Jv_NewStringUtf8Const (meth->name), false);
return e;
}
diff --git a/libjava/java/util/natResourceBundle.cc b/libjava/java/util/natResourceBundle.cc
index 35e90ee23d3..e8d4fb4fd43 100644
--- a/libjava/java/util/natResourceBundle.cc
+++ b/libjava/java/util/natResourceBundle.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2003 Free Software Foundation
+/* Copyright (C) 2002, 2003, 2005 Free Software Foundation
This file is part of libgcj.
@@ -12,31 +12,18 @@ details. */
#include <gcj/cni.h>
#include <jvm.h>
+#include <java-stack.h>
#include <java/util/ResourceBundle.h>
-#include <java/lang/SecurityManager.h>
#include <java/lang/ClassLoader.h>
#include <java/lang/Class.h>
-#include <java/lang/ArrayIndexOutOfBoundsException.h>
-#include <gnu/gcj/runtime/StackTrace.h>
+
+using namespace java::lang;
java::lang::ClassLoader *
java::util::ResourceBundle::getCallingClassLoader ()
{
- gnu::gcj::runtime::StackTrace *t = new gnu::gcj::runtime::StackTrace(6);
- try
- {
- /* Frame 0 is this method, frame 1 is getBundle, so starting at
- frame 2 we might see the user's class. FIXME: should account
- for reflection, JNI, etc, here. */
- for (int i = 2; ; ++i)
- {
- jclass klass = t->classAt(i);
- if (klass != NULL)
- return klass->getClassLoaderInternal();
- }
- }
- catch (::java::lang::ArrayIndexOutOfBoundsException *e)
- {
- }
+ jclass caller = _Jv_StackTrace::GetCallingClass (&ResourceBundle::class$);
+ if (caller)
+ return caller->getClassLoaderInternal();
return NULL;
}
diff --git a/libjava/prims.cc b/libjava/prims.cc
index cf0fed10dd4..9281711ae89 100644
--- a/libjava/prims.cc
+++ b/libjava/prims.cc
@@ -147,10 +147,10 @@ unblock_signal (int signum __attribute__ ((__unused__)))
#ifdef HANDLE_SEGV
SIGNAL_HANDLER (catch_segv)
{
- java::lang::NullPointerException *nullp
- = new java::lang::NullPointerException;
unblock_signal (SIGSEGV);
MAKE_THROW_FRAME (nullp);
+ java::lang::NullPointerException *nullp
+ = new java::lang::NullPointerException;
throw nullp;
}
#endif
@@ -158,14 +158,14 @@ SIGNAL_HANDLER (catch_segv)
#ifdef HANDLE_FPE
SIGNAL_HANDLER (catch_fpe)
{
- java::lang::ArithmeticException *arithexception
- = new java::lang::ArithmeticException (JvNewStringLatin1 ("/ by zero"));
unblock_signal (SIGFPE);
#ifdef HANDLE_DIVIDE_OVERFLOW
HANDLE_DIVIDE_OVERFLOW;
#else
MAKE_THROW_FRAME (arithexception);
#endif
+ java::lang::ArithmeticException *arithexception
+ = new java::lang::ArithmeticException (JvNewStringLatin1 ("/ by zero"));
throw arithexception;
}
#endif
diff --git a/libjava/stacktrace.cc b/libjava/stacktrace.cc
new file mode 100644
index 00000000000..0777d903a21
--- /dev/null
+++ b/libjava/stacktrace.cc
@@ -0,0 +1,527 @@
+// stacktrace.cc - Functions for unwinding & inspecting the call stack.
+
+/* Copyright (C) 2005 Free Software Foundation
+
+ This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
+details. */
+
+#include <config.h>
+
+#include <jvm.h>
+#include <gcj/cni.h>
+#include <java-interp.h>
+#include <java-stack.h>
+
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#include <java/lang/Class.h>
+#include <java/lang/Long.h>
+#include <java/util/ArrayList.h>
+#include <java/util/IdentityHashMap.h>
+#include <gnu/java/lang/MainThread.h>
+#include <gnu/gcj/runtime/NameFinder.h>
+
+#include <sysdep/backtrace.h>
+
+using namespace java::lang;
+using namespace java::lang::reflect;
+using namespace java::util;
+using namespace gnu::gcj::runtime;
+
+struct _Jv_FindCallingClassState: _Jv_UnwindState
+{
+ jclass result;
+};
+
+// Maps ncode values to their containing native class.
+// NOTE: Currently this Map contradicts class GC for native classes. This map
+// (and the "new class stack") will need to use WeakReferences in order to
+// enable native class GC.
+static java::util::IdentityHashMap *ncodeMap;
+
+// Check the "class stack" for any classes initialized since we were last
+// called, and add them to ncodeMap.
+void
+_Jv_StackTrace::UpdateNCodeMap ()
+{
+ // The Map should be large enough so that a typical Java app doesn't cause
+ // it to rehash, without using too much memory. ~5000 entries should be
+ // enough.
+ if (ncodeMap == NULL)
+ ncodeMap = new java::util::IdentityHashMap (5087);
+
+ jclass klass;
+ while ((klass = _Jv_PopClass ()))
+ {
+ //printf ("got %s\n", klass->name->data);
+#ifdef INTERPRETER
+ JvAssert (! _Jv_IsInterpretedClass (klass));
+#endif
+ for (int i=0; i < klass->method_count; i++)
+ {
+ _Jv_Method *method = &klass->methods[i];
+ // Add non-abstract methods to ncodeMap.
+ if (method->ncode)
+ {
+ //printf("map->put 0x%x / %s.%s\n", method->ncode, klass->name->data,
+ // method->name->data);
+ ncodeMap->put ((java::lang::Object *) method->ncode, klass);
+ }
+ }
+ }
+}
+
+// Given a native frame, return the class which this code belongs
+// to. Returns NULL if this IP is not associated with a native Java class.
+// If NCODE is supplied, it will be set with the ip for the entry point of the
+// enclosing method.
+jclass
+_Jv_StackTrace::ClassForFrame (_Jv_StackFrame *frame)
+{
+ JvAssert (frame->type == frame_native);
+ jclass klass = NULL;
+ // use _Unwind_FindEnclosingFunction to find start of method
+ //void *entryPoint = _Unwind_FindEnclosingFunction (ip);
+
+ // look it up in ncodeMap
+ if (frame->start_ip)
+ klass = (jclass) ncodeMap->get ((jobject) frame->start_ip);
+
+ return klass;
+}
+
+_Unwind_Reason_Code
+_Jv_StackTrace::UnwindTraceFn (struct _Unwind_Context *context, void *state_ptr)
+{
+ _Jv_UnwindState *state = (_Jv_UnwindState *) state_ptr;
+ jint pos = state->pos;
+
+ // Check if the trace buffer needs to be extended.
+ if (pos == state->length)
+ {
+ int newLength = state->length *= 2;
+ void *newFrames = _Jv_AllocBytes (newLength * sizeof(_Jv_StackFrame));
+ memcpy (newFrames, state->frames, state->length * sizeof(_Jv_StackFrame));
+ state->frames = (_Jv_StackFrame *) newFrames;
+ state->length = newLength;
+ }
+
+ _Unwind_Ptr func_addr = _Unwind_GetRegionStart (context);
+
+ // If we see the interpreter's main function, "pop" an entry off the
+ // interpreter stack and use that instead, so that the trace goes through
+ // the java code and not the interpreter itself. This assumes a 1:1
+ // correspondance between call frames in the interpreted stack and occurances
+ // of _Jv_InterpMethod::run() on the native stack.
+ if (func_addr == (_Unwind_Ptr) &_Jv_InterpMethod::run)
+ {
+ state->frames[pos].type = frame_interpreter;
+ state->frames[pos].interp.meth = state->interp_frame->self;
+ state->frames[pos].interp.pc = state->interp_frame->pc;
+ state->interp_frame = state->interp_frame->next;
+ }
+ else
+ {
+ state->frames[pos].type = frame_native;
+ state->frames[pos].ip = (void *) _Unwind_GetIP (context);
+ state->frames[pos].start_ip = (void *) func_addr;
+ }
+
+ //printf ("unwind ip: %p\n", _Unwind_GetIP (context));
+
+ _Unwind_Reason_Code result = _URC_NO_REASON;
+ if (state->trace_function != NULL)
+ result = (state->trace_function) (state);
+ state->pos++;
+ return result;
+}
+
+// Return a raw stack trace from the current point of execution. The raw
+// trace will include all functions that have unwind info.
+_Jv_StackTrace *
+_Jv_StackTrace::GetStackTrace(void)
+{
+ int trace_size = 100;
+ _Jv_StackFrame frames[trace_size];
+ _Jv_UnwindState state (trace_size);
+ state.frames = (_Jv_StackFrame *) &frames;
+
+#ifdef SJLJ_EXCEPTIONS
+ // The Unwind interface doesn't work with the SJLJ exception model.
+ // Fall back to a platform-specific unwinder.
+ fallback_backtrace (&state);
+#else /* SJLJ_EXCEPTIONS */
+ _Unwind_Backtrace (UnwindTraceFn, &state);
+#endif /* SJLJ_EXCEPTIONS */
+
+ // Copy the trace and return it.
+ int traceSize = sizeof (_Jv_StackTrace) +
+ (sizeof (_Jv_StackFrame) * state.pos);
+ _Jv_StackTrace *trace = (_Jv_StackTrace *) _Jv_AllocBytes (traceSize);
+ trace->length = state.pos;
+ memcpy (trace->frames, state.frames, sizeof (_Jv_StackFrame) * state.pos);
+ return trace;
+}
+
+void
+_Jv_StackTrace::getLineNumberForFrame(_Jv_StackFrame *frame, NameFinder *finder,
+ jstring *sourceFileName, jint *lineNum)
+{
+ if (frame->type == frame_interpreter)
+ {
+ _Jv_InterpMethod *interp_meth = frame->interp.meth;
+ _Jv_InterpClass *interp_class =
+ (_Jv_InterpClass *) interp_meth->defining_class->aux_info;
+ *sourceFileName = interp_class->source_file_name;
+ *lineNum = interp_meth->get_source_line(frame->interp.pc);
+ return;
+ }
+ // Use dladdr() to determine in which binary the address IP resides.
+#if defined (HAVE_DLFCN_H) && defined (HAVE_DLADDR)
+ extern char **_Jv_argv;
+ Dl_info info;
+ jstring binaryName = NULL;
+
+ void *ip = frame->ip;
+ _Unwind_Ptr offset = 0;
+
+ if (dladdr (ip, &info))
+ {
+ if (info.dli_fname)
+ binaryName = JvNewStringUTF (info.dli_fname);
+ else
+ return;
+
+ // addr2line expects relative addresses for shared libraries.
+ if (strcmp (info.dli_fname, _Jv_argv[0]) == 0)
+ offset = (_Unwind_Ptr) ip;
+ else
+ offset = (_Unwind_Ptr) ip - (_Unwind_Ptr) info.dli_fbase;
+
+ //printf ("linenum ip: %p\n", ip);
+ //printf ("%s: 0x%x\n", info.dli_fname, offset);
+ //offset -= sizeof(void *);
+
+ // The unwinder gives us the return address. In order to get the right
+ // line number for the stack trace, roll it back a little.
+ offset -= 1;
+
+ // printf ("%s: 0x%x\n", info.dli_fname, offset);
+
+ finder->lookup (binaryName, (jlong) offset);
+ *sourceFileName = finder->getSourceFile();
+ *lineNum = finder->getLineNum();
+ }
+#endif
+}
+
+// Look up class and method info for the given stack frame, setting
+// frame->klass and frame->meth if they are known.
+void
+_Jv_StackTrace::FillInFrameInfo (_Jv_StackFrame *frame)
+{
+ jclass klass = NULL;
+ _Jv_Method *meth = NULL;
+
+ if (frame->type == frame_native)
+ {
+ klass = _Jv_StackTrace::ClassForFrame (frame);
+
+ if (klass != NULL)
+ // Find method in class
+ for (int j = 0; j < klass->method_count; j++)
+ {
+ if (klass->methods[j].ncode == frame->start_ip)
+ {
+ meth = &klass->methods[j];
+ break;
+ }
+ }
+ }
+ else if (frame->type == frame_interpreter)
+ {
+ _Jv_InterpMethod *interp_meth = frame->interp.meth;
+ klass = interp_meth->defining_class;
+ meth = interp_meth->self;
+ }
+ else
+ JvFail ("Unknown frame type");
+
+ frame->klass = klass;
+ frame->meth = meth;
+}
+
+// Convert raw stack frames to a Java array of StackTraceElement objects.
+JArray< ::java::lang::StackTraceElement *>*
+_Jv_StackTrace::GetStackTraceElements (_Jv_StackTrace *trace,
+ Throwable *throwable __attribute__((unused)))
+{
+ ArrayList *list = new ArrayList ();
+
+#ifdef SJLJ_EXCEPTIONS
+ // We can't use the nCodeMap without unwinder support. Instead,
+ // fake the method name by giving the IP in hex - better than nothing.
+ jstring hex = JvNewStringUTF ("0x");
+
+ for (int i = 0; i < trace->length; i++)
+ {
+ jstring sourceFileName = NULL;
+ jint lineNum = -1;
+ _Jv_StackFrame *frame = &trace->frames[i];
+
+ jstring className = NULL;
+ jstring methodName = hex->concat (Long::toHexString ((jlong) frame->ip));
+
+ StackTraceElement *element = new StackTraceElement (sourceFileName,
+ lineNum, className, methodName, 0);
+ list->add (element);
+ }
+
+#else /* SJLJ_EXCEPTIONS */
+
+ //JvSynchronized (ncodeMap);
+ UpdateNCodeMap ();
+
+ NameFinder *finder = new NameFinder();
+ int start_idx = 0;
+ int end_idx = trace->length - 1;
+
+ // First pass: strip superfluous frames from beginning and end of the trace.
+ for (int i = 0; i < trace->length; i++)
+ {
+ _Jv_StackFrame *frame = &trace->frames[i];
+ FillInFrameInfo (frame);
+
+ if (!frame->klass || !frame->meth)
+ // Not a Java frame.
+ continue;
+
+ // Throw away the top of the stack till we see:
+ // - the constructor(s) of this Throwable, or
+ // - the Throwable.fillInStackTrace call.
+ if (frame->klass == throwable->getClass()
+ && strcmp (frame->meth->name->chars(), "<init>") == 0)
+ start_idx = i + 1;
+
+ if (frame->klass == &Throwable::class$
+ && strcmp (frame->meth->name->chars(), "fillInStackTrace") == 0)
+ start_idx = i + 1;
+
+ // End the trace at the application's main() method if we see call_main.
+ if (frame->klass == &gnu::java::lang::MainThread::class$
+ && strcmp (frame->meth->name->chars(), "call_main") == 0)
+ end_idx = i - 1;
+ }
+
+ // Second pass: Look up line-number info for remaining frames.
+ for (int i = start_idx; i <= end_idx; i++)
+ {
+ _Jv_StackFrame *frame = &trace->frames[i];
+
+ if (frame->klass == NULL)
+ // Not a Java frame.
+ continue;
+
+ jstring className = frame->klass->getName ();
+ jstring methodName = NULL;
+ if (frame->meth)
+ methodName = JvNewStringUTF (frame->meth->name->chars());
+
+ jstring sourceFileName = NULL;
+ jint lineNum = -1;
+
+ getLineNumberForFrame(frame, finder, &sourceFileName, &lineNum);
+
+ StackTraceElement *element = new StackTraceElement (sourceFileName, lineNum,
+ className, methodName, 0);
+ list->add (element);
+ }
+
+ finder->close();
+#endif /* SJLJ_EXCEPTIONS */
+
+ JArray<Object *> *array = JvNewObjectArray (list->size (),
+ &StackTraceElement::class$, NULL);
+
+ return (JArray<StackTraceElement *>*) list->toArray (array);
+}
+
+struct CallingClassTraceData
+{
+ jclass checkClass;
+ jclass foundClass;
+ _Jv_Method *foundMeth;
+ bool seen_checkClass;
+};
+
+_Unwind_Reason_Code
+_Jv_StackTrace::calling_class_trace_fn (_Jv_UnwindState *state)
+{
+ CallingClassTraceData *trace_data = (CallingClassTraceData *)
+ state->trace_data;
+ _Jv_StackFrame *frame = &state->frames[state->pos];
+ FillInFrameInfo (frame);
+
+ if (trace_data->seen_checkClass
+ && frame->klass
+ && frame->klass != trace_data->checkClass)
+ {
+ trace_data->foundClass = frame->klass;
+ trace_data->foundMeth = frame->meth;
+ return _URC_NORMAL_STOP;
+ }
+
+ if (frame->klass == trace_data->checkClass)
+ trace_data->seen_checkClass = true;
+
+ return _URC_NO_REASON;
+}
+
+// Find the class immediately above the given class on the call stack. Any
+// intermediate non-Java
+// frames are ignored. If the calling class could not be determined (eg because
+// the unwinder is not supported on this platform), NULL is returned.
+// This function is used to implement calling-classloader checks and reflection
+// accessibility checks.
+// CHECKCLASS is typically the class calling GetCallingClass. The first class
+// above CHECKCLASS on the call stack will be returned.
+jclass
+_Jv_StackTrace::GetCallingClass (jclass checkClass)
+{
+ jclass result = NULL;
+ GetCallerInfo (checkClass, &result, NULL);
+ return result;
+}
+
+void
+_Jv_StackTrace::GetCallerInfo (jclass checkClass, jclass *caller_class,
+ _Jv_Method **caller_meth)
+{
+#ifndef SJLJ_EXCEPTIONS
+ int trace_size = 20;
+ _Jv_StackFrame frames[trace_size];
+ _Jv_UnwindState state (trace_size);
+ state.frames = (_Jv_StackFrame *) &frames;
+
+ CallingClassTraceData trace_data;
+ trace_data.checkClass = checkClass;
+ trace_data.seen_checkClass = false;
+ trace_data.foundClass = NULL;
+ trace_data.foundMeth = NULL;
+
+ state.trace_function = calling_class_trace_fn;
+ state.trace_data = (void *) &trace_data;
+
+ //JvSynchronized (ncodeMap);
+ UpdateNCodeMap ();
+
+ _Unwind_Backtrace (UnwindTraceFn, &state);
+
+ if (caller_class)
+ *caller_class = trace_data.foundClass;
+ if (caller_meth)
+ *caller_meth = trace_data.foundMeth;
+#else
+ return NULL;
+#endif
+}
+
+// Return a java array containing the Java classes on the stack above CHECKCLASS.
+JArray<jclass> *
+_Jv_StackTrace::GetClassContext (jclass checkClass)
+{
+ JArray<jclass> *result = NULL;
+
+ int trace_size = 100;
+ _Jv_StackFrame frames[trace_size];
+ _Jv_UnwindState state (trace_size);
+ state.frames = (_Jv_StackFrame *) &frames;
+
+ //JvSynchronized (ncodeMap);
+ UpdateNCodeMap ();
+
+ _Unwind_Backtrace (UnwindTraceFn, &state);
+
+ // Count the number of Java frames on the stack.
+ int jframe_count = 0;
+ bool seen_checkClass = false;
+ int start_pos = -1;
+ for (int i = 0; i < state.pos; i++)
+ {
+ _Jv_StackFrame *frame = &state.frames[i];
+ FillInFrameInfo (frame);
+
+ if (seen_checkClass
+ && frame->klass
+ && frame->klass != checkClass)
+ {
+ jframe_count++;
+ if (start_pos == -1)
+ start_pos = i;
+ }
+
+ if (!seen_checkClass
+ && frame->klass
+ && frame->klass == checkClass)
+ seen_checkClass = true;
+ }
+ result = (JArray<jclass> *) _Jv_NewObjectArray (jframe_count, &Class::class$, NULL);
+ int pos = 0;
+
+ for (int i = start_pos; i < state.pos; i++)
+ {
+ _Jv_StackFrame *frame = &state.frames[i];
+ if (frame->klass)
+ elements(result)[pos++] = frame->klass;
+ }
+ return result;
+}
+
+_Unwind_Reason_Code
+_Jv_StackTrace::non_system_trace_fn (_Jv_UnwindState *state)
+{
+ _Jv_StackFrame *frame = &state->frames[state->pos];
+ FillInFrameInfo (frame);
+
+ ClassLoader *classLoader = NULL;
+
+ if (frame->klass)
+ {
+ classLoader = frame->klass->getClassLoaderInternal();
+ if (classLoader != NULL && classLoader != ClassLoader::systemClassLoader)
+ {
+ state->trace_data = (void *) classLoader;
+ return _URC_NORMAL_STOP;
+ }
+ }
+
+ return _URC_NO_REASON;
+}
+
+ClassLoader *
+_Jv_StackTrace::GetFirstNonSystemClassLoader ()
+{
+ int trace_size = 32;
+ _Jv_StackFrame frames[trace_size];
+ _Jv_UnwindState state (trace_size);
+ state.frames = (_Jv_StackFrame *) &frames;
+ state.trace_function = non_system_trace_fn;
+ state.trace_data = NULL;
+
+ //JvSynchronized (ncodeMap);
+ UpdateNCodeMap ();
+
+ _Unwind_Backtrace (UnwindTraceFn, &state);
+
+ if (state.trace_data)
+ return (ClassLoader *) state.trace_data;
+
+ return NULL;
+}
diff --git a/libjava/sysdep/generic/backtrace.h b/libjava/sysdep/generic/backtrace.h
new file mode 100644
index 00000000000..fe9d68f1b70
--- /dev/null
+++ b/libjava/sysdep/generic/backtrace.h
@@ -0,0 +1,22 @@
+// backtrace.h - Fallback backtrace implementation. default implementation.
+
+/* Copyright (C) 2005 Free Software Foundation
+
+ This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
+details. */
+
+#ifndef __SYSDEP_BACKTRACE_H__
+#define __SYSDEP_BACKTRACE_H__
+
+#include <java-stack.h>
+
+/* Store return addresses of the current program stack in
+ STATE and return the exact number of values stored. */
+void
+fallback_backtrace (_Jv_UnwindState *)
+{
+}
+#endif
diff --git a/libjava/sysdep/i386/backtrace.h b/libjava/sysdep/i386/backtrace.h
new file mode 100644
index 00000000000..b10840213a4
--- /dev/null
+++ b/libjava/sysdep/i386/backtrace.h
@@ -0,0 +1,42 @@
+// backtrace.h - Fallback backtrace implementation. i386 implementation.
+
+/* Copyright (C) 2005 Free Software Foundation
+
+ This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
+details. */
+
+#ifndef __SYSDEP_BACKTRACE_H__
+#define __SYSDEP_BACKTRACE_H__
+
+#include <java-stack.h>
+
+#define HAVE_FALLBACK_BACKTRACE
+
+/* Store return addresses of the current program stack in
+ STATE and return the exact number of values stored. */
+void
+fallback_backtrace (_Jv_UnwindState *state)
+{
+ register void *_ebp __asm__ ("ebp");
+ register void *_esp __asm__ ("esp");
+ unsigned int *rfp;
+
+ int i = state->pos;
+ for (rfp = *(unsigned int**)_ebp;
+ rfp && i < state->length;
+ rfp = *(unsigned int **)rfp)
+ {
+ int diff = *rfp - (unsigned int)rfp;
+ if ((void*)rfp < _esp || diff > 4 * 1024 || diff < 0)
+ break;
+
+ state->frames[i].type = frame_native;
+ state->frames[i].ip = (void*)(rfp[1]-4);
+ i++;
+ }
+ state->pos = i;
+}
+#endif