Fix for 073-mismatched-field test
ART distinguishes between static and instance field resolution whereas
Java doesn't. Interface static fields bind more closely than those of
superclasses. Implement field resolution code for the verifier so that
it can determine incompatible class change errors when a static field
binds before an instance field.
Also don't search all iftable interfaces, search them in superclass
order (as the specification dictates).
Change-Id: I43b45bada8b9099ad805b244be10833d59bacfe3
diff --git a/src/class_linker.cc b/src/class_linker.cc
index ab5f9d6..d59323b 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -72,11 +72,11 @@
Thread::Current()->ThrowNewException("Ljava/lang/NoSuchMethodError;", msg.str().c_str());
}
-void ThrowNoSuchFieldError(bool is_static, Class* c, const StringPiece& type,
+void ThrowNoSuchFieldError(const StringPiece& scope, Class* c, const StringPiece& type,
const StringPiece& name) {
ClassHelper kh(c);
std::ostringstream msg;
- msg << "no " << (is_static ? "static": "instance") << " field " << name << " of type " << type
+ msg << "no " << scope << "field " << name << " of type " << type
<< " in class " << kh.GetDescriptor() << " or its superclasses";
std::string location(kh.GetLocation());
if (!location.empty()) {
@@ -2796,7 +2796,33 @@
if (resolved != NULL) {
dex_cache->SetResolvedField(field_idx, resolved);
} else {
- ThrowNoSuchFieldError(is_static, klass, type, name);
+ ThrowNoSuchFieldError(is_static ? "static " : "instance ", klass, type, name);
+ }
+ return resolved;
+}
+
+Field* ClassLinker::ResolveFieldJLS(const DexFile& dex_file,
+ uint32_t field_idx,
+ DexCache* dex_cache,
+ const ClassLoader* class_loader) {
+ Field* resolved = dex_cache->GetResolvedField(field_idx);
+ if (resolved != NULL) {
+ return resolved;
+ }
+ const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx);
+ Class* klass = ResolveType(dex_file, field_id.class_idx_, dex_cache, class_loader);
+ if (klass == NULL) {
+ DCHECK(Thread::Current()->IsExceptionPending());
+ return NULL;
+ }
+
+ const char* name = dex_file.GetFieldName(field_id);
+ const char* type = dex_file.GetFieldTypeDescriptor(field_id);
+ resolved = klass->FindField(name, type);
+ if (resolved != NULL) {
+ dex_cache->SetResolvedField(field_idx, resolved);
+ } else {
+ ThrowNoSuchFieldError("", klass, type, name);
}
return resolved;
}
diff --git a/src/class_linker.h b/src/class_linker.h
index 5cd72b8..db30936 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -196,6 +196,27 @@
const ClassLoader* class_loader,
bool is_static);
+ Field* ResolveFieldJLS(uint32_t field_idx, const Method* referrer) {
+ Field* resolved_field = referrer->GetDexCacheResolvedFields()->Get(field_idx);
+ if (UNLIKELY(resolved_field == NULL)) {
+ Class* declaring_class = referrer->GetDeclaringClass();
+ DexCache* dex_cache = declaring_class->GetDexCache();
+ const ClassLoader* class_loader = declaring_class->GetClassLoader();
+ const DexFile& dex_file = FindDexFile(dex_cache);
+ resolved_field = ResolveFieldJLS(dex_file, field_idx, dex_cache, class_loader);
+ }
+ return resolved_field;
+ }
+
+ // Resolve a field with a given ID from the DexFile, storing the
+ // result in DexCache. The ClassLinker and ClassLoader are used as
+ // in ResolveType. No is_static argument is provided so that Java
+ // field resolution semantics are followed.
+ Field* ResolveFieldJLS(const DexFile& dex_file,
+ uint32_t field_idx,
+ DexCache* dex_cache,
+ const ClassLoader* class_loader);
+
// Get shorty from method index without resolution. Used to do handlerization.
const char* MethodShorty(uint32_t method_idx, Method* referrer);
diff --git a/src/dex_verifier.cc b/src/dex_verifier.cc
index 46a5bec..e002917 100644
--- a/src/dex_verifier.cc
+++ b/src/dex_verifier.cc
@@ -3304,7 +3304,7 @@
}
Field* DexVerifier::GetStaticField(int field_idx) {
- Field* field = Runtime::Current()->GetClassLinker()->ResolveField(field_idx, method_, true);
+ Field* field = Runtime::Current()->GetClassLinker()->ResolveFieldJLS(field_idx, method_);
if (field == NULL) {
const DexFile::FieldId& field_id = dex_file_->GetFieldId(field_idx);
LOG(INFO) << "unable to resolve static field " << field_idx << " ("
@@ -3327,7 +3327,7 @@
}
Field* DexVerifier::GetInstanceField(const RegType& obj_type, int field_idx) {
- Field* field = Runtime::Current()->GetClassLinker()->ResolveField(field_idx, method_, false);
+ Field* field = Runtime::Current()->GetClassLinker()->ResolveFieldJLS(field_idx, method_);
if (field == NULL) {
const DexFile::FieldId& field_id = dex_file_->GetFieldId(field_idx);
LOG(INFO) << "unable to resolve instance field " << field_idx << " ("
diff --git a/src/object.cc b/src/object.cc
index 1ef7201..10d4289 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -957,17 +957,43 @@
Field* Class::FindStaticField(const StringPiece& name, const StringPiece& type) {
// Is the field in this class (or its interfaces), or any of its
// superclasses (or their interfaces)?
- for (Class* c = this; c != NULL; c = c->GetSuperClass()) {
+ ClassHelper kh;
+ for (Class* k = this; k != NULL; k = k->GetSuperClass()) {
// Is the field in this class?
- Field* f = c->FindDeclaredStaticField(name, type);
+ Field* f = k->FindDeclaredStaticField(name, type);
if (f != NULL) {
return f;
}
-
// Is this field in any of this class' interfaces?
- for (int32_t i = 0; i < c->GetIfTableCount(); ++i) {
- InterfaceEntry* interface_entry = c->GetIfTable()->Get(i);
- Class* interface = interface_entry->GetInterface();
+ kh.ChangeClass(k);
+ for (uint32_t i = 0; i < kh.NumInterfaces(); ++i) {
+ Class* interface = kh.GetInterface(i);
+ f = interface->FindDeclaredStaticField(name, type);
+ if (f != NULL) {
+ return f;
+ }
+ }
+ }
+ return NULL;
+}
+
+Field* Class::FindField(const StringPiece& name, const StringPiece& type) {
+ // Find a field using the JLS field resolution order
+ ClassHelper kh;
+ for (Class* k = this; k != NULL; k = k->GetSuperClass()) {
+ // Is the field in this class?
+ Field* f = k->FindDeclaredInstanceField(name, type);
+ if (f != NULL) {
+ return f;
+ }
+ f = k->FindDeclaredStaticField(name, type);
+ if (f != NULL) {
+ return f;
+ }
+ // Is this field in any of this class' interfaces?
+ kh.ChangeClass(k);
+ for (uint32_t i = 0; i < kh.NumInterfaces(); ++i) {
+ Class* interface = kh.GetInterface(i);
f = interface->FindDeclaredStaticField(name, type);
if (f != NULL) {
return f;
diff --git a/src/object.h b/src/object.h
index 80bb000..28ab98b 100644
--- a/src/object.h
+++ b/src/object.h
@@ -1656,6 +1656,9 @@
void SetReferenceStaticOffsets(uint32_t new_reference_offsets);
+ // Find a static or instance field using the JLS resolution order
+ Field* FindField(const StringPiece& name, const StringPiece& type);
+
// Finds the given instance field in this class or a superclass.
Field* FindInstanceField(const StringPiece& name, const StringPiece& type);