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]

Speed up array allocation


Jeff's profiling pointed out that _Jv_FindArrayClass is really slow.
This patch introduces a new class field, "arrayclass", in which a
pointer to the array class representing an array of itself is
kept. Primitive class TYPEs did actaully this already by reusing the
methods field. Note that this is safe because the classloader of an
array object is always equal to the classloader of its element type.
This avoids having to craft a name for the class and do a hashtable
lookup on every non-primitive array allocation.

This results in about a speed up on the attached benchmark from ~ 21s
-> 7s on my machine. It still runs somewhat slower than Hotspot
though. One obvious performance sink which remains is
_Jv_GetArrayElementFromElementType. It would be really nice if we
could figure out a way to avoid this.

The compiler side of the patch is trivial but it does, of course,
break binary compatibility.

regards

  [ bryce ]

2001-01-05  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.
	(_Jv_NewPrimArray): Ditto.
	(_Jv_PrimClass constructor): Initialize "depth", "ancestors", and
	"idt" for completeness. Initialze "arrayclass" using _Jv_NewArrayClass.
	* 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.
	* java/lang/reflect/natArray.cc (newInstance): Use _Jv_GetArrayClass.
	* java/lang/reflect/natMethod.cc (_Jv_GetTypesFromSignature): Ditto.

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/05 06:18:29
@@ -405,8 +405,8 @@
 
   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))
@@ -443,7 +443,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))
@@ -547,10 +547,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 +611,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: 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/05 06:18:29
@@ -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*);
@@ -337,6 +347,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/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/05 06:18:29
@@ -530,26 +530,31 @@
   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)
+// 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 +562,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;
@@ -575,66 +580,56 @@
       }      
     array_name = _Jv_makeUtf8Const (signature, index);
   }
-
-  jclass array_class = _Jv_FindClassInCache (array_name, element->loader);
 
-  if (! array_class)
-    {
-      // 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;
-
-      // FIXME: initialize other Class instance variables,
-      // e.g. `fields'.
-
-      // say this class is initialized and ready to go!
-      array_class->state = JV_STATE_DONE;
-
-      // vmspec, section 5.3.3 describes this
-      if (element->loader != loader)
-	_Jv_RegisterInitiatingLoader (array_class, loader);
-    }
-
-  // For primitive types, point back at this array.
-  if (element->isPrimitive())
-    element->methods = (_Jv_Method *) 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];
+
+  // Generate the interface dispatch table.
+  _Jv_PrepareConstantTimeTables (array_class);
+
+  // as per vmspec 5.3.3.2
+  array_class->accflags = element->accflags;
+
+  // FIXME: initialize other Class instance variables,
+  // e.g. `fields'.
+
+  // say this class is initialized and ready to go!
+  array_class->state = JV_STATE_DONE;
+
+  // vmspec, section 5.3.3 describes this
+  if (element->loader != loader)
+    _Jv_RegisterInitiatingLoader (array_class, loader);
 
-  return array_class;
+  element->arrayclass = array_class;
 }
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/05 06:18:29
@@ -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/05 06:18:29
@@ -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)
2001-01-05  Bryce McKinlay  <bryce@albatross.co.nz>

	* class.c (make_class_data): Add new class field "arrayclass".
	* decl.c (init_decl_processing): Push initial value for "arrayclass".

Index: class.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/java/class.c,v
retrieving revision 1.81
diff -u -r1.81 class.c
--- class.c	2000/12/18 21:15:52	1.81
+++ class.c	2001/01/05 06:33:02
@@ -1441,6 +1441,7 @@
   PUSH_FIELD_VALUE (cons, "depth", integer_zero_node);
   PUSH_FIELD_VALUE (cons, "ancestors", null_pointer_node);
   PUSH_FIELD_VALUE (cons, "idt", null_pointer_node);
+  PUSH_FIELD_VALUE (cons, "arrayclass", null_pointer_node);
 
   FINISH_RECORD_CONSTRUCTOR (cons);
 
Index: decl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/java/decl.c,v
retrieving revision 1.80
diff -u -r1.80 decl.c
--- decl.c	2000/12/24 00:43:40	1.80
+++ decl.c	2001/01/05 06:33:05
@@ -672,6 +672,7 @@
   PUSH_FIELD (class_type_node, field, "depth", short_type_node);
   PUSH_FIELD (class_type_node, field, "ancestors", ptr_type_node);
   PUSH_FIELD (class_type_node, field, "idt", ptr_type_node);  
+  PUSH_FIELD (class_type_node, field, "arrayclass", 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);

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