This is the mail archive of the java-patches@sourceware.cygnus.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]

Patch: New interface lookup, and inlining, Take 2


This is a new version of the interface dispatch patch I posted last December.
Because non-trivial changes would be required to the interpreter in order to
make it work with index based lookup, the major change in this version is that
it retains the existing interface lookup code in parallel, so that the
interpreter continues to work. An added benefit is backwards compatibility with
the current compiler - patched and unpatched compilers should continue to work
with this code.

I'm still waiting for the FSF to process my copyright assignment form for the
compiler patches, but I think that this stuff can be committed now?

2000-02-16  Bryce McKinlay  <bryce@albatross.co.nz>

        * java/lang/Class.h (union _Jv_IDispatchTable): New declaration.
        (struct _Jv_ifaces): New declaration.
        JV_CLASS: New macro definition.
        (getComponentType): Relocate below isArray() for inlining.
        (getModifiers): Declare `inline'.
        (getSuperclass): Ditto.
        (isArray): Ditto.
        (isPrimitive): Ditto.
        (_Jv_IsAssignableFrom): New prototype.
        (_Jv_LookupInterfaceMethodIdx): New prototype. Predeclare with "C"
        linkage.
        (_Jv_InitClass): Move from natClass.cc. Declare `inline'.
        Check for JV_STATE_DONE before invoking initializeClass().
        (_Jv_PrepareConstantTimeTables): New prototype.
        (_Jv_GetInterfaces): Ditto.
        (_Jv_GenerateITable): Ditto.
        (_Jv_GetMethodString): Ditto.
        (_Jv_AppendPartialITable): Ditto.
        (_Jv_FindIIndex): Ditto.
        depth, ancestors, idt: New fields.

        * java/lang/natClass.cc (isAssignableFrom): Move functionality to
        inline function `_Jv_IsAssignableFrom'. Use that function.
        (isInstance): Declare `inline'.
        (initializeClass): Get lock on class before checking `state'. Unlock
        before calling resolveClass0. Call _Jv_PrepareConstantTimeTables with
        the lock held.
        (_Jv_LookupInterfaceMethod): Use _Jv_GetMessageString.
        (_Jv_IsAssignableFrom): New inline function. Test assignability using
        class->depth and ancestor table.
        (_Jv_IsInstanceOf): Use _Jv_IsAssignableFrom.
        (_Jv_CheckCast): Move from prims.cc. Use JV_CLASS and
        _Jv_IsAssignableFrom.
        (_Jv_CheckArrayStore): Ditto.
        (_Jv_LookupInterfaceMethodIdx): New function.
        INITIAL_IOFFSETS_LEN, INITIAL_IFACES_LEN: New #defines.
        (_Jv_PrepareConstantTimeTables): New function.
        (_Jv_IndexOf): Ditto.
        (_Jv_GetInterfaces): Ditto.
        (_Jv_GenerateITable): Ditto.
        (_Jv_GetMethodString): Ditto.
        (_Jv_AppendPartialITable): Ditto.
        iindex_mutex, iindex_mutex_initialized: New static fields.
        (_Jv_FindIIndex): New function.

        * java/lang/natClassLoader.cc (_Jv_NewClass): Set new jclass fields.

        * prims.cc (_Jv_CheckCast): Moved to natClass.cc.
        (_Jv_CheckArrayStore): Ditto.
        (JvNewCharArray, JvNewBooleanArray, JvNewByteArray, JvNewShortArray,
        JvNewIntArray, JvNewLongArray, JvNewFloatArray, JvNewDoubleArray):
        Moved to gcj/array.h.
        (_Jv_Realloc): New function.

        * gcj/cni.h: Move _Jv_PrimClass definitions to gcj/array.h.

        * gcj/array.h: _Jv_PrimClass definitions moved from gcj/cni.h.
        (JvNewCharArray, JvNewBooleanArray, JvNewByteArray,
        JvNewShortArray, JvNewIntArray, JvNewLongArray, JvNewFloatArray,
        JvNewDoubleArray): Implementations moved from prims.cc and
        declared `inline'.

        * gcj/javaprims.h (_Jv_Realloc): Prototype.

        * include/jvm.h (_Jv_LookupInterfaceMethodIdx): Prototype.

Index: java/lang/natClass.cc
===================================================================
RCS file: /cvs/java/libgcj/libjava/java/lang/natClass.cc,v
retrieving revision 1.16
diff -u -r1.16 natClass.cc
--- natClass.cc	2000/01/19 18:39:26	1.16
+++ natClass.cc	2000/02/16 03:38:37
@@ -10,13 +10,15 @@
 
 #include <config.h>
 
-#include <stdlib.h>
+#include <limits.h>
 #include <string.h>
 
 #pragma implementation "Class.h"
 
 #include <gcj/cni.h>
 #include <jvm.h>
+#include <java-threads.h>
+
 #include <java/lang/Class.h>
 #include <java/lang/ClassLoader.h>
 #include <java/lang/String.h>
@@ -26,6 +28,8 @@
 #include <java/lang/reflect/Field.h>
 #include <java/lang/reflect/Constructor.h>
 #include <java/lang/AbstractMethodError.h>
+#include <java/lang/ArrayStoreException.h>
+#include <java/lang/ClassCastException.h>
 #include <java/lang/ClassNotFoundException.h>
 #include <java/lang/IllegalAccessException.h>
 #include <java/lang/IllegalAccessError.h>
@@ -33,6 +37,7 @@
 #include <java/lang/InstantiationException.h>
 #include <java/lang/NoClassDefFoundError.h>
 #include <java/lang/NoSuchFieldException.h>
+#include <java/lang/NoSuchMethodError.h>
 #include <java/lang/NoSuchMethodException.h>
 #include <java/lang/Thread.h>
 #include <java/lang/NullPointerException.h>
@@ -607,40 +612,10 @@
 jboolean
 java::lang::Class::isAssignableFrom (jclass klass)
 {
-  if (this == klass)
-    return true;
-  // Primitive types must be equal, which we just tested for.
-  if (isPrimitive () || ! klass || klass->isPrimitive())
-    return false;
-
-  // If target is array, so must source be.
-  if (isArray ())
-    {
-      if (! klass->isArray())
-	return false;
-      return getComponentType()->isAssignableFrom(klass->getComponentType());
-    }
-
-  if (isAssignableFrom (klass->getSuperclass()))
-    return true;
-
-  if (isInterface())
-    {
-      // See if source implements this interface.
-      for (int i = 0; i < klass->interface_count; ++i)
-	{
-	  jclass interface = klass->interfaces[i];
-	  // FIXME: ensure that class is prepared here.
-	  // See Spec 12.3.2.
-	  if (isAssignableFrom (interface))
-	    return true;
-	}
-    }
-
-  return false;
+  return _Jv_IsAssignableFrom (this, klass);
 }
 
-jboolean
+inline jboolean
 java::lang::Class::isInstance (jobject obj)
 {
   if (! obj || isPrimitive ())
@@ -648,7 +623,7 @@
   return isAssignableFrom (obj->getClass());
 }
 
-jboolean
+inline jboolean
 java::lang::Class::isInterface (void)
 {
   return (accflags & java::lang::reflect::Modifier::INTERFACE) != 0;
@@ -704,36 +679,32 @@
 void
 java::lang::Class::initializeClass (void)
 {
-  // Short-circuit to avoid needless locking.
+  // jshort-circuit to avoid needless locking.
   if (state == JV_STATE_DONE)
     return;
 
-  // do this before we enter the monitor below, since this can cause
-  // exceptions.  Here we assume, that reading "state" is an atomic
-  // operation, I pressume that is true? --Kresten
+  // Step 1.
+  _Jv_MonitorEnter (this);
+
   if (state < JV_STATE_LINKED)
-    {
+    {    
 #ifdef INTERPRETER
       if (_Jv_IsInterpretedClass (this))
 	{
+	  // this can throw exceptions, so exit the monitor as a precaution.
+	  _Jv_MonitorExit (this);
 	  java::lang::ClassLoader::resolveClass0 (this);
-
-	  // Step 1.
 	  _Jv_MonitorEnter (this);
 	}
       else
 #endif
         {
-          // Step 1.
-	  _Jv_MonitorEnter (this);
 	  _Jv_PrepareCompiledClass (this);
 	}
-    }
-  else
-    {
-      // Step 1.
-      _Jv_MonitorEnter (this);
     }
+  
+  if (state <= JV_STATE_LINKED)
+    _Jv_PrepareConstantTimeTables (this);
 
   // Step 2.
   java::lang::Thread *self = java::lang::Thread::currentThread();
@@ -829,14 +800,14 @@
 
 _Jv_Method *
 _Jv_LookupDeclaredMethod (jclass klass, _Jv_Utf8Const *name,
-			_Jv_Utf8Const *signature)
+                          _Jv_Utf8Const *signature)
 {
   for (; klass; klass = klass->getSuperclass())
     {
       _Jv_Method *meth = _Jv_GetMethodLocal (klass, name, signature);
 
       if (meth)
-	return meth;
+        return meth;
     }
 
   return NULL;
@@ -855,15 +826,15 @@
 
 static void *
 _Jv_FindMethodInCache (jclass klass,
-		       _Jv_Utf8Const *name,
-		       _Jv_Utf8Const *signature)
+                       _Jv_Utf8Const *name,
+                       _Jv_Utf8Const *signature)
 {
   int index = name->hash & MCACHE_SIZE;
   _Jv_mcache *mc = method_cache + index;
   _Jv_Method *m = mc->method;
 
   if (mc->klass == klass
-      && m != NULL		// thread safe check
+      && m != NULL             // thread safe check
       && _Jv_equalUtf8Consts (m->name, name)
       && _Jv_equalUtf8Consts (m->signature, signature))
     return mc->method->ncode;
@@ -872,7 +843,7 @@
 
 static void
 _Jv_AddMethodToCache (jclass klass,
-			_Jv_Method *method)
+                       _Jv_Method *method)
 {
   _Jv_MonitorEnter (&ClassClass); 
 
@@ -886,8 +857,10 @@
 
 void *
 _Jv_LookupInterfaceMethod (jclass klass, _Jv_Utf8Const *name,
-			   _Jv_Utf8Const *signature)
+                           _Jv_Utf8Const *signature)
 {
+  using namespace java::lang::reflect;
+
   void *ncode = _Jv_FindMethodInCache (klass, name, signature);
   if (ncode != 0)
     return ncode;
@@ -896,31 +869,432 @@
     {
       _Jv_Method *meth = _Jv_GetMethodLocal (klass, name, signature);
       if (! meth)
-	continue;
+        continue;
 
-      if (java::lang::reflect::Modifier::isStatic(meth->accflags))
-	JvThrow (new java::lang::IncompatibleClassChangeError);
-      if (java::lang::reflect::Modifier::isAbstract(meth->accflags))
-	JvThrow (new java::lang::AbstractMethodError);
-      if (! java::lang::reflect::Modifier::isPublic(meth->accflags))
-	JvThrow (new java::lang::IllegalAccessError);
+      if (Modifier::isStatic(meth->accflags))
+	JvThrow (new java::lang::IncompatibleClassChangeError
+	         (_Jv_GetMethodString (klass, meth->name)));
+      if (Modifier::isAbstract(meth->accflags))
+	JvThrow (new java::lang::AbstractMethodError
+	         (_Jv_GetMethodString (klass, meth->name)));
+      if (! Modifier::isPublic(meth->accflags))
+	JvThrow (new java::lang::IllegalAccessError
+	         (_Jv_GetMethodString (klass, meth->name)));
 
       _Jv_AddMethodToCache (klass, meth);
 
       return meth->ncode;
     }
   JvThrow (new java::lang::IncompatibleClassChangeError);
-  return NULL;			// Placate compiler.
+  return NULL;                 // Placate compiler.
 }
 
-void
-_Jv_InitClass (jclass klass)
+// Fast interface method lookup by index.
+void *
+_Jv_LookupInterfaceMethodIdx (jclass klass, jclass iface, int method_idx)
 {
-  klass->initializeClass();
+  _Jv_IDispatchTable *cldt = klass->idt;
+  int idx = iface->idt->iface.ioffsets[cldt->cls.iindex] + method_idx;
+  return cldt->cls.itable[idx];
+}
+
+inline jboolean
+_Jv_IsAssignableFrom (jclass target, jclass source)
+{
+  if (target == &ObjectClass 
+      || source == target 
+      || (source->ancestors != NULL 
+          && source->ancestors[source->depth - target->depth] == target))
+     return true;
+     
+  // If target is array, so must source be.  
+  if (target->isArray ())
+    {
+      if (! source->isArray())
+	return false;
+      return _Jv_IsAssignableFrom(target->getComponentType(), 
+                                  source->getComponentType());
+    }
+        
+  if (target->isInterface())
+    {
+      _Jv_IDispatchTable *cl_idt = source->idt;
+      _Jv_IDispatchTable *if_idt = target->idt;
+      jshort cl_iindex = cl_idt->cls.iindex;
+      if (cl_iindex <= if_idt->iface.ioffsets[0])
+        {
+	  jshort offset = if_idt->iface.ioffsets[cl_iindex];
+	  if (offset < cl_idt->cls.itable_length
+	      && cl_idt->cls.itable[offset] == target)
+	    return true;
+	}
+      return false;
+    }
+    
+  return false;
 }
 
 jboolean
 _Jv_IsInstanceOf(jobject obj, jclass cl)
+{
+  return (obj ? _Jv_IsAssignableFrom (cl, JV_CLASS (obj)) : false);
+}
+
+void *
+_Jv_CheckCast (jclass c, jobject obj)
+{
+  if (obj != NULL && ! _Jv_IsAssignableFrom(c, JV_CLASS (obj)))
+    JvThrow (new java::lang::ClassCastException);
+  return obj;
+}
+
+void
+_Jv_CheckArrayStore (jobject arr, jobject obj)
+{
+  if (obj)
+    {
+      JvAssert (arr != NULL);
+      jclass elt_class = (JV_CLASS (arr))->getComponentType();
+      jclass obj_class = JV_CLASS (obj);
+      if (! _Jv_IsAssignableFrom (elt_class, obj_class))
+	JvThrow (new java::lang::ArrayStoreException);
+    }
+}
+
+#define INITIAL_IOFFSETS_LEN 4
+#define INITIAL_IFACES_LEN 4
+
+// Generate tables for constant-time assignment testing and interface
+// method lookup. This implemenents the technique described by Per Bothner
+// <per@bothner.com> on the java-discuss mailing list on 1999-09-02:
+// http://sourceware.cygnus.com/ml/java-discuss/1999-q3/msg00377.html
+void 
+_Jv_PrepareConstantTimeTables (jclass klass)
+{  
+  if (klass->isPrimitive () || klass->isInterface ())
+    return;
+  
+  // jshort-circuit in case we've been called already.
+  if ((klass->idt != NULL) || klass->depth != 0)
+    return;
+
+  // Calculate the class depth and ancestor table. The depth of a class 
+  // is how many "extends" it is removed from Object. Thus the depth of 
+  // java.lang.Object is 0, but the depth of java.io.FilterOutputStream 
+  // is 2. Depth is defined for all regular and array classes, but not 
+  // interfaces or primitive types.
+   
+  jclass klass0 = klass;
+  while (klass0 != &ObjectClass)
+    {
+      klass0 = klass0->superclass;
+      klass->depth++;
+    }
+
+  // We do class member testing in constant time by using a small table 
+  // of all the ancestor classes within each class. The first element is 
+  // a pointer to the current class, and the rest are pointers to the 
+  // classes ancestors, ordered from the current class down by decreasing 
+  // depth. We do not include java.lang.Object in the table of ancestors, 
+  // since it is redundant.
+	
+  klass->ancestors = (jclass *) _Jv_Malloc (klass->depth * sizeof (jclass));
+  klass0 = klass;
+  for (int index = 0; index < klass->depth; index++)
+    {
+      klass->ancestors[index] = klass0;
+      klass0 = klass0->superclass;
+    }
+    
+  if (klass->isArray () 
+      || java::lang::reflect::Modifier::isAbstract (klass->accflags))
+    return;
+
+  klass->idt = 
+    (_Jv_IDispatchTable *) _Jv_Malloc (sizeof (_Jv_IDispatchTable));
+    
+  _Jv_ifaces ifaces;
+
+  ifaces.count = 0;
+  ifaces.len = INITIAL_IFACES_LEN;
+  ifaces.list = (jclass *) _Jv_Malloc (ifaces.len * sizeof (jclass *));
+
+  int itable_size = _Jv_GetInterfaces (klass, &ifaces);
+
+  if (ifaces.count > 0)
+    {
+      klass->idt->cls.itable = 
+	(void **) _Jv_Malloc (itable_size * sizeof (void *));
+      klass->idt->cls.itable_length = itable_size;
+          
+      jshort *itable_offsets = 
+	(jshort *) _Jv_Malloc (ifaces.count * sizeof (jshort));
+
+      _Jv_GenerateITable (klass, &ifaces, itable_offsets);
+
+      jshort cls_iindex = 
+	_Jv_FindIIndex (ifaces.list, itable_offsets, ifaces.count);
+
+      for (int i=0; i < ifaces.count; i++)
+	{
+	  ifaces.list[i]->idt->iface.ioffsets[cls_iindex] =
+	    itable_offsets[i];
+	}
+
+      klass->idt->cls.iindex = cls_iindex;	    
+
+      _Jv_Free (ifaces.list);
+      _Jv_Free (itable_offsets);
+    }
+  else 
+    {
+      klass->idt->cls.iindex = SHRT_MAX;
+    }
+}
+
+// Return index of item in list, or -1 if item is not present.
+jshort
+_Jv_IndexOf (void *item, void **list, jshort list_len)
 {
-  return cl->isInstance(obj);
+  for (int i=0; i < list_len; i++)
+    {
+      if (list[i] == item)
+        return i;
+    }
+  return -1;
+}
+
+// Find all unique interfaces directly or indirectly implemented by klass.
+// Returns the size of the interface dispatch table (itable) for klass, which 
+// is the number of unique interfaces plus the total number of methods that 
+// those interfaces declare. May extend ifaces if required.
+jshort
+_Jv_GetInterfaces (jclass klass, _Jv_ifaces *ifaces)
+{
+  jshort result = 0;
+  
+  for (int i=0; i < klass->interface_count; i++)
+    {
+      jclass iface = klass->interfaces[i];
+      if (_Jv_IndexOf (iface, (void **) ifaces->list, ifaces->count) == -1)
+        {
+	  if (ifaces->count + 1 >= ifaces->len)
+	    {
+	      /* Resize ifaces list */
+	      ifaces->len = ifaces->len * 2;
+	      ifaces->list = (jclass *) _Jv_Realloc (ifaces->list, 
+	                     ifaces->len * sizeof(jclass));
+	    }
+	  ifaces->list[ifaces->count] = iface;
+	  ifaces->count++;
+
+	  result += _Jv_GetInterfaces (klass->interfaces[i], ifaces);
+	}
+    }
+    
+  if (klass->isInterface())
+    {
+      result += klass->method_count + 1;
+    }
+  else
+    {
+      if (klass->superclass)
+        {
+	  result += _Jv_GetInterfaces (klass->superclass, ifaces);
+	}
+    }
+  return result;
+}
+
+// Fill out itable in klass, resolving method declarations in each ifaces.
+// itable_offsets is filled out with the position of each iface in itable,
+// such that itable[itable_offsets[n]] == ifaces.list[n].
+void
+_Jv_GenerateITable (jclass klass, _Jv_ifaces *ifaces, jshort *itable_offsets)
+{
+  void **itable = klass->idt->cls.itable;
+  jshort itable_pos = 0;
+
+  for (int i=0; i < ifaces->count; i++)
+    { 
+      jclass iface = ifaces->list[i];
+      itable_offsets[i] = itable_pos;
+      itable_pos = _Jv_AppendPartialITable (klass, iface, itable,
+                   itable_pos);
+      
+      /* Create interface dispatch table for iface */
+      if (iface->idt == NULL)
+	{
+	  iface->idt = 
+	    (_Jv_IDispatchTable *) _Jv_Malloc (sizeof (_Jv_IDispatchTable));
+
+	  // The first element of ioffsets is its length (itself included).
+	  jshort *ioffsets = 
+	    (jshort *) _Jv_Malloc (INITIAL_IOFFSETS_LEN * sizeof (jshort));
+	  ioffsets[0] = INITIAL_IOFFSETS_LEN;
+	  for (int i=1; i < INITIAL_IOFFSETS_LEN; i++)
+	    ioffsets[i] = -1;
+
+	  iface->idt->iface.ioffsets = ioffsets;	    
+	}
+    }
+}
+
+// Format method name for use in error messages.
+jstring
+_Jv_GetMethodString (jclass klass, _Jv_Utf8Const *name)
+{
+  jstring r = JvNewStringUTF (klass->name->data);
+  r = r->concat (JvNewStringUTF ("."));
+  r = r->concat (JvNewStringUTF (name->data));
+  return r;
+}
+
+void 
+_Jv_ThrowNoSuchMethodError ()
+{
+  JvThrow (new java::lang::NoSuchMethodError ());
+}
+
+// Each superinterface of a class (i.e. each interface that the class
+// directly or indirectly implements) has a corresponding "Partial
+// Interface Dispatch Table" whose size is (number of methods + 1) words.
+// The first word is a pointer to the interface (i.e. the java.lang.Class
+// instance for that interface).  The remaining words are pointers to the
+// actual methods that implement the methods declared in the interface,
+// in order of declaration.
+//
+// Append partial interface dispatch table for "iface" to "itable", at
+// position itable_pos.
+// Returns the offset at which the next partial ITable should be appended.
+jshort
+_Jv_AppendPartialITable (jclass klass, jclass iface, void **itable, 
+                         jshort pos)
+{
+  using namespace java::lang::reflect;
+
+  itable[pos++] = (void *) iface;
+  _Jv_Method *meth;
+  
+  for (int j=0; j < iface->method_count; j++)
+    {
+      meth = NULL;
+      for (jclass cl = klass; cl; cl = cl->getSuperclass())
+        {
+	  meth = _Jv_GetMethodLocal (cl, iface->methods[j].name,
+                 iface->methods[j].signature);
+		 
+	  if (meth)
+	    break;
+	}
+
+      if (meth && (meth->name->data[0] == '<'))
+	{
+	  // leave a placeholder in the itable for hidden init methods.
+          itable[pos] = NULL;	
+	}
+      else if (meth)
+        {
+	  if (Modifier::isStatic(meth->accflags))
+	    JvThrow (new java::lang::IncompatibleClassChangeError
+	             (_Jv_GetMethodString (klass, meth->name)));
+	  if (Modifier::isAbstract(meth->accflags))
+	    JvThrow (new java::lang::AbstractMethodError
+	             (_Jv_GetMethodString (klass, meth->name)));
+	  if (! Modifier::isPublic(meth->accflags))
+	    JvThrow (new java::lang::IllegalAccessError
+	             (_Jv_GetMethodString (klass, meth->name)));
+
+	  itable[pos] = meth->ncode;
+	}
+      else
+        {
+	  // The method doesn't exist in klass. Binary compatibility rules
+	  // permit this, so we delay the error until runtime using a pointer
+	  // to a method which throws an exception.
+	  itable[pos] = (void *) _Jv_ThrowNoSuchMethodError;
+	}
+      pos++;
+    }
+    
+  return pos;
+}
+
+static _Jv_Mutex_t iindex_mutex;
+bool iindex_mutex_initialized = false;
+
+// We need to find the correct offset in the Class Interface Dispatch 
+// Table for a given interface. Once we have that, invoking an interface 
+// method just requires combining the Method's index in the interface 
+// (known at compile time) to get the correct method.  Doing a type test 
+// (cast or instanceof) is the same problem: Once we have a possible Partial 
+// Interface Dispatch Table, we just compare the first element to see if it 
+// matches the desired interface. So how can we find the correct offset?  
+// Our solution is to keep a vector of candiate offsets in each interface 
+// (idt->iface.ioffsets), and in each class we have an index 
+// (idt->cls.iindex) used to select the correct offset from ioffsets.
+//
+// Calculate and return iindex for a new class. 
+// ifaces is a vector of num interfaces that the class implements.
+// offsets[j] is the offset in the interface dispatch table for the
+// interface corresponding to ifaces[j].
+// May extend the interface ioffsets if required.
+jshort
+_Jv_FindIIndex (jclass *ifaces, jshort *offsets, jshort num)
+{
+  int i;
+  int j;
+  
+  // Acquire a global lock to prevent itable corruption in case of multiple 
+  // classes that implement an intersecting set of interfaces being linked
+  // simultaneously. We can assume that the mutex will be initialized
+  // single-threaded.
+  if (! iindex_mutex_initialized)
+    {
+      _Jv_MutexInit (&iindex_mutex);
+      iindex_mutex_initialized = true;
+    }
+  
+  _Jv_MutexLock (&iindex_mutex);
+  
+  for (i=1;; i++)  /* each potential position in ioffsets */
+    {
+      for (j=0;; j++)  /* each iface */
+        {
+	  if (j >= num)
+	    goto found;
+	  if (i > ifaces[j]->idt->iface.ioffsets[0])
+	    continue;
+	  int ioffset = ifaces[j]->idt->iface.ioffsets[i];
+	  /* We can potentially share this position with another class. */
+	  if (ioffset >= 0 && ioffset != offsets[j])
+	    break; /* Nope. Try next i. */	  
+	}
+    }
+  found:
+  for (j = 0; j < num; j++)
+    {
+      int len = ifaces[j]->idt->iface.ioffsets[0];
+      if (i >= len) 
+	{
+	  /* Resize ioffsets. */
+	  int newlen = 2 * len;
+	  if (i >= newlen)
+	    newlen = i + 3;
+	  jshort *old_ioffsets = ifaces[j]->idt->iface.ioffsets;
+	  jshort *new_ioffsets = (jshort *) _Jv_Realloc (old_ioffsets, 
+	                                  newlen * sizeof(jshort));	  
+	  new_ioffsets[0] = newlen;
+
+	  while (len < newlen)
+	    new_ioffsets[len++] = -1;
+	  
+	  ifaces[j]->idt->iface.ioffsets = new_ioffsets;
+	}
+      ifaces[j]->idt->iface.ioffsets[i] = offsets[j];
+    }
+
+  _Jv_MutexUnlock (&iindex_mutex);
+
+  return i;
 }
Index: java/lang/Class.h
===================================================================
RCS file: /cvs/java/libgcj/libjava/java/lang/Class.h,v
retrieving revision 1.15
diff -u -r1.15 Class.h
--- Class.h	2000/01/26 23:56:36	1.15
+++ Class.h	2000/02/16 03:38:38
@@ -22,6 +22,10 @@
 extern "C" void _Jv_InitClass (jclass klass);
 extern "C" void _Jv_RegisterClasses (jclass *classes);
 
+// This must be predefined with "C" linkage.
+extern "C" void *_Jv_LookupInterfaceMethodIdx (jclass klass, jclass iface, 
+                                               int meth_idx);
+
 // These are the possible values for the `state' field of the class
 // structure.  Note that ordering is important here.  Whenever the
 // state changes, one should notify all waiters of this class.
@@ -60,13 +64,41 @@
   _Jv_Utf8Const *signature;
   _Jv_ushort accflags;
   void *ncode;
-
   _Jv_Method *getNextMethod ()
   { return this + 1; }
 };
 
+// Interface Dispatch Tables 
+union _Jv_IDispatchTable
+{
+  struct
+  {
+    // Index into interface's ioffsets.
+    jshort iindex;
+    jshort itable_length;
+    // Class Interface dispatch table.
+    void **itable;
+  } cls;
+
+  struct
+  {
+    // Offsets into implementation class itables.
+    jshort *ioffsets;
+  } iface;
+};
+
+// Used by _Jv_GetInterfaces ()
+struct _Jv_ifaces
+{
+  jclass *list;
+  jshort len;
+  jshort count;
+};
+
 #define JV_PRIMITIVE_VTABLE ((_Jv_VTable *) -1)
 
+#define JV_CLASS(Obj) ((jclass) (*(_Jv_VTable **) Obj)->clas)
+
 class java::lang::Class : public java::lang::Object
 {
 public:
@@ -78,11 +110,6 @@
       return loader;
     }
 
-  jclass getComponentType (void)
-    {
-      return isArray () ? (* (jclass *) &methods) : 0;
-    }
-
   java::lang::reflect::Constructor *getConstructor (JArray<jclass> *);
   JArray<java::lang::reflect::Constructor *> *getConstructors (void);
   java::lang::reflect::Constructor *getDeclaredConstructor (JArray<jclass> *);
@@ -112,7 +139,7 @@
   java::lang::reflect::Method *getMethod (jstring, JArray<jclass> *);
   JArray<java::lang::reflect::Method *> *getMethods (void);
 
-  jint getModifiers (void)
+  inline jint getModifiers (void)
     {
       return accflags;
     }
@@ -123,21 +150,26 @@
   java::io::InputStream *getResourceAsStream (jstring resourceName);
   JArray<jobject> *getSigners (void);
 
-  jclass getSuperclass (void)
+  inline jclass getSuperclass (void)
     {
       return superclass;
     }
 
-  jboolean isArray (void)
+  inline jboolean isArray (void)
     {
       return name->data[0] == '[';
     }
 
+  inline jclass getComponentType (void)
+    {
+      return isArray () ? (* (jclass *) &methods) : 0;
+    }
+
   jboolean isAssignableFrom (jclass cls);
   jboolean isInstance (jobject obj);
   jboolean isInterface (void);
-
-  jboolean isPrimitive (void)
+  
+  inline jboolean isPrimitive (void)
     {
       return vtable == JV_PRIMITIVE_VTABLE;
     }
@@ -150,11 +182,12 @@
     {
       return size_in_bytes;
     }
-
+    
   // finalization
   void finalize ();
 
-private:
+private:   
+
   void checkMemberAccess (jint flags);
 
   // Various functions to handle class initialization.
@@ -165,10 +198,19 @@
   // Friend functions implemented in natClass.cc.
   friend _Jv_Method *_Jv_GetMethodLocal (jclass klass, _Jv_Utf8Const *name,
 					 _Jv_Utf8Const *signature);
+  friend jboolean _Jv_IsAssignableFrom(jclass, jclass);
+  friend void *_Jv_LookupInterfaceMethodIdx (jclass klass, jclass iface, 
+					     int method_idx);
+
+  inline friend void 
+  _Jv_InitClass (jclass klass)
+  {
+    if (klass->state != JV_STATE_DONE)
+      klass->initializeClass ();
+  }
+
   friend _Jv_Method* _Jv_LookupDeclaredMethod (jclass, _Jv_Utf8Const *, 
 					       _Jv_Utf8Const*);
-  friend void _Jv_InitClass (jclass klass);
-
   friend jfieldID JvGetFirstInstanceField (jclass);
   friend jint JvNumInstanceFields (jclass);
   friend jfieldID JvGetFirstStaticField (jclass);
@@ -208,6 +250,12 @@
 			      java::lang::ClassLoader *loader);
 
   friend void _Jv_PrepareCompiledClass (jclass);
+  friend void _Jv_PrepareConstantTimeTables (jclass);
+  friend jshort _Jv_GetInterfaces (jclass, _Jv_ifaces *);
+  friend void _Jv_GenerateITable (jclass, _Jv_ifaces *, jshort *);
+  friend jstring _Jv_GetMethodString(jclass, _Jv_Utf8Const *);
+  friend jshort _Jv_AppendPartialITable (jclass, jclass, void **, jshort);
+  friend jshort _Jv_FindIIndex (jclass *, jshort *, jshort);
 
 #ifdef INTERPRETER
   friend jboolean _Jv_IsInterpretedClass (jclass);
@@ -216,6 +264,10 @@
 				       _Jv_Utf8Const*);
   friend void _Jv_InitField (jobject, jclass, int);
   friend _Jv_word _Jv_ResolvePoolEntry (jclass, int);
+  friend _Jv_Method *_Jv_SearchMethodInClass (jclass cls, jclass klass, 
+                        		      _Jv_Utf8Const *method_name, 
+					      _Jv_Utf8Const *method_signature);
+
   friend void _Jv_PrepareClass (jclass);
 
   friend class _Jv_ClassReader;	
@@ -268,6 +320,12 @@
   // The thread which has locked this class.  Used during class
   // initialization.
   java::lang::Thread *thread;
+  // How many levels of "extends" this class is removed from Object.
+  jshort depth;
+  // Vector of this class's superclasses, ordered by decreasing depth.
+  jclass *ancestors;
+  // Interface Dispatch Table.
+  _Jv_IDispatchTable *idt;
 };
 
 #endif /* __JAVA_LANG_CLASS_H__ */
Index: java/lang/natClassLoader.cc
===================================================================
RCS file: /cvs/java/libgcj/libjava/java/lang/natClassLoader.cc,v
retrieving revision 1.17
diff -u -r1.17 natClassLoader.cc
--- natClassLoader.cc	2000/02/10 17:15:22	1.17
+++ natClassLoader.cc	2000/02/16 03:38:39
@@ -512,6 +512,9 @@
   ret->interface_count = 0;
   ret->state = JV_STATE_NOTHING;
   ret->thread = NULL;
+  ret->depth = 0;
+  ret->ancestors = NULL;
+  ret->idt = NULL;
 
   _Jv_RegisterClass (ret);
 
Index: prims.cc
===================================================================
RCS file: /cvs/java/libgcj/libjava/prims.cc,v
retrieving revision 1.20
diff -u -r1.20 prims.cc
--- prims.cc	2000/02/01 06:14:25	1.20
+++ prims.cc	2000/02/16 03:38:40
@@ -42,11 +42,9 @@
 #include <java/lang/ArrayIndexOutOfBoundsException.h>
 #include <java/lang/ArithmeticException.h>
 #include <java/lang/ClassFormatError.h>
-#include <java/lang/ClassCastException.h>
 #include <java/lang/NegativeArraySizeException.h>
 #include <java/lang/NullPointerException.h>
 #include <java/lang/OutOfMemoryError.h>
-#include <java/lang/ArrayStoreException.h>
 #include <java/lang/System.h>
 #include <java/lang/reflect/Modifier.h>
 #include <java/io/PrintStream.h>
@@ -286,31 +284,6 @@
 	   (java::lang::String::valueOf(bad_index)));
 }
 
-void*
-_Jv_CheckCast (jclass c, jobject obj)
-{
-  if (obj != NULL && ! c->isAssignableFrom(obj->getClass()))
-    JvThrow (new java::lang::ClassCastException);
-  return obj;
-}
-
-void
-_Jv_CheckArrayStore (jobject arr, jobject obj)
-{
-  if (obj)
-    {
-      JvAssert (arr != NULL);
-      jclass arr_class = arr->getClass();
-      JvAssert (arr_class->isArray());
-      jclass elt_class = arr_class->getComponentType();
-      jclass obj_class = obj->getClass();
-      if (! elt_class->isAssignableFrom(obj_class))
-	JvThrow (new java::lang::ArrayStoreException);
-    }
-}
-
-
-
 // Allocate some unscanned memory and throw an exception if no memory.
 void *
 _Jv_AllocBytesChecked (jsize size)
@@ -421,54 +394,6 @@
   return arr;
 }
 
-jcharArray
-JvNewCharArray (jint length)
-{
-  return (jcharArray) _Jv_NewPrimArray (JvPrimClass (char), length);
-}
-
-jbooleanArray
-JvNewBooleanArray (jint length)
-{
-  return (jbooleanArray) _Jv_NewPrimArray (JvPrimClass (boolean), length);
-}
-
-jbyteArray
-JvNewByteArray (jint length)
-{
-  return (jbyteArray) _Jv_NewPrimArray (JvPrimClass (byte), length);
-}
-
-jshortArray
-JvNewShortArray (jint length)
-{
-  return (jshortArray) _Jv_NewPrimArray (JvPrimClass (short), length);
-}
-
-jintArray
-JvNewIntArray (jint length)
-{
-  return (jintArray) _Jv_NewPrimArray (JvPrimClass (int), length);
-}
-
-jlongArray
-JvNewLongArray (jint length)
-{
-  return (jlongArray) _Jv_NewPrimArray (JvPrimClass (long), length);
-}
-
-jfloatArray
-JvNewFloatArray (jint length)
-{
-  return (jfloatArray) _Jv_NewPrimArray (JvPrimClass (float), length);
-}
-
-jdoubleArray
-JvNewDoubleArray (jint length)
-{
-  return (jdoubleArray) _Jv_NewPrimArray (JvPrimClass (double), length);
-}
-
 jobject
 _Jv_NewArray (jint type, jint size)
 {
@@ -918,22 +843,33 @@
 
 
 void *
-_Jv_MallocUnchecked (jsize size)
+_Jv_Malloc (jsize size)
 {
   if (size == 0)
     size = 1;
-  return malloc ((size_t) size);
+  void *ptr = malloc ((size_t) size);
+  if (ptr == NULL)
+    JvThrow (no_memory);
+  return ptr;
 }
 
 void *
-_Jv_Malloc (jsize size)
+_Jv_Realloc (void *ptr, jsize size)
 {
   if (size == 0)
     size = 1;
-  void *ptr = malloc ((size_t) size);
+  ptr = realloc (ptr, (size_t) size);
   if (ptr == NULL)
     JvThrow (no_memory);
   return ptr;
+}
+
+void *
+_Jv_MallocUnchecked (jsize size)
+{
+  if (size == 0)
+    size = 1;
+  return malloc ((size_t) size);
 }
 
 void
Index: gcj/cni.h
===================================================================
RCS file: /cvs/java/libgcj/libjava/gcj/cni.h,v
retrieving revision 1.3
diff -u -r1.3 cni.h
--- cni.h	2000/01/19 18:39:23	1.3
+++ cni.h	2000/02/16 03:38:40
@@ -93,11 +93,6 @@
   return _Jv_NewStringUTF (bytes);
 }
 
-extern class _Jv_PrimClass _Jv_byteClass, _Jv_shortClass, _Jv_intClass,
-  _Jv_longClass, _Jv_booleanClass, _Jv_charClass, _Jv_floatClass,
-  _Jv_doubleClass, _Jv_voidClass;
-#define JvPrimClass(TYPE) ((jclass) & _Jv_##TYPE##Class)
-
 class JvSynchronize
 {
 private:
Index: gcj/array.h
===================================================================
RCS file: /cvs/java/libgcj/libjava/gcj/array.h,v
retrieving revision 1.5
diff -u -r1.5 array.h
--- array.h	2000/01/26 00:55:49	1.5
+++ array.h	2000/02/16 03:38:40
@@ -55,18 +55,68 @@
 typedef JArray<jdouble> *jdoubleArray;
 typedef JArray<jstring> *jstringArray;
 
-extern "C" jbooleanArray JvNewBooleanArray (jint length);
-extern "C" jbyteArray JvNewByteArray (jint length);
-extern "C" jcharArray JvNewCharArray (jint length);
-extern "C" jshortArray JvNewShortArray (jint length);
-extern "C" jintArray JvNewIntArray (jint length);
-extern "C" jlongArray JvNewLongArray (jint length);
-extern "C" jfloatArray JvNewFloatArray (jint length);
-extern "C" jdoubleArray JvNewDoubleArray (jint length);
+extern class _Jv_PrimClass _Jv_byteClass, _Jv_shortClass, _Jv_intClass,
+  _Jv_longClass, _Jv_booleanClass, _Jv_charClass, _Jv_floatClass,
+  _Jv_doubleClass, _Jv_voidClass;
+#define JvPrimClass(TYPE) ((jclass) & _Jv_##TYPE##Class)
+
 extern "C" jobjectArray _Jv_NewObjectArray(jsize length, jclass, jobject init);
+extern "C" jobject _Jv_NewPrimArray (jclass eltype, jint count);
+
+extern inline jobjectArray 
+JvNewObjectArray (jsize length, jclass cls, jobject init)
+{ 
+  return _Jv_NewObjectArray (length, cls, init); 
+}
+
+extern inline jcharArray 
+JvNewCharArray (jint length)
+{
+  return (jcharArray) _Jv_NewPrimArray (JvPrimClass (char), length);
+}
+
+extern inline jbooleanArray 
+JvNewBooleanArray (jint length)
+{
+  return (jbooleanArray) _Jv_NewPrimArray (JvPrimClass (boolean), length);
+}
+
+extern inline jbyteArray 
+JvNewByteArray (jint length)
+{
+  return (jbyteArray) _Jv_NewPrimArray (JvPrimClass (byte), length);
+}
+
+extern inline jshortArray 
+JvNewShortArray (jint length)
+{
+  return (jshortArray) _Jv_NewPrimArray (JvPrimClass (short), length);
+}
+
+extern inline jintArray 
+JvNewIntArray (jint length)
+{
+  return (jintArray) _Jv_NewPrimArray (JvPrimClass (int), length);
+}
+
+extern inline jlongArray 
+JvNewLongArray (jint length)
+{
+  return (jlongArray) _Jv_NewPrimArray (JvPrimClass (long), length);
+}
+
+extern inline jfloatArray 
+JvNewFloatArray (jint length)
+{
+  return (jfloatArray) _Jv_NewPrimArray (JvPrimClass (float), length);
+}
+
+extern inline jdoubleArray 
+JvNewDoubleArray (jint length)
+{
+  return (jdoubleArray) _Jv_NewPrimArray (JvPrimClass (double), length);
+}
 
-inline jobjectArray JvNewObjectArray (jsize length, jclass cls, jobject init)
-{ return _Jv_NewObjectArray (length, cls, init); }
 
 extern "C" jstringArray JvConvertArgv(int argc, const char **argv);
 
Index: gcj/javaprims.h
===================================================================
RCS file: /cvs/java/libgcj/libjava/gcj/javaprims.h,v
retrieving revision 1.4
diff -u -r1.4 javaprims.h
--- javaprims.h	2000/01/19 18:39:24	1.4
+++ javaprims.h	2000/02/16 03:38:41
@@ -273,6 +273,7 @@
 extern "C" void _Jv_Throw (void *) __attribute__ ((__noreturn__));
 extern "C" void _Jv_Sjlj_Throw (void *) __attribute__ ((__noreturn__));
 extern "C" void* _Jv_Malloc (jsize) __attribute__((__malloc__));
+extern "C" void* _Jv_Realloc (void *, jsize);
 extern "C" void _Jv_Free (void*);
 
 typedef unsigned short _Jv_ushort __attribute__((__mode__(__HI__)));
Index: include/jvm.h
===================================================================
RCS file: /cvs/java/libgcj/libjava/include/jvm.h,v
retrieving revision 1.16
diff -u -r1.16 jvm.h
--- jvm.h	2000/02/10 20:31:48	1.16
+++ jvm.h	2000/02/16 03:38:42
@@ -156,7 +156,9 @@
   __attribute__((__malloc__));
 extern "C" void *_Jv_CheckCast (jclass klass, jobject obj);
 extern "C" void *_Jv_LookupInterfaceMethod (jclass klass, Utf8Const *name,
-					    Utf8Const *signature);
+                                           Utf8Const *signature);
+extern "C" void *_Jv_LookupInterfaceMethodIdx (jclass klass, jclass iface, 
+                                               int meth_idx);
 extern "C" void _Jv_CheckArrayStore (jobject array, jobject obj);
 extern "C" void _Jv_RegisterClass (jclass klass);
 extern "C" void _Jv_RegisterClasses (jclass *classes);

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