This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

New stack trace code


This patch contains a better, cleaner, and somewhat faster stack trace mechanism for libgcj. Its based entirely around GCC's Unwind machinery, with a (very limited) fallback mechanism available to get basic stack traces on targets that don't currently support the Unwinder (mingw is the big one).

Some advantages include:

- Source code info for interpreted frames is provided
- Source code info for native frames in shared libraries is provided
- Common infrastructure is used for both printStackTrace() output and security checks/stack enumeration.
- Security checks (calling classloader, reflection accessibility, etc) are very efficient - no heap allocation required and always enumerates the minimum number of frames necessary to complete the check. The underlying Unwinder is the bottleneck now.
- Hopefully more secure as stack walking functionality is only exposed to native code


Caveats:

- As with any extensive patch, bugs have undoubtably slipped through - please test!
- Because we use addr2line more extensively than previously, Throwable.printStackTrace() can be noticeably slow when the stack trace goes through large shared libraries (like libgcj). If your application calls printStackTrace() this may cause a performance problem - you can disable addr2line with:


-Dgnu.gcj.runtime.NameFinder.use_addr2line=false

We should be able to improve this by dropping addr2line and instead reading DWARF debug_line info directly - Casey Marshall has a patch pending for this but it needs to be updated.

I am hoping to get this into the 4.0 branch, as the user-visible improvements are quite substantial. However since its such a big patch I am only committing to mainline at the moment - this should give it a chance for any serious bugs to be identified. I'm confident that it is working well on various linux targets (tested against Eclipse and mauve), however there may be corner bugs and problems on other platforms. I'll give it a few days to see what happens on mainline before making a decision on putting it into 4.0.

Bryce


2005-03-10  Bryce McKinlay  <mckinlay@redhat.com>

	New Stack Trace code.
	* 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.

Index: Makefile.am
===================================================================
RCS file: /cvs/gcc/gcc/libjava/Makefile.am,v
retrieving revision 1.455.2.2
diff -u -r1.455.2.2 Makefile.am
--- Makefile.am	6 Mar 2005 20:15:21 -0000	1.455.2.2
+++ Makefile.am	10 Mar 2005 15:36:50 -0000
@@ -217,7 +217,7 @@
 # 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 @@
 
 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/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/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/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 \
Index: configure.ac
===================================================================
RCS file: /cvs/gcc/gcc/libjava/configure.ac,v
retrieving revision 1.19
diff -u -r1.19 configure.ac
--- configure.ac	23 Feb 2005 01:05:45 -0000	1.19
+++ configure.ac	10 Mar 2005 15:36:51 -0000
@@ -715,6 +715,7 @@
 
 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.
Index: configure.host
===================================================================
RCS file: /cvs/gcc/gcc/libjava/configure.host,v
retrieving revision 1.64
diff -u -r1.64 configure.host
--- configure.host	25 Nov 2004 03:46:56 -0000	1.64
+++ configure.host	10 Mar 2005 15:36:51 -0000
@@ -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 @@
 slow_pthread_self=
 can_unwind_signal=no
 disable_dladdr=
+fallback_backtrace_h=sysdep/generic/backtrace.h
 
 case "${target_optspace}:${host}" in
   yes:*)
@@ -259,6 +262,13 @@
 	;;
 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}"
Index: defineclass.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/defineclass.cc,v
retrieving revision 1.44
diff -u -r1.44 defineclass.cc
--- defineclass.cc	7 Feb 2005 21:29:03 -0000	1.44
+++ defineclass.cc	10 Mar 2005 15:36:51 -0000
@@ -229,6 +229,7 @@
     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_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 @@
   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 (),
Index: exception.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/exception.cc,v
retrieving revision 1.24
diff -u -r1.24 exception.cc
--- exception.cc	24 Oct 2003 09:29:41 -0000	1.24
+++ exception.cc	10 Mar 2005 15:36:51 -0000
@@ -15,7 +15,6 @@
 
 #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>
Index: interpret.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/interpret.cc,v
retrieving revision 1.48
diff -u -r1.48 interpret.cc
--- interpret.cc	5 Jan 2005 19:03:10 -0000	1.48
+++ interpret.cc	10 Mar 2005 15:36:52 -0000
@@ -13,11 +13,6 @@
 #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 @@
 
 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 @@
     {
       sp[top-(n+x)-i] = sp[top-i];
     }
-  
 }
 
 // Used to convert from floating types to integral types.
@@ -248,15 +222,16 @@
        | (((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 @@
 			      void* __this)
 {
   _Jv_InterpMethod *_this = (_Jv_InterpMethod *) __this;
-  _this->run (ret, args);
+  run (ret, args, _this);
 }
 
 void
@@ -288,7 +263,7 @@
   jobject rcv = (jobject) args[0].ptr;
   JvSynchronize mutex (rcv);
 
-  _this->run (ret, args);
+  run (ret, args, _this);
 }
 
 void
@@ -299,7 +274,7 @@
 {
   _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_InitClass (sync);
   JvSynchronize mutex (sync);
 
-  _this->run (ret, args);
+  run (ret, args, _this);
 }
 
 #ifdef DIRECT_THREADED
@@ -783,29 +758,23 @@
       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 @@
   // 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 @@
 #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 @@
 	 * 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 @@
 	// 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 @@
 	// 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 @@
 
     perform_invoke:
       {
+        SAVE_PC();
+	
 	/* here goes the magic again... */
 	ffi_cif *cif = &rmeth->cif;
 	ffi_raw *raw = (ffi_raw*) sp;
@@ -2423,7 +2401,8 @@
     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 @@
     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 @@
     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 @@
     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 @@
       {
 	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 @@
 	// 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 @@
 	// 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 @@
       {
 	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 @@
       {
 	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 @@
     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 @@
     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 @@
 
     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 @@
 #ifdef DIRECT_THREADED
     checkcast_resolved:
       {
+        SAVE_PC();
 	jobject value = POPA ();
 	jclass to = (jclass) AVAL ();
 	if (value != NULL && ! to->isInstance (value))
@@ -3058,9 +3045,10 @@
 
     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 @@
 	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 @@
 #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 @@
 }
 #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)
Index: prims.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/prims.cc,v
retrieving revision 1.104
diff -u -r1.104 prims.cc
--- prims.cc	23 Feb 2005 17:36:24 -0000	1.104
+++ prims.cc	10 Mar 2005 15:36:52 -0000
@@ -147,10 +147,10 @@
 #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 @@
 #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
Index: stacktrace.cc
===================================================================
RCS file: stacktrace.cc
diff -N stacktrace.cc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ stacktrace.cc	10 Mar 2005 15:36:52 -0000
@@ -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;
+}
Index: gnu/classpath/Configuration.java.in
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gnu/classpath/Configuration.java.in,v
retrieving revision 1.5
diff -u -r1.5 Configuration.java.in
--- gnu/classpath/Configuration.java.in	31 Jan 2003 17:54:12 -0000	1.5
+++ gnu/classpath/Configuration.java.in	10 Mar 2005 15:36:52 -0000
@@ -52,7 +52,7 @@
   // 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;
Index: gnu/gcj/runtime/MethodRef.java
===================================================================
RCS file: gnu/gcj/runtime/MethodRef.java
diff -N gnu/gcj/runtime/MethodRef.java
--- gnu/gcj/runtime/MethodRef.java	3 Dec 2002 13:53:27 -0000	1.1
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,25 +0,0 @@
-// gnu.gcj.runtime.MethodRef -- used by StackTrace.
-
-/* Copyright (C) 2002  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.  */
-
-package gnu.gcj.runtime;
-
-import gnu.gcj.RawData;
-
-class MethodRef
-{
-  MethodRef(RawData /* Actually _Jv_Method */ m, Class k)
-  {
-    klass = k;
-    method = m;
-  }
-
-  public RawData method; // Actually a raw pointer to _Jv_Method
-  public Class klass;
-}
Index: gnu/gcj/runtime/NameFinder.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gnu/gcj/runtime/NameFinder.java,v
retrieving revision 1.8
diff -u -r1.8 NameFinder.java
--- gnu/gcj/runtime/NameFinder.java	12 Feb 2005 13:51:10 -0000	1.8
+++ gnu/gcj/runtime/NameFinder.java	10 Mar 2005 15:36:52 -0000
@@ -9,6 +9,7 @@
 
 package gnu.gcj.runtime;
 
+import gnu.classpath.Configuration;
 import gnu.gcj.RawData;
 
 import java.lang.StringBuffer;
@@ -19,456 +20,156 @@
 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.
+   * The name of the binary to look up.
    */
-  private final String executable;
+  private String binaryFile;
+  private String sourceFile;
+  private int lineNum;
+  private HashMap procs = new HashMap();
 
-  /**
-   * Process used for demangling names.
-   */
-  private Process cppfilt;
-
-  private BufferedWriter cppfiltOut;
-  private BufferedReader cppfiltIn;
-
-  /**
-   * Process used for translating addresses to function/file names.
-   */
-  private Process addr2line;
-
-  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)
-      {
-	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);
+      if (proc != null)
+      {
+	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);
       }
+    
+    if (addr2line.proc == null)      
+      return;
+    
+    String hexAddr = "0x" + Long.toHexString(addr);
+    String name;
 
-    String fileName = file;
-    int line = -1;
-    if (fileName != null)
+    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 */ }
-	  }
-
-	if (line == 0)
-	  line =-1;
+      addr2line.out.write(hexAddr);
+      addr2line.out.newLine();
+      addr2line.out.flush();
+      String result = addr2line.in.readLine();
 
-	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 @@
     // 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 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();
+      }
   }
 }
Index: gnu/gcj/runtime/StackTrace.java
===================================================================
RCS file: gnu/gcj/runtime/StackTrace.java
diff -N gnu/gcj/runtime/StackTrace.java
--- gnu/gcj/runtime/StackTrace.java	2 Oct 2003 07:10:34 -0000	1.3
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,167 +0,0 @@
-/* gnu.gcj.runtime.StackTrace -- VM support methods for walking the
-   stack.
-   Copyright (C) 1998, 1999, 2002 Free Software Foundation, Inc.
-
-This file is part of GNU Classpath.
-
-GNU Classpath is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-GNU Classpath is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Classpath; see the file COPYING.  If not, write to the
-Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-02111-1307 USA.
-
-Linking this library statically or dynamically with other modules is
-making a combined work based on this library.  Thus, the terms and
-conditions of the GNU General Public License cover the whole
-combination.
-
-As a special exception, the copyright holders of this library give you
-permission to link this library with independent modules to produce an
-executable, regardless of the license terms of these independent
-modules, and to copy and distribute the resulting executable under
-terms of your choice, provided that you also meet, for each linked
-independent module, the terms and conditions of the license of that
-module.  An independent module is a module which is not derived from
-or based on this library.  If you modify this library, you may extend
-this exception to your version of the library, but you are not
-obligated to do so.  If you do not wish to do so, delete this
-exception statement from your version. */
-
-package gnu.gcj.runtime;
-
-import gnu.gcj.RawData;
-import java.util.TreeMap;
-import java.util.IdentityHashMap;
-import java.util.SortedMap;
-import gnu.gcj.runtime.NameFinder;
-import java.util.NoSuchElementException;
-
-/**
- * VM dependent state and support methods for walking the stack.
- * <p>
- * This is the version used by libgcj (http://gcc.gnu.org/java/).
- *
- * @author Mark Wielaard (mark@klomp.org)
- * @author Andrew Haley (aph@redhat.com)
- */
-public final class StackTrace
-{
-  /**
-   * Fill in the stack trace with the top n frames on current
-   * execution stack.  Can return null if the VM does not support
-   * capturing the VM execution state.
-   *
-   * @see Throwable#fillInStackTrace()
-   */
-  public StackTrace(int n)
-  {
-    fillInStackTrace(n, 1);
-  }
-
-  /**
-   * Fill in the stack trace with state of the entire execution stack,
-   * starting from frame <code>offset</code>.  Can return null if the
-   * VM does not support capturing the VM execution state.
-   *
-   * This can be very expensive.  If you only want part of the stack,
-   * see <code>Throwable.fillInStackTrace(int)</code>
-   *
-   * @see Throwable#fillInStackTrace()
-   */
-  public StackTrace()
-  {
-    int n = 64;
-    
-    do
-      {
-	n *= 4;
-	fillInStackTrace(n, 1);
-      }
-    while (len >= n);
-  }
-
-  /**
-   * Return the class containing the execution point represented by
-   * the Nth frame down the stack.  The zeroth frame represents the
-   * top of the stack, which is the method that called classAt().
-   *
-   * If the Nth frame down the stack was not create by a method
-   * invocation, return null.
-   *
-   * It is not necessary to call <code>fillInStackTrace()</code> with
-   * a size greater than N before calling this method; if the current
-   * stack trace is insufficiently large, it will be expanded as
-   * required.  This requires some caution if
-   * <code>fillInStackTrace()</code> is called from a different
-   * invocation to the one that calls <code>classAt()</code>.
-   * classAt() will not call <code>fillInStackTrace()</code> unless N
-   * is greater than the current length.
-   *
-   */
-  public native Class classAt(int n);
-
-  /**
-   * Return the name of the method containing the execution point
-   * represented by the Nth frame down the stack.  The zeroth frame
-   * represents the top of the stack, which is the method that called
-   * classAt().
-   *
-   * If the Nth frame down the stack was not create by a method
-   * invocation, return null.
-   *
-   * It is not necessary to call <code>fillInStackTrace()</code> with
-   * a size greater than N before calling this method; if the current
-   * stack trace is insufficiently large, it will be expanded as
-   * required.  This requires some caution if
-   * <code>fillInStackTrace()</code> is called from a different
-   * invocation to the one that calls <code>classAt()</code>.
-   * classAt() will not call <code>fillInStackTrace()</code> unless N
-   * is greater than the current length.
-   *
-   */
-  public native String methodAt(int n);
-
-  /**
-   * Return the length of this stack trace.
-   *
-   */
-  public int length ()
-  {
-    return len;
-  }
-
-  public static native Class getClass(RawData ip);
-
-  private static native void update();
-  private static MethodRef methodAtAddress(RawData addr)
-  {
-    update();
-    synchronized (map)
-      {
-	return (MethodRef) map.get (addr);
-      }
-  }
-
-  gnu.gcj.RawData stackTraceAddrs()
-  {
-    return addrs;
-  }
-  
-  private native void fillInStackTrace(int n, int offset);
-  protected native void finalize();
-
-  private static native MethodRef getCompiledMethodRef(RawData addr);
-  private static IdentityHashMap map = new IdentityHashMap();
-
-  private gnu.gcj.RawData addrs;
-  private int len;
-}
Index: gnu/gcj/runtime/natNameFinder.cc
===================================================================
RCS file: gnu/gcj/runtime/natNameFinder.cc
diff -N gnu/gcj/runtime/natNameFinder.cc
--- gnu/gcj/runtime/natNameFinder.cc	9 Apr 2004 04:39:24 -0000	1.6
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,157 +0,0 @@
-// natNameFinder.cc - native helper methods for NameFinder.java
-
-/* Copyright (C) 2002, 2003, 2004  Free Software Foundation, Inc
-
-   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.  */
-
-/**
- * @author Mark Wielaard (mark@klomp.org)
- * Based on the old name-finder.cc by Andrew Haley <aph@cygnus.com>.
- */
-
-#include <config.h>
-
-#include <string.h>
-
-#include <gcj/cni.h>
-#include <jvm.h>
-#include <java/lang/String.h>
-#include <java/lang/StackTraceElement.h>
-#include <java/lang/StringBuffer.h>
-#include <java-interp.h>
-
-#include <gnu/gcj/runtime/NameFinder.h>
-
-#ifdef HAVE_DLFCN_H
-#include <dlfcn.h>
-#endif
-
-// On some systems, a prefix is attached to a method name before
-// it is exported as a label. The GCC preprocessor predefines 
-// this prefix as the macro __USER_LABEL_PREFIX__ which expands to
-// a string (not string constant) representing the prefix, if any.
-#undef LABEL_PREFIX
-#ifdef __USER_LABEL_PREFIX__
-
-#define USER_LABEL_PREFIX_STRING_0(s) #s
-#define USER_LABEL_PREFIX_STRING(s) USER_LABEL_PREFIX_STRING_0(s)
-
-#define LABEL_PREFIX USER_LABEL_PREFIX_STRING(__USER_LABEL_PREFIX__)
-
-#else /* __USER_LABEL_PREFIX__ */
-
-#define LABEL_PREFIX ""
-
-#endif /* ! __USER_LABEL_PREFIX__ */
-
-java::lang::StackTraceElement*
-gnu::gcj::runtime::NameFinder::newElement (java::lang::String* fileName,
-                                           jint lineNumber,
-                                           java::lang::String* className,
-                                           java::lang::String* methName,
-                                           jboolean isNative)
-{
-  return new java::lang::StackTraceElement( fileName, lineNumber,
-                                            className, methName, isNative);
-}
-                                          
-java::lang::String*
-gnu::gcj::runtime::NameFinder::getExternalLabel (java::lang::String* name)
-{
-  jsize nameLen = JvGetStringUTFLength (name);
-  jsize pfxLen = strlen (LABEL_PREFIX);
-  char *newName = (char *) JvMalloc (pfxLen + nameLen + 1);
-  *(newName + 0) = '\0';
-  strcpy (newName, LABEL_PREFIX);
-  JvGetStringUTFRegion (name, 0, name->length(), newName + pfxLen);
-  *(newName + pfxLen + nameLen) = '\0';
-  return JvNewStringLatin1 (newName);
-}
-
-java::lang::String*
-gnu::gcj::runtime::NameFinder::getExecutable (void)
-{
-  return JvNewStringLatin1 (_Jv_ThisExecutable ());
-}
-
-java::lang::String*
-gnu::gcj::runtime::NameFinder::getAddrAsString(RawData* addrs, jint n)
-{
-  _Jv_frame_info *p = (_Jv_frame_info *) addrs;
-  typedef unsigned word_t __attribute ((mode (word)));
-  word_t w = (word_t) p[n].addr;
-  int digits = sizeof (void *) * 2;
-  char hex[digits+5];
-
-  strcpy (hex, "0x");
-  for (int i = digits - 1; i >= 0; i--)
-    {
-      int digit = w % 16;
-
-      w /= 16;
-      hex[i+2] = digit > 9 ? 'a' + digit - 10 : '0' + digit;
-    }
-  hex [digits+2] = 0;
-
-  return JvNewStringLatin1(hex);
-}
-
-java::lang::StackTraceElement*
-gnu::gcj::runtime::NameFinder::dladdrLookup(RawData* addrs, jint n)
-{
-#if defined (HAVE_DLFCN_H) && defined (HAVE_DLADDR)
-  extern char **_Jv_argv;
-  char name[1024];
-  char file_name[1024];
-  _Jv_frame_info *stack = (_Jv_frame_info *) addrs;
-  void* p = stack[n].addr;
-  Dl_info dl_info;
-   
-  if (dladdr (p, &dl_info))
-    {
-      if (dl_info.dli_fname)
-        strncpy (file_name, dl_info.dli_fname, sizeof file_name);
-      if (dl_info.dli_sname)
-        strncpy (name, dl_info.dli_sname, sizeof name);
-     
-     /* Don't trust dladdr() if the address is from the main program. */
-     if (dl_info.dli_fname != NULL
-         && dl_info.dli_sname != NULL
-         && (_Jv_argv == NULL || strcmp (file_name, _Jv_argv[0]) != 0))
-       return createStackTraceElement (JvNewStringLatin1 (name),
-				       JvNewStringLatin1 (file_name));
-    }
-#endif
-  return NULL;
-}
-
-java::lang::StackTraceElement *
-gnu::gcj::runtime::NameFinder::lookupInterp(RawData* addrs, jint n)
-{
-#ifdef INTERPRETER
-  _Jv_frame_info *stack = (_Jv_frame_info *) addrs;
-  if (stack[n].interp == NULL)
-    return NULL;
-
-  _Jv_InterpMethod *meth
-    = reinterpret_cast<_Jv_InterpMethod *> (stack[n].interp);
-  java::lang::StringBuffer *sb = new java::lang::StringBuffer();
-  sb->append(_Jv_NewStringUtf8Const(meth->self->name));
-  sb->append(_Jv_NewStringUtf8Const(meth->self->signature));
-  // FIXME: source file name and line number can be found from
-  // bytecode debug information.  But currently we don't keep that
-  // around.
-  // FIXME: is using the defining class correct here?
-  java::lang::String *className = meth->defining_class->getName();
-  java::lang::String *methodName
-	  = demangleInterpreterMethod(sb->toString(), className);
-  return new java::lang::StackTraceElement(NULL, -1,
-					   className, methodName, false);
-#else // INTERPRETER
-  return NULL;
-#endif // INTERPRETER
-}
Index: gnu/gcj/runtime/natStackTrace.cc
===================================================================
RCS file: gnu/gcj/runtime/natStackTrace.cc
diff -N gnu/gcj/runtime/natStackTrace.cc
--- gnu/gcj/runtime/natStackTrace.cc	18 Oct 2004 14:07:42 -0000	1.8
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,241 +0,0 @@
-// natStackTrace.cc - native helper methods for Throwable
-
-/* Copyright (C) 2000, 2002, 2003  Free Software Foundation, Inc
-
-   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.  */
-
-/**
- * @author Andrew Haley <aph@cygnus.com>
- * @author Mark Wielaard <mark@klomp.org>
- *
- * Native helper methods for VM specific Throwable support.
- */
-
-#include <config.h>
-#include <platform.h>
-
-#include <string.h>
-
-#include <jvm.h>
-#include <gcj/cni.h>
-#include <gnu/gcj/RawData.h>
-#include <java/lang/Object.h>
-#include <java-threads.h>
-#include <gnu/gcj/runtime/MethodRef.h>
-#include <gnu/gcj/runtime/StackTrace.h>
-#include <java/lang/Thread.h>
-#include <java-interp.h>
-#include <java/util/IdentityHashMap.h>
-#include <java/lang/ArrayIndexOutOfBoundsException.h>
-
-#include <sys/types.h>
-
-#include <stdlib.h>
-
-#include <unistd.h>
-
-#ifdef HAVE_EXECINFO_H
-#include <execinfo.h>
-#endif
-
-#include <unwind.h>
-
-
-#ifdef INTERPRETER
-extern "C" void *_Unwind_FindEnclosingFunction (void *pc)
-  __attribute__((pure));
-#endif // INTERPRETER
-
-// Fill in this stack trace with MAXLEN elements starting at offset.
-void
-gnu::gcj::runtime::StackTrace::fillInStackTrace (jint maxlen, jint offset)
-{
-#ifdef HAVE_BACKTRACE
-  offset += 1;
-  void *_p[maxlen + offset];
-  len = backtrace (_p, maxlen + offset) - offset;
-  void **p = _p + offset;
-  _Jv_frame_info *frame;
-  if (len > 0)
-    {
-#ifdef INTERPRETER
-      extern void *const _Jv_StartOfInterpreter;
-      extern void * _Jv_EndOfInterpreter;
-
-      java::lang::Thread *thread = java::lang::Thread::currentThread();
-      _Jv_MethodChain *interp_frame
-	= (thread ? reinterpret_cast<_Jv_MethodChain *> (thread->interp_frame)
-	   : NULL);
-#endif // INTERPRETER
-
-      frame = (_Jv_frame_info *) _Jv_Malloc (len * sizeof (_Jv_frame_info));
-      for (int n = 0; n < len; n++)
-	{
-	  void *pc = p[n];
-	  frame[n].addr = pc;
-
-#ifdef INTERPRETER
-	  frame[n].interp = 0;
-
-	  // If _Jv_StartOfInterpreter is NULL either we've never
-	  // entered the intepreter or _Unwind_FindEnclosingFunction
-	  // is broken.
-	  if (__builtin_expect (_Jv_StartOfInterpreter != NULL, false))
-	    {
-	      // _Jv_StartOfInterpreter marks the very first
-	      // instruction in the interpreter, but
-	      // _Jv_EndOfInterpreter is an upper bound.  If PC is
-	      // less than _Jv_EndOfInterpreter it might be in the
-	      // interpreter: we call _Unwind_FindEnclosingFunction to
-	      // find out.
-	      if (pc >= _Jv_StartOfInterpreter
-		  && (pc < _Jv_EndOfInterpreter
-		      || _Jv_EndOfInterpreter == NULL))
-		{
-		  if (_Unwind_FindEnclosingFunction (pc) 
-		      == _Jv_StartOfInterpreter)
-		    {
-		      frame[n].interp = (void *) interp_frame->self;
-		      interp_frame = interp_frame->next;
-		    }
-		  else
-		    {
-		      // We've found an address that we know is not within
-		      // the interpreter.  We use that to refine our upper
-		      // bound on where the interpreter ends.
-		      _Jv_EndOfInterpreter = pc;
-		    }
-		}
-	    }
-#endif // INTERPRETER
-
-	}
-    }
-  else
-    frame = NULL;
-
-  addrs = reinterpret_cast<gnu::gcj::RawData *> (frame);
-#else // HAVE_BACKTRACE
-  (void)maxlen;
-  (void)offset;
-#endif // HAVE_BACKTRACE
-}
-
-/* Obtain the next power-of-2 of some integer.  */
-static inline jint
-nextpowerof2 (jint n)
-{
-  n |= (n >> 1);
-  n |= (n >> 2);
-  n |= (n >> 4);
-  n |= (n >> 8);
-  n |= (n >> 16);
-  return n+1;
-}
-
-#define GET_FRAME(N)						\
-({								\
-  if ((N) >= len)						\
-    fillInStackTrace (nextpowerof2 (N), 1);			\
-  if ((N) < 0 || (N) >= len)					\
-    throw new ::java::lang::ArrayIndexOutOfBoundsException ();	\
-								\
-  _Jv_frame_info *frame = (_Jv_frame_info *)addrs;		\
-  &frame[N];							\
-})
-
-gnu::gcj::runtime::MethodRef *
-gnu::gcj::runtime::StackTrace::getCompiledMethodRef (gnu::gcj::RawData *addr)
-{
-  void *p = _Unwind_FindEnclosingFunction (addr);
-  return gnu::gcj::runtime::StackTrace
-    ::methodAtAddress ((gnu::gcj::RawData *)p);
-}
-
-java::lang::Class *
-gnu::gcj::runtime::StackTrace::getClass (gnu::gcj::RawData *p)
-{
-  gnu::gcj::runtime::MethodRef *ref = getCompiledMethodRef (p);
-  if (ref)
-    return ref->klass;
-  else
-    return NULL;
-}
-
-java::lang::Class *
-gnu::gcj::runtime::StackTrace::classAt (jint n)
-{
-  _Jv_frame_info *frame = GET_FRAME (n);
-
-#ifdef INTERPRETER
-  if (frame->interp)
-    {
-      _Jv_InterpMethod *meth
-	= reinterpret_cast<_Jv_InterpMethod *> (frame->interp);
-      return meth->defining_class;
-    }
-#endif // INTERPRETER
-  
-  return getClass ((gnu::gcj::RawData *)frame->addr);
-}
-
-java::lang::String*
-gnu::gcj::runtime::StackTrace::methodAt (jint n)
-{
-  _Jv_frame_info *frame = GET_FRAME (n);
-  _Jv_Method *meth = NULL;
-
-#ifdef INTERPRETER
-  if (frame->interp)
-    {
-      meth
-	= reinterpret_cast<_Jv_InterpMethod *> (frame->interp)
-	->get_method();
-    }
-#endif // INTERPRETER
-  
-  if (! meth)
-    {
-      gnu::gcj::runtime::MethodRef *ref
-	= getCompiledMethodRef ((gnu::gcj::RawData *)frame->addr);
-      if (ref)
-	meth = (_Jv_Method *)ref->method;
-    }
-
-  return meth 
-    ? _Jv_NewStringUtf8Const (meth->name)
-    : NULL ;
-}
-
-void
-gnu::gcj::runtime::StackTrace::update(void)
-{
-  jclass klass;
-
-  while ((klass = _Jv_PopClass ()))
-    {
-      for (int i=0; i<klass->method_count; i++)
-	{
-	  JvSynchronize sync (map);
-	  _Jv_Method *meth = &(klass->methods[i]);
-	  if (meth->ncode) // i.e. if p is not abstract
-	    {
-	      gnu::gcj::runtime::MethodRef *ref
-		= new gnu::gcj::runtime::MethodRef 
-		((gnu::gcj::RawData *)meth, klass);
-	      map->put ((java::lang::Object*)(meth->ncode), ref);
-	    }
-	}
-    }
-}
-
-void
-gnu::gcj::runtime::StackTrace::finalize(void)
-{
-  if (addrs != NULL)
-    _Jv_Free (addrs);
-}
Index: gnu/java/lang/MainThread.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gnu/java/lang/MainThread.java,v
retrieving revision 1.3
diff -u -r1.3 MainThread.java
--- gnu/java/lang/MainThread.java	12 Feb 2005 13:51:10 -0000	1.3
+++ gnu/java/lang/MainThread.java	10 Mar 2005 15:36:52 -0000
@@ -127,5 +127,7 @@
     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();
 }
Index: include/java-interp.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/include/java-interp.h,v
retrieving revision 1.27
diff -u -r1.27 java-interp.h
--- include/java-interp.h	27 Nov 2004 12:37:32 -0000	1.27
+++ include/java-interp.h	10 Mar 2005 15:36:52 -0000
@@ -23,6 +23,11 @@
 #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 @@
   }
 };
 
+// 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 @@
 
   _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 @@
   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_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 @@
   }
 };
 
-// A structure of this type is used to link together interpreter
-// invocations on the stack.
-struct _Jv_MethodChain
-{
-  const _Jv_InterpMethod *self;
-  _Jv_MethodChain **ptr;
-  _Jv_MethodChain *next;
+// The interpreted call stack, represented by a linked list of frames.
+struct _Jv_InterpFrame
+{
+  _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;
   }
Index: include/java-stack.h
===================================================================
RCS file: include/java-stack.h
diff -N include/java-stack.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ include/java-stack.h	10 Mar 2005 15:36:52 -0000
@@ -0,0 +1,125 @@
+// java-stack.h - Definitions 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.  */
+
+#ifndef __JV_STACKTRACE_H__
+#define __JV_STACKTRACE_H__
+
+#include <unwind.h>
+
+#include <gcj/cni.h>
+#include <gcj/javaprims.h>
+
+#include <java-interp.h>
+
+#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
+{
+  frame_native,
+  frame_interpreter
+};
+
+#ifdef INTERPRETER
+struct _Jv_InterpFrameInfo
+{
+  _Jv_InterpMethod *meth;
+  pc_t pc;
+};
+#endif
+
+union _Jv_FrameInfo
+{
+};
+
+struct _Jv_StackFrame
+{
+  _Jv_FrameType type;   /* Native or interpreted.  */
+  union {
+#ifdef INTERPRETER
+    _Jv_InterpFrameInfo interp;
+#endif
+    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:
+  int length;
+  _Jv_StackFrame frames[];
+
+  static void UpdateNCodeMap ();
+  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 (jclass);
+  static void GetCallerInfo (jclass checkClass, jclass *, _Jv_Method **);
+  static JArray<jclass> *GetClassContext (jclass checkClass);
+  static ClassLoader *GetFirstNonSystemClassLoader (void);
+  
+};
+
+
+#endif /* __JV_STACKTRACE_H__ */
Index: include/jvm.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/include/jvm.h,v
retrieving revision 1.77.2.1
diff -u -r1.77.2.1 jvm.h
--- include/jvm.h	7 Mar 2005 17:11:28 -0000	1.77.2.1
+++ include/jvm.h	10 Mar 2005 15:36:52 -0000
@@ -120,20 +120,6 @@
   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.
Index: java/lang/Class.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/Class.h,v
retrieving revision 1.78
diff -u -r1.78 Class.h
--- java/lang/Class.h	17 Feb 2005 19:17:08 -0000	1.78
+++ java/lang/Class.h	10 Mar 2005 15:36:52 -0000
@@ -21,7 +21,6 @@
 #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 @@
 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 @@
   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 @@
 #endif
 
   friend class ::_Jv_BytecodeVerifier;
-  friend class gnu::gcj::runtime::StackTrace;
   friend class java::io::VMObjectStreamClass;
 
   friend class ::_Jv_Linker;
Index: java/lang/VMClassLoader.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/VMClassLoader.java,v
retrieving revision 1.13
diff -u -r1.13 VMClassLoader.java
--- java/lang/VMClassLoader.java	2 Feb 2005 20:59:40 -0000	1.13
+++ java/lang/VMClassLoader.java	10 Mar 2005 15:36:52 -0000
@@ -304,12 +304,10 @@
 	    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;
Index: java/lang/VMThrowable.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/VMThrowable.java,v
retrieving revision 1.3
diff -u -r1.3 VMThrowable.java
--- java/lang/VMThrowable.java	9 Apr 2004 04:39:24 -0000	1.3
+++ java/lang/VMThrowable.java	10 Mar 2005 15:36:52 -0000
@@ -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, 2003 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -37,8 +37,7 @@
 
 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 @@
  */
 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 @@
    * @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 @@
    * @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;
 }
Index: java/lang/natClass.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/natClass.cc,v
retrieving revision 1.84
diff -u -r1.84 natClass.cc
--- java/lang/natClass.cc	17 Feb 2005 19:17:08 -0000	1.84
+++ java/lang/natClass.cc	10 Mar 2005 15:36:52 -0000
@@ -53,7 +53,6 @@
 #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 @@
 #include <java-cpool.h>
 #include <java-interp.h>
 #include <java-assert.h>
+#include <java-stack.h>
 #include <execution.h>
 
 
@@ -101,20 +101,10 @@
 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::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
Index: java/lang/natRuntime.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/natRuntime.cc,v
retrieving revision 1.47
diff -u -r1.47 natRuntime.cc
--- java/lang/natRuntime.cc	23 Feb 2005 17:36:25 -0000	1.47
+++ java/lang/natRuntime.cc	10 Mar 2005 15:36:52 -0000
@@ -16,6 +16,7 @@
 #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,7 +30,6 @@
 #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 +164,7 @@
   if (do_search)
     {
       ClassLoader *sys = ClassLoader::getSystemClassLoader();
-      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)
 	{
Index: java/lang/natVMSecurityManager.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/natVMSecurityManager.cc,v
retrieving revision 1.3
diff -u -r1.3 natVMSecurityManager.cc
--- java/lang/natVMSecurityManager.cc	18 Jun 2003 14:13:59 -0000	1.3
+++ java/lang/natVMSecurityManager.cc	10 Mar 2005 15:36:52 -0000
@@ -12,43 +12,18 @@
 
 #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;
 }
Index: java/lang/natVMThrowable.cc
===================================================================
RCS file: java/lang/natVMThrowable.cc
diff -N java/lang/natVMThrowable.cc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ java/lang/natVMThrowable.cc	10 Mar 2005 15:36:52 -0000
@@ -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);
+}
Index: java/lang/reflect/natArray.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/reflect/natArray.cc,v
retrieving revision 1.13
diff -u -r1.13 natArray.cc
--- java/lang/reflect/natArray.cc	26 Aug 2003 14:55:30 -0000	1.13
+++ java/lang/reflect/natArray.cc	10 Mar 2005 15:36:52 -0000
@@ -14,6 +14,7 @@
 
 #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 @@
   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++)
Index: java/lang/reflect/natConstructor.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/reflect/natConstructor.cc,v
retrieving revision 1.10
diff -u -r1.10 natConstructor.cc
--- java/lang/reflect/natConstructor.cc	26 Oct 2003 02:25:41 -0000	1.10
+++ java/lang/reflect/natConstructor.cc	10 Mar 2005 15:36:52 -0000
@@ -12,6 +12,7 @@
 
 #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 @@
   // 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;
     }
Index: java/lang/reflect/natField.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/reflect/natField.cc,v
retrieving revision 1.17
diff -u -r1.17 natField.cc
--- java/lang/reflect/natField.cc	22 Feb 2005 03:13:35 -0000	1.17
+++ java/lang/reflect/natField.cc	10 Mar 2005 15:36:52 -0000
@@ -13,6 +13,7 @@
 #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 @@
   // 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;
     }
Index: java/lang/reflect/natMethod.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/reflect/natMethod.cc,v
retrieving revision 1.44
diff -u -r1.44 natMethod.cc
--- java/lang/reflect/natMethod.cc	17 Feb 2005 19:17:08 -0000	1.44
+++ java/lang/reflect/natMethod.cc	10 Mar 2005 15:36:52 -0000
@@ -13,6 +13,7 @@
 #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 @@
   // 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;
     }
Index: java/util/natResourceBundle.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/util/natResourceBundle.cc,v
retrieving revision 1.7
diff -u -r1.7 natResourceBundle.cc
--- java/util/natResourceBundle.cc	21 Jan 2003 21:16:46 -0000	1.7
+++ java/util/natResourceBundle.cc	10 Mar 2005 15:36:52 -0000
@@ -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 @@
 
 #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;
 }
Index: java/util/logging/natLogger.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/util/logging/natLogger.cc,v
retrieving revision 1.1
diff -u -r1.1 natLogger.cc
--- java/util/logging/natLogger.cc	21 Feb 2005 18:19:01 -0000	1.1
+++ java/util/logging/natLogger.cc	10 Mar 2005 15:36:52 -0000
@@ -17,7 +17,7 @@
 
 #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 @@
 #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;
 }
Index: sysdep/generic/backtrace.h
===================================================================
RCS file: sysdep/generic/backtrace.h
diff -N sysdep/generic/backtrace.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sysdep/generic/backtrace.h	10 Mar 2005 15:36:52 -0000
@@ -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
Index: sysdep/i386/backtrace.h
===================================================================
RCS file: sysdep/i386/backtrace.h
diff -N sysdep/i386/backtrace.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sysdep/i386/backtrace.h	10 Mar 2005 15:36:52 -0000
@@ -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

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]