This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
Preliminary patch: New stack trace infrastructure
- From: Bryce McKinlay <mckinlay at redhat dot com>
- To: Java Patches <java-patches at gcc dot gnu dot org>
- Date: Fri, 26 Nov 2004 01:46:12 -0500
- Subject: 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);
}
/**