PR libgcj/25265: Throw NoSuchMethodError for missing methods

Andrew Haley aph@redhat.com
Tue Dec 6 18:45:00 GMT 2005


This adds a new method to every class that is invoked when we try to
invoke a nonexistent method.  I've made it package private, which I
think is right: opinions welcomed.

Note that this is a binary *in*compatible change that requires apps to
be recompiled.  We've just bumped libgcj.so to libgcj.so.7, so
everything has to be recompiled anyway, so IMO that's OK.

The way we prematurely throw errors has casued us so much pain that I
think this is worth doing now, even though it means an ABI change.

Andrew.


Index: link.cc
===================================================================
*** link.cc	(revision 107894)
--- link.cc	(working copy)
*************** _Jv_Linker::link_symbol_table (jclass kl
*** 915,926 ****
  
        _Jv_Utf8Const *signature = sym.signature;
  
-       {
- 	static char *bounce = (char *)_Jv_ThrowNoSuchMethodError;
- 	ptrdiff_t offset = (char *)(klass->vtable) - bounce;
- 	klass->otable->offsets[index] = offset;
-       }
- 
        if (target_class == NULL)
  	throw new java::lang::NoClassDefFoundError 
  	  (_Jv_NewStringUTF (sym.class_name->chars()));
--- 991,996 ----
*************** _Jv_Linker::link_symbol_table (jclass kl
*** 948,961 ****
  	  meth = _Jv_LookupDeclaredMethod(target_class, sym.name, 
  					  sym.signature);
  
! 	  if (meth != NULL)
  	    {
! 	      int offset = _Jv_VTable::idx_to_offset (meth->index);
! 	      if (offset == -1)
! 		JvFail ("Bad method index");
! 	      JvAssert (meth->index < target_class->vtable_method_count);
! 	      klass->otable->offsets[index] = offset;
  	    }
  	  if (debug_link)
  	    fprintf (stderr, "  offsets[%d] = %d (class %s@%p : %s(%s))\n",
  		     (int)index,
--- 1018,1059 ----
  	  meth = _Jv_LookupDeclaredMethod(target_class, sym.name, 
  					  sym.signature);
  
! 	  // Every class has a throwNoSuchMethodErrorIndex method that
! 	  // it inherits from java.lang.Object.  Find its vtable
! 	  // offset.
! 	  static int throwNoSuchMethodErrorIndex;
! 	  if (throwNoSuchMethodErrorIndex == 0)
  	    {
! 	      Utf8Const* name 
! 		= _Jv_makeUtf8Const ("throwNoSuchMethodError", 
! 				     strlen ("throwNoSuchMethodError"));
! 	      Utf8Const* sig = _Jv_makeUtf8Const ("()V", strlen ("()V"));
! 	      _Jv_Method* meth
! 		= _Jv_LookupDeclaredMethod (&java::lang::Object::class$, 
! 					    name, sig);
! 	      throwNoSuchMethodErrorIndex 
! 		= _Jv_VTable::idx_to_offset (meth->index);
  	    }
+ 	  
+ 	  // If we don't find a nonstatic method, insert the
+ 	  // vtable index of Object.throwNoSuchMethodError().
+ 	  // This defers the missing method error until an attempt
+ 	  // is made to execute it.	  
+ 	  {
+ 	    int offset;
+ 	    
+ 	    if (meth != NULL)
+ 	      offset = _Jv_VTable::idx_to_offset (meth->index);
+ 	    else
+ 	      offset = throwNoSuchMethodErrorIndex;		    
+ 	    
+ 	    if (offset == -1)
+ 	      JvFail ("Bad method index");
+ 	    JvAssert (meth->index < target_class->vtable_method_count);
+ 	    
+ 	    klass->otable->offsets[index] = offset;
+ 	  }
+ 
  	  if (debug_link)
  	    fprintf (stderr, "  offsets[%d] = %d (class %s@%p : %s(%s))\n",
  		     (int)index,
Index: java/lang/Object.java
===================================================================
*** java/lang/Object.java	(revision 107894)
--- java/lang/Object.java	(working copy)
*************** public class Object
*** 506,511 ****
--- 506,519 ----
    // completeness (some day we'll be able to auto-generate Object.h).
    private final native void sync_init();
  
+   // If we fail to find a method at class loading time we put the
+   // vtable index of this method in its place: any attempt to call
+   // that method will result in an error.
+   void throwNoSuchMethodError()
+   {
+     throw new NoSuchMethodError("in " + getClass());
+   }
+ 
    // Note that we don't mention the sync_info field here.  If we do,
    // jc1 will not work correctly.
  }
Index: java/lang/Object.h
===================================================================
*** java/lang/Object.h	(revision 107894)
--- java/lang/Object.h	(working copy)
*************** private:
*** 83,88 ****
--- 83,91 ----
  
      // Initialize the sync_info field.  Not called with JV_HASH_SYNCHRONIZATION.
      void sync_init (void);
+ 
+ public:
+   virtual void throwNoSuchMethodError (void);
  };
  
  #endif /* __JAVA_LANG_OBJECT_H__ */



More information about the Java-patches mailing list