OSDN Git Service

2001-05-18 Andrew Haley <aph@cambridge.redhat.com>
[pf3gnuchains/gcc-fork.git] / libjava / resolve.cc
index 634c08f..d165c80 100644 (file)
@@ -1,6 +1,6 @@
 // resolve.cc - Code for linking and resolving classes and pool entries.
 
-/* Copyright (C) 1999, 2000  Red Hat, Inc.
+/* Copyright (C) 1999, 2000, 2001  Free Software Foundation
 
    This file is part of libgcj.
 
@@ -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>
@@ -31,6 +32,17 @@ details.  */
 #include <java/lang/IncompatibleClassChangeError.h>
 #include <java/lang/reflect/Modifier.h>
 
+void
+_Jv_ResolveField (_Jv_Field *field, java::lang::ClassLoader *loader)
+{
+  if (! field->isResolved ())
+    {
+      _Jv_Utf8Const *sig = (_Jv_Utf8Const*)field->type;
+      field->type = _Jv_FindClassFromSignature (sig->data, loader);
+      field->flags &= ~_Jv_FIELD_UNRESOLVED_FLAG;
+    }
+}
+
 #ifdef INTERPRETER
 
 static void throw_internal_error (char *msg)
@@ -40,11 +52,9 @@ static void throw_class_format_error (jstring msg)
 static void throw_class_format_error (char *msg)
        __attribute__ ((__noreturn__));
 
-#define ClassObject _CL_Q34java4lang6Object
-extern java::lang::Class ClassObject;
-#define ObjectClass _CL_Q34java4lang6Object
-extern java::lang::Class ObjectClass;
-
+// Exceptional return values for _Jv_DetermineVTableIndex
+#define METHOD_NOT_THERE (-2)
+#define METHOD_INACCESSIBLE (-1)
 
 static int get_alignment_from_class (jclass);
 
@@ -60,7 +70,7 @@ static _Jv_Utf8Const *init_name = _Jv_makeUtf8Const ("<init>", 6);
 
 static void throw_incompatible_class_change_error (jstring msg)
 {
-  JvThrow (new java::lang::IncompatibleClassChangeError (msg));
+  throw new java::lang::IncompatibleClassChangeError (msg);
 }
 
 _Jv_word
@@ -88,7 +98,7 @@ _Jv_ResolvePoolEntry (jclass klass, int index)
       if (! found)
        {
          jstring str = _Jv_NewStringUTF (name->data);
-         JvThrow (new java::lang::ClassNotFoundException (str));
+         throw new java::lang::ClassNotFoundException (str);
        }
 
       if ((found->accflags & Modifier::PUBLIC) == Modifier::PUBLIC
@@ -100,7 +110,7 @@ _Jv_ResolvePoolEntry (jclass klass, int index)
        }
       else
        {
-         JvThrow (new java::lang::IllegalAccessError (found->getName()));
+         throw new java::lang::IllegalAccessError (found->getName());
        }
     }
     break;
@@ -175,17 +185,16 @@ _Jv_ResolvePoolEntry (jclass klass, int index)
                    _Jv_ResolveField (field, cls->loader);
 
                  if (field_type != 0 && field->type != field_type)
-                   JvThrow
-                     (new java::lang::LinkageError
-                      (JvNewStringLatin1 
-                       ("field type mismatch with different loaders")));
+                   throw new java::lang::LinkageError
+                     (JvNewStringLatin1 
+                      ("field type mismatch with different loaders"));
 
                  the_field = field;
                  goto end_of_field_search;
                }
              else
                {
-                 JvThrow (new java::lang::IllegalAccessError);
+                 throw new java::lang::IllegalAccessError;
                }
            }
        }
@@ -230,59 +239,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 == METHOD_NOT_THERE)
+       throw_incompatible_class_change_error
+         (JvNewStringLatin1 ("method not found"));
+
       if (the_method == 0)
        {
          jstring msg = JvNewStringLatin1 ("method ");
@@ -290,7 +318,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));
+         throw new java::lang::NoSuchMethodError (msg);
        }
       
       pool->data[index].rmethod = 
@@ -307,25 +335,49 @@ _Jv_ResolvePoolEntry (jclass klass, int index)
   return pool->data[index];
 }
 
-
-void
-_Jv_ResolveField (_Jv_Field *field, java::lang::ClassLoader *loader)
+// 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)
 {
-  if (! field->isResolved ())
+  using namespace java::lang::reflect;
+
+  for (int i = 0;  i < cls->method_count;  i++)
     {
-      _Jv_Utf8Const *sig = (_Jv_Utf8Const*)field->type;
-      field->type = _Jv_FindClassFromSignature (sig->data, loader);
-      field->flags &= ~_Jv_FIELD_UNRESOLVED_FLAG;
+      _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
+       {
+         throw new java::lang::IllegalAccessError;
+       }
     }
+  return 0;
 }
 
 /** FIXME: this is a terribly inefficient algorithm!  It would improve
     things if compiled classes to know vtable offset, and _Jv_Method had
     a field for this.
 
-    Returns  if this class does not declare the given method.
-    Returns -1 if the given method does not appear in the vtable.
-               i.e., it is static, private, final or a constructor.
+    Returns METHOD_NOT_THERE if this class does not declare the given method.
+    Returns METHOD_INACCESSIBLE if the given method does not appear in the
+               vtable, i.e., it is static, private, final or a constructor.
     Otherwise, returns the vtable index.  */
 int 
 _Jv_DetermineVTableIndex (jclass klass,
@@ -341,7 +393,7 @@ _Jv_DetermineVTableIndex (jclass klass,
       int prev = _Jv_DetermineVTableIndex (super_class,
                                           name,
                                           signature);
-      if (prev != 0)
+      if (prev != METHOD_NOT_THERE)
        return prev;
     }
 
@@ -355,7 +407,7 @@ _Jv_DetermineVTableIndex (jclass klass,
 
   /* now, if we do not declare this method, return zero */
   if (meth == NULL)
-    return 0;
+    return METHOD_NOT_THERE;
 
   /* so now, we know not only that the super class does not declare the
    * method, but we do!  So, this is a first declaration of the method. */
@@ -372,21 +424,21 @@ _Jv_DetermineVTableIndex (jclass klass,
                         | Modifier::FINAL)) != 0
       || (klass->accflags & Modifier::FINAL) != 0
       || _Jv_equalUtf8Consts (name, init_name))
-    return -1;
+    return METHOD_INACCESSIBLE;
 
   /* reaching this point, we know for sure, that the method in question
    * will be in the vtable.  The question is where. */
 
   /* the base offset, is where we will start assigning vtable
-   * indexes for this class.  It is 1 for base classes
-   * (vtable->method[0] is unused), and for non-base classes it is the
-   * number of entries in the super class' vtable plus 1. */
+   * indexes for this class.  It is 0 for base classes
+   * and for non-base classes it is the
+   * number of entries in the super class' vtable. */
 
   int base_offset;
   if (super_class == 0)
-    base_offset = 1;
+    base_offset = 0;
   else
-    base_offset = super_class->vtable_method_count+1;
+    base_offset = super_class->vtable_method_count;
 
   /* we will consider methods 0..this_method_index-1.  And for each one,
    * determine if it is new (i.e., if it appears in the super class),
@@ -433,7 +485,7 @@ _Jv_DetermineVTableIndex (jclass klass,
 static void
 _Jv_abstractMethodError ()
 {
-  JvThrow (new java::lang::AbstractMethodError);
+  throw new java::lang::AbstractMethodError;
 }
 
 void 
@@ -631,8 +683,7 @@ _Jv_PrepareClass(jclass klass)
        {
          clz->state = JV_STATE_ERROR;
          clz->notifyAll ();
-         JvThrow (new java::lang::IncompatibleClassChangeError 
-                          (clz->getName ()));
+         throw new java::lang::IncompatibleClassChangeError (clz->getName ());
        }
 
       /* FIXME: At this point, if (loader != super_class->loader), we
@@ -649,6 +700,7 @@ _Jv_PrepareClass(jclass klass)
     _Jv_AllocBytesChecked (sizeof (_Jv_VTable) 
                           + (sizeof (void*) * (vtable_count)));
   vtable->clas = clz;
+  vtable->gc_descr = _Jv_BuildGCDescr(clz);
 
   {
     jclass effective_superclass = super_class;
@@ -658,10 +710,10 @@ _Jv_PrepareClass(jclass klass)
     while (effective_superclass && effective_superclass->vtable == NULL)
       effective_superclass = effective_superclass->superclass;
 
-    /* copy super class' vtable entries (index 0 goes unused). */
+    /* copy super class' vtable entries. */
     if (effective_superclass && effective_superclass->vtable)
-      memcpy ((void*)&vtable->method[1],
-             (void*)&effective_superclass->vtable->method[1],
+      memcpy ((void*)&vtable->method[0],
+             (void*)&effective_superclass->vtable->method[0],
              sizeof (void*) * effective_superclass->vtable_method_count);
   }
 
@@ -674,12 +726,12 @@ _Jv_PrepareClass(jclass klass)
                                            this_meth->name,
                                            this_meth->signature);
 
-      if (index == 0)
+      if (index == METHOD_NOT_THERE)
        throw_internal_error ("method now found in own class");
 
-      if (index != -1)
+      if (index != METHOD_INACCESSIBLE)
        {
-         if (index > clz->vtable_method_count+1)
+         if (index > clz->vtable_method_count)
            throw_internal_error ("vtable problem...");
 
          if (clz->interpreted_methods[i] == 0)
@@ -750,7 +802,8 @@ _Jv_InitField (jobject obj, jclass klass, int index)
       /* fall through */
 
     case JV_CONSTANT_ResolvedString:
-      if (! (field->type == &StringClass || field->type == &ObjectClass))
+      if (! (field->type == &StringClass
+            || field->type == &java::lang::Class::class$))
        throw_class_format_error ("string initialiser to non-string field");
 
       *(jstring*)addr = pool->data[init].string;
@@ -990,6 +1043,13 @@ init_cif (_Jv_Utf8Const* signature,
   return item_count;
 }
 
+#if FFI_NATIVE_RAW_API
+#   define FFI_PREP_RAW_CLOSURE ffi_prep_raw_closure
+#   define FFI_RAW_SIZE ffi_raw_size
+#else
+#   define FFI_PREP_RAW_CLOSURE ffi_prep_java_raw_closure
+#   define FFI_RAW_SIZE ffi_java_raw_size
+#endif
 
 /* we put this one here, and not in interpret.cc because it
  * calls the utility routines count_arguments 
@@ -1028,7 +1088,7 @@ _Jv_InterpMethod::ncode ()
 
   ffi_closure_fun fun;
 
-  args_raw_size = ffi_raw_size (&closure->cif);
+  args_raw_size = FFI_RAW_SIZE (&closure->cif);
 
   JvAssert ((self->accflags & Modifier::NATIVE) == 0);
 
@@ -1044,10 +1104,10 @@ _Jv_InterpMethod::ncode ()
       fun = (ffi_closure_fun)&_Jv_InterpMethod::run_normal;
     }
 
-  ffi_prep_raw_closure (&closure->closure,
-                       &closure->cif, 
-                       fun,
-                       (void*) this);
+  FFI_PREP_RAW_CLOSURE (&closure->closure,
+                       &closure->cif, 
+                       fun,
+                       (void*)this);
 
   self->ncode = (void*)closure;
   return self->ncode;
@@ -1079,7 +1139,7 @@ _Jv_JNIMethod::ncode ()
 
   ffi_closure_fun fun;
 
-  args_raw_size = ffi_raw_size (&closure->cif);
+  args_raw_size = FFI_RAW_SIZE (&closure->cif);
 
   // Initialize the argument types and CIF that represent the actual
   // underlying JNI function.
@@ -1106,7 +1166,7 @@ _Jv_JNIMethod::ncode ()
   // interpreted code use JNI.
   fun = (ffi_closure_fun) &_Jv_JNIMethod::call;
 
-  ffi_prep_raw_closure (&closure->closure,
+  FFI_PREP_RAW_CLOSURE (&closure->closure,
                        &closure->cif, 
                        fun,
                        (void*) this);
@@ -1149,10 +1209,9 @@ _Jv_BuildResolvedMethod (_Jv_Method* method,
 static void
 throw_class_format_error (jstring msg)
 {
-  if (msg == 0)
-    JvThrow (new java::lang::ClassFormatError);
-  else
-    JvThrow (new java::lang::ClassFormatError (msg));
+  throw (msg
+        ? new java::lang::ClassFormatError (msg)
+        : new java::lang::ClassFormatError);
 }
 
 static void
@@ -1164,8 +1223,7 @@ throw_class_format_error (char *msg)
 static void
 throw_internal_error (char *msg)
 {
-  JvThrow 
-    (new java::lang::InternalError (JvNewStringLatin1 (msg)));
+  throw new java::lang::InternalError (JvNewStringLatin1 (msg));
 }