diff options
Diffstat (limited to 'libjava/link.cc')
-rw-r--r-- | libjava/link.cc | 155 |
1 files changed, 75 insertions, 80 deletions
diff --git a/libjava/link.cc b/libjava/link.cc index 3f45ac119a2..909a7b68a0e 100644 --- a/libjava/link.cc +++ b/libjava/link.cc @@ -100,6 +100,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 +109,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 +134,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,6 +146,18 @@ _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. @@ -143,23 +170,14 @@ _Jv_Linker::find_field (jclass klass, jclass owner, _Jv_Utf8Const *field_name, _Jv_Utf8Const *field_type_name) { - jclass field_type = 0; - - 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); - } + // FIXME: this allocates a _Jv_Utf8Const each time. We should make + // it cheaper. + jclass 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) { @@ -174,12 +192,11 @@ _Jv_Linker::find_field (jclass klass, jclass owner, 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")); @@ -665,12 +682,21 @@ _Jv_Linker::generate_itable (jclass klass, _Jv_ifaces *ifaces, // Format method name for use in error messages. jstring -_Jv_GetMethodString (jclass klass, _Jv_Utf8Const *name) +_Jv_GetMethodString (jclass klass, _Jv_Method *meth, + jclass derived) { - jstring r = klass->name->toString(); - r = r->concat (JvNewStringUTF (".")); - r = r->concat (name->toString()); - return r; + using namespace java::lang; + StringBuffer *buf = new StringBuffer (klass->name->toString()); + buf->append (jchar ('.')); + buf->append (meth->name->toString()); + buf->append ((jchar) ' '); + buf->append (meth->signature->toString()); + if (derived) + { + buf->append(JvNewStringLatin1(" in ")); + buf->append(derived->name->toString()); + } + return buf->toString(); } void @@ -679,6 +705,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. @@ -720,15 +753,15 @@ _Jv_Linker::append_partial_itable (jclass klass, jclass iface, { if ((meth->accflags & Modifier::STATIC) != 0) throw new java::lang::IncompatibleClassChangeError - (_Jv_GetMethodString (klass, meth->name)); - if ((meth->accflags & Modifier::ABSTRACT) != 0) - throw new java::lang::AbstractMethodError - (_Jv_GetMethodString (klass, meth->name)); + (_Jv_GetMethodString (klass, meth)); if ((meth->accflags & Modifier::PUBLIC) == 0) throw new java::lang::IllegalAccessError - (_Jv_GetMethodString (klass, meth->name)); + (_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 { @@ -1092,13 +1125,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) @@ -1161,9 +1187,9 @@ _Jv_Linker::layout_vtable_methods (jclass klass) using namespace java::lang; StringBuffer *sb = new StringBuffer(); sb->append(JvNewStringLatin1("method ")); - sb->append(_Jv_GetMethodString(klass, meth->name)); + sb->append(_Jv_GetMethodString(klass, meth)); sb->append(JvNewStringLatin1(" overrides final method ")); - sb->append(_Jv_GetMethodString(declarer, super_meth->name)); + sb->append(_Jv_GetMethodString(declarer, super_meth)); throw new VerifyError(sb->toString()); } } @@ -1190,6 +1216,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); @@ -1238,33 +1266,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; - while (klass != NULL) - { - for (int j = 0; j < klass->method_count; ++j) - { - if (klass->methods[j].index == i) - { - StringBuffer *buf = new StringBuffer (); - buf->append (_Jv_NewStringUtf8Const (klass->methods[j].name)); - buf->append ((jchar) ' '); - buf->append (_Jv_NewStringUtf8Const (klass->methods[j].signature)); - throw new AbstractMethodError (buf->toString ()); - } - } - 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 @@ -1391,9 +1395,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. @@ -1648,11 +1650,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"; @@ -1689,10 +1687,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 |