diff options
author | bryce <bryce@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-03-10 19:02:21 +0000 |
---|---|---|
committer | bryce <bryce@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-03-10 19:02:21 +0000 |
commit | 04c95bc933562928623c859240c17a70f2a1311c (patch) | |
tree | 7b6e8c5a43f4dcb0d8d4ac926f4562a978e11786 /libjava | |
parent | 5bd3d8171f767d4995706ea87092c5dc688fff21 (diff) | |
download | gcc-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')
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 |