/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ART_RUNTIME_VERIFIER_REG_TYPE_INL_H_ #define ART_RUNTIME_VERIFIER_REG_TYPE_INL_H_ #include "reg_type.h" #include "base/casts.h" #include "base/scoped_arena_allocator.h" #include "method_verifier.h" #include "mirror/class.h" #include "verifier_deps.h" namespace art { namespace verifier { inline bool RegType::CanAccess(const RegType& other) const { DCHECK(IsReferenceTypes()); DCHECK(!IsNull()); if (Equals(other)) { return true; // Trivial accessibility. } else { bool this_unresolved = IsUnresolvedTypes(); bool other_unresolved = other.IsUnresolvedTypes(); if (!this_unresolved && !other_unresolved) { return GetClass()->CanAccess(other.GetClass()); } else if (!other_unresolved) { return other.GetClass()->IsPublic(); // Be conservative, only allow if other is public. } else { return false; // More complicated test not possible on unresolved types, be conservative. } } } inline bool RegType::CanAccessMember(ObjPtr klass, uint32_t access_flags) const { DCHECK(IsReferenceTypes()); if (IsNull()) { return true; } if (!IsUnresolvedTypes()) { return GetClass()->CanAccessMember(klass, access_flags); } else { return false; // More complicated test not possible on unresolved types, be conservative. } } inline bool RegType::IsConstantBoolean() const { if (!IsConstant()) { return false; } else { const ConstantType* const_val = down_cast(this); return const_val->ConstantValue() >= 0 && const_val->ConstantValue() <= 1; } } inline bool RegType::AssignableFrom(const RegType& lhs, const RegType& rhs, bool strict, MethodVerifier* verifier) { if (lhs.Equals(rhs)) { return true; } else { switch (lhs.GetAssignmentType()) { case AssignmentType::kBoolean: return rhs.IsBooleanTypes(); case AssignmentType::kByte: return rhs.IsByteTypes(); case AssignmentType::kShort: return rhs.IsShortTypes(); case AssignmentType::kChar: return rhs.IsCharTypes(); case AssignmentType::kInteger: return rhs.IsIntegralTypes(); case AssignmentType::kFloat: return rhs.IsFloatTypes(); case AssignmentType::kLongLo: return rhs.IsLongTypes(); case AssignmentType::kDoubleLo: return rhs.IsDoubleTypes(); case AssignmentType::kConflict: LOG(WARNING) << "RegType::AssignableFrom lhs is Conflict!"; return false; case AssignmentType::kReference: if (rhs.IsZeroOrNull()) { return true; // All reference types can be assigned null. } else if (!rhs.IsReferenceTypes()) { return false; // Expect rhs to be a reference type. } else if (lhs.IsUninitializedTypes() || rhs.IsUninitializedTypes()) { // Uninitialized types are only allowed to be assigned to themselves. // TODO: Once we have a proper "reference" super type, this needs to be extended. return false; } else if (lhs.IsJavaLangObject()) { return true; // All reference types can be assigned to Object. } else if (!strict && !lhs.IsUnresolvedTypes() && lhs.GetClass()->IsInterface()) { // If we're not strict allow assignment to any interface, see comment in ClassJoin. return true; } else if (lhs.IsJavaLangObjectArray()) { return rhs.IsObjectArrayTypes(); // All reference arrays may be assigned to Object[] } else if (lhs.HasClass() && rhs.HasClass()) { // Test assignability from the Class point-of-view. bool result = lhs.GetClass()->IsAssignableFrom(rhs.GetClass()); // Record assignability dependency. The `verifier` is null during unit tests and // VerifiedMethod::GenerateSafeCastSet. if (verifier != nullptr) { VerifierDeps::MaybeRecordAssignability( verifier->GetDexFile(), lhs.GetClass(), rhs.GetClass(), strict, result); } return result; } else { // Unresolved types are only assignable for null and equality. // Null cannot be the left-hand side. return false; } case AssignmentType::kNotAssignable: break; } LOG(FATAL) << "Unexpected register type in IsAssignableFrom: '" << lhs << "' := '" << rhs << "'"; UNREACHABLE(); } } inline bool RegType::IsAssignableFrom(const RegType& src, MethodVerifier* verifier) const { return AssignableFrom(*this, src, false, verifier); } inline bool RegType::IsStrictlyAssignableFrom(const RegType& src, MethodVerifier* verifier) const { return AssignableFrom(*this, src, true, verifier); } inline const DoubleHiType* DoubleHiType::GetInstance() { DCHECK(instance_ != nullptr); return instance_; } inline const DoubleLoType* DoubleLoType::GetInstance() { DCHECK(instance_ != nullptr); return instance_; } inline const LongHiType* LongHiType::GetInstance() { DCHECK(instance_ != nullptr); return instance_; } inline const LongLoType* LongLoType::GetInstance() { DCHECK(instance_ != nullptr); return instance_; } inline const FloatType* FloatType::GetInstance() { DCHECK(instance_ != nullptr); return instance_; } inline const CharType* CharType::GetInstance() { DCHECK(instance_ != nullptr); return instance_; } inline const ShortType* ShortType::GetInstance() { DCHECK(instance_ != nullptr); return instance_; } inline const ByteType* ByteType::GetInstance() { DCHECK(instance_ != nullptr); return instance_; } inline const IntegerType* IntegerType::GetInstance() { DCHECK(instance_ != nullptr); return instance_; } inline const BooleanType* BooleanType::GetInstance() { DCHECK(BooleanType::instance_ != nullptr); return BooleanType::instance_; } inline const ConflictType* ConflictType::GetInstance() { DCHECK(instance_ != nullptr); return instance_; } inline const UndefinedType* UndefinedType::GetInstance() { DCHECK(instance_ != nullptr); return instance_; } inline const NullType* NullType::GetInstance() { DCHECK(instance_ != nullptr); return instance_; } inline void* RegType::operator new(size_t size, ScopedArenaAllocator* allocator) { return allocator->Alloc(size, kArenaAllocMisc); } } // namespace verifier } // namespace art #endif // ART_RUNTIME_VERIFIER_REG_TYPE_INL_H_