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]

Preliminary patch: New stack trace infrastructure


There is still some cleanup work to be done and missing pieces to be filled in (most noteably, AccessController), but here is a preliminary snapshot of the new stack trace infrastructure code.

Basically, this code will give clean looking, accurate stack traces using the DWARF2 debugging information and gcj's compiled metadata.

Key benefits:

- It gives stack traces, complete with line numbers, through interpreted bytecode (part of this code is based on an earlier implementation from Mark Wielaard - thanks Mark!)
- It gives stack traces through shared libraries. Currently, addr2line is still used to do this, which can be a noticeable performance problem when it has to open big libraries like libgcj, but I plan to integrate Casey Marshall's DWARF2 debug-info reading code soon. For now we may wish to disable addr2line usage for applications where printStackTrace() must be fast.
- Stack trace implementation is secure: stack frame -> class association is no longer based on mangled names, so classes wont be able to illegally elevate their privileges just by being called the same name as a secure class.
- Stack printing looks nicer and is smarter about which frames to include or exclude.


Behold:

$ gij Hello
Exception in thread "main" java.lang.ClassNotFoundException: asdasda not found in [file:./, core:/]
at java.net.URLClassLoader.findClass (URLClassLoader.java:960)
at java.lang.ClassLoader.loadClass (ClassLoader.java:314)
at java.lang.Class.forName (natClass.cc:89)
at Hello.main (Hello.java:13)


$ gcj -g -O2 Hello.java --main=Hello
$ ./a.out
Exception in thread "main" java.lang.ClassNotFoundException: asdasda not found in [file:./, core:/]
at java.net.URLClassLoader.findClass (URLClassLoader.java:960)
at java.lang.ClassLoader.loadClass (ClassLoader.java:314)
at java.lang.Class.forName (natClass.cc:89)
at Hello.main (Hello.java:13)


I've been using this for a while locally, so I'm confident that this code is reasonably stable on Linux systems, however systems that don't use DWARF2 EH (eg Windows) will need work.

Bryce

Index: Makefile.am
===================================================================
RCS file: /cvs/gcc/gcc/libjava/Makefile.am,v
retrieving revision 1.432
diff -u -r1.432 Makefile.am
--- Makefile.am	25 Nov 2004 12:54:36 -0000	1.432
+++ Makefile.am	26 Nov 2004 06:09:17 -0000
@@ -206,7 +206,7 @@
 libgij_la_LIBADD = libgcj.la
 libgij_la_DEPENDENCIES = libgcj.la libgcj.spec
 
-libgcj_la_SOURCES = prims.cc jni.cc exception.cc \
+libgcj_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) \
 	$(built_java_source_files) \
@@ -2607,6 +2607,7 @@
 gnu/java/locale/Calendar_de.java \
 gnu/java/locale/Calendar_en.java \
 gnu/java/locale/Calendar_nl.java \
+gnu/java/locale/LocaleHelper.java \
 gnu/java/locale/LocaleInformation.java \
 gnu/java/locale/LocaleInformation_af_ZA.java \
 gnu/java/locale/LocaleInformation_ar_AE.java \
@@ -2794,6 +2795,7 @@
 gnu/java/security/OID.java \
 gnu/java/security/PolicyFile.java \
 gnu/java/security/action/GetPropertyAction.java \
+gnu/java/security/action/GetSystemClassLoaderAction.java \
 gnu/java/security/action/GetSecurityPropertyAction.java \
 gnu/java/security/action/SetAccessibleAction.java \
 gnu/java/security/der/BitString.java \
@@ -3331,6 +3333,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: Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/libjava/Makefile.in,v
retrieving revision 1.461
diff -u -r1.461 Makefile.in
--- Makefile.in	25 Nov 2004 12:54:38 -0000	1.461
+++ Makefile.in	26 Nov 2004 06:09:18 -0000
@@ -372,9 +372,9 @@
 am__DEPENDENCIES_4 = gnu/regexp/MessagesBundle.properties.lo \
 	gnu/regexp/MessagesBundle_fr.properties.lo
 am__DEPENDENCIES_5 = $(am__DEPENDENCIES_4)
-am__libgcj_la_SOURCES_DIST = prims.cc jni.cc exception.cc link.cc \
-	defineclass.cc interpret.cc verify.cc gnu/gcj/natCore.cc \
-	gnu/gcj/convert/JIS0208_to_Unicode.cc \
+am__libgcj_la_SOURCES_DIST = prims.cc jni.cc exception.cc \
+	stacktrace.cc link.cc defineclass.cc interpret.cc verify.cc \
+	gnu/gcj/natCore.cc gnu/gcj/convert/JIS0208_to_Unicode.cc \
 	gnu/gcj/convert/JIS0212_to_Unicode.cc \
 	gnu/gcj/convert/Unicode_to_JIS.cc gnu/gcj/convert/natIconv.cc \
 	gnu/gcj/convert/natInput_EUCJIS.cc \
@@ -404,7 +404,7 @@
 	java/lang/natString.cc java/lang/natStringBuffer.cc \
 	java/lang/natSystem.cc java/lang/natThread.cc \
 	java/lang/natVMClassLoader.cc \
-	java/lang/natVMSecurityManager.cc \
+	java/lang/natVMSecurityManager.cc java/lang/natVMThrowable.cc \
 	java/lang/ref/natReference.cc java/lang/reflect/natArray.cc \
 	java/lang/reflect/natConstructor.cc \
 	java/lang/reflect/natField.cc java/lang/reflect/natMethod.cc \
@@ -615,6 +615,7 @@
 	gnu/java/locale/Calendar.java gnu/java/locale/Calendar_de.java \
 	gnu/java/locale/Calendar_en.java \
 	gnu/java/locale/Calendar_nl.java \
+	gnu/java/locale/LocaleHelper.java \
 	gnu/java/locale/LocaleInformation.java \
 	gnu/java/locale/LocaleInformation_af_ZA.java \
 	gnu/java/locale/LocaleInformation_ar_AE.java \
@@ -797,6 +798,7 @@
 	gnu/java/nio/charset/UTF_8.java gnu/java/security/Engine.java \
 	gnu/java/security/OID.java gnu/java/security/PolicyFile.java \
 	gnu/java/security/action/GetPropertyAction.java \
+	gnu/java/security/action/GetSystemClassLoaderAction.java \
 	gnu/java/security/action/GetSecurityPropertyAction.java \
 	gnu/java/security/action/SetAccessibleAction.java \
 	gnu/java/security/der/BitString.java \
@@ -2356,7 +2358,7 @@
 	java/lang/natString.lo java/lang/natStringBuffer.lo \
 	java/lang/natSystem.lo java/lang/natThread.lo \
 	java/lang/natVMClassLoader.lo \
-	java/lang/natVMSecurityManager.lo \
+	java/lang/natVMSecurityManager.lo java/lang/natVMThrowable.lo \
 	java/lang/ref/natReference.lo java/lang/reflect/natArray.lo \
 	java/lang/reflect/natConstructor.lo \
 	java/lang/reflect/natField.lo java/lang/reflect/natMethod.lo \
@@ -3602,6 +3604,7 @@
 	gnu/java/lang/reflect/TypeSignature.lo \
 	gnu/java/locale/Calendar.lo gnu/java/locale/Calendar_de.lo \
 	gnu/java/locale/Calendar_en.lo gnu/java/locale/Calendar_nl.lo \
+	gnu/java/locale/LocaleHelper.lo \
 	gnu/java/locale/LocaleInformation.lo \
 	gnu/java/locale/LocaleInformation_af_ZA.lo \
 	gnu/java/locale/LocaleInformation_ar_AE.lo \
@@ -3781,6 +3784,7 @@
 	gnu/java/security/Engine.lo gnu/java/security/OID.lo \
 	gnu/java/security/PolicyFile.lo \
 	gnu/java/security/action/GetPropertyAction.lo \
+	gnu/java/security/action/GetSystemClassLoaderAction.lo \
 	gnu/java/security/action/GetSecurityPropertyAction.lo \
 	gnu/java/security/action/SetAccessibleAction.lo \
 	gnu/java/security/der/BitString.lo \
@@ -4154,8 +4158,8 @@
 @USING_POSIX_THREADS_TRUE@am__objects_24 = posix-threads.lo
 @USING_WIN32_THREADS_TRUE@am__objects_25 = win32-threads.lo
 @USING_NO_THREADS_TRUE@am__objects_26 = no-threads.lo
-am_libgcj_la_OBJECTS = prims.lo jni.lo exception.lo link.lo \
-	defineclass.lo interpret.lo verify.lo $(am__objects_6) \
+am_libgcj_la_OBJECTS = prims.lo jni.lo exception.lo stacktrace.lo \
+	link.lo defineclass.lo interpret.lo verify.lo $(am__objects_6) \
 	$(am__objects_7) $(am__objects_15) $(am__objects_16) \
 	$(am__objects_17) $(am__objects_18) $(am__objects_19) \
 	$(am__objects_20) $(am__objects_21) $(am__objects_22) \
@@ -4552,7 +4556,7 @@
 libgij_la_SOURCES = gij.cc
 libgij_la_LIBADD = libgcj.la
 libgij_la_DEPENDENCIES = libgcj.la libgcj.spec
-libgcj_la_SOURCES = prims.cc jni.cc exception.cc \
+libgcj_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) \
 	$(built_java_source_files) \
@@ -6472,6 +6476,7 @@
 gnu/java/locale/Calendar_de.java \
 gnu/java/locale/Calendar_en.java \
 gnu/java/locale/Calendar_nl.java \
+gnu/java/locale/LocaleHelper.java \
 gnu/java/locale/LocaleInformation.java \
 gnu/java/locale/LocaleInformation_af_ZA.java \
 gnu/java/locale/LocaleInformation_ar_AE.java \
@@ -6659,6 +6664,7 @@
 gnu/java/security/OID.java \
 gnu/java/security/PolicyFile.java \
 gnu/java/security/action/GetPropertyAction.java \
+gnu/java/security/action/GetSystemClassLoaderAction.java \
 gnu/java/security/action/GetSecurityPropertyAction.java \
 gnu/java/security/action/SetAccessibleAction.java \
 gnu/java/security/der/BitString.java \
@@ -7191,6 +7197,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 \
@@ -8165,6 +8172,8 @@
 	java/lang/$(DEPDIR)/$(am__dirstamp)
 java/lang/natVMSecurityManager.lo: java/lang/$(am__dirstamp) \
 	java/lang/$(DEPDIR)/$(am__dirstamp)
+java/lang/natVMThrowable.lo: java/lang/$(am__dirstamp) \
+	java/lang/$(DEPDIR)/$(am__dirstamp)
 java/lang/ref/$(am__dirstamp):
 	@$(mkdir_p) java/lang/ref
 	@: > java/lang/ref/$(am__dirstamp)
@@ -8940,6 +8949,8 @@
 	gnu/java/locale/$(DEPDIR)/$(am__dirstamp)
 gnu/java/locale/Calendar_nl.lo: gnu/java/locale/$(am__dirstamp) \
 	gnu/java/locale/$(DEPDIR)/$(am__dirstamp)
+gnu/java/locale/LocaleHelper.lo: gnu/java/locale/$(am__dirstamp) \
+	gnu/java/locale/$(DEPDIR)/$(am__dirstamp)
 gnu/java/locale/LocaleInformation.lo: gnu/java/locale/$(am__dirstamp) \
 	gnu/java/locale/$(DEPDIR)/$(am__dirstamp)
 gnu/java/locale/LocaleInformation_af_ZA.lo:  \
@@ -9520,6 +9531,9 @@
 gnu/java/security/action/GetPropertyAction.lo:  \
 	gnu/java/security/action/$(am__dirstamp) \
 	gnu/java/security/action/$(DEPDIR)/$(am__dirstamp)
+gnu/java/security/action/GetSystemClassLoaderAction.lo:  \
+	gnu/java/security/action/$(am__dirstamp) \
+	gnu/java/security/action/$(DEPDIR)/$(am__dirstamp)
 gnu/java/security/action/GetSecurityPropertyAction.lo:  \
 	gnu/java/security/action/$(am__dirstamp) \
 	gnu/java/security/action/$(DEPDIR)/$(am__dirstamp)
@@ -14880,6 +14894,8 @@
 	-rm -f gnu/java/locale/Calendar_en.lo
 	-rm -f gnu/java/locale/Calendar_nl.$(OBJEXT)
 	-rm -f gnu/java/locale/Calendar_nl.lo
+	-rm -f gnu/java/locale/LocaleHelper.$(OBJEXT)
+	-rm -f gnu/java/locale/LocaleHelper.lo
 	-rm -f gnu/java/locale/LocaleInformation.$(OBJEXT)
 	-rm -f gnu/java/locale/LocaleInformation.lo
 	-rm -f gnu/java/locale/LocaleInformation_af_ZA.$(OBJEXT)
@@ -15332,6 +15348,8 @@
 	-rm -f gnu/java/security/action/GetPropertyAction.lo
 	-rm -f gnu/java/security/action/GetSecurityPropertyAction.$(OBJEXT)
 	-rm -f gnu/java/security/action/GetSecurityPropertyAction.lo
+	-rm -f gnu/java/security/action/GetSystemClassLoaderAction.$(OBJEXT)
+	-rm -f gnu/java/security/action/GetSystemClassLoaderAction.lo
 	-rm -f gnu/java/security/action/SetAccessibleAction.$(OBJEXT)
 	-rm -f gnu/java/security/action/SetAccessibleAction.lo
 	-rm -f gnu/java/security/der/BitString.$(OBJEXT)
@@ -16658,6 +16676,8 @@
 	-rm -f java/lang/natVMClassLoader.lo
 	-rm -f java/lang/natVMSecurityManager.$(OBJEXT)
 	-rm -f java/lang/natVMSecurityManager.lo
+	-rm -f java/lang/natVMThrowable.$(OBJEXT)
+	-rm -f java/lang/natVMThrowable.lo
 	-rm -f java/lang/ref/PhantomReference.$(OBJEXT)
 	-rm -f java/lang/ref/PhantomReference.lo
 	-rm -f java/lang/ref/Reference.$(OBJEXT)
@@ -19549,6 +19569,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/posix-threads.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/posix.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/prims.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stacktrace.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/verify.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/win32-threads.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/win32.Plo@am__quote@
@@ -19761,6 +19782,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote@gnu/java/locale/$(DEPDIR)/Calendar_de.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@gnu/java/locale/$(DEPDIR)/Calendar_en.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@gnu/java/locale/$(DEPDIR)/Calendar_nl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@gnu/java/locale/$(DEPDIR)/LocaleHelper.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@gnu/java/locale/$(DEPDIR)/LocaleInformation.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@gnu/java/locale/$(DEPDIR)/LocaleInformation_af_ZA.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@gnu/java/locale/$(DEPDIR)/LocaleInformation_ar_AE.Plo@am__quote@
@@ -19987,6 +20009,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote@gnu/java/security/$(DEPDIR)/PolicyFile.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@gnu/java/security/action/$(DEPDIR)/GetPropertyAction.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@gnu/java/security/action/$(DEPDIR)/GetSecurityPropertyAction.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@gnu/java/security/action/$(DEPDIR)/GetSystemClassLoaderAction.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@gnu/java/security/action/$(DEPDIR)/SetAccessibleAction.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@gnu/java/security/der/$(DEPDIR)/BitString.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@gnu/java/security/der/$(DEPDIR)/DER.Plo@am__quote@
@@ -20650,6 +20673,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote@java/lang/$(DEPDIR)/natThread.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@java/lang/$(DEPDIR)/natVMClassLoader.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@java/lang/$(DEPDIR)/natVMSecurityManager.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@java/lang/$(DEPDIR)/natVMThrowable.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@java/lang/$(DEPDIR)/s_atan.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@java/lang/$(DEPDIR)/s_ceil.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@java/lang/$(DEPDIR)/s_copysign.Plo@am__quote@
Index: defineclass.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/defineclass.cc,v
retrieving revision 1.42
diff -u -r1.42 defineclass.cc
--- defineclass.cc	25 Nov 2004 03:46:56 -0000	1.42
+++ defineclass.cc	26 Nov 2004 06:09:18 -0000
@@ -613,26 +617,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);
+    }
 }
 
 
@@ -1281,6 +1313,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: interpret.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/interpret.cc,v
retrieving revision 1.47
diff -u -r1.47 interpret.cc
--- interpret.cc	25 Nov 2004 03:46:56 -0000	1.47
+++ interpret.cc	26 Nov 2004 06:09:18 -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,19 @@
 }
 #endif
 
+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.100
diff -u -r1.100 prims.cc
--- prims.cc	25 Nov 2004 03:46:56 -0000	1.100
+++ prims.cc	26 Nov 2004 06:09:18 -0000
@@ -148,10 +148,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
@@ -159,14 +159,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	26 Nov 2004 06:09:18 -0000
@@ -0,0 +1,380 @@
+// stacktrace.cc - Functions for unwinding & inspecting the call stack.
+
+/* 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 <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/util/ArrayList.h>
+#include <java/util/IdentityHashMap.h>
+#include <gnu/java/lang/MainThread.h>
+#include <gnu/gcj/runtime/NameFinder.h>
+
+using namespace java::lang;
+using namespace java::lang::reflect;
+using namespace java::util;
+using namespace gnu::gcj::runtime;
+
+struct _Jv_UnwindState
+{
+  _Jv_StackFrame *frames;
+  jint length;
+  jint pos;
+  _Jv_InterpFrame *interp_frame;
+};
+
+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 an IP value for 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::ClassForIP (void *ip, void **ncode)
+{
+  jclass klass = NULL;
+  // use _Unwind_FindEnclosingFunction to find start of method
+  void *entryPoint = _Unwind_FindEnclosingFunction (ip);
+
+  // look it up in ncodeMap
+  if (entryPoint)
+    {
+      klass = (jclass) ncodeMap->get ((jobject) entryPoint);
+      if (ncode)
+        *ncode = entryPoint;
+    }
+  /*
+  if (!klass)
+    printf ("0x%x/0x%x: lookup failed\n", ip, entryPoint);
+  else
+    printf ("0x%x/0x%x: class %s\n", ip, entryPoint, klass->name->data);
+  */
+  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);
+    }
+
+  //printf ("unwind ip: %p\n", _Unwind_GetIP (context));
+
+  state->pos++;
+  return _URC_NO_REASON;
+}
+
+
+// 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)
+{
+  //printf ("getStackTrace()\n");
+  int trace_size = 100;
+  _Jv_StackFrame frames[trace_size];
+  _Jv_UnwindState state;
+  state.frames = (_Jv_StackFrame *) &frames;
+  state.length = trace_size;
+  state.pos = 0;
+  Thread *thread = Thread::currentThread();
+  // Check for NULL currentThread(), in case an exception is created very early
+  // during the runtime startup.
+  if (thread)
+    state.interp_frame = (_Jv_InterpFrame *) thread->interp_frame;
+  
+  _Unwind_Backtrace (UnwindTraceFn, &state);
+  
+  // 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
+}
+
+// Fill in class / method info for given stack frame
+void
+_Jv_StackTrace::FillInFrameInfo (_Jv_StackFrame *frame)
+{
+  jclass klass = NULL;
+  _Jv_Method *meth = NULL;
+  
+  if (frame->type == frame_native)
+    {
+      void *ncode = NULL;
+      klass = _Jv_StackTrace::ClassForIP (frame->ip, &ncode);
+
+      if (klass != NULL)
+        {
+	  // Find method in class
+	  for (int j = 0; j < klass->method_count; j++)
+	    {
+	      if (klass->methods[j].ncode == ncode)
+		{
+		  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 ("");
+  
+  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)
+{
+  //JvSynchronized (ncodeMap);
+  
+  UpdateNCodeMap ();
+  
+  ArrayList *list = new ArrayList ();
+  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();
+
+  JArray<Object *> *array = JvNewObjectArray (list->size (), 
+    &StackTraceElement::class$, NULL);
+
+  return (JArray<StackTraceElement *>*) list->toArray (array);
+}
+
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	26 Nov 2004 06:09:18 -0000
@@ -52,11 +52,15 @@
   // 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;
 
+  // Whether the stack-trace code should attempt to use "addr2line" to
+  // look up souce file info for stack frames.
+  boolean USE_ADDR2LINE = true;
+
   // Name of default AWT peer library.
   String default_awt_peer_toolkit = "@TOOLKIT@";
 }
Index: gnu/gcj/runtime/NameFinder.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gnu/gcj/runtime/NameFinder.java,v
retrieving revision 1.7
diff -u -r1.7 NameFinder.java
--- gnu/gcj/runtime/NameFinder.java	9 Apr 2004 04:39:24 -0000	1.7
+++ gnu/gcj/runtime/NameFinder.java	26 Nov 2004 06:09:18 -0000
@@ -9,6 +9,7 @@
 
 package gnu.gcj.runtime;
 
+import gnu.classpath.Configuration;
 import gnu.gcj.RawData;
 
 import java.lang.StringBuffer;
@@ -19,431 +20,139 @@
 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.
- *
- * There are a couple of system properties that can be set to manipulate the
- * result (all default 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_interpreter</code>
- *     Whether runtime interpreter calls (methods in the _Jv_InterpMethod class
- *     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>
- * </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();
-  private static final boolean remove_interpreter
-	  = 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;
-
-  /**
-   * 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 interpreter = 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 interpreter frames.
-	    unknown = 0;
-	    interpreter = 0;
-	  }
-	else if (remove_unknown && CName == null 
-		 && (MName == null || MName.startsWith("0x")))
-	  unknown++;
-	else if (remove_interpreter
-		 && ((CName == null
-		      && MName != null && MName.startsWith("ffi_"))
-		     || (CName != null && CName.equals("_Jv_InterpMethod"))))
-	  interpreter++;
-	else if ("main(java.lang.String[])".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 interpreter
-    // calls or have no usefull information whatsoever.
-    // Unless that means we filter out all info.
-    int nr_elements = end-begin-unknown-interpreter+1;
-    if ((begin > 0 || end < length-1 || unknown > 0 || interpreter > 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_interpreter
-		     && ((CName == null
-			 && MName != null && MName.startsWith("ffi_"))
-			|| (CName != null && CName.equals("_Jv_InterpMethod"))))
-	      ; // Skip interpreter runtime frame
-	    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 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 (! Configuration.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)
+      {
+      }
   }
 
   /**
@@ -483,7 +192,7 @@
     // Demangle the type arguments
     int arrayDepth = 0;
     char c = (index < length) ? m.charAt(index) : ')';
-    while (c != ')')
+    while (c != ')')      
       {
 	String type;
 	switch(c)
@@ -556,18 +265,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/natNameFinder.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gnu/gcj/runtime/natNameFinder.cc,v
retrieving revision 1.6
diff -u -r1.6 natNameFinder.cc
--- gnu/gcj/runtime/natNameFinder.cc	9 Apr 2004 04:39:24 -0000	1.6
+++ gnu/gcj/runtime/natNameFinder.cc	26 Nov 2004 06:09:18 -0000
@@ -47,36 +47,8 @@
 #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 ());
-}
+#if 0
 
 java::lang::String*
 gnu::gcj::runtime::NameFinder::getAddrAsString(RawData* addrs, jint n)
@@ -100,34 +72,6 @@
   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)
@@ -155,3 +99,4 @@
   return NULL;
 #endif // INTERPRETER
 }
+#endif // 0
Index: gnu/gcj/runtime/natStackTrace.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gnu/gcj/runtime/natStackTrace.cc,v
retrieving revision 1.8
diff -u -r1.8 natStackTrace.cc
--- gnu/gcj/runtime/natStackTrace.cc	18 Oct 2004 14:07:42 -0000	1.8
+++ gnu/gcj/runtime/natStackTrace.cc	26 Nov 2004 06:09:18 -0000
@@ -45,15 +45,11 @@
 #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)
 {
+#if 0
 #ifdef HAVE_BACKTRACE
   offset += 1;
   void *_p[maxlen + offset];
@@ -123,6 +119,7 @@
   (void)maxlen;
   (void)offset;
 #endif // HAVE_BACKTRACE
+#endif
 }
 
 /* Obtain the next power-of-2 of some integer.  */
@@ -169,6 +166,7 @@
 java::lang::Class *
 gnu::gcj::runtime::StackTrace::classAt (jint n)
 {
+#if 0
   _Jv_frame_info *frame = GET_FRAME (n);
 
 #ifdef INTERPRETER
@@ -181,11 +179,15 @@
 #endif // INTERPRETER
   
   return getClass ((gnu::gcj::RawData *)frame->addr);
+#endif
+  //return NULL;
+  throw new java::lang::ArrayIndexOutOfBoundsException();
 }
 
 java::lang::String*
 gnu::gcj::runtime::StackTrace::methodAt (jint n)
 {
+#if 0
   _Jv_frame_info *frame = GET_FRAME (n);
   _Jv_Method *meth = NULL;
 
@@ -209,11 +211,13 @@
   return meth 
     ? _Jv_NewStringUtf8Const (meth->name)
     : NULL ;
+#endif
 }
 
 void
 gnu::gcj::runtime::StackTrace::update(void)
 {
+  #if 0
   jclass klass;
 
   while ((klass = _Jv_PopClass ()))
@@ -231,6 +235,7 @@
 	    }
 	}
     }
+  #endif
 }
 
 void
Index: gnu/java/lang/MainThread.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gnu/java/lang/MainThread.java,v
retrieving revision 1.2
diff -u -r1.2 MainThread.java
--- gnu/java/lang/MainThread.java	29 Jul 2004 13:48:17 -0000	1.2
+++ gnu/java/lang/MainThread.java	26 Nov 2004 06:09:18 -0000
@@ -125,5 +125,7 @@
     return mainName;
   }
 
+  // Note: this function name is special-cased by 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.26
diff -u -r1.26 java-interp.h
--- include/java-interp.h	25 Nov 2004 03:47:00 -0000	1.26
+++ include/java-interp.h	26 Nov 2004 06:09:19 -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>
 }
@@ -98,6 +103,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;
@@ -106,6 +146,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 () 
@@ -138,17 +182,20 @@
   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);
+  static jboolean IsInterpreterFrame(void *ip);
 
   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;
@@ -158,11 +205,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;
@@ -222,23 +272,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	26 Nov 2004 06:09:19 -0000
@@ -0,0 +1,84 @@
+// java-stack.h - Definitions for unwinding & inspecting the call stack.
+
+/* 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.  */
+
+#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 <gnu/gcj/runtime/NameFinder.h>
+
+using namespace gnu::gcj::runtime;
+
+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
+    void *ip;  
+  };
+//  _Jv_FrameInfo info;   /* Frame-type specific data.  */
+  jclass klass;
+  _Jv_Method *meth;
+};
+
+class _Jv_StackTrace
+{
+private:
+  int length;
+  _Jv_StackFrame frames[];
+
+  static void UpdateNCodeMap ();
+  static jclass ClassForIP (void *ip, void **ncode);
+  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);
+
+public:
+  static _Jv_StackTrace *GetStackTrace (void);
+  static JArray< ::java::lang::StackTraceElement *>*
+    GetStackTraceElements (_Jv_StackTrace *trace, 
+    java::lang::Throwable *throwable);
+};
+
+#endif /* __JV_STACKTRACE_H__ */
Index: include/jvm.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/include/jvm.h,v
retrieving revision 1.70
diff -u -r1.70 jvm.h
--- include/jvm.h	25 Nov 2004 03:47:00 -0000	1.70
+++ include/jvm.h	26 Nov 2004 06:09:19 -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.74
diff -u -r1.74 Class.h
--- java/lang/Class.h	26 Nov 2004 02:27:54 -0000	1.74
+++ java/lang/Class.h	26 Nov 2004 06:09:19 -0000
@@ -238,11 +238,12 @@
 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;
@@ -473,6 +474,7 @@
   friend class ::_Jv_ClassReader;	
   friend class ::_Jv_InterpClass;
   friend class ::_Jv_InterpMethod;
+  friend class ::_Jv_StackTrace;
 #endif
 
 #ifdef JV_MARKOBJ_DECL
Index: java/lang/VMClassLoader.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/VMClassLoader.java,v
retrieving revision 1.11
diff -u -r1.11 VMClassLoader.java
--- java/lang/VMClassLoader.java	25 Nov 2004 03:47:04 -0000	1.11
+++ java/lang/VMClassLoader.java	26 Nov 2004 06:09:19 -0000
@@ -274,12 +274,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	26 Nov 2004 06:09:19 -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,6 +37,7 @@
 
 package java.lang;
 
+import gnu.gcj.RawDataManaged;
 import gnu.gcj.runtime.NameFinder;
 import gnu.gcj.runtime.StackTrace;
 
@@ -51,10 +52,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 +66,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 +76,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.83
diff -u -r1.83 natClass.cc
--- java/lang/natClass.cc	25 Nov 2004 03:47:04 -0000	1.83
+++ java/lang/natClass.cc	26 Nov 2004 06:09:19 -0000
@@ -101,6 +101,7 @@
 java::lang::Class::forName (jstring className)
 {
   java::lang::ClassLoader *loader = NULL;
+#if 0
   gnu::gcj::runtime::StackTrace *t 
     = new gnu::gcj::runtime::StackTrace(4);
   java::lang::Class *klass = NULL;
@@ -115,7 +116,7 @@
   catch (::java::lang::ArrayIndexOutOfBoundsException *e)
     {
     }
-
+#endif
   return forName (className, true, loader);
 }
 
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	26 Nov 2004 06:09:19 -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/net/URLConnection.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/net/URLConnection.java,v
retrieving revision 1.34
diff -u -r1.34 URLConnection.java
--- java/net/URLConnection.java	28 Sep 2004 11:02:35 -0000	1.34
+++ java/net/URLConnection.java	26 Nov 2004 06:09:20 -0000
@@ -1012,9 +1012,16 @@
 	propVal = (propVal == null) ? "" : (propVal + "|");
 	propVal = propVal + "gnu.java.net.content|sun.net.www.content";
 
+	// The content type could contain additional paramters, ie
+	// "text/html; charset=ISO-8859-1".
+	String typeClass = contentType;
+	int parameterBegin = typeClass.indexOf(';');
+	if (parameterBegin >= 0)
+	  typeClass = typeClass.substring(0, parameterBegin);
+
 	// Replace the '/' character in the content type with '.' and
 	// all other non-alphabetic, non-numeric characters with '_'.
-	char[] cArray = contentType.toCharArray();
+	char[] cArray = typeClass.toCharArray();
 	for (int i = 0; i < cArray.length; i++)
 	  {
 	    if (cArray[i] == '/')
Index: java/net/natInetAddressPosix.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/net/natInetAddressPosix.cc,v
retrieving revision 1.5
diff -u -r1.5 natInetAddressPosix.cc
--- java/net/natInetAddressPosix.cc	14 Aug 2004 05:04:52 -0000	1.5
+++ java/net/natInetAddressPosix.cc	26 Nov 2004 06:09:20 -0000
@@ -131,15 +131,10 @@
 
   if (host != NULL)
     {
-      char *hostname;
-      char buf[100];
-      int len = JvGetStringUTFLength(host);
-      if (len < 100)
-	hostname = buf;
-      else
-	hostname = (char*) _Jv_AllocBytes (len+1);
+      int len = JvGetStringUTFLength (host);
+      char *hostname = (char *) __builtin_alloca (len + 1);
       JvGetStringUTFRegion (host, 0, host->length(), hostname);
-      buf[len] = '\0';
+      hostname[len] = '\0';
 #ifdef HAVE_GETHOSTBYNAME_R
       while (true)
 	{
Index: java/util/Calendar.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/util/Calendar.java,v
retrieving revision 1.25
diff -u -r1.25 Calendar.java
--- java/util/Calendar.java	22 Oct 2004 17:14:26 -0000	1.25
+++ java/util/Calendar.java	26 Nov 2004 06:09:20 -0000
@@ -665,18 +665,9 @@
    */
   public final void set(int year, int month, int date)
   {
-    isTimeSet = false;
-    fields[YEAR] = year;
-    fields[MONTH] = month;
-    fields[DATE] = date;
-    isSet[YEAR] = isSet[MONTH] = isSet[DATE] = true;
-    isSet[WEEK_OF_YEAR] = false;
-    isSet[DAY_OF_YEAR] = false;
-    isSet[WEEK_OF_MONTH] = false;
-    isSet[DAY_OF_WEEK] = false;
-    isSet[DAY_OF_WEEK_IN_MONTH] = false;
-
-    isSet[DST_OFFSET] = false;  // May have crossed a DST boundary.
+    set(Calendar.YEAR, year);
+    set(Calendar.MONTH, month);
+    set(Calendar.DATE, date);
   }
 
   /**
@@ -690,11 +681,8 @@
   public final void set(int year, int month, int date, int hour, int minute)
   {
     set(year, month, date);
-    fields[HOUR_OF_DAY] = hour;
-    fields[MINUTE] = minute;
-    isSet[HOUR_OF_DAY] = isSet[MINUTE] = true;
-    isSet[AM_PM] = false;
-    isSet[HOUR] = false;
+    set(Calendar.HOUR_OF_DAY, hour);
+    set(Calendar.MINUTE, minute);
   }
 
   /**
@@ -710,8 +698,7 @@
 			int hour, int minute, int second)
   {
     set(year, month, date, hour, minute);
-    fields[SECOND] = second;
-    isSet[SECOND] = true;
+    set(Calendar.SECOND, second);
   }
 
   /**

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