diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/mirror/class.h | 17 | ||||
| -rw-r--r-- | src/verifier/method_verifier.cc | 13 | ||||
| -rw-r--r-- | src/verifier/reg_type_cache.cc | 56 |
3 files changed, 62 insertions, 24 deletions
diff --git a/src/mirror/class.h b/src/mirror/class.h index 0661b42170..16ca2bddd5 100644 --- a/src/mirror/class.h +++ b/src/mirror/class.h @@ -235,6 +235,23 @@ class MANAGED Class : public StaticStorageBase { 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 8ca5b82018..6338659073 100644 --- a/src/verifier/method_verifier.cc +++ b/src/verifier/method_verifier.cc @@ -2613,7 +2613,8 @@ const RegType& MethodVerifier::ResolveClassAndCheckAccess(uint32_t class_idx) { 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 @@ mirror::AbstractMethod* MethodVerifier::VerifyInvocationArgs(const Instruction* } 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::Field* MethodVerifier::GetInstanceField(const RegType& obj_type, int fie 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 RegType& MethodVerifier::GetDeclaringClass() { 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 a575f7705b..ce3e6f6219 100644 --- a/src/verifier/reg_type_cache.cc +++ b/src/verifier/reg_type_cache.cc @@ -31,7 +31,17 @@ uint16_t RegTypeCache::primitive_count_ = 0; 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 @@ bool RegTypeCache::MatchDescriptor(size_t idx, const char* descriptor, bool prec 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 @@ const RegType& RegTypeCache::From(mirror::ClassLoader* loader, const char* descr // 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::From(mirror::ClassLoader* loader, const char* descr 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 @@ const RegType& RegTypeCache::FromUninitialized(const RegType& uninit_type) { 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 @@ const RegType& RegTypeCache::FromUninitialized(const RegType& uninit_type) { } 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 @@ const RegType& RegTypeCache::GetComponentType(const RegType& array, mirror::Clas 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()); } } |