OSDN Git Service

* config/bfin/bfin.c (emit_link_insn, effective_address_32bit_p,
[pf3gnuchains/gcc-fork.git] / libjava / link.cc
index 8dd809b..0a70573 100644 (file)
@@ -90,8 +90,11 @@ _Jv_Linker::resolve_field (_Jv_Field *field, java::lang::ClassLoader *loader)
 {
   if (! field->isResolved ())
     {
-      _Jv_Utf8Const *sig = (_Jv_Utf8Const*)field->type;
-      field->type = _Jv_FindClassFromSignature (sig->chars(), loader);
+      _Jv_Utf8Const *sig = (_Jv_Utf8Const *) field->type;
+      jclass type = _Jv_FindClassFromSignature (sig->chars(), loader);
+      if (type == NULL)
+       throw new java::lang::NoClassDefFoundError(field->name->toString());
+      field->type = type;
       field->flags &= ~_Jv_FIELD_UNRESOLVED_FLAG;
     }
 }
@@ -100,6 +103,7 @@ _Jv_Linker::resolve_field (_Jv_Field *field, java::lang::ClassLoader *loader)
 // superclasses and interfaces.
 _Jv_Field *
 _Jv_Linker::find_field_helper (jclass search, _Jv_Utf8Const *name,
+                              _Jv_Utf8Const *type_name,
                               jclass *declarer)
 {
   while (search)
@@ -108,7 +112,21 @@ _Jv_Linker::find_field_helper (jclass search, _Jv_Utf8Const *name,
       for (int i = 0; i < search->field_count; ++i)
        {
          _Jv_Field *field = &search->fields[i];
-         if (_Jv_equalUtf8Consts (field->name, name))
+         if (! _Jv_equalUtf8Consts (field->name, name))
+           continue;
+
+         if (! field->isResolved ())
+           resolve_field (field, search->loader);
+
+         // Note that we compare type names and not types.  This is
+         // bizarre, but we do it because we want to find a field
+         // (and terminate the search) if it has the correct
+         // descriptor -- but then later reject it if the class
+         // loader check results in different classes.  We can't just
+         // pass in the descriptor and check that way, because when
+         // the field is already resolved there is no easy way to
+         // find its descriptor again.
+         if (_Jv_equalUtf8Consts (type_name, field->type->name))
            {
              *declarer = search;
              return field;
@@ -119,7 +137,7 @@ _Jv_Linker::find_field_helper (jclass search, _Jv_Utf8Const *name,
       for (int i = 0; i < search->interface_count; ++i)
        {
          _Jv_Field *result = find_field_helper (search->interfaces[i], name,
-                                                declarer);
+                                                type_name, declarer);
          if (result)
            return result;
        }
@@ -131,35 +149,42 @@ _Jv_Linker::find_field_helper (jclass search, _Jv_Utf8Const *name,
   return NULL;
 }
 
+bool
+_Jv_Linker::has_field_p (jclass search, _Jv_Utf8Const *field_name)
+{
+  for (int i = 0; i < search->field_count; ++i)
+    {
+      _Jv_Field *field = &search->fields[i];
+      if (_Jv_equalUtf8Consts (field->name, field_name))
+       return true;
+    }
+  return false;
+}
+
 // Find a field.
 // KLASS is the class that is requesting the field.
 // OWNER is the class in which the field should be found.
 // FIELD_TYPE_NAME is the type descriptor for the field.
+// Fill FOUND_CLASS with the address of the class in which the field
+// is actually declared.
 // This function does the class loader type checks, and
 // also access checks.  Returns the field, or throws an
 // exception on error.
 _Jv_Field *
 _Jv_Linker::find_field (jclass klass, jclass owner,
+                       jclass *found_class,
                        _Jv_Utf8Const *field_name,
                        _Jv_Utf8Const *field_type_name)
 {
-  jclass field_type = 0;
+  // FIXME: this allocates a _Jv_Utf8Const each time.  We should make
+  // it cheaper.
+  jclass field_type = _Jv_FindClassFromSignature (field_type_name->chars(),
+                                                 klass->loader);
+  if (field_type == NULL)
+    throw new java::lang::NoClassDefFoundError(field_name->toString());
 
-  if (owner->loader != klass->loader)
-    {
-      // FIXME: The implementation of this function
-      // (_Jv_FindClassFromSignature) will generate an instance of
-      // _Jv_Utf8Const for each call if the field type is a class name
-      // (Lxx.yy.Z;).  This may be too expensive to do for each and
-      // every fieldref being resolved.  For now, we fix the problem
-      // by only doing it when we have a loader different from the
-      // class declaring the field.
-      field_type = _Jv_FindClassFromSignature (field_type_name->chars(),
-                                              klass->loader);
-    }
-
-  jclass found_class = 0;
-  _Jv_Field *the_field = find_field_helper (owner, field_name, &found_class);
+  _Jv_Field *the_field = find_field_helper (owner, field_name,
+                                           field_type->name, found_class);
 
   if (the_field == 0)
     {
@@ -172,14 +197,13 @@ _Jv_Linker::find_field (jclass klass, jclass owner,
       throw new java::lang::NoSuchFieldError (sb->toString());
     }
 
-  if (_Jv_CheckAccess (klass, found_class, the_field->flags))
+  if (_Jv_CheckAccess (klass, *found_class, the_field->flags))
     {
-      // Resolve the field using the class' own loader if necessary.
-
-      if (!the_field->isResolved ())
-       resolve_field (the_field, found_class->loader);
-
-      if (field_type != 0 && the_field->type != field_type)
+      // Note that the field returned by find_field_helper is always
+      // resolved.  There's no point checking class loaders here,
+      // since we already did the work to look up all the types.
+      // FIXME: being lazy here would be nice.
+      if (the_field->type != field_type)
        throw new java::lang::LinkageError
          (JvNewStringLatin1 
           ("field type mismatch with different loaders"));
@@ -190,7 +214,7 @@ _Jv_Linker::find_field (jclass klass, jclass owner,
        = new java::lang::StringBuffer ();
       sb->append(klass->getName());
       sb->append(JvNewStringLatin1(": "));
-      sb->append(found_class->getName());
+      sb->append((*found_class)->getName());
       sb->append(JvNewStringLatin1("."));
       sb->append(_Jv_NewStringUtf8Const (field_name));
       throw new java::lang::IllegalAccessError(sb->toString());
@@ -278,9 +302,13 @@ _Jv_Linker::resolve_pool_entry (jclass klass, int index)
        _Jv_Utf8Const *field_name = pool->data[name_index].utf8;
        _Jv_Utf8Const *field_type_name = pool->data[type_index].utf8;
 
-       _Jv_Field *the_field = find_field (klass, owner, field_name,
+       jclass found_class = 0;
+       _Jv_Field *the_field = find_field (klass, owner, 
+                                          &found_class,
+                                          field_name,
                                           field_type_name);
-
+       if (owner != found_class)
+         _Jv_InitClass (found_class);
        pool->data[index].field = the_field;
        pool->tags[index] |= JV_CONSTANT_ResolvedFlag;
       }
@@ -688,6 +716,13 @@ _Jv_ThrowNoSuchMethodError ()
   throw new java::lang::NoSuchMethodError;
 }
 
+// This is put in empty vtable slots.
+static void
+_Jv_abstractMethodError (void)
+{
+  throw new java::lang::AbstractMethodError();
+}
+
 // 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.
@@ -730,14 +765,14 @@ _Jv_Linker::append_partial_itable (jclass klass, jclass iface,
          if ((meth->accflags & Modifier::STATIC) != 0)
            throw new java::lang::IncompatibleClassChangeError
              (_Jv_GetMethodString (klass, meth));
-         if ((meth->accflags & Modifier::ABSTRACT) != 0)
-           throw new java::lang::AbstractMethodError
-             (_Jv_GetMethodString (klass, meth));
          if ((meth->accflags & Modifier::PUBLIC) == 0)
            throw new java::lang::IllegalAccessError
              (_Jv_GetMethodString (klass, meth));
 
-         itable[pos] = meth->ncode;
+         if ((meth->accflags & Modifier::ABSTRACT) != 0)
+           itable[pos] = (void *) &_Jv_abstractMethodError;
+         else
+           itable[pos] = meth->ncode;
        }
       else
         {
@@ -938,7 +973,8 @@ _Jv_Linker::link_symbol_table (jclass klass)
       // Try fields.
       {
        wait_for_state(target_class, JV_STATE_PREPARED);
-       _Jv_Field *the_field = find_field (klass, target_class,
+       jclass found_class;
+       _Jv_Field *the_field = find_field (klass, target_class, &found_class,
                                           sym.name, sym.signature);
        if ((the_field->flags & java::lang::reflect::Modifier::STATIC))
          throw new java::lang::IncompatibleClassChangeError;
@@ -1018,7 +1054,8 @@ _Jv_Linker::link_symbol_table (jclass klass)
       // Try fields.
       {
        wait_for_state(target_class, JV_STATE_PREPARED);
-       _Jv_Field *the_field = find_field (klass, target_class,
+       jclass found_class;
+       _Jv_Field *the_field = find_field (klass, target_class, &found_class,
                                           sym.name, sym.signature);
        if ((the_field->flags & java::lang::reflect::Modifier::STATIC))
          klass->atable->addresses[index] = the_field->u.addr;
@@ -1101,13 +1138,6 @@ _Jv_Linker::link_exception_table (jclass self)
   self->catch_classes->classname = (_Jv_Utf8Const *)-1;
 }
   
-// This is put in empty vtable slots.
-static void
-_Jv_abstractMethodError (void)
-{
-  throw new java::lang::AbstractMethodError();
-}
-
 // Set itable method indexes for members of interface IFACE.
 void
 _Jv_Linker::layout_interface_methods (jclass iface)
@@ -1199,6 +1229,8 @@ _Jv_Linker::set_vtable_entries (jclass klass, _Jv_VTable *vtable)
       if (meth->index == (_Jv_ushort) -1)
        continue;
       if ((meth->accflags & Modifier::ABSTRACT))
+       // FIXME: it might be nice to have a libffi trampoline here,
+       // so we could pass in the method name and other information.
        vtable->set_method(meth->index, (void *) &_Jv_abstractMethodError);
       else
        vtable->set_method(meth->index, meth->ncode);
@@ -1247,30 +1279,9 @@ _Jv_Linker::make_vtable (jclass klass)
   // override an old one.
   set_vtable_entries (klass, vtable);
 
-  // It is an error to have an abstract method in a concrete class.
-  if (! (klass->accflags & Modifier::ABSTRACT))
-    {
-      for (int i = 0; i < klass->vtable_method_count; ++i)
-       if (vtable->get_method(i) == (void *) &_Jv_abstractMethodError)
-         {
-           using namespace java::lang;
-           jclass orig = klass;
-           while (klass != NULL)
-             {
-               for (int j = 0; j < klass->method_count; ++j)
-                 {
-                   if (klass->methods[j].index == i)
-                     throw new AbstractMethodError(_Jv_GetMethodString(klass,
-                                                                       &klass->methods[j],
-                                                                       orig));
-                 }
-               klass = klass->getSuperclass ();
-             }
-           // Couldn't find the name, which is weird.
-           // But we still must throw the error.
-           throw new AbstractMethodError ();
-         }
-    }
+  // Note that we don't check for abstract methods here.  We used to,
+  // but there is a JVMS clarification that indicates that a check
+  // here would be too eager.  And, a simple test case confirms this.
 }
 
 // Lay out the class, allocating space for static fields and computing
@@ -1397,9 +1408,7 @@ _Jv_Linker::ensure_class_linked (jclass klass)
       // a reference to a class we can't access.  This can validly
       // occur in an obscure case involving the InnerClasses
       // attribute.
-#ifdef INTERPRETER
       if (! _Jv_IsInterpretedClass (klass))
-#endif
        {
          // Resolve class constants first, since other constant pool
          // entries may rely on these.
@@ -1654,11 +1663,7 @@ _Jv_Linker::print_class_loaded (jclass klass)
 
   // We use a somewhat bogus test for the ABI here.
   char *abi;
-#ifdef INTERPRETER
   if (_Jv_IsInterpretedClass (klass))
-#else
-  if (false)
-#endif
     abi = "bytecode";
   else if (klass->state == JV_STATE_PRELOADING)
     abi = "BC-compiled";
@@ -1695,10 +1700,7 @@ _Jv_Linker::wait_for_state (jclass klass, int state)
   if (gcj::verbose_class_flag
       && (klass->state == JV_STATE_COMPILED
          || klass->state == JV_STATE_PRELOADING)
-#ifdef INTERPRETER
-      && ! _Jv_IsInterpretedClass (klass)
-#endif
-      )
+      && ! _Jv_IsInterpretedClass (klass))
     print_class_loaded (klass);
 
   try