Stack traces, etc.

Andrew Haley aph@redhat.com
Fri Nov 29 16:10:00 GMT 2002


This is the core of a large patch that allows gcj to walk the stack,
inspecting method invocation frames. This allows us to implememnt
protection domains in a fairly straightforward way. This patch also
fixes a known bug in Class.forname(string).
The idea is that a method creates a StackTrace and may then extract
from it the method and class that owns each frame. A new libgcc
function, _Unwind_FindEnclosingFunction, uses the DWARF unwinder
machinery to convert a PC address to the starting address of a
function. In turn, an IdentityHashMap maps function addresses to
method references, and these may be used to get class loaders or
protection domains. Walking the stack in this way is somewhat less
expensive than throwing an exception.
Tom Tromey has written code that uses this machinery to implement some
protection domain functionality. However, it's not yet ready for
submission.
I've appended a compiler patch that must be checked in at at exactly
the same time as this patch.
The interface to StackTrace will probably change. In any case, it's
only for libgcj's internal use.
Known bugs:
* This doesn't work with CNI methods, because the pointer in a method
 table points to the GOT entry for a CNI method, not the method
 itself. This can be fixed by using -Bsymbolic when linking a DSO.
* This implementation has a security hole, in that anyone may call
 StackTrace.classAt() and get the calling class. We'll have to
 restrict the availability of StackTrace.
* StackTrace.methodAt() doesn't at present return the argument types
 of a method. In any case, it might make more sense to return an
 instance of java.lang.reflect.Method rather than a string.
Andrew.
2002年11月29日 Andrew Haley <aph@redhat.com>
 * java/lang/natClassLoader.cc (_Jv_PrepareCompiledClass): Call _Jv_PushClass.
 (_Jv_InitNewClassFields): Set protectionDomain and chain = NULL.
 (_Jv_PopClass): New.
 (_Jv_PushClass): New.
 * java/lang/natClass.cc (forName (jstring)): Use a StackTrace to
 discover the ClassLoader of our caller.
 (_Jv_CheckArrayStore): Don't check that a class is assignment
 compatible with Object.
 * gnu/gcj/runtime/StackTrace.java: Renamed from java.lang.VMThrowable.
 (StackTrace(), StackTrace(int)): New constructors.
 (classAt, methodAt, update, methodAtAddress): New methods.
 (map): New field.
 * java/lang/Throwable.java (fillInStackTrace): Call StackTrace to
 get the stack trace.
 (Throwable.vmState): Now an instance of StackTrace.
 * java/lang/Class.h (getClassLoaderInternal): New.
 (class Class): Be friendly with _Jv_PopClass and _Jv_PushClass.
 Be friendly with gnu::gcj::runtime::StackTrace.
 (Object.chain): New field.
 * include/java-interp.h (class _Jv_InterpMethod): Be friendly with
 gnu::gcj::runtime::StackTrace.
 * gnu/gcj/runtime/NameFinder.java (sanitizeStack): Use
 gnu::gcj::runtime::StackTrace, not java::lang::VMThrowable.
 * gcj/javaprims.h ("Java"): Remove class java.lang.VMThrowable.
 * prims.cc (_Jv_NewObjectArray): Use getClassLoaderInternal()
 instead of getClassLoader().
 * verify.cc (class _Jv_BytecodeVerifier): Likewise.
 (_Jv_CreateJavaVM): Use gnu::gcj::runtime::StackTrace, not
 java::lang::VMThrowable.
 * Makefile.am (core_java_source_files): Remove VMThrowable.java.
 (ordinary_java_source_files): Add MethodRef.java, StackTrace.java.
 (nat_source_files): Remove natVMThrowable.cc; add natStackTrace.cc.
 * Makefile.in: Rebuild.
Index: Makefile.am
===================================================================
RCS file: /cvs/gcc/gcc/libjava/Makefile.am,v
retrieving revision 1.261
diff -p -2 -c -r1.261 Makefile.am
*** Makefile.am	21 Nov 2002 10:45:12 -0000	1.261
--- Makefile.am	29 Nov 2002 23:50:27 -0000
*************** java/lang/VirtualMachineError.java \
*** 1557,1561 ****
 java/lang/VMClassLoader.java \
 java/lang/VMSecurityManager.java \
- java/lang/VMThrowable.java \
 java/lang/Void.java \
 java/io/BufferedInputStream.java \
--- 1557,1560 ----
*************** gnu/gcj/runtime/FinalizerThread.java \
*** 1721,1726 ****
--- 1720,1727 ----
 gnu/gcj/runtime/FirstThread.java \
 gnu/gcj/runtime/JNIWeakRef.java \
+ gnu/gcj/runtime/MethodRef.java \
 gnu/gcj/runtime/NameFinder.java \
 gnu/gcj/runtime/SharedLibLoader.java \
+ gnu/gcj/runtime/StackTrace.java \
 gnu/gcj/runtime/StringBuffer.java \
 gnu/gcj/runtime/VMClassLoader.java \
*************** gnu/gcj/runtime/natFirstThread.cc \
*** 2317,2320 ****
--- 2318,2322 ----
 gnu/gcj/runtime/natNameFinder.cc \
 gnu/gcj/runtime/natSharedLibLoader.cc \
+ gnu/gcj/runtime/natStackTrace.cc \
 gnu/gcj/runtime/natStringBuffer.cc \
 java/io/natFile.cc \
*************** java/lang/natStringBuffer.cc \
*** 2335,2339 ****
 java/lang/natSystem.cc \
 java/lang/natThread.cc \
- java/lang/natVMThrowable.cc \
 java/lang/ref/natReference.cc \
 java/lang/reflect/natArray.cc \
--- 2337,2340 ----
Index: prims.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/prims.cc,v
retrieving revision 1.74
diff -p -2 -c -r1.74 prims.cc
*** prims.cc	2 Nov 2002 21:33:30 -0000	1.74
--- prims.cc	29 Nov 2002 23:50:30 -0000
*************** details. */
*** 46,49 ****
--- 46,50 ----
 #include <java/lang/Thread.h>
 #include <java/lang/ThreadGroup.h>
+ #include <gnu/gcj/runtime/StackTrace.h>
 #include <java/lang/ArrayIndexOutOfBoundsException.h>
 #include <java/lang/ArithmeticException.h>
*************** details. */
*** 54,58 ****
 #include <java/lang/OutOfMemoryError.h>
 #include <java/lang/System.h>
- #include <java/lang/VMThrowable.h>
 #include <java/lang/reflect/Modifier.h>
 #include <java/io/PrintStream.h>
--- 55,58 ----
*************** _Jv_NewObjectArray (jsize count, jclass 
*** 459,464 ****
 size += count * sizeof (jobject);
 
! // FIXME: second argument should be "current loader"
! jclass klass = _Jv_GetArrayClass (elementClass, 0);
 
 obj = (jobjectArray) _Jv_AllocArray (size, klass);
--- 459,464 ----
 size += count * sizeof (jobject);
 
! jclass klass = _Jv_GetArrayClass (elementClass,
! 				 elementClass->getClassLoaderInternal());
 
 obj = (jobjectArray) _Jv_AllocArray (size, klass);
*************** _Jv_CreateJavaVM (void* /*vm_args*/)
*** 911,916 ****
 
 // Turn stack trace generation off while creating exception objects.
! _Jv_InitClass (&java::lang::VMThrowable::class$);
! java::lang::VMThrowable::trace_enabled = 0;
 
 INIT_SEGV;
--- 911,916 ----
 
 // Turn stack trace generation off while creating exception objects.
! _Jv_InitClass (&gnu::gcj::runtime::StackTrace::class$);
! gnu::gcj::runtime::StackTrace::trace_enabled = 0;
 
 INIT_SEGV;
*************** _Jv_CreateJavaVM (void* /*vm_args*/)
*** 921,928 ****
 (JvNewStringLatin1 ("/ by zero"));
 #endif
! 
 no_memory = new java::lang::OutOfMemoryError;
! 
! java::lang::VMThrowable::trace_enabled = 1;
 
 #ifdef USE_LTDL
--- 921,928 ----
 (JvNewStringLatin1 ("/ by zero"));
 #endif
! 
 no_memory = new java::lang::OutOfMemoryError;
! 
! gnu::gcj::runtime::StackTrace::trace_enabled = 1;
 
 #ifdef USE_LTDL
Index: verify.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/verify.cc,v
retrieving revision 1.45
diff -p -2 -c -r1.45 verify.cc
*** verify.cc	27 Nov 2002 05:59:39 -0000	1.45
--- verify.cc	29 Nov 2002 23:50:31 -0000
*************** private:
*** 406,410 ****
 using namespace java::lang;
 java::lang::ClassLoader *loader
! 	= verifier->current_class->getClassLoader();
 // We might see either kind of name. Sigh.
 if (data.name->data[0] == 'L'
--- 406,410 ----
 using namespace java::lang;
 java::lang::ClassLoader *loader
! 	= verifier->current_class->getClassLoaderInternal();
 // We might see either kind of name. Sigh.
 if (data.name->data[0] == 'L'
*************** private:
*** 572,576 ****
 if (key == reference_type)
 	return type (_Jv_GetArrayClass (data.klass,
! 					data.klass->getClassLoader ()));
 else
 	verifier->verify_fail ("internal error in type::to_array()");
--- 572,576 ----
 if (key == reference_type)
 	return type (_Jv_GetArrayClass (data.klass,
! 					data.klass->getClassLoaderInternal()));
 else
 	verifier->verify_fail ("internal error in type::to_array()");
*************** private:
*** 696,700 ****
 			{
 			 java::lang::ClassLoader *loader
! 			 = verifier->current_class->getClassLoader();
 			 k = _Jv_GetArrayClass (k, loader);
 			 --arraycount;
--- 696,700 ----
 			{
 			 java::lang::ClassLoader *loader
! 			 = verifier->current_class->getClassLoaderInternal();
 			 k = _Jv_GetArrayClass (k, loader);
 			 --arraycount;
Index: gcj/javaprims.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gcj/javaprims.h,v
retrieving revision 1.42
diff -p -2 -c -r1.42 javaprims.h
*** gcj/javaprims.h	30 Sep 2002 05:19:07 -0000	1.42
--- gcj/javaprims.h	29 Nov 2002 23:50:32 -0000
*************** extern "Java"
*** 212,216 ****
 class VMClassLoader;
 class VMSecurityManager;
- class VMThrowable;
 class VerifyError;
 class VirtualMachineError;
--- 212,215 ----
Index: gnu/gcj/runtime/MethodRef.java
===================================================================
RCS file: gnu/gcj/runtime/MethodRef.java
diff -N gnu/gcj/runtime/MethodRef.java
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- gnu/gcj/runtime/MethodRef.java	29 Nov 2002 23:50:32 -0000
***************
*** 0 ****
--- 1,30 ----
+ // gnu.gcj.runtime.MethodRef -- used by StackTrace.
+ 
+ /* Copyright (C) 2002 Free Software Foundation
+ 
+ This file is part of libgcj.
+ 
+ This software is copyrighted work licensed under the terms of the
+ Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
+ details. */
+ 
+ package gnu.gcj.runtime;
+ 
+ import gnu.gcj.RawData;
+ import java.util.TreeMap;
+ import java.util.SortedMap;
+ import gnu.gcj.runtime.NameFinder;
+ import java.util.NoSuchElementException;
+ 
+ class MethodRef
+ {
+ MethodRef(RawData /* Actually _Jv_Method */ m, Class k)
+ {
+ klass = k;
+ method = m;
+ }
+ 
+ public RawData method; // Actually a raw pointer to _Jv_Method
+ public Class klass;
+ }
+ 
Index: gnu/gcj/runtime/NameFinder.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gnu/gcj/runtime/NameFinder.java,v
retrieving revision 1.3
diff -p -2 -c -r1.3 NameFinder.java
*** gnu/gcj/runtime/NameFinder.java	2 Sep 2002 15:55:56 -0000	1.3
--- gnu/gcj/runtime/NameFinder.java	29 Nov 2002 23:50:32 -0000
*************** import java.io.File;
*** 50,54 ****
 * <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.
--- 50,54 ----
 * <code>close()</code> should be called to get rid of all resources.
 *
! * This class is used from <code>java.lang.StackTrace</code>.
 *
 * Currently the <code>lookup(long[])</code> method is not thread safe.
*************** public class NameFinder
*** 279,283 ****
 	 && (CName.equals(className)
 		|| CName.equals("java.lang.Throwable")
! 		|| CName.equals("java.lang.VMThrowable"))
 	 && MName != null
 	 && (MName.startsWith(consName)
--- 279,283 ----
 	 && (CName.equals(className)
 		|| CName.equals("java.lang.Throwable")
! 		|| CName.equals("java.lang.StackTrace"))
 	 && MName != null
 	 && (MName.startsWith(consName)
Index: gnu/gcj/runtime/StackTrace.java
===================================================================
RCS file: gnu/gcj/runtime/StackTrace.java
diff -N gnu/gcj/runtime/StackTrace.java
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- gnu/gcj/runtime/StackTrace.java	29 Nov 2002 23:50:32 -0000
***************
*** 0 ****
--- 1,196 ----
+ /* gnu.gcj.runtime.StackTrace -- VM support methods for walking the
+ stack.
+ Copyright (C) 1998, 1999, 2002 Free Software Foundation, Inc.
+ 
+ This file is part of GNU Classpath.
+ 
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+ 
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+ 
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA.
+ 
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+ 
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+ 
+ package gnu.gcj.runtime;
+ 
+ import gnu.gcj.RawData;
+ import java.util.TreeMap;
+ import java.util.IdentityHashMap;
+ import java.util.SortedMap;
+ import gnu.gcj.runtime.NameFinder;
+ import java.util.NoSuchElementException;
+ 
+ /**
+ * VM dependent state and support methods for walking the stack.
+ * <p>
+ * This is the version used by libgcj (http://gcc.gnu.org/java/).
+ *
+ * @author Mark Wielaard (mark@klomp.org)
+ * @author Andrew Haley (aph@redhat.com)
+ */
+ public final class StackTrace
+ {
+ private gnu.gcj.RawData stackTraceAddrs;
+ private int length;
+ 
+ /**
+ * Fill in the stack trace with the top n frames on current execution stack.
+ * Called by <code>Throwable.fillInStackTrace()</code> to get the state of
+ * the VM. Can return null if the VM does not support capturing the VM
+ * execution state.
+ *
+ * @see Throwable#fillInStackTrace()
+ */
+ public StackTrace(int n)
+ {
+ fillInStackTrace(n);
+ }
+ 
+ /**
+ * Fill in the stack trace with state of the entire execution stack.
+ * Called by <code>Throwable.fillInStackTrace()</code> to get the state of
+ * the VM. Can return null if the VM does not support capturing the VM
+ * execution state.
+ *
+ * This can be very expensive. If you only want path of the stack,
+ * see <code>Throwable.fillInStackTrace(int)</code>
+ *
+ * @see Throwable#fillInStackTrace()
+ */
+ public StackTrace()
+ {
+ int n = 64;
+ 
+ do
+ {
+ 	n *= 4;
+ 	fillInStackTrace(n);
+ }
+ while (length >= n);
+ }
+ 
+ /**
+ * Fill in the stack trace with the top n frames on current execution stack.
+ * Called by <code>Throwable.fillInStackTrace()</code> to get the state of
+ * the VM. Can return null when the VM does not support caputing the VM
+ * execution state.
+ *
+ * @return a new StackTrace containing the current execution stack trace.
+ * @see Throwable#fillInStackTrace()
+ */
+ public native void fillInStackTrace(int n);
+ 
+ /**
+ * Return a <code>StackTraceElement</code> array based on the execution
+ * state of the VM as captured by <code>fillInStackTrace</code>.
+ * Called by <code>Throwable.getStackTrace()</code>.
+ *
+ * @return a non-null but possible zero length array of StackTraceElement.
+ * @see Throwable#getStackTrace()
+ */
+ StackTraceElement[] getStackTrace(Throwable t)
+ {
+ StackTraceElement[] result;
+ if (stackTraceAddrs != null)
+ {
+ 	NameFinder nameFinder = new NameFinder();
+ 	result = nameFinder.lookup(t, stackTraceAddrs, length);
+ 	nameFinder.close();
+ }
+ else
+ result = new StackTraceElement[0];
+ 
+ return result;
+ }
+ 
+ /**
+ * Return the class containing the execution point represented by
+ * the Nth frame down the stack. The zeroth frame represents the
+ * top of the stack, which is the method that called classAt().
+ *
+ * If the Nth frame down the stack was not create by a method
+ * invocation, return null.
+ *
+ * It is not necessary to call <code>fillInStackTrace()</code> with
+ * a size greater than N before calling this method; if the current
+ * stack trace is insufficiently large, it will be expanded as
+ * required. This requires some caution if
+ * <code>fillInStackTrace()</code> is called from a different
+ * invocation to the one that calls <code>classAt()</code>.
+ * classAt() will not call <code>fillInStackTrace()</code> unless N
+ * is greater than the current length.
+ *
+ */
+ public native Class classAt (int n);
+ 
+ /**
+ * Return the name of the method containing the execution point
+ * represented by the Nth frame down the stack. The zeroth frame
+ * represents the top of the stack, which is the method that called
+ * classAt().
+ *
+ * If the Nth frame down the stack was not create by a method
+ * invocation, return null.
+ *
+ * It is not necessary to call <code>fillInStackTrace()</code> with
+ * a size greater than N before calling this method; if the current
+ * stack trace is insufficiently large, it will be expanded as
+ * required. This requires some caution if
+ * <code>fillInStackTrace()</code> is called from a different
+ * invocation to the one that calls <code>classAt()</code>.
+ * classAt() will not call <code>fillInStackTrace()</code> unless N
+ * is greater than the current length.
+ *
+ */
+ public native String methodAt (int n);
+ 
+ 
+ /**
+ * Return the length of this stack trace.
+ *
+ */
+ public int getLength ()
+ {
+ return length;
+ }
+ 
+ // Setting this flag to false prevents fillInStackTrace() from running.
+ static boolean trace_enabled = true;
+ 
+ private static native void update();
+ private static MethodRef methodAtAddress (RawData addr)
+ {
+ update();
+ synchronized (map)
+ {
+ 	return (MethodRef) map.get (addr);
+ }
+ }
+ private static native MethodRef getCompiledMethodRef (RawData addr);
+ private static IdentityHashMap map = new IdentityHashMap();
+ }
Index: gnu/gcj/runtime/natStackTrace.cc
===================================================================
RCS file: gnu/gcj/runtime/natStackTrace.cc
diff -N gnu/gcj/runtime/natStackTrace.cc
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- gnu/gcj/runtime/natStackTrace.cc	29 Nov 2002 23:50:32 -0000
***************
*** 0 ****
--- 1,198 ----
+ // natStackTrace.cc - native helper methods for Throwable
+ 
+ /* Copyright (C) 2000, 2002 Free Software Foundation, Inc
+ 
+ This file is part of libgcj.
+ 
+ This software is copyrighted work licensed under the terms of the
+ Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
+ details. */
+ 
+ /**
+ * @author Andrew Haley <aph@cygnus.com>
+ * @author Mark Wielaard <mark@klomp.org>
+ *
+ * Native helper methods for VM specific Throwable support.
+ */
+ 
+ #include <config.h>
+ 
+ #include <string.h>
+ 
+ #include <jvm.h>
+ #include <gcj/cni.h>
+ #include <gnu/gcj/RawData.h>
+ #include <java/lang/Object.h>
+ #include <java-threads.h>
+ #include <gnu/gcj/runtime/MethodRef.h>
+ #include <gnu/gcj/runtime/StackTrace.h>
+ #include <java/lang/Thread.h>
+ #include <java-interp.h>
+ #include <java/util/IdentityHashMap.h>
+ #include <java/lang/ArrayIndexOutOfBoundsException.h>
+ 
+ #include <sys/types.h>
+ 
+ #include <stdlib.h>
+ 
+ #include <unistd.h>
+ 
+ #ifdef HAVE_EXECINFO_H
+ #include <execinfo.h>
+ #endif
+ 
+ #include <unwind.h>
+ 
+ void
+ gnu::gcj::runtime::StackTrace::fillInStackTrace (jint len)
+ {
+ if (! trace_enabled)
+ return;
+ #if defined (HAVE_BACKTRACE)
+ // We subtract 1 from the number of elements because we don't want
+ // to include the calls to fillInStackTrace in the trace.
+ void *_p[len+1];
+ int n = backtrace (_p, len+1) - 1; 
+ void **p = _p+1;
+ #endif
+ _Jv_frame_info *addrs;
+ if (n > 0)
+ {
+ #ifdef INTERPRETER
+ extern void _Jv_StartOfInterpreter (void);
+ extern void _Jv_EndOfInterpreter (void);
+ 
+ java::lang::Thread *thread = java::lang::Thread::currentThread();
+ _Jv_MethodChain *interp_frame
+ 	= (thread ? reinterpret_cast<_Jv_MethodChain *> (thread->interp_frame)
+ 	 : NULL);
+ #endif // INTERPRETER
+ 
+ length = n;
+ int len = n;
+ addrs = (_Jv_frame_info *) _Jv_Malloc (n * sizeof (_Jv_frame_info));
+ for (n = 0; n < len; n++)
+ 	{
+ 	 addrs[n].addr = p[n];
+ #ifdef INTERPRETER
+ 	 if (p[n] >= &_Jv_StartOfInterpreter && p[n] <= &_Jv_EndOfInterpreter)
+ 	 {
+ 	 addrs[n].interp = (void *) interp_frame->self;
+ 	 interp_frame = interp_frame->next;
+ 	 }
+ 	 else
+ 	 addrs[n].interp = 0;
+ #endif // INTERPRETER
+ 	}
+ }
+ else
+ addrs = NULL;
+ 
+ stackTraceAddrs = reinterpret_cast<gnu::gcj::RawData *> (addrs);
+ }
+ 
+ /* Obtain the next power-of-2 of some integer. */
+ static inline jint
+ nextpowerof2 (jint n)
+ {
+ n |= (n >> 1);
+ n |= (n >> 2);
+ n |= (n >> 4);
+ n |= (n >> 8);
+ n |= (n >> 16);
+ return n+1;
+ }
+ 
+ static _Jv_frame_info *
+ get_frame (::gnu::gcj::runtime::StackTrace *t, jint n, void *stackTraceAddrs)
+ {
+ if (n >= t->getLength()) 
+ t->fillInStackTrace (nextpowerof2 (n));
+ if (n < 0 || n >= t->getLength()) 
+ throw new ::java::lang::ArrayIndexOutOfBoundsException ();
+ 
+ _Jv_frame_info *stack = (_Jv_frame_info *)stackTraceAddrs;
+ return &stack[n];
+ } 
+ 
+ gnu::gcj::runtime::MethodRef *
+ gnu::gcj::runtime::StackTrace::getCompiledMethodRef (gnu::gcj::RawData *addr)
+ {
+ void *p = _Unwind_FindEnclosingFunction (addr);
+ return gnu::gcj::runtime::StackTrace
+ ::methodAtAddress ((gnu::gcj::RawData *)p);
+ }
+ 
+ java::lang::Class *
+ gnu::gcj::runtime::StackTrace::classAt (jint n)
+ {
+ _Jv_frame_info *frame = get_frame (this, n, stackTraceAddrs);
+ 
+ #ifdef INTERPRETER
+ if (frame->interp)
+ {
+ _Jv_InterpMethod *meth
+ 	= reinterpret_cast<_Jv_InterpMethod *> (frame->interp);
+ return meth->defining_class;
+ }
+ #endif // INTERPRETER
+ 
+ gnu::gcj::runtime::MethodRef *ref 
+ = getCompiledMethodRef ((gnu::gcj::RawData *)frame->addr);
+ if (ref)
+ return ref->klass;
+ else
+ return NULL;
+ }
+ 
+ java::lang::String*
+ gnu::gcj::runtime::StackTrace::methodAt (jint n)
+ {
+ _Jv_frame_info *frame = get_frame (this, n, stackTraceAddrs);
+ _Jv_Method *meth = NULL;
+ 
+ #ifdef INTERPRETER
+ if (frame->interp)
+ {
+ meth
+ 	= reinterpret_cast<_Jv_InterpMethod *> (frame->interp)
+ 	->get_method();
+ }
+ #endif // INTERPRETER
+ 
+ if (! meth)
+ {
+ gnu::gcj::runtime::MethodRef *ref
+ 	= getCompiledMethodRef ((gnu::gcj::RawData *)frame->addr);
+ if (ref)
+ 	meth = (_Jv_Method *)ref->method;
+ }
+ 
+ return meth 
+ ? _Jv_NewStringUtf8Const (meth->name)
+ : NULL ;
+ }
+ 
+ void
+ gnu::gcj::runtime::StackTrace::update(void)
+ {
+ jclass klass;
+ 
+ while ((klass = _Jv_PopClass ()))
+ {
+ for (int i=0; i<klass->method_count; i++)
+ 	{
+ 	 JvSynchronize sync (map);
+ 	 _Jv_Method *meth = &(klass->methods[i]);
+ 	 if (meth->ncode) // i.e. if p is not abstract
+ 	 {
+ 	 gnu::gcj::runtime::MethodRef *ref
+ 		= new gnu::gcj::runtime::MethodRef 
+ 		((gnu::gcj::RawData *)meth, klass);
+ 	 map->put ((java::lang::Object*)(meth->ncode), ref);
+ 	 }
+ 	}
+ }
+ }
+ 
+ 
Index: include/java-interp.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/include/java-interp.h,v
retrieving revision 1.18
diff -p -2 -c -r1.18 java-interp.h
*** include/java-interp.h	29 Aug 2002 17:53:28 -0000	1.18
--- include/java-interp.h	29 Nov 2002 23:50:33 -0000
*************** details. */
*** 22,25 ****
--- 22,26 ----
 #include <java/lang/Class.h>
 #include <java/lang/ClassLoader.h>
+ #include <gnu/gcj/runtime/StackTrace.h>
 
 extern "C" {
*************** class _Jv_InterpMethod : public _Jv_Meth
*** 141,144 ****
--- 142,146 ----
 friend class _Jv_BytecodeVerifier;
 friend class gnu::gcj::runtime::NameFinder;
+ friend class gnu::gcj::runtime::StackTrace;
 
 friend void _Jv_PrepareClass(jclass);
Index: java/lang/Class.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/Class.h,v
retrieving revision 1.50
diff -p -2 -c -r1.50 Class.h
*** java/lang/Class.h	4 Nov 2002 02:45:31 -0000	1.50
--- java/lang/Class.h	29 Nov 2002 23:50:33 -0000
*************** details. */
*** 21,24 ****
--- 21,25 ----
 #include <java/security/ProtectionDomain.h>
 #include <java/lang/Package.h>
+ #include <gnu/gcj/runtime/StackTrace.h>
 
 // We declare these here to avoid including gcj/cni.h.
*************** public:
*** 139,142 ****
--- 140,150 ----
 java::lang::ClassLoader *getClassLoader (void);
 
+ // This is an internal method that circumvents the usual security
+ // checks when getting the class loader.
+ java::lang::ClassLoader *getClassLoaderInternal (void)
+ {
+ return loader;
+ }
+ 
 java::lang::reflect::Constructor *getConstructor (JArray<jclass> *);
 JArray<java::lang::reflect::Constructor *> *getConstructors (void);
*************** private: 
*** 297,300 ****
--- 305,310 ----
 friend jclass _Jv_FindClassInCache (_Jv_Utf8Const *name,
 				 java::lang::ClassLoader *loader);
+ friend jclass _Jv_PopClass (void);
+ friend void _Jv_PushClass (jclass k);
 friend void _Jv_NewArrayClass (jclass element,
 				 java::lang::ClassLoader *loader,
*************** private: 
*** 350,353 ****
--- 360,364 ----
 
 friend class _Jv_BytecodeVerifier;
+ friend class gnu::gcj::runtime::StackTrace;
 
 // Chain for class pool.
*************** private: 
*** 404,407 ****
--- 415,420 ----
 // Security Domain to which this class belongs (or null).
 java::security::ProtectionDomain *protectionDomain;
+ // Used by Jv_PopClass and _Jv_PushClass to communicate with StackTrace.
+ jclass chain;
 };
 
Index: java/lang/Throwable.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/Throwable.java,v
retrieving revision 1.14
diff -p -2 -c -r1.14 Throwable.java
*** java/lang/Throwable.java	4 Oct 2002 16:47:36 -0000	1.14
--- java/lang/Throwable.java	29 Nov 2002 23:50:33 -0000
*************** import java.io.ObjectInputStream;
*** 45,48 ****
--- 45,49 ----
 import java.io.IOException;
 import java.io.OutputStream;
+ import gnu.gcj.runtime.StackTrace;
 
 /**
*************** public class Throwable implements Serial
*** 490,494 ****
 public Throwable fillInStackTrace()
 {
! vmState = VMThrowable.fillInStackTrace(this);
 stackTrace = null; // Should be regenerated when used.
 
--- 491,495 ----
 public Throwable fillInStackTrace()
 {
! vmState = new StackTrace(128);
 stackTrace = null; // Should be regenerated when used.
 
*************** public class Throwable implements Serial
*** 554,557 ****
 * Cleared when no longer needed.
 */
! private transient VMThrowable vmState;
 }
--- 555,558 ----
 * Cleared when no longer needed.
 */
! private transient StackTrace vmState;
 }
Index: java/lang/VMThrowable.java
===================================================================
RCS file: java/lang/VMThrowable.java
diff -N java/lang/VMThrowable.java
*** java/lang/VMThrowable.java	24 Aug 2002 22:46:19 -0000	1.1
--- /dev/null	1 Jan 1970 00:00:00 -0000
***************
*** 1,97 ****
- /* java.lang.VMThrowable -- VM support methods for Throwable.
- Copyright (C) 1998, 1999, 2002 Free Software Foundation, Inc.
- 
- This file is part of GNU Classpath.
- 
- GNU Classpath is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
- 
- GNU Classpath is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
- 
- You should have received a copy of the GNU General Public License
- along with GNU Classpath; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307 USA.
- 
- Linking this library statically or dynamically with other modules is
- making a combined work based on this library. Thus, the terms and
- conditions of the GNU General Public License cover the whole
- combination.
- 
- As a special exception, the copyright holders of this library give you
- permission to link this library with independent modules to produce an
- executable, regardless of the license terms of these independent
- modules, and to copy and distribute the resulting executable under
- terms of your choice, provided that you also meet, for each linked
- independent module, the terms and conditions of the license of that
- module. An independent module is a module which is not derived from
- or based on this library. If you modify this library, you may extend
- this exception to your version of the library, but you are not
- obligated to do so. If you do not wish to do so, delete this
- exception statement from your version. */
- 
- package java.lang;
- 
- import gnu.gcj.runtime.NameFinder;
- 
- /**
- * VM dependant state and support methods Throwabele.
- * It is deliberately package local and final and should only be accessed
- * by the Throwable class.
- * <p>
- * This is the version used by libgcj (http://gcc.gnu.org/java/).
- *
- * @author Mark Wielaard (mark@klomp.org)
- */
- final class VMThrowable
- {
- private gnu.gcj.RawData stackTraceAddrs;
- private int length;
- 
- /**
- * Private contructor, create VMThrowables with fillInStackTrace();
- */
- private VMThrowable() { }
- 
- /**
- * Fill in the stack trace with the current execution stack.
- * Called by <code>Throwable.fillInStackTrace()</code> to get the state of
- * the VM. Can return null when the VM does not support caputing the VM
- * execution state.
- *
- * @return a new VMThrowable containing the current execution stack trace.
- * @see Throwable#fillInStackTrace()
- */
- static native VMThrowable fillInStackTrace(Throwable t);
- 
- /**
- * Returns an <code>StackTraceElement</code> array based on the execution
- * state of the VM as captured by <code>fillInStackTrace</code>.
- * Called by <code>Throwable.getStackTrace()</code>.
- *
- * @return a non-null but possible zero length array of StackTraceElement.
- * @see Throwable#getStackTrace()
- */
- StackTraceElement[] getStackTrace(Throwable t)
- {
- StackTraceElement[] result;
- if (stackTraceAddrs != null)
- {
- 	NameFinder nameFinder = new NameFinder();
- 	result = nameFinder.lookup(t, stackTraceAddrs, length);
- 	nameFinder.close();
- }
- else
- result = new StackTraceElement[0];
- 
- return result;
- }
- 
- // Setting this flag to false prevents fillInStackTrace() from running.
- static boolean trace_enabled = true;
- }
--- 0 ----
Index: java/lang/natClass.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/natClass.cc,v
retrieving revision 1.55
diff -p -2 -c -r1.55 natClass.cc
*** java/lang/natClass.cc	10 Nov 2002 21:07:27 -0000	1.55
--- java/lang/natClass.cc	29 Nov 2002 23:50:35 -0000
*************** details. */
*** 37,40 ****
--- 37,41 ----
 #include <java/lang/IllegalArgumentException.h>
 #include <java/lang/IncompatibleClassChangeError.h>
+ #include <java/lang/ArrayIndexOutOfBoundsException.h>
 #include <java/lang/InstantiationException.h>
 #include <java/lang/NoClassDefFoundError.h>
*************** details. */
*** 48,52 ****
--- 49,56 ----
 #include <java/lang/SecurityManager.h>
 #include <java/lang/StringBuffer.h>
+ #include <gnu/gcj/runtime/StackTrace.h>
 #include <gcj/method.h>
+ #include <gnu/gcj/runtime/MethodRef.h>
+ #include <gnu/gcj/RawData.h>
 
 #include <java-cpool.h>
*************** java::lang::Class::forName (jstring clas
*** 72,76 ****
 throw new java::lang::ClassNotFoundException (className);
 
- // FIXME: should use bootstrap class loader if loader is null.
 jclass klass = (buffer[0] == '[' 
 		 ? _Jv_FindClassFromSignature (name->data, loader)
--- 76,79 ----
*************** jclass
*** 89,94 ****
 java::lang::Class::forName (jstring className)
 {
! // FIXME: should use class loader from calling method.
! return forName (className, true, NULL);
 }
 
--- 92,112 ----
 java::lang::Class::forName (jstring className)
 {
! java::lang::ClassLoader *loader = NULL;
! gnu::gcj::runtime::StackTrace *t 
! = new gnu::gcj::runtime::StackTrace(4);
! java::lang::Class *klass = NULL;
! try
! {
! for (int i=1; !klass; i++)
! 	{
! 	 klass = t->classAt (i);
! 	}
! loader = klass->getClassLoader();
! }
! catch (::java::lang::ArrayIndexOutOfBoundsException *e)
! {
! }
! 
! return forName (className, true, loader);
 }
 
*************** _Jv_CheckArrayStore (jobject arr, jobjec
*** 1041,1044 ****
--- 1059,1064 ----
 JvAssert (arr != NULL);
 jclass elt_class = (JV_CLASS (arr))->getComponentType();
+ if (elt_class == &java::lang::Object::class$)
+ 	return;
 jclass obj_class = JV_CLASS (obj);
 if (__builtin_expect 
Index: java/lang/natClassLoader.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/natClassLoader.cc,v
retrieving revision 1.52
diff -p -2 -c -r1.52 natClassLoader.cc
*** java/lang/natClassLoader.cc	11 Oct 2002 22:10:37 -0000	1.52
--- java/lang/natClassLoader.cc	29 Nov 2002 23:50:35 -0000
*************** details. */
*** 41,44 ****
--- 41,45 ----
 #include <java/io/Serializable.h>
 #include <java/lang/Cloneable.h>
+ #include <java/util/HashMap.h>
 
 /////////// java.lang.ClassLoader native methods ////////////
*************** _Jv_PrepareCompiledClass (jclass klass)
*** 327,330 ****
--- 328,333 ----
 
 klass->notifyAll ();
+ 
+ _Jv_PushClass (klass);
 }
 
*************** _Jv_InitNewClassFields (jclass ret)
*** 588,591 ****
--- 591,596 ----
 ret->idt = NULL;
 ret->arrayclass = NULL;
+ ret->protectionDomain = NULL;
+ ret->chain = NULL;
 }
 
*************** _Jv_NewArrayClass (jclass element, java:
*** 732,734 ****
--- 737,767 ----
 
 element->arrayclass = array_class;
+ }
+ 
+ static jclass stack_head;
+ 
+ // These two functions form a stack of classes. When a class is loaded
+ // it is pushed onto the stack by the class loader; this is so that
+ // StackTrace can quickly determine which classes have been loaded.
+ 
+ jclass
+ _Jv_PopClass (void)
+ {
+ JvSynchronize sync (&java::lang::Class::class$);
+ if (stack_head)
+ {
+ jclass tmp = stack_head;
+ stack_head = tmp->chain;
+ return tmp;
+ }
+ return NULL;
+ }
+ 
+ void
+ _Jv_PushClass (jclass k)
+ {
+ JvSynchronize sync (&java::lang::Class::class$);
+ jclass tmp = stack_head;
+ stack_head = k;
+ k->chain = tmp;
 }
Index: java/lang/natVMThrowable.cc
===================================================================
RCS file: java/lang/natVMThrowable.cc
diff -N java/lang/natVMThrowable.cc
*** java/lang/natVMThrowable.cc	10 Nov 2002 21:07:27 -0000	1.4
--- /dev/null	1 Jan 1970 00:00:00 -0000
***************
*** 1,97 ****
- // natVMThrowable.cc - native helper methods for Throwable
- 
- /* Copyright (C) 2000, 2002 Free Software Foundation, Inc
- 
- This file is part of libgcj.
- 
- This software is copyrighted work licensed under the terms of the
- Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
- details. */
- 
- /**
- * @author Andrew Haley <aph@cygnus.com>
- * @author Mark Wielaard <mark@klomp.org>
- *
- * Native helper methods for VM specific Throwable support.
- */
- 
- #include <config.h>
- 
- #include <string.h>
- 
- #include <jvm.h>
- #include <gcj/cni.h>
- #include <gnu/gcj/RawData.h>
- #include <java/lang/Object.h>
- #include <java-threads.h>
- #include <java/lang/Throwable.h>
- #include <java/lang/VMThrowable.h>
- #include <java/lang/Thread.h>
- #include <java-interp.h>
- 
- #include <sys/types.h>
- 
- #include <stdlib.h>
- 
- #include <unistd.h>
- 
- #ifdef HAVE_EXECINFO_H
- #include <execinfo.h>
- #endif
- 
- /* 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. */
- 
- java::lang::VMThrowable *
- java::lang::VMThrowable::fillInStackTrace (java::lang::Throwable*)
- {
- if (! trace_enabled)
- return NULL;
- #if defined (HAVE_BACKTRACE)
- VMThrowable* state = new VMThrowable;
- void *p[128];
- 
- // We subtract 1 from the number of elements because we don't want
- // to include the calls to fillInStackTrace in the trace.
- int n = backtrace (p, 128) - 1; 
- 
- _Jv_frame_info *addrs;
- if (n > 0)
- {
- #ifdef INTERPRETER
- extern void _Jv_StartOfInterpreter (void);
- extern void _Jv_EndOfInterpreter (void);
- 
- java::lang::Thread *thread = java::lang::Thread::currentThread();
- _Jv_MethodChain *interp_frame
- 	= (thread ? reinterpret_cast<_Jv_MethodChain *> (thread->interp_frame)
- 	 : NULL);
- #endif // INTERPRETER
- 
- state->length = n;
- int len = n;
- addrs = (_Jv_frame_info *) _Jv_Malloc (n * sizeof (_Jv_frame_info));
- for (n = 0; n < len; n++)
- 	{
- 	 addrs[n].addr = p[n];
- #ifdef INTERPRETER
- 	 if (p[n] >= &_Jv_StartOfInterpreter && p[n] <= &_Jv_EndOfInterpreter)
- 	 {
- 	 addrs[n].interp = (void *) interp_frame->self;
- 	 interp_frame = interp_frame->next;
- 	 }
- 	 else
- 	 addrs[n].interp = 0;
- #endif // INTERPRETER
- 	}
- }
- else
- addrs = NULL;
- 
- state->stackTraceAddrs = reinterpret_cast<gnu::gcj::RawData *> (addrs);
- 
- return state;
- #endif
- return NULL;
- }
--- 0 ----
Index: java/class.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/class.c,v
retrieving revision 1.138
diff -u -r1.138 class.c
--- java/class.c 18 Nov 2002 15:46:31 -0000 1.138
+++ java/class.c 29 Nov 2002 17:54:47 -0000
@@ -1665,6 +1665,7 @@
 PUSH_FIELD_VALUE (cons, "idt", null_pointer_node);
 PUSH_FIELD_VALUE (cons, "arrayclass", null_pointer_node);
 PUSH_FIELD_VALUE (cons, "protectionDomain", null_pointer_node);
+ PUSH_FIELD_VALUE (cons, "chain", null_pointer_node);
 
 FINISH_RECORD_CONSTRUCTOR (cons);
 
Index: java/decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/decl.c,v
retrieving revision 1.137
diff -u -r1.137 decl.c
--- java/decl.c 18 Nov 2002 18:13:33 -0000 1.137
+++ java/decl.c 29 Nov 2002 17:54:48 -0000
@@ -708,6 +708,7 @@
 PUSH_FIELD (class_type_node, field, "idt", ptr_type_node); 
 PUSH_FIELD (class_type_node, field, "arrayclass", ptr_type_node); 
 PUSH_FIELD (class_type_node, field, "protectionDomain", ptr_type_node);
+ PUSH_FIELD (class_type_node, field, "chain", ptr_type_node);
 for (t = TYPE_FIELDS (class_type_node); t != NULL_TREE; t = TREE_CHAIN (t))
 FIELD_PRIVATE (t) = 1;
 push_super_field (class_type_node, object_type_node);


More information about the Java mailing list

AltStyle によって変換されたページ (->オリジナル) /