diff --git a/libjava/ChangeLog b/libjava/ChangeLog
index c33749c7a5a10c837686b67b0356b7717366f0be..18dcf20df63ba5f6ebf952c3feaa1a57bb4f9444 100644
--- a/libjava/ChangeLog
+++ b/libjava/ChangeLog
@@ -1,3 +1,77 @@
+2000-03-07  Bryce McKinlay  <bryce@albatross.co.nz>
+
+	* resolve.cc (_Jv_SearchMethodInClass): New function.
+	(_Jv_ResolvePoolEntry): Search superinterfaces for interface methods.
+	* java/lang/Class.h (_Jv_SearchMethodInClass): New prototype.
+
+2000-03-07  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 class 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.
+
 2000-03-06  Tom Tromey  <tromey@cygnus.com>
 
 	* jni.cc (MARK_NONE): New define.
diff --git a/libjava/gcj/array.h b/libjava/gcj/array.h
index 29be1ccbb9e3533734a021ba2b32dcbafdeeb856..8b355e263526467ee8db5dd61fd419e80659532f 100644
--- a/libjava/gcj/array.h
+++ b/libjava/gcj/array.h
@@ -55,18 +55,68 @@ typedef JArray<jfloat> *jfloatArray;
 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);
 
diff --git a/libjava/gcj/cni.h b/libjava/gcj/cni.h
index 1c0510045eb871ef05065626523f868d89a44e1e..2cad18584912023da535a009ef69a7689330a4e1 100644
--- a/libjava/gcj/cni.h
+++ b/libjava/gcj/cni.h
@@ -93,11 +93,6 @@ JvNewStringUTF (const char *bytes)
   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:
diff --git a/libjava/gcj/javaprims.h b/libjava/gcj/javaprims.h
index b88580eb959bdbd84906c1eafd415b9da6f1e9a3..2f3c4638b41543de0f924516baa5ce4acc9a249f 100644
--- a/libjava/gcj/javaprims.h
+++ b/libjava/gcj/javaprims.h
@@ -272,6 +272,7 @@ extern "C" jsize _Jv_GetStringUTFRegion (jstring, jsize, jsize, char *);
 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__)));
diff --git a/libjava/include/jvm.h b/libjava/include/jvm.h
index 40a0c2a983005df6d14113928a5a486402d0ab7d..d24a5ff5830498f7276d1c263b0df9a724463808 100644
--- a/libjava/include/jvm.h
+++ b/libjava/include/jvm.h
@@ -156,7 +156,9 @@ extern "C" jobject _Jv_NewMultiArray (jclass klass, jint dims, ...)
   __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);
diff --git a/libjava/java/lang/Class.h b/libjava/java/lang/Class.h
index 717eed7af00852657982e48e2fdad382bda5b503..8aefb70087d6da04e3213ba921a06fdffb6223d8 100644
--- a/libjava/java/lang/Class.h
+++ b/libjava/java/lang/Class.h
@@ -22,6 +22,10 @@ details.  */
 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 @@ struct _Jv_Method
   _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 @@ public:
       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 @@ public:
   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 @@ public:
   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 @@ public:
     {
       return size_in_bytes;
     }
-
+    
   // finalization
   void finalize ();
 
-private:
+private:   
+
   void checkMemberAccess (jint flags);
 
   void initializeClass (void);
@@ -162,10 +195,19 @@ private:
   // 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);
@@ -205,6 +247,12 @@ private:
 			      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);
@@ -213,6 +261,10 @@ private:
 				       _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;	
@@ -265,6 +317,12 @@ private:
   // 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__ */
diff --git a/libjava/java/lang/natClass.cc b/libjava/java/lang/natClass.cc
index 42af71585ef7d8b2f1315f5ad215b25b9490113f..64b25d0ca1a5ab03487ed9af712728e37439ca8f 100644
--- a/libjava/java/lang/natClass.cc
+++ b/libjava/java/lang/natClass.cc
@@ -10,13 +10,15 @@ details.  */
 
 #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 @@ details.  */
 #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/ExceptionInInitializerError.h>
 #include <java/lang/IllegalAccessException.h>
@@ -34,6 +38,7 @@ details.  */
 #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>
@@ -608,40 +613,10 @@ java::lang::Class::getMethods (void)
 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 ())
@@ -649,7 +624,7 @@ java::lang::Class::isInstance (jobject obj)
   return isAssignableFrom (obj->getClass());
 }
 
-jboolean
+inline jboolean
 java::lang::Class::isInterface (void)
 {
   return (accflags & java::lang::reflect::Modifier::INTERFACE) != 0;
@@ -696,36 +671,32 @@ java::lang::Class::finalize (void)
 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();
@@ -828,14 +799,14 @@ _Jv_GetMethodLocal (jclass klass, _Jv_Utf8Const *name,
 
 _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;
@@ -854,15 +825,15 @@ static _Jv_mcache method_cache[MCACHE_SIZE + 1];
 
 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;
@@ -871,7 +842,7 @@ _Jv_FindMethodInCache (jclass klass,
 
 static void
 _Jv_AddMethodToCache (jclass klass,
-			_Jv_Method *method)
+                       _Jv_Method *method)
 {
   _Jv_MonitorEnter (&ClassClass); 
 
@@ -885,8 +856,10 @@ _Jv_AddMethodToCache (jclass klass,
 
 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;
@@ -895,31 +868,432 @@ _Jv_LookupInterfaceMethod (jclass klass, _Jv_Utf8Const *name,
     {
       _Jv_Method *meth = _Jv_GetMethodLocal (klass, name, signature);
       if (! meth)
-	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);
+        continue;
+
+      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)
+{
+  _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)
 {
-  klass->initializeClass();
+  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 cl->isInstance(obj);
+  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 implements 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;
+  
+  // Short-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)
+{
+  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;
 }
diff --git a/libjava/java/lang/natClassLoader.cc b/libjava/java/lang/natClassLoader.cc
index 39ee0ba8b470a6410eb6838eb823d93b76bcf2a3..a3eeaab60b24c0c8af3c7c205e4200bf9f27b17a 100644
--- a/libjava/java/lang/natClassLoader.cc
+++ b/libjava/java/lang/natClassLoader.cc
@@ -503,6 +503,9 @@ _Jv_NewClass (_Jv_Utf8Const *name, jclass superclass,
   ret->interface_count = 0;
   ret->state = JV_STATE_NOTHING;
   ret->thread = NULL;
+  ret->depth = 0;
+  ret->ancestors = NULL;
+  ret->idt = NULL;
 
   _Jv_RegisterClass (ret);
 
diff --git a/libjava/prims.cc b/libjava/prims.cc
index 2c5c464e1ed8b972a096b969646666b74eb161a1..beec6a6d953781d42477996ef715378d6c00f6b0 100644
--- a/libjava/prims.cc
+++ b/libjava/prims.cc
@@ -42,11 +42,9 @@ details.  */
 #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 @@ _Jv_ThrowBadArrayIndex(jint bad_index)
 	   (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 @@ _Jv_NewPrimArray (jclass eltype, jint count)
   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)
 {
@@ -919,24 +844,35 @@ _Jv_SetMaximumHeapSize (const char *arg)
 
 
 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
 _Jv_Free (void* ptr)
 {
diff --git a/libjava/resolve.cc b/libjava/resolve.cc
index 634c08fa11ec9f022bdcc0579e9ba93b8d1853d8..b471361530454f8ff7633cb112d89570bd727359 100644
--- a/libjava/resolve.cc
+++ b/libjava/resolve.cc
@@ -24,6 +24,7 @@ details.  */
 #include <java/lang/InternalError.h>
 #include <java/lang/VirtualMachineError.h>
 #include <java/lang/NoSuchFieldError.h>
+#include <java/lang/NoSuchMethodError.h>
 #include <java/lang/ClassFormatError.h>
 #include <java/lang/IllegalAccessError.h>
 #include <java/lang/AbstractMethodError.h>
@@ -230,59 +231,78 @@ _Jv_ResolvePoolEntry (jclass klass, int index)
       _Jv_Method *the_method = 0;
       jclass found_class = 0;
 
-      // we make a loop here, because methods are allowed to be moved to
-      // a super class, and still be visible.. (binary compatibility).
+      // First search the class itself.
+      the_method = _Jv_SearchMethodInClass (owner, klass, 
+	           method_name, method_signature);
 
-      for (jclass cls = owner; cls != 0; cls = cls->getSuperclass ())
-	{
-	  for (int i = 0;  i < cls->method_count;  i++)
-	    {
-	      _Jv_Method *method = &cls->methods[i];
-	      if (   (!_Jv_equalUtf8Consts (method->name,
-					    method_name))
-		  || (!_Jv_equalUtf8Consts (method->signature,
-					    method_signature)))
-		continue;
+      if (the_method != 0)
+        {
+	  found_class = owner;
+          goto end_of_method_search;
+	}
 
-	      if (cls == klass 
-		  || ((method->accflags & Modifier::PUBLIC) != 0)
-		  || (((method->accflags & Modifier::PROTECTED) != 0)
-		      && cls->isAssignableFrom (klass))
-		  || (((method->accflags & Modifier::PRIVATE) == 0)
-		      && _Jv_ClassNameSamePackage (cls->name,
-						   klass->name)))
-		{
-		  // FIXME: if (cls->loader != klass->loader), then we
-		  // must actually check that the types of arguments
-		  // correspond.  That is, for each argument type, and
-		  // the return type, doing _Jv_FindClassFromSignature
-		  // with either loader should produce the same result,
-		  // i.e., exactly the same jclass object. JVMS 5.4.3.3
-
-		  the_method = method;
+      // If we are resolving an interface method, search the interface's 
+      // superinterfaces (A superinterface is not an interface's superclass - 
+      // a superinterface is implemented by the interface).
+      if (pool->tags[index] == JV_CONSTANT_InterfaceMethodref)
+        {
+	  _Jv_ifaces ifaces;
+	  ifaces.count = 0;
+	  ifaces.len = 4;
+	  ifaces.list = (jclass *) _Jv_Malloc (ifaces.len * sizeof (jclass *));
+
+	  _Jv_GetInterfaces (owner, &ifaces);	  
+          
+	  for (int i=0; i < ifaces.count; i++)
+	    {
+	      jclass cls = ifaces.list[i];
+	      the_method = _Jv_SearchMethodInClass (cls, klass, method_name, 
+	                                            method_signature);
+	      if (the_method != 0)
+	        {
 		  found_class = cls;
-
-		  
-		  if (pool->tags[index] == JV_CONSTANT_InterfaceMethodref)
-		    vtable_index = -1;
-		  else
-		    vtable_index = _Jv_DetermineVTableIndex
-		      (cls, method_name, method_signature);
-
-		  if (vtable_index == 0)
-		    throw_incompatible_class_change_error
-		      (JvNewStringLatin1 ("method not found"));
-
-		  goto end_of_method_search;
-		}
-	      else
-		{
-		  JvThrow (new java::lang::IllegalAccessError);
+                  break;
 		}
 	    }
+	  
+	  _Jv_Free (ifaces.list);
+	  
+	  if (the_method != 0)
+	    goto end_of_method_search;
+	}
+
+      // Finally, search superclasses. 
+      for (jclass cls = owner->getSuperclass (); cls != 0; 
+           cls = cls->getSuperclass ())
+	{
+	  the_method = _Jv_SearchMethodInClass (cls, klass, 
+	               method_name, method_signature);
+          if (the_method != 0)
+	    {
+	      found_class = cls;
+	      break;
+	    }
 	}
 
     end_of_method_search:
+    
+      // FIXME: if (cls->loader != klass->loader), then we
+      // must actually check that the types of arguments
+      // correspond.  That is, for each argument type, and
+      // the return type, doing _Jv_FindClassFromSignature
+      // with either loader should produce the same result,
+      // i.e., exactly the same jclass object. JVMS 5.4.3.3    
+    
+      if (pool->tags[index] == JV_CONSTANT_InterfaceMethodref)
+	vtable_index = -1;
+      else
+	vtable_index = _Jv_DetermineVTableIndex
+	  (found_class, method_name, method_signature);
+
+      if (vtable_index == 0)
+	throw_incompatible_class_change_error
+	  (JvNewStringLatin1 ("method not found"));
+
       if (the_method == 0)
 	{
 	  jstring msg = JvNewStringLatin1 ("method ");
@@ -290,7 +310,7 @@ _Jv_ResolvePoolEntry (jclass klass, int index)
 	  msg = msg->concat (JvNewStringLatin1("."));
 	  msg = msg->concat (_Jv_NewStringUTF (method_name->data));
 	  msg = msg->concat (JvNewStringLatin1(" was not found."));
-	  JvThrow(new java::lang::NoSuchFieldError (msg));
+	  JvThrow(new java::lang::NoSuchMethodError (msg));
 	}
       
       pool->data[index].rmethod = 
@@ -307,6 +327,41 @@ _Jv_ResolvePoolEntry (jclass klass, int index)
   return pool->data[index];
 }
 
+// Find a method declared in the cls that is referenced from klass and
+// perform access checks.
+_Jv_Method *
+_Jv_SearchMethodInClass (jclass cls, jclass klass, 
+                         _Jv_Utf8Const *method_name, 
+			 _Jv_Utf8Const *method_signature)
+{
+  using namespace java::lang::reflect;
+
+  for (int i = 0;  i < cls->method_count;  i++)
+    {
+      _Jv_Method *method = &cls->methods[i];
+      if (   (!_Jv_equalUtf8Consts (method->name,
+				    method_name))
+	  || (!_Jv_equalUtf8Consts (method->signature,
+				    method_signature)))
+	continue;
+
+      if (cls == klass 
+	  || ((method->accflags & Modifier::PUBLIC) != 0)
+	  || (((method->accflags & Modifier::PROTECTED) != 0)
+	      && cls->isAssignableFrom (klass))
+	  || (((method->accflags & Modifier::PRIVATE) == 0)
+	      && _Jv_ClassNameSamePackage (cls->name,
+					   klass->name)))
+	{
+	  return method;
+	}
+      else
+	{
+	  JvThrow (new java::lang::IllegalAccessError);
+	}
+    }
+  return 0;
+}
 
 void
 _Jv_ResolveField (_Jv_Field *field, java::lang::ClassLoader *loader)