This is the mail archive of the java-patches@sources.redhat.com 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]

Re: Speed up array allocation


Tom Tromey wrote:

> Bryce> Perhaps we need to special case array classes in the reflection
> Bryce> code? Methods for an array class always == methods for object
> Bryce> class.
>
> That would certainly work.  It requires changing a lot of places in
> natClass.cc, at least, though.  I imagine it will end up being a
> fairly ugly change.

Actually, no changes are required. Thats because "method_count" is still
0, so the reflection code never attempts to dereference our overloaded
methods field (which is fine because arrays have no methods other than
those inherited from Object). When testing it I did find a reflection bug
however - this is incorporated into the new version of the patch below,
along with some optimizations for interface dispatch stuff and an
optimized _Jv_NewObjectArray. I'm checking this in now.

regards

  [ bryce ]


2001-01-08  Bryce McKinlay  <bryce@albatross.co.nz>

	* java/lang/Class.h (_Jv_InitClass): Use __builtin_expect.
	(_Jv_NewArrayClass): Renamed from _Jv_FindArrayClass.
	(_Jv_GetArrayClass): New inline function.
	(arrayclass): New field.
	* prims.cc (_Jv_NewObjectArray): Use _Jv_GetArrayClass. Don't use
	_Jv_GetArrayElementFromElementType. 
	(_Jv_NewPrimArray): Ditto.
	(_Jv_PrimClass constructor): Initialize "depth", "ancestors", and
	"idt" for completeness. Initialze "arrayclass" using _Jv_NewArrayClass.
	Set Modifier::ABSTRACT.
	* java/lang/natClassLoader.cc (_Jv_NewClass): Initialize "arrayclass".
	(_Jv_NewArrayClass): Renamed from _Jv_FindArrayClass. Now void. 
	Now synchronized. Array classes are now referenced from
	elementClass->arrayclass. Don't use _Jv_FindClassInCache.
	Set array classes' accessibility flags correctly. Optimize so that
	all array classes share the same IDT.
	* java/lang/reflect/natArray.cc (newInstance): Use _Jv_GetArrayClass.
	* java/lang/reflect/natMethod.cc (_Jv_GetTypesFromSignature): Ditto.
	* java/lang/natClass.cc (_getFields): Increment offset. Prevent fields
	in superclasses from overwriting classes own fields.
	(_Jv_IsAssignableFrom): Check for NULL source idt instead of calling
	Modifier::isAbstract().
	(null_idt): New static field.
	(_Jv_PrepareConstantTimeTables): Optimize case where class implements
	no interfaces.
	(_Jv_IndexOf): Made inline.
	* boehm.cc (_Jv_MarkObj): Mark "arrayclass" field.


Index: java/lang/Class.h
===================================================================
RCS file: /cvs/gcc/egcs/libjava/java/lang/Class.h,v
retrieving revision 1.27
diff -u -r1.27 Class.h
--- Class.h	2000/11/26 03:58:55	1.27
+++ Class.h	2001/01/08 23:08:40
@@ -210,7 +210,7 @@
   inline friend void 
   _Jv_InitClass (jclass klass)
   {
-    if (klass->state == JV_STATE_DONE)
+    if (__builtin_expect (klass->state == JV_STATE_DONE, true))
       return;
     klass->initializeClass ();  
   }
@@ -254,9 +254,9 @@
 			       java::lang::ClassLoader *loader);
   friend jclass _Jv_FindClassInCache (_Jv_Utf8Const *name,
 				      java::lang::ClassLoader *loader);
-  friend jclass _Jv_FindArrayClass (jclass element,
-				    java::lang::ClassLoader *loader,
-				    _Jv_VTable *array_vtable = 0);
+  friend void _Jv_NewArrayClass (jclass element,
+				 java::lang::ClassLoader *loader,
+				 _Jv_VTable *array_vtable = 0);
   friend jclass _Jv_NewClass (_Jv_Utf8Const *name, jclass superclass,
 			      java::lang::ClassLoader *loader);
 
@@ -268,6 +268,16 @@
   friend jshort _Jv_AppendPartialITable (jclass, jclass, void **, jshort);
   friend jshort _Jv_FindIIndex (jclass *, jshort *, jshort);
 
+  // Return array class corresponding to element type KLASS, creating it if
+  // neccessary.
+  inline friend jclass
+  _Jv_GetArrayClass (jclass klass, java::lang::ClassLoader *loader)
+  {
+    if (__builtin_expect (!klass->arrayclass, false))
+      _Jv_NewArrayClass (klass, loader);
+    return klass->arrayclass;
+  }
+
 #ifdef INTERPRETER
   friend jboolean _Jv_IsInterpretedClass (jclass);
   friend void _Jv_InitField (jobject, jclass, _Jv_Field*);
@@ -302,8 +312,7 @@
   // Class constants.
   _Jv_Constants constants;
   // Methods.  If this is an array class, then this field holds a
-  // pointer to the element type.  If this is a primitive class, this
-  // is used to cache a pointer to the appropriate array type.
+  // pointer to the element type.
   _Jv_Method *methods;
   // Number of methods.  If this class is primitive, this holds the
   // character used to represent this type in a signature.
@@ -337,6 +346,8 @@
   jclass *ancestors;
   // Interface Dispatch Table.
   _Jv_IDispatchTable *idt;
+  // Pointer to the class that represents an array of this class.
+  jclass arrayclass;
 };
 
 #endif /* __JAVA_LANG_CLASS_H__ */
Index: java/lang/natClass.cc
===================================================================
RCS file: /cvs/gcc/egcs/libjava/java/lang/natClass.cc,v
retrieving revision 1.31
diff -u -r1.31 natClass.cc
--- natClass.cc	2000/12/28 04:33:53	1.31
+++ natClass.cc	2001/01/08 23:08:41
@@ -421,7 +421,7 @@
 	  rfield->offset = (char *) field - (char *) fields;
 	  rfield->declaringClass = this;
 	  rfield->name = _Jv_NewStringUtf8Const (field->name);
-	  (elements (result))[offset + i] = rfield;
+	  (elements (result))[offset++] = rfield;
 	}
     }
   jclass superclass = getSuperclass();
@@ -929,8 +929,7 @@
       // Abstract classes have no IDT, and IDTs provide no way to check
       // two interfaces for assignability.
       if (__builtin_expect 
-         (java::lang::reflect::Modifier::isAbstract (source->accflags)
-          || source->isInterface(), false))
+          (source->idt == NULL || source->isInterface(), false))
         return _Jv_InterfaceAssignableFrom (target, source);
 	
       _Jv_IDispatchTable *cl_idt = source->idt;
@@ -1007,6 +1006,8 @@
 #define INITIAL_IOFFSETS_LEN 4
 #define INITIAL_IFACES_LEN 4
 
+static _Jv_IDispatchTable null_idt = { {SHRT_MAX, 0, NULL} };
+
 // Generate tables for constant-time assignment testing and interface
 // method lookup. This implements the technique described by Per Bothner
 // <per@bothner.com> on the java-discuss mailing list on 1999-09-02:
@@ -1028,8 +1029,10 @@
   // interfaces or primitive types.
    
   jclass klass0 = klass;
+  jboolean has_interfaces = 0;
   while (klass0 != &ObjectClass)
     {
+      has_interfaces += klass0->interface_count;
       klass0 = klass0->superclass;
       klass->depth++;
     }
@@ -1051,6 +1054,14 @@
     
   if (java::lang::reflect::Modifier::isAbstract (klass->accflags))
     return;
+  
+  // Optimization: If klass implements no interfaces, use a common
+  // predefined interface table.
+  if (!has_interfaces)
+    {
+      klass->idt = &null_idt;
+      return;
+    }
 
   klass->idt = 
     (_Jv_IDispatchTable *) _Jv_Malloc (sizeof (_Jv_IDispatchTable));
@@ -1095,7 +1106,7 @@
 }
 
 // Return index of item in list, or -1 if item is not present.
-jshort
+inline jshort
 _Jv_IndexOf (void *item, void **list, jshort list_len)
 {
   for (int i=0; i < list_len; i++)
Index: java/lang/natClassLoader.cc
===================================================================
RCS file: /cvs/gcc/egcs/libjava/java/lang/natClassLoader.cc,v
retrieving revision 1.27
diff -u -r1.27 natClassLoader.cc
--- natClassLoader.cc	2000/10/06 01:49:31	1.27
+++ natClassLoader.cc	2001/01/08 23:08:41
@@ -530,26 +530,35 @@
   ret->depth = 0;
   ret->ancestors = NULL;
   ret->idt = NULL;
+  ret->arrayclass = NULL;
 
   _Jv_RegisterClass (ret);
 
   return ret;
 }
 
-jclass
-_Jv_FindArrayClass (jclass element, java::lang::ClassLoader *loader,
-		    _Jv_VTable *array_vtable)
+static _Jv_IDispatchTable *array_idt = NULL;
+static jshort array_depth = 0;
+static jclass *array_ancestors = NULL;
+
+// Create a class representing an array of ELEMENT and store a pointer to it
+// in element->arrayclass. LOADER is the ClassLoader which _initiated_ the 
+// instantiation of this array. ARRAY_VTABLE is the vtable to use for the new 
+// array class. This parameter is optional.
+void
+_Jv_NewArrayClass (jclass element, java::lang::ClassLoader *loader,
+		   _Jv_VTable *array_vtable)
 {
+  JvSynchronize sync (element);
+
   _Jv_Utf8Const *array_name;
   int len;
+
+  if (element->arrayclass)
+    return;
+
   if (element->isPrimitive())
-    {
-      // For primitive types the array is cached in the class.
-      jclass ret = (jclass) element->methods;
-      if (ret)
-	return ret;
-      len = 3;
-    }
+    len = 3;
   else
     len = element->name->length + 5;
 
@@ -557,7 +566,7 @@
     char signature[len];
     int index = 0;
     signature[index++] = '[';
-    // Compute name of array class to see if we've already cached it.
+    // Compute name of array class.
     if (element->isPrimitive())
       {
 	signature[index++] = (char) element->method_count;
@@ -576,65 +585,76 @@
     array_name = _Jv_makeUtf8Const (signature, index);
   }
 
-  jclass array_class = _Jv_FindClassInCache (array_name, element->loader);
-
-  if (! array_class)
+  // Create new array class.
+  jclass array_class = _Jv_NewClass (array_name, &ObjectClass,
+  				     element->loader);
+
+  // Note that `vtable_method_count' doesn't include the initial
+  // gc_descr slot.
+  JvAssert (ObjectClass.vtable_method_count == NUM_OBJECT_METHODS);
+  int dm_count = ObjectClass.vtable_method_count;
+
+  // Create a new vtable by copying Object's vtable (except the
+  // class pointer, of course).  Note that we allocate this as
+  // unscanned memory -- the vtables are handled specially by the
+  // GC.
+  int size = (sizeof (_Jv_VTable) + ((dm_count - 1) * sizeof (void *)));
+  _Jv_VTable *vtable;
+  if (array_vtable)
+    vtable = array_vtable;
+  else
+    vtable = (_Jv_VTable *) _Jv_AllocBytes (size);
+  vtable->clas = array_class;
+  memcpy (vtable->method, ObjectClass.vtable->method,
+	  dm_count * sizeof (void *));
+  vtable->gc_descr = ObjectClass.vtable->gc_descr;
+  array_class->vtable = vtable;
+  array_class->vtable_method_count = ObjectClass.vtable_method_count;
+
+  // Stash the pointer to the element type.
+  array_class->methods = (_Jv_Method *) element;
+
+  // Register our interfaces.
+  static jclass interfaces[] = { &CloneableClass, &SerializableClass };
+  array_class->interfaces = interfaces;
+  array_class->interface_count = sizeof interfaces / sizeof interfaces[0];
+
+  // Since all array classes have the same interface dispatch table, we can 
+  // cache one and reuse it. It is not neccessary to synchronize this.
+  if (!array_idt)
     {
-      // Create new array class.
-      array_class = _Jv_NewClass (array_name, &ObjectClass, element->loader);
-
-      // Note that `vtable_method_count' doesn't include the initial
-      // gc_descr slot.
-      JvAssert (ObjectClass.vtable_method_count == NUM_OBJECT_METHODS);
-      int dm_count = ObjectClass.vtable_method_count;
-
-      // Create a new vtable by copying Object's vtable (except the
-      // class pointer, of course).  Note that we allocate this as
-      // unscanned memory -- the vtables are handled specially by the
-      // GC.
-      int size = (sizeof (_Jv_VTable) + ((dm_count - 1) * sizeof (void *)));
-      _Jv_VTable *vtable;
-      if (array_vtable)
-	vtable = array_vtable;
-      else
-	vtable = (_Jv_VTable *) _Jv_AllocBytes (size);
-      vtable->clas = array_class;
-      memcpy (vtable->method, ObjectClass.vtable->method,
-	      dm_count * sizeof (void *));
-      vtable->gc_descr = ObjectClass.vtable->gc_descr;
-      array_class->vtable = vtable;
-      array_class->vtable_method_count = ObjectClass.vtable_method_count;
-
-      // Stash the pointer to the element type.
-      array_class->methods = (_Jv_Method *) element;
-
-      // Register our interfaces.
-      static jclass interfaces[] = { &CloneableClass, &SerializableClass };
-      array_class->interfaces = interfaces;
-      array_class->interface_count = sizeof interfaces / sizeof interfaces[0];
-
-      // FIXME: Shouldn't this be synchronized? _Jv_PrepareConstantTimeTables
-      // needs to be called with the mutex for array_class held.
-      // Generate the interface dispatch table.
       _Jv_PrepareConstantTimeTables (array_class);
-
-      // as per vmspec 5.3.3.2
-      array_class->accflags = element->accflags;
+      array_idt = array_class->idt;
+      array_depth = array_class->depth;
+      array_ancestors = array_class->ancestors;
+    }
+  else
+    {
+      array_class->idt = array_idt;
+      array_class->depth = array_depth;
+      array_class->ancestors = array_ancestors;
+    }
 
-      // FIXME: initialize other Class instance variables,
-      // e.g. `fields'.
+  using namespace java::lang::reflect;
+  {
+    // Array classes are "abstract final"...
+    _Jv_ushort accflags = Modifier::FINAL | Modifier::ABSTRACT;
+    // ... and inherit accessibility from element type, per vmspec 5.3.3.2
+    accflags |= (element->accflags & Modifier::PUBLIC);
+    accflags |= (element->accflags & Modifier::PROTECTED);
+    accflags |= (element->accflags & Modifier::PRIVATE);      
+    array_class->accflags = accflags;
+  }
 
-      // say this class is initialized and ready to go!
-      array_class->state = JV_STATE_DONE;
+  // An array class has no visible instance fields. "length" is invisible to 
+  // reflection.
 
-      // vmspec, section 5.3.3 describes this
-      if (element->loader != loader)
-	_Jv_RegisterInitiatingLoader (array_class, loader);
-    }
+  // say this class is initialized and ready to go!
+  array_class->state = JV_STATE_DONE;
 
-  // For primitive types, point back at this array.
-  if (element->isPrimitive())
-    element->methods = (_Jv_Method *) array_class;
+  // vmspec, section 5.3.3 describes this
+  if (element->loader != loader)
+    _Jv_RegisterInitiatingLoader (array_class, loader);
 
-  return array_class;
+  element->arrayclass = array_class;
 }
Index: prims.cc
===================================================================
RCS file: /cvs/gcc/egcs/libjava/prims.cc,v
retrieving revision 1.43
diff -u -r1.43 prims.cc
--- prims.cc	2000/12/22 06:19:23	1.43
+++ prims.cc	2001/01/08 23:08:41
@@ -394,19 +394,13 @@
 
   JvAssert (! elementClass->isPrimitive ());
 
+  // Ensure that elements pointer is properly aligned.
   jobjectArray obj = NULL;
-  size_t size = (size_t) _Jv_GetArrayElementFromElementType (obj,
-							     elementClass);
-
-  // Check for overflow.
-  if (__builtin_expect ((size_t) count > 
-			(SIZE_T_MAX - size) / sizeof (jobject), false))
-    JvThrow (no_memory);
-
+  size_t size = (size_t) elements (obj);
   size += count * sizeof (jobject);
 
-  // FIXME: second argument should be "current loader" //
-  jclass klass = _Jv_FindArrayClass (elementClass, 0);
+  // FIXME: second argument should be "current loader"
+  jclass klass = _Jv_GetArrayClass (elementClass, 0);
 
   obj = (jobjectArray) _Jv_AllocArray (size, klass);
   if (__builtin_expect (! obj, false))
@@ -414,11 +408,11 @@
   // Cast away const.
   jsize *lp = const_cast<jsize *> (&obj->length);
   *lp = count;
-  jobject *ptr = elements(obj);
   // We know the allocator returns zeroed memory.  So don't bother
   // zeroing it again.
   if (init)
     {
+      jobject *ptr = elements(obj);
       while (--count >= 0)
 	*ptr++ = init;
     }
@@ -443,7 +437,7 @@
 			(SIZE_T_MAX - size) / elsize, false))
     JvThrow (no_memory);
 
-  jclass klass = _Jv_FindArrayClass (eltype, 0);
+  jclass klass = _Jv_GetArrayClass (eltype, 0);
 
   __JArray *arr = (__JArray*) _Jv_AllocObj (size + elsize * count, klass);
   if (__builtin_expect (! arr, false))
@@ -529,7 +523,7 @@
       // the same order they are declared in Class.h.
       next = NULL;
       name = _Jv_makeUtf8Const ((char *) cname, -1);
-      accflags = Modifier::PUBLIC | Modifier::FINAL;
+      accflags = Modifier::PUBLIC | Modifier::FINAL | Modifier::ABSTRACT;
       superclass = NULL;
       constants.size = 0;
       constants.tags = NULL;
@@ -547,10 +541,15 @@
       interface_count = 0;
       state = JV_STATE_DONE;
       thread = NULL;
+      depth = -1;
+      ancestors = NULL;
+      idt = NULL;
 
       // Note that we have to set `methods' to NULL.
       if (sig != 'V')
-	_Jv_FindArrayClass (this, NULL, (_Jv_VTable *) array_vtable);
+	_Jv_NewArrayClass (this, NULL, (_Jv_VTable *) array_vtable);
+      else
+        arrayclass = NULL;
     }
 };
 
@@ -606,8 +605,8 @@
 
       }
     case '[':
-      return _Jv_FindArrayClass (_Jv_FindClassFromSignature (&sig[1], loader),
-				 loader);
+      return _Jv_GetArrayClass (_Jv_FindClassFromSignature (&sig[1], loader),
+				loader);
     }
   JvFail ("couldn't understand class signature");
   return NULL;			// Placate compiler.
Index: boehm.cc
===================================================================
RCS file: /cvs/gcc/egcs/libjava/boehm.cc,v
retrieving revision 1.22
diff -u -r1.22 boehm.cc
--- boehm.cc	2000/10/06 01:49:31	1.22
+++ boehm.cc	2001/01/08 23:08:41
@@ -225,6 +225,8 @@
 	}
       p = (ptr_t) c->loader;
       MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, cBlabel);
+      p = (ptr_t) c->arrayclass;
+      MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, cDlabel);
 
 #ifdef INTERPRETER
       if (_Jv_IsInterpretedClass (c))
Index: java/lang/reflect/natArray.cc
===================================================================
RCS file: /cvs/gcc/egcs/libjava/java/lang/reflect/natArray.cc,v
retrieving revision 1.8
diff -u -r1.8 natArray.cc
--- natArray.cc	2000/10/06 01:49:31	1.8
+++ natArray.cc	2001/01/08 23:08:41
@@ -54,7 +54,7 @@
   jclass arrayType = componentType;
   for (int i = 0;  i < ndims;  i++)  // FIXME 2nd arg should 
                                      // be "current" loader
-    arrayType = _Jv_FindArrayClass (arrayType, 0);
+    arrayType = _Jv_GetArrayClass (arrayType, 0);
 
   return _Jv_NewMultiArray (arrayType, ndims, dims);
 }
Index: java/lang/reflect/natMethod.cc
===================================================================
RCS file: /cvs/gcc/egcs/libjava/java/lang/reflect/natMethod.cc,v
retrieving revision 1.19
diff -u -r1.19 natMethod.cc
--- natMethod.cc	2000/12/28 04:34:33	1.19
+++ natMethod.cc	2001/01/08 23:08:41
@@ -286,7 +286,7 @@
 
       // FIXME: 2'nd argument should be "current loader"
       while (--num_arrays >= 0)
-	type = _Jv_FindArrayClass (type, 0);
+	type = _Jv_GetArrayClass (type, 0);
       // ARGPTR can be NULL if we are processing the return value of a
       // call from Constructor.
       if (argPtr)

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