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


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

RFC Patch: garbage free StackTrace methods


I recently noticed that we allocate new StackTrace objects for each
class.forName() when we're looking for a class loader.  Allocating a
StackTrace object involves a couple more allocations as well.   But a
quick look at the code tells us that we can get the same thing done with
no allocations.

This patch also postpones the potentially expensive
Thread.currentThread() call until we know we actually need it (when
unwinding interpreted frames).

Neither change results in earth shattering improvements - but I found
measurable improvements in memory usage with ecj (100k smaller heap
during large compile).

Here's my first go...

AG


2004-02-26  Anthony Green  <green@redhat.com>

	* gnu/gcj/runtime/natStackTrace.cc (firstClass): New method.
	* gnu/gcj/runtime/StackTrace.cc (firstClass): Ditto.
	* java/lang/natClass.cc (forName): Use it.
	(getClassLoader): Ditto.


Index: gnu/gcj/runtime/StackTrace.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gnu/gcj/runtime/StackTrace.java,v
retrieving revision 1.3
diff -c -p -r1.3 StackTrace.java
*** gnu/gcj/runtime/StackTrace.java	2 Oct 2003 07:10:34 -0000	1.3
--- gnu/gcj/runtime/StackTrace.java	27 Feb 2004 00:11:16 -0000
*************** public final class StackTrace
*** 156,161 ****
--- 156,163 ----
      return addrs;
    }
    
+   public static native Class firstClass(int maxdepth);
+ 
    private native void fillInStackTrace(int n, int offset);
    protected native void finalize();
  
Index: gnu/gcj/runtime/natStackTrace.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gnu/gcj/runtime/natStackTrace.cc,v
retrieving revision 1.6
diff -c -p -r1.6 natStackTrace.cc
*** gnu/gcj/runtime/natStackTrace.cc	2 Oct 2003 07:10:34 -0000	1.6
--- gnu/gcj/runtime/natStackTrace.cc	27 Feb 2004 00:11:16 -0000
*************** details.  */
*** 44,49 ****
--- 44,95 ----
  
  #include <unwind.h>
  
+ // Find the first class on the stack.
+ jclass
+ gnu::gcj::runtime::StackTrace::firstClass (jint maxdepth)
+ {
+   jclass clazz = NULL;
+ 
+   // Initialize this class, just in case it hasn't been done yet.
+   _Jv_InitClass (&gnu::gcj::runtime::StackTrace::class$);
+ 
+ #ifdef HAVE_BACKTRACE
+   maxdepth += 2;
+   void *_p[maxdepth];
+   int length = backtrace (_p, maxdepth) - 1;
+   void **p = &_p[1];
+   if (length > 0)
+     {
+ #ifdef INTERPRETER
+       extern void _Jv_StartOfInterpreter (void);
+       extern void _Jv_EndOfInterpreter (void);
+ #endif // INTERPRETER
+       for (int n = 0; clazz == NULL && n < length; n++)
+ 	{
+ #ifdef INTERPRETER
+ 	  if (p[n] >= &_Jv_StartOfInterpreter && p[n] <=
&_Jv_EndOfInterpreter)
+ 	    {
+ 	      java::lang::Thread *thread =
java::lang::Thread::currentThread();
+ 	      if (thread)
+ 		{
+ 		  return 
+ 		    (reinterpret_cast<_Jv_MethodChain *> 
+ 		     (thread->interp_frame))->self->defining_class;
+ 		}
+ 	      else
+ 		{
+ 		  // Is this even possible?  Keep looking for now.
+ 		}
+ 	    }
+ #endif // INTERPRETER
+ 	  clazz = getClass ((gnu::gcj::RawData *) p[n]);
+ 	}
+     }
+ #else // HAVE_BACKTRACE
+   (void)maxdepth;
+ #endif // HAVE_BACKTRACE
+   return clazz;
+ }
  
  // Fill in this stack trace with MAXLEN elements starting at offset.
  void
*************** gnu::gcj::runtime::StackTrace::fillInSta
*** 61,70 ****
        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));
--- 107,115 ----
        extern void _Jv_StartOfInterpreter (void);
        extern void _Jv_EndOfInterpreter (void);
  
!       int have_thread = 0;
!       java::lang::Thread *thread = NULL;
!       _Jv_MethodChain *interp_frame;
  #endif // INTERPRETER
  
        frame = (_Jv_frame_info *) _Jv_Malloc (len * sizeof
(_Jv_frame_info));
*************** gnu::gcj::runtime::StackTrace::fillInSta
*** 74,79 ****
--- 119,133 ----
  #ifdef INTERPRETER
  	  if (p[n] >= &_Jv_StartOfInterpreter && p[n] <=
&_Jv_EndOfInterpreter)
  	    {
+ 	      if (! have_thread)
+ 		{
+ 		  thread = java::lang::Thread::currentThread();
+ 		  interp_frame = 
+ 		    (thread ? 
+ 		     reinterpret_cast<_Jv_MethodChain *> (thread->interp_frame)
+ 		     : NULL);
+ 		  have_thread = 1;
+ 		}
  	      frame[n].interp = (void *) interp_frame->self;
  	      interp_frame = interp_frame->next;
  	    }
Index: java/lang/natClass.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/natClass.cc,v
retrieving revision 1.74
diff -c -p -r1.74 natClass.cc
*** java/lang/natClass.cc	3 Dec 2003 21:26:59 -0000	1.74
--- java/lang/natClass.cc	27 Feb 2004 00:11:17 -0000
*************** jclass
*** 95,115 ****
  java::lang::Class::forName (jstring className)
  {
    java::lang::ClassLoader *loader = NULL;
!   gnu::gcj::runtime::StackTrace *t 
!     = new gnu::gcj::runtime::StackTrace(4);
!   java::lang::Class *klass = NULL;
!   try
!     {
!       for (int i = 1; !klass; i++)
! 	{
! 	  klass = t->classAt (i);
! 	}
!       loader = klass->getClassLoaderInternal();
!     }
!   catch (::java::lang::ArrayIndexOutOfBoundsException *e)
!     {
!     }
! 
    return forName (className, true, loader);
  }
  
--- 95,103 ----
  java::lang::Class::forName (jstring className)
  {
    java::lang::ClassLoader *loader = NULL;
!   java::lang::Class *klass = gnu::gcj::runtime::StackTrace::firstClass
(4);
!   if (klass)
!     loader = klass->getClassLoaderInternal();
    return forName (className, true, loader);
  }
  
*************** java::lang::Class::getClassLoader (void)
*** 119,139 ****
    java::lang::SecurityManager *s =
java::lang::System::getSecurityManager();
    if (s != NULL)
      {
-       gnu::gcj::runtime::StackTrace *t 
- 	= new gnu::gcj::runtime::StackTrace(4);
-       Class *caller = NULL;
        ClassLoader *caller_loader = NULL;
!       try
! 	{
! 	  for (int i = 1; !caller; i++)
! 	    {
! 	      caller = t->classAt (i);
! 	    }
! 	  caller_loader = caller->getClassLoaderInternal();
! 	}
!       catch (::java::lang::ArrayIndexOutOfBoundsException *e)
! 	{
! 	}
  
        // If the caller has a non-null class loader, and that loader
        // is not this class' loader or an ancestor thereof, then do a
--- 107,116 ----
    java::lang::SecurityManager *s =
java::lang::System::getSecurityManager();
    if (s != NULL)
      {
        ClassLoader *caller_loader = NULL;
!       Class *caller = gnu::gcj::runtime::StackTrace::firstClass (4);
!       if (caller)
! 	caller_loader = caller->getClassLoaderInternal();
  
        // If the caller has a non-null class loader, and that loader
        // is not this class' loader or an ancestor thereof, then do a




-- 
Anthony Green <green@redhat.com>
Red Hat, Inc.


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