Stack traces, etc.

Andrew Haley aph@redhat.com
Mon Dec 2 12:27:00 GMT 2002


Revised, VMThrowable reinstated, testing now.  Checkin tomorrow unless
anyone complains.

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 -w -p -2 -c -r1.261 Makefile.am
*** Makefile.am	21 Nov 2002 10:45:12 -0000	1.261
--- Makefile.am	2 Dec 2002 20:23:07 -0000
*************** gnu/gcj/runtime/FinalizerThread.java \
*** 1721,1726 ****
--- 1721,1728 ----
  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 ****
--- 2319,2323 ----
  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 \
--- 2338,2341 ----
Index: prims.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/prims.cc,v
retrieving revision 1.74
diff -w -p -2 -c -r1.74 prims.cc
*** prims.cc	2 Nov 2002 21:33:30 -0000	1.74
--- prims.cc	2 Dec 2002 20:23:10 -0000
*************** _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);
Index: verify.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/verify.cc,v
retrieving revision 1.45
diff -w -p -2 -c -r1.45 verify.cc
*** verify.cc	27 Nov 2002 05:59:39 -0000	1.45
--- verify.cc	2 Dec 2002 20:23:11 -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: 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	2 Dec 2002 20:23:11 -0000
***************
*** 0 ****
--- 1,25 ----
+ // gnu.gcj.runtime.MethodRef -- used by StackTrace.
+ 
+ /* Copyright (C) 2002  Free Software Foundation
+ 
+    This file is part of libgcj.
+ 
+ This software is copyrighted work licensed under the terms of the
+ Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
+ details.  */
+ 
+ package gnu.gcj.runtime;
+ 
+ import gnu.gcj.RawData;
+ 
+ class MethodRef
+ {
+   MethodRef(RawData /* Actually _Jv_Method */ m, Class k)
+   {
+     klass = k;
+     method = m;
+   }
+ 
+   public RawData method; // Actually a raw pointer to _Jv_Method
+   public Class klass;
+ }
Index: gnu/gcj/runtime/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	2 Dec 2002 20:23:11 -0000
***************
*** 0 ****
--- 1,164 ----
+ /* gnu.gcj.runtime.StackTrace -- VM support methods for walking the
+    stack.
+    Copyright (C) 1998, 1999, 2002 Free Software Foundation, Inc.
+ 
+ This file is part of GNU Classpath.
+ 
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+ 
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ General Public License for more details.
+ 
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING.  If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA.
+ 
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library.  Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+ 
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module.  An independent module is a module which is not derived from
+ or based on this library.  If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so.  If you do not wish to do so, delete this
+ exception statement from your version. */
+ 
+ package gnu.gcj.runtime;
+ 
+ import gnu.gcj.RawData;
+ import java.util.TreeMap;
+ import java.util.IdentityHashMap;
+ import java.util.SortedMap;
+ import gnu.gcj.runtime.NameFinder;
+ import java.util.NoSuchElementException;
+ 
+ /**
+  * VM dependent state and support methods for walking the stack.
+  * <p>
+  * This is the version used by libgcj (http://gcc.gnu.org/java/).
+  *
+  * @author Mark Wielaard (mark@klomp.org)
+  * @author Andrew Haley (aph@redhat.com)
+  */
+ public final class StackTrace
+ {
+   /**
+    * Fill in the stack trace with the top n frames on current
+    * execution stack.  Can return null if the VM does not support
+    * capturing the VM execution state.
+    *
+    * @see Throwable#fillInStackTrace()
+    */
+   public StackTrace(int n)
+   {
+     fillInStackTrace(n, 1);
+   }
+ 
+   /**
+    * Fill in the stack trace with state of the entire execution stack,
+    * starting from frame <code>offset</code>.  Can return null if the
+    * VM does not support capturing the VM execution state.
+    *
+    * This can be very expensive.  If you only want part of the stack,
+    * see <code>Throwable.fillInStackTrace(int)</code>
+    *
+    * @see Throwable#fillInStackTrace()
+    */
+   public StackTrace()
+   {
+     int n = 64;
+     
+     do
+       {
+ 	n *= 4;
+ 	fillInStackTrace(n, 1);
+       }
+     while (len >= n);
+   }
+ 
+   /**
+    * Return the class containing the execution point represented by
+    * the Nth frame down the stack.  The zeroth frame represents the
+    * top of the stack, which is the method that called classAt().
+    *
+    * If the Nth frame down the stack was not create by a method
+    * invocation, return null.
+    *
+    * It is not necessary to call <code>fillInStackTrace()</code> with
+    * a size greater than N before calling this method; if the current
+    * stack trace is insufficiently large, it will be expanded as
+    * required.  This requires some caution if
+    * <code>fillInStackTrace()</code> is called from a different
+    * invocation to the one that calls <code>classAt()</code>.
+    * classAt() will not call <code>fillInStackTrace()</code> unless N
+    * is greater than the current length.
+    *
+    */
+   public native Class classAt(int n);
+ 
+   /**
+    * Return the name of the method containing the execution point
+    * represented by the Nth frame down the stack.  The zeroth frame
+    * represents the top of the stack, which is the method that called
+    * classAt().
+    *
+    * If the Nth frame down the stack was not create by a method
+    * invocation, return null.
+    *
+    * It is not necessary to call <code>fillInStackTrace()</code> with
+    * a size greater than N before calling this method; if the current
+    * stack trace is insufficiently large, it will be expanded as
+    * required.  This requires some caution if
+    * <code>fillInStackTrace()</code> is called from a different
+    * invocation to the one that calls <code>classAt()</code>.
+    * classAt() will not call <code>fillInStackTrace()</code> unless N
+    * is greater than the current length.
+    *
+    */
+   public native String methodAt(int n);
+ 
+   /**
+    * Return the length of this stack trace.
+    *
+    */
+   public int length ()
+   {
+     return len;
+   }
+ 
+   private static native void update();
+   private static MethodRef methodAtAddress(RawData addr)
+   {
+     update();
+     synchronized (map)
+       {
+ 	return (MethodRef) map.get (addr);
+       }
+   }
+ 
+   gnu.gcj.RawData stackTraceAddrs()
+   {
+     return addrs;
+   }
+   
+   private native void fillInStackTrace(int n, int offset);
+ 
+   private static native MethodRef getCompiledMethodRef(RawData addr);
+   private static IdentityHashMap map = new IdentityHashMap();
+ 
+   private gnu.gcj.RawData addrs;
+   private int len;
+ }
Index: gnu/gcj/runtime/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	2 Dec 2002 20:23:11 -0000
***************
*** 0 ****
--- 1,194 ----
+ // 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>
+ 
+ 
+ // Fill in this stack trace with N elements starting at offset.
+ void
+ gnu::gcj::runtime::StackTrace::fillInStackTrace (jint maxlen, jint offset)
+ {
+ #if defined (HAVE_BACKTRACE)
+   offset += 1;
+   void *_p[maxlen + offset];
+   len = backtrace (_p, maxlen + offset) - offset;
+   void **p = _p + offset;
+ #endif
+   _Jv_frame_info *frame;
+   if (len > 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
+ 
+       frame = (_Jv_frame_info *) _Jv_Malloc (len * sizeof (_Jv_frame_info));
+       for (int n = 0; n < len; n++)
+ 	{
+ 	  frame[n].addr = p[n];
+ #ifdef INTERPRETER
+ 	  if (p[n] >= &_Jv_StartOfInterpreter && p[n] <= &_Jv_EndOfInterpreter)
+ 	    {
+ 	      frame[n].interp = (void *) interp_frame->self;
+ 	      interp_frame = interp_frame->next;
+ 	    }
+ 	  else
+ 	    frame[n].interp = 0;
+ #endif // INTERPRETER
+ 	}
+     }
+   else
+     frame = NULL;
+ 
+   addrs = reinterpret_cast<gnu::gcj::RawData *> (frame);
+ }
+ 
+ /* Obtain the next power-of-2 of some integer.  */
+ static inline jint
+ nextpowerof2 (jint n)
+ {
+   n |= (n >> 1);
+   n |= (n >> 2);
+   n |= (n >> 4);
+   n |= (n >> 8);
+   n |= (n >> 16);
+   return n+1;
+ }
+ 
+ #define GET_FRAME(N)						\
+ ({								\
+   if ((N) >= len)						\
+     fillInStackTrace (nextpowerof2 (N), 1);			\
+   if ((N) < 0 || (N) >= len)					\
+     throw new ::java::lang::ArrayIndexOutOfBoundsException ();	\
+ 								\
+   _Jv_frame_info *frame = (_Jv_frame_info *)addrs;		\
+   &frame[N];							\
+ })
+ 
+ gnu::gcj::runtime::MethodRef *
+ gnu::gcj::runtime::StackTrace::getCompiledMethodRef (gnu::gcj::RawData *addr)
+ {
+   void *p = _Unwind_FindEnclosingFunction (addr);
+   return gnu::gcj::runtime::StackTrace
+     ::methodAtAddress ((gnu::gcj::RawData *)p);
+ }
+ 
+ java::lang::Class *
+ gnu::gcj::runtime::StackTrace::classAt (jint n)
+ {
+   _Jv_frame_info *frame = GET_FRAME (n);
+ 
+ #ifdef INTERPRETER
+   if (frame->interp)
+     {
+       _Jv_InterpMethod *meth
+ 	= reinterpret_cast<_Jv_InterpMethod *> (frame->interp);
+       return meth->defining_class;
+     }
+ #endif // INTERPRETER
+   
+   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 (n);
+   _Jv_Method *meth = NULL;
+ 
+ #ifdef INTERPRETER
+   if (frame->interp)
+     {
+       meth
+ 	= reinterpret_cast<_Jv_InterpMethod *> (frame->interp)
+ 	->get_method();
+     }
+ #endif // INTERPRETER
+   
+   if (! meth)
+     {
+       gnu::gcj::runtime::MethodRef *ref
+ 	= getCompiledMethodRef ((gnu::gcj::RawData *)frame->addr);
+       if (ref)
+ 	meth = (_Jv_Method *)ref->method;
+     }
+ 
+   return meth 
+     ? _Jv_NewStringUtf8Const (meth->name)
+     : NULL ;
+ }
+ 
+ void
+ gnu::gcj::runtime::StackTrace::update(void)
+ {
+   jclass klass;
+ 
+   while ((klass = _Jv_PopClass ()))
+     {
+       for (int i=0; i<klass->method_count; i++)
+ 	{
+ 	  JvSynchronize sync (map);
+ 	  _Jv_Method *meth = &(klass->methods[i]);
+ 	  if (meth->ncode) // i.e. if p is not abstract
+ 	    {
+ 	      gnu::gcj::runtime::MethodRef *ref
+ 		= new gnu::gcj::runtime::MethodRef 
+ 		((gnu::gcj::RawData *)meth, klass);
+ 	      map->put ((java::lang::Object*)(meth->ncode), ref);
+ 	    }
+ 	}
+     }
+ }
+ 
+ 
Index: include/java-interp.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/include/java-interp.h,v
retrieving revision 1.18
diff -w -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	2 Dec 2002 20:23:12 -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 -w -p -2 -c -r1.50 Class.h
*** java/lang/Class.h	4 Nov 2002 02:45:31 -0000	1.50
--- java/lang/Class.h	2 Dec 2002 20:23:12 -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/VMThrowable.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/VMThrowable.java,v
retrieving revision 1.1
diff -w -p -2 -c -r1.1 VMThrowable.java
*** java/lang/VMThrowable.java	24 Aug 2002 22:46:19 -0000	1.1
--- java/lang/VMThrowable.java	2 Dec 2002 20:23:12 -0000
*************** package java.lang;
*** 39,45 ****
  
  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.
--- 39,46 ----
  
  import gnu.gcj.runtime.NameFinder;
+ import gnu.gcj.runtime.StackTrace;
  
  /**
!  * VM dependent state and support methods Throwable.
   * It is deliberately package local and final and should only be accessed
   * by the Throwable class.
*************** import gnu.gcj.runtime.NameFinder;
*** 51,56 ****
  final class VMThrowable
  {
!   private gnu.gcj.RawData stackTraceAddrs;
!   private int length;
  
    /**
--- 52,56 ----
  final class VMThrowable
  {
!   private gnu.gcj.runtime.StackTrace trace;
  
    /**
*************** final class VMThrowable
*** 68,72 ****
     * @see Throwable#fillInStackTrace()
     */
!   static native VMThrowable fillInStackTrace(Throwable t);
  
    /**
--- 68,85 ----
     * @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;
!   }
  
    /**
*************** final class VMThrowable
*** 81,88 ****
    {
      StackTraceElement[] result;
!     if (stackTraceAddrs != null)
        {
  	NameFinder nameFinder = new NameFinder();
! 	result = nameFinder.lookup(t, stackTraceAddrs, length);
  	nameFinder.close();
        }
--- 94,102 ----
    {
      StackTraceElement[] result;
!     if (trace != null)
        {
  	NameFinder nameFinder = new NameFinder();
! 	result = nameFinder.lookup(t, trace.stackTraceAddrs(), 
! 				   trace.length());
  	nameFinder.close();
        }
Index: java/lang/natClass.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/natClass.cc,v
retrieving revision 1.55
diff -w -p -2 -c -r1.55 natClass.cc
*** java/lang/natClass.cc	10 Nov 2002 21:07:27 -0000	1.55
--- java/lang/natClass.cc	2 Dec 2002 20:23:13 -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 -w -p -2 -c -r1.52 natClassLoader.cc
*** java/lang/natClassLoader.cc	11 Oct 2002 22:10:37 -0000	1.52
--- java/lang/natClassLoader.cc	2 Dec 2002 20:23:13 -0000
*************** _Jv_PrepareCompiledClass (jclass klass)
*** 327,330 ****
--- 327,332 ----
  
    klass->notifyAll ();
+ 
+   _Jv_PushClass (klass);
  }
  
*************** _Jv_InitNewClassFields (jclass ret)
*** 588,591 ****
--- 590,595 ----
    ret->idt = NULL;
    ret->arrayclass = NULL;
+   ret->protectionDomain = NULL;
+   ret->chain = NULL;
  }
  
*************** _Jv_NewArrayClass (jclass element, java:
*** 732,734 ****
--- 736,766 ----
  
    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 ----



More information about the Java mailing list