Don't always mark array types as precise.
Array types are always final, as they cannot be sub-classed, they may be
assigned by types that aren't themselves, e.g. Object[] may be assigned a
String[]. Introduce CannotBeAssignedFromOtherTypes to capture this property
and use in the verifier instead of IsFinal to mark things as precise.
Change-Id: I34debd3164ca1b876be94b6722457cee6e1e9bd3
diff --git a/src/mirror/class.h b/src/mirror/class.h
index 0661b42..16ca2bd 100644
--- a/src/mirror/class.h
+++ b/src/mirror/class.h
@@ -235,6 +235,23 @@
return (GetAccessFlags() & kAccClassIsPhantomReference) != 0;
}
+ // Can references of this type be assigned to by things of another type? For non-array types
+ // this is a matter of whether sub-classes may exist - which they can't if the type is final.
+ // For array classes, where all the classes are final due to there being no sub-classes, an
+ // Object[] may be assigned to by a String[] but a String[] may not be assigned to by other
+ // types as the component is final.
+ bool CannotBeAssignedFromOtherTypes() const {
+ if (!IsArrayClass()) {
+ return IsFinal();
+ } else {
+ Class* component = GetComponentType();
+ if (component->IsPrimitive()) {
+ return false;
+ } else {
+ return component->CannotBeAssignedFromOtherTypes();
+ }
+ }
+ }
String* GetName() const; // Returns the cached name.
void SetName(String* name) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Sets the cached name.
diff --git a/src/verifier/method_verifier.cc b/src/verifier/method_verifier.cc
index 8ca5b82..6338659 100644
--- a/src/verifier/method_verifier.cc
+++ b/src/verifier/method_verifier.cc
@@ -2613,7 +2613,8 @@
const RegType& referrer = GetDeclaringClass();
mirror::Class* klass = dex_cache_->GetResolvedType(class_idx);
const RegType& result =
- klass != NULL ? reg_types_.FromClass(descriptor, klass, klass->IsFinal())
+ klass != NULL ? reg_types_.FromClass(descriptor, klass,
+ klass->CannotBeAssignedFromOtherTypes())
: reg_types_.FromDescriptor(class_loader_, descriptor, false);
if (result.IsConflict()) {
Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "accessing broken descriptor '" << descriptor
@@ -2829,8 +2830,9 @@
}
if (method_type != METHOD_INTERFACE && !actual_arg_type.IsZero()) {
mirror::Class* klass = res_method->GetDeclaringClass();
- const RegType& res_method_class = reg_types_.FromClass(ClassHelper(klass).GetDescriptor(),
- klass, klass->IsFinal());
+ const RegType& res_method_class =
+ reg_types_.FromClass(ClassHelper(klass).GetDescriptor(), klass,
+ klass->CannotBeAssignedFromOtherTypes());
if (!res_method_class.IsAssignableFrom(actual_arg_type)) {
Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "'this' argument '" << actual_arg_type
<< "' not instance of '" << res_method_class << "'";
@@ -3085,7 +3087,7 @@
mirror::Class* klass = field->GetDeclaringClass();
const RegType& field_klass =
reg_types_.FromClass(dex_file_->GetFieldDeclaringClassDescriptor(field_id),
- klass, klass->IsFinal());
+ klass, klass->CannotBeAssignedFromOtherTypes());
if (obj_type.IsUninitializedTypes() &&
(!IsConstructor() || GetDeclaringClass().Equals(obj_type) ||
!field_klass.Equals(GetDeclaringClass()))) {
@@ -3300,7 +3302,8 @@
const char* descriptor = dex_file_->GetTypeDescriptor(dex_file_->GetTypeId(method_id.class_idx_));
if (mirror_method_ != NULL) {
mirror::Class* klass = mirror_method_->GetDeclaringClass();
- declaring_class_ = ®_types_.FromClass(descriptor, klass, klass->IsFinal());
+ declaring_class_ = ®_types_.FromClass(descriptor, klass,
+ klass->CannotBeAssignedFromOtherTypes());
} else {
declaring_class_ = ®_types_.FromDescriptor(class_loader_, descriptor, false);
}
diff --git a/src/verifier/reg_type_cache.cc b/src/verifier/reg_type_cache.cc
index a575f77..ce3e6f6 100644
--- a/src/verifier/reg_type_cache.cc
+++ b/src/verifier/reg_type_cache.cc
@@ -31,7 +31,17 @@
static bool MatchingPrecisionForClass(RegType* entry, bool precise)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- return (entry->IsPreciseReference() == precise) || (entry->GetClass()->IsFinal() && !precise);
+ if (entry->IsPreciseReference() == precise) {
+ // We were or weren't looking for a precise reference and we found what we need.
+ return true;
+ } else {
+ if (!precise && entry->GetClass()->CannotBeAssignedFromOtherTypes()) {
+ // We weren't looking for a precise reference, as we're looking up based on a descriptor, but
+ // we found a matching entry based on the descriptor. Return the precise entry in that case.
+ return true;
+ }
+ return false;
+ }
}
void RegTypeCache::FillPrimitiveTypes() {
@@ -112,10 +122,13 @@
if (entry->descriptor_ != descriptor) {
return false;
}
- if (entry->HasClass() && MatchingPrecisionForClass(entry, precise)) {
- return true;
+ if (entry->HasClass()) {
+ return MatchingPrecisionForClass(entry, precise);
}
- return entry->IsUnresolvedReference();
+ // There is no notion of precise unresolved references, the precise information is just dropped
+ // on the floor.
+ DCHECK(entry->IsUnresolvedReference());
+ return true;
}
mirror::Class* RegTypeCache::ResolveClass(const char* descriptor, mirror::ClassLoader* loader) {
@@ -166,7 +179,7 @@
// 2- Precise Flag passed as true.
RegType* entry;
// Create an imprecise type if we can't tell for a fact that it is precise.
- if ((klass->IsFinal()) || precise) {
+ if (klass->CannotBeAssignedFromOtherTypes() || precise) {
DCHECK(!(klass->IsAbstract()) || klass->IsArrayClass());
DCHECK(!klass->IsInterface());
entry = new PreciseReferenceType(klass, descriptor, entries_.size());
@@ -193,6 +206,8 @@
const RegType& RegTypeCache::FromClass(const char* descriptor, mirror::Class* klass, bool precise) {
if (klass->IsPrimitive()) {
+ // Note: precise isn't used for primitive classes. A char is assignable to an int. All
+ // primitive classes are final.
return RegTypeFromPrimitiveType(klass->GetPrimitiveType());
} else {
// Look for the reference in the list of entries to have.
@@ -362,8 +377,9 @@
entry = new UnresolvedReferenceType(descriptor.c_str(), entries_.size());
} else {
mirror::Class* klass = uninit_type.GetClass();
+ DCHECK(!klass->IsArrayClass());
if(uninit_type.IsUninitializedThisReference() && !klass->IsFinal()) {
- // For uninitialized this reference look for reference types that are not precise.
+ // For uninitialized "this reference" look for reference types that are not precise.
for (size_t i = primitive_count_; i < entries_.size(); i++) {
RegType* cur_entry = entries_[i];
if (cur_entry->IsReference() && cur_entry->GetClass() == klass) {
@@ -372,21 +388,22 @@
}
entry = new ReferenceType(klass, "", entries_.size());
} else {
- if (klass->IsFinal()) {
- if (klass->IsInstantiable()) {
- for (size_t i = primitive_count_; i < entries_.size(); i++) {
- RegType* cur_entry = entries_[i];
- if (cur_entry->IsPreciseReference() && cur_entry->GetClass() == klass) {
- return *cur_entry;
- }
+ if (klass->IsFinal()) {
+ if (klass->IsInstantiable()) {
+ for (size_t i = primitive_count_; i < entries_.size(); i++) {
+ RegType* cur_entry = entries_[i];
+ if (cur_entry->IsPreciseReference() && cur_entry->GetClass() == klass) {
+ return *cur_entry;
}
- // Precise type was not found , create one !
- entry = new PreciseReferenceType(klass, "", entries_.size());
- } else {
- return Conflict();
}
+ // Precise type was not found , create one !
+ entry = new PreciseReferenceType(klass, "", entries_.size());
+ } else {
+ return Conflict();
+ }
} else {
- // Not a final class, create an imprecise reference. Look up if we have it in the cache first.
+ // Not a final class, create an imprecise reference. Look up if we have it in the cache
+ // first.
for (size_t i = primitive_count_; i < entries_.size(); i++) {
RegType* cur_entry = entries_[i];
if (cur_entry->IsReference() && !(cur_entry->IsPrecise()) &&
@@ -504,7 +521,8 @@
return FromDescriptor(loader, component.c_str(), false);
} else {
mirror::Class* klass = array.GetClass()->GetComponentType();
- return FromClass(ClassHelper(klass).GetDescriptor(), klass, klass->IsFinal());
+ return FromClass(ClassHelper(klass).GetDescriptor(), klass,
+ klass->CannotBeAssignedFromOtherTypes());
}
}