| /* |
| * 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_H_ |
| #define ART_RUNTIME_VERIFIER_REG_TYPE_H_ |
| |
| #include <stdint.h> |
| #include <limits> |
| #include <set> |
| #include <string> |
| |
| #include "base/macros.h" |
| #include "base/mutex.h" |
| #include "gc_root.h" |
| #include "handle_scope.h" |
| #include "object_callbacks.h" |
| #include "primitive.h" |
| |
| namespace art { |
| namespace mirror { |
| class Class; |
| } // namespace mirror |
| |
| namespace verifier { |
| |
| class RegTypeCache; |
| /* |
| * RegType holds information about the "type" of data held in a register. |
| */ |
| class RegType { |
| public: |
| virtual bool IsUndefined() const { return false; } |
| virtual bool IsConflict() const { return false; } |
| virtual bool IsBoolean() const { return false; } |
| virtual bool IsByte() const { return false; } |
| virtual bool IsChar() const { return false; } |
| virtual bool IsShort() const { return false; } |
| virtual bool IsInteger() const { return false; } |
| virtual bool IsLongLo() const { return false; } |
| virtual bool IsLongHi() const { return false; } |
| virtual bool IsFloat() const { return false; } |
| virtual bool IsDouble() const { return false; } |
| virtual bool IsDoubleLo() const { return false; } |
| virtual bool IsDoubleHi() const { return false; } |
| virtual bool IsUnresolvedReference() const { return false; } |
| virtual bool IsUninitializedReference() const { return false; } |
| virtual bool IsUninitializedThisReference() const { return false; } |
| virtual bool IsUnresolvedAndUninitializedReference() const { return false; } |
| virtual bool IsUnresolvedAndUninitializedThisReference() const { |
| return false; |
| } |
| virtual bool IsUnresolvedMergedReference() const { return false; } |
| virtual bool IsUnresolvedSuperClass() const { return false; } |
| virtual bool IsReference() const { return false; } |
| virtual bool IsPreciseReference() const { return false; } |
| virtual bool IsPreciseConstant() const { return false; } |
| virtual bool IsPreciseConstantLo() const { return false; } |
| virtual bool IsPreciseConstantHi() const { return false; } |
| virtual bool IsImpreciseConstantLo() const { return false; } |
| virtual bool IsImpreciseConstantHi() const { return false; } |
| virtual bool IsImpreciseConstant() const { return false; } |
| virtual bool IsConstantTypes() const { return false; } |
| bool IsConstant() const { |
| return IsImpreciseConstant() || IsPreciseConstant(); |
| } |
| bool IsConstantLo() const { |
| return IsImpreciseConstantLo() || IsPreciseConstantLo(); |
| } |
| bool IsPrecise() const { |
| return IsPreciseConstantLo() || IsPreciseConstant() || |
| IsPreciseConstantHi(); |
| } |
| bool IsLongConstant() const { return IsConstantLo(); } |
| bool IsConstantHi() const { |
| return (IsPreciseConstantHi() || IsImpreciseConstantHi()); |
| } |
| bool IsLongConstantHigh() const { return IsConstantHi(); } |
| virtual bool IsUninitializedTypes() const { return false; } |
| virtual bool IsUnresolvedTypes() const { return false; } |
| |
| bool IsLowHalf() const { |
| return (IsLongLo() || IsDoubleLo() || IsPreciseConstantLo() || IsImpreciseConstantLo()); |
| } |
| bool IsHighHalf() const { |
| return (IsLongHi() || IsDoubleHi() || IsPreciseConstantHi() || IsImpreciseConstantHi()); |
| } |
| bool IsLongOrDoubleTypes() const { return IsLowHalf(); } |
| // Check this is the low half, and that type_h is its matching high-half. |
| inline bool CheckWidePair(const RegType& type_h) const { |
| if (IsLowHalf()) { |
| return ((IsImpreciseConstantLo() && type_h.IsPreciseConstantHi()) || |
| (IsImpreciseConstantLo() && type_h.IsImpreciseConstantHi()) || |
| (IsPreciseConstantLo() && type_h.IsPreciseConstantHi()) || |
| (IsPreciseConstantLo() && type_h.IsImpreciseConstantHi()) || |
| (IsDoubleLo() && type_h.IsDoubleHi()) || |
| (IsLongLo() && type_h.IsLongHi())); |
| } |
| return false; |
| } |
| // The high half that corresponds to this low half |
| const RegType& HighHalf(RegTypeCache* cache) const |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| |
| bool IsConstantBoolean() const; |
| virtual bool IsConstantChar() const { return false; } |
| virtual bool IsConstantByte() const { return false; } |
| virtual bool IsConstantShort() const { return false; } |
| virtual bool IsOne() const { return false; } |
| virtual bool IsZero() const { return false; } |
| bool IsReferenceTypes() const { |
| return IsNonZeroReferenceTypes() || IsZero(); |
| } |
| virtual bool IsNonZeroReferenceTypes() const { return false; } |
| bool IsCategory1Types() const { |
| return IsChar() || IsInteger() || IsFloat() || IsConstant() || IsByte() || |
| IsShort() || IsBoolean(); |
| } |
| bool IsCategory2Types() const { |
| return IsLowHalf(); // Don't expect explicit testing of high halves |
| } |
| bool IsBooleanTypes() const { return IsBoolean() || IsConstantBoolean(); } |
| bool IsByteTypes() const { |
| return IsConstantByte() || IsByte() || IsBoolean(); |
| } |
| bool IsShortTypes() const { |
| return IsShort() || IsByte() || IsBoolean() || IsConstantShort(); |
| } |
| bool IsCharTypes() const { |
| return IsChar() || IsBooleanTypes() || IsConstantChar(); |
| } |
| bool IsIntegralTypes() const { |
| return IsInteger() || IsConstant() || IsByte() || IsShort() || IsChar() || |
| IsBoolean(); |
| } |
| // Give the constant value encoded, but this shouldn't be called in the |
| // general case. |
| bool IsArrayIndexTypes() const { return IsIntegralTypes(); } |
| // Float type may be derived from any constant type |
| bool IsFloatTypes() const { return IsFloat() || IsConstant(); } |
| bool IsLongTypes() const { return IsLongLo() || IsLongConstant(); } |
| bool IsLongHighTypes() const { |
| return (IsLongHi() || IsPreciseConstantHi() || IsImpreciseConstantHi()); |
| } |
| bool IsDoubleTypes() const { return IsDoubleLo() || IsLongConstant(); } |
| bool IsDoubleHighTypes() const { |
| return (IsDoubleHi() || IsPreciseConstantHi() || IsImpreciseConstantHi()); |
| } |
| virtual bool IsLong() const { return false; } |
| bool HasClass() const { |
| bool result = !klass_.IsNull(); |
| DCHECK_EQ(result, HasClassVirtual()); |
| return result; |
| } |
| virtual bool HasClassVirtual() const { return false; } |
| bool IsJavaLangObject() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| bool IsArrayTypes() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| bool IsObjectArrayTypes() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| Primitive::Type GetPrimitiveType() const; |
| bool IsJavaLangObjectArray() const |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| bool IsInstantiableTypes() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| const std::string& GetDescriptor() const { |
| DCHECK(HasClass() || |
| (IsUnresolvedTypes() && !IsUnresolvedMergedReference() && |
| !IsUnresolvedSuperClass())); |
| return descriptor_; |
| } |
| mirror::Class* GetClass() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { |
| DCHECK(!IsUnresolvedReference()); |
| DCHECK(!klass_.IsNull()) << Dump(); |
| DCHECK(HasClass()); |
| return klass_.Read(); |
| } |
| uint16_t GetId() const { return cache_id_; } |
| const RegType& GetSuperClass(RegTypeCache* cache) const |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| |
| virtual std::string Dump() const |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0; |
| |
| // Can this type access other? |
| bool CanAccess(const RegType& other) const |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| |
| // Can this type access a member with the given properties? |
| bool CanAccessMember(mirror::Class* klass, uint32_t access_flags) const |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| |
| // Can this type be assigned by src? |
| // Note: Object and interface types may always be assigned to one another, see |
| // comment on |
| // ClassJoin. |
| bool IsAssignableFrom(const RegType& src) const |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| |
| // Can this array type potentially be assigned by src. |
| // This function is necessary as array types are valid even if their components types are not, |
| // e.g., when they component type could not be resolved. The function will return true iff the |
| // types are assignable. It will return false otherwise. In case of return=false, soft_error |
| // will be set to true iff the assignment test failure should be treated as a soft-error, i.e., |
| // when both array types have the same 'depth' and the 'final' component types may be assignable |
| // (both are reference types). |
| bool CanAssignArray(const RegType& src, RegTypeCache& reg_types, |
| Handle<mirror::ClassLoader> class_loader, bool* soft_error) const |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| |
| // Can this type be assigned by src? Variant of IsAssignableFrom that doesn't |
| // allow assignment to |
| // an interface from an Object. |
| bool IsStrictlyAssignableFrom(const RegType& src) const |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| |
| // Are these RegTypes the same? |
| bool Equals(const RegType& other) const { return GetId() == other.GetId(); } |
| |
| // Compute the merge of this register from one edge (path) with incoming_type |
| // from another. |
| const RegType& Merge(const RegType& incoming_type, RegTypeCache* reg_types) const |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| |
| /* |
| * A basic Join operation on classes. For a pair of types S and T the Join, |
| *written S v T = J, is |
| * S <: J, T <: J and for-all U such that S <: U, T <: U then J <: U. That is |
| *J is the parent of |
| * S and T such that there isn't a parent of both S and T that isn't also the |
| *parent of J (ie J |
| * is the deepest (lowest upper bound) parent of S and T). |
| * |
| * This operation applies for regular classes and arrays, however, for |
| *interface types there |
| * needn't be a partial ordering on the types. We could solve the problem of a |
| *lack of a partial |
| * order by introducing sets of types, however, the only operation permissible |
| *on an interface is |
| * invoke-interface. In the tradition of Java verifiers [1] we defer the |
| *verification of interface |
| * types until an invoke-interface call on the interface typed reference at |
| *runtime and allow |
| * the perversion of Object being assignable to an interface type (note, |
| *however, that we don't |
| * allow assignment of Object or Interface to any concrete class and are |
| *therefore type safe). |
| * |
| * [1] Java bytecode verification: algorithms and formalizations, Xavier Leroy |
| */ |
| static mirror::Class* ClassJoin(mirror::Class* s, mirror::Class* t) |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| |
| virtual ~RegType() {} |
| |
| void VisitRoots(RootVisitor* visitor, const RootInfo& root_info) const |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| |
| protected: |
| RegType(mirror::Class* klass, const std::string& descriptor, |
| uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) |
| : descriptor_(descriptor), klass_(klass), cache_id_(cache_id) { |
| if (kIsDebugBuild) { |
| CheckInvariants(); |
| } |
| } |
| |
| void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| |
| const std::string descriptor_; |
| mutable GcRoot<mirror::Class> |
| klass_; // Non-const only due to moving classes. |
| const uint16_t cache_id_; |
| |
| friend class RegTypeCache; |
| |
| private: |
| static bool AssignableFrom(const RegType& lhs, const RegType& rhs, bool strict) |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| |
| DISALLOW_COPY_AND_ASSIGN(RegType); |
| }; |
| |
| // Bottom type. |
| class ConflictType FINAL : public RegType { |
| public: |
| bool IsConflict() const OVERRIDE { return true; } |
| |
| std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| |
| // Get the singleton Conflict instance. |
| static const ConflictType* GetInstance() PURE; |
| |
| // Create the singleton instance. |
| static const ConflictType* CreateInstance(mirror::Class* klass, |
| const std::string& descriptor, |
| uint16_t cache_id) |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| |
| // Destroy the singleton instance. |
| static void Destroy(); |
| |
| private: |
| ConflictType(mirror::Class* klass, const std::string& descriptor, |
| uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) |
| : RegType(klass, descriptor, cache_id) {} |
| |
| static const ConflictType* instance_; |
| }; |
| |
| // A variant of the bottom type used to specify an undefined value in the |
| // incoming registers. |
| // Merging with UndefinedType yields ConflictType which is the true bottom. |
| class UndefinedType FINAL : public RegType { |
| public: |
| bool IsUndefined() const OVERRIDE { return true; } |
| |
| std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| |
| // Get the singleton Undefined instance. |
| static const UndefinedType* GetInstance() PURE; |
| |
| // Create the singleton instance. |
| static const UndefinedType* CreateInstance(mirror::Class* klass, |
| const std::string& descriptor, |
| uint16_t cache_id) |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| |
| // Destroy the singleton instance. |
| static void Destroy(); |
| |
| private: |
| UndefinedType(mirror::Class* klass, const std::string& descriptor, |
| uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) |
| : RegType(klass, descriptor, cache_id) {} |
| |
| static const UndefinedType* instance_; |
| }; |
| |
| class PrimitiveType : public RegType { |
| public: |
| PrimitiveType(mirror::Class* klass, const std::string& descriptor, |
| uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| |
| bool HasClassVirtual() const OVERRIDE { return true; } |
| }; |
| |
| class Cat1Type : public PrimitiveType { |
| public: |
| Cat1Type(mirror::Class* klass, const std::string& descriptor, |
| uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| }; |
| |
| class IntegerType : public Cat1Type { |
| public: |
| bool IsInteger() const OVERRIDE { return true; } |
| std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| static const IntegerType* CreateInstance(mirror::Class* klass, |
| const std::string& descriptor, |
| uint16_t cache_id) |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| static const IntegerType* GetInstance() PURE; |
| static void Destroy(); |
| |
| private: |
| IntegerType(mirror::Class* klass, const std::string& descriptor, |
| uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) |
| : Cat1Type(klass, descriptor, cache_id) {} |
| static const IntegerType* instance_; |
| }; |
| |
| class BooleanType FINAL : public Cat1Type { |
| public: |
| bool IsBoolean() const OVERRIDE { return true; } |
| std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| static const BooleanType* CreateInstance(mirror::Class* klass, |
| const std::string& descriptor, |
| uint16_t cache_id) |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| static const BooleanType* GetInstance() PURE; |
| static void Destroy(); |
| |
| private: |
| BooleanType(mirror::Class* klass, const std::string& descriptor, |
| uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) |
| : Cat1Type(klass, descriptor, cache_id) {} |
| |
| static const BooleanType* instance_; |
| }; |
| |
| class ByteType FINAL : public Cat1Type { |
| public: |
| bool IsByte() const OVERRIDE { return true; } |
| std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| static const ByteType* CreateInstance(mirror::Class* klass, |
| const std::string& descriptor, |
| uint16_t cache_id) |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| static const ByteType* GetInstance() PURE; |
| static void Destroy(); |
| |
| private: |
| ByteType(mirror::Class* klass, const std::string& descriptor, |
| uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) |
| : Cat1Type(klass, descriptor, cache_id) {} |
| static const ByteType* instance_; |
| }; |
| |
| class ShortType FINAL : public Cat1Type { |
| public: |
| bool IsShort() const OVERRIDE { return true; } |
| std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| static const ShortType* CreateInstance(mirror::Class* klass, |
| const std::string& descriptor, |
| uint16_t cache_id) |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| static const ShortType* GetInstance() PURE; |
| static void Destroy(); |
| |
| private: |
| ShortType(mirror::Class* klass, const std::string& descriptor, |
| uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) |
| : Cat1Type(klass, descriptor, cache_id) {} |
| static const ShortType* instance_; |
| }; |
| |
| class CharType FINAL : public Cat1Type { |
| public: |
| bool IsChar() const OVERRIDE { return true; } |
| std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| static const CharType* CreateInstance(mirror::Class* klass, |
| const std::string& descriptor, |
| uint16_t cache_id) |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| static const CharType* GetInstance() PURE; |
| static void Destroy(); |
| |
| private: |
| CharType(mirror::Class* klass, const std::string& descriptor, |
| uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) |
| : Cat1Type(klass, descriptor, cache_id) {} |
| static const CharType* instance_; |
| }; |
| |
| class FloatType FINAL : public Cat1Type { |
| public: |
| bool IsFloat() const OVERRIDE { return true; } |
| std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| static const FloatType* CreateInstance(mirror::Class* klass, |
| const std::string& descriptor, |
| uint16_t cache_id) |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| static const FloatType* GetInstance() PURE; |
| static void Destroy(); |
| |
| private: |
| FloatType(mirror::Class* klass, const std::string& descriptor, |
| uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) |
| : Cat1Type(klass, descriptor, cache_id) {} |
| static const FloatType* instance_; |
| }; |
| |
| class Cat2Type : public PrimitiveType { |
| public: |
| Cat2Type(mirror::Class* klass, const std::string& descriptor, |
| uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| }; |
| |
| class LongLoType FINAL : public Cat2Type { |
| public: |
| std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| bool IsLongLo() const OVERRIDE { return true; } |
| bool IsLong() const OVERRIDE { return true; } |
| static const LongLoType* CreateInstance(mirror::Class* klass, |
| const std::string& descriptor, |
| uint16_t cache_id) |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| static const LongLoType* GetInstance() PURE; |
| static void Destroy(); |
| |
| private: |
| LongLoType(mirror::Class* klass, const std::string& descriptor, |
| uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) |
| : Cat2Type(klass, descriptor, cache_id) {} |
| static const LongLoType* instance_; |
| }; |
| |
| class LongHiType FINAL : public Cat2Type { |
| public: |
| std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| bool IsLongHi() const OVERRIDE { return true; } |
| static const LongHiType* CreateInstance(mirror::Class* klass, |
| const std::string& descriptor, |
| uint16_t cache_id) |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| static const LongHiType* GetInstance() PURE; |
| static void Destroy(); |
| |
| private: |
| LongHiType(mirror::Class* klass, const std::string& descriptor, |
| uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) |
| : Cat2Type(klass, descriptor, cache_id) {} |
| static const LongHiType* instance_; |
| }; |
| |
| class DoubleLoType FINAL : public Cat2Type { |
| public: |
| std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| bool IsDoubleLo() const OVERRIDE { return true; } |
| bool IsDouble() const OVERRIDE { return true; } |
| static const DoubleLoType* CreateInstance(mirror::Class* klass, |
| const std::string& descriptor, |
| uint16_t cache_id) |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| static const DoubleLoType* GetInstance() PURE; |
| static void Destroy(); |
| |
| private: |
| DoubleLoType(mirror::Class* klass, const std::string& descriptor, |
| uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) |
| : Cat2Type(klass, descriptor, cache_id) {} |
| static const DoubleLoType* instance_; |
| }; |
| |
| class DoubleHiType FINAL : public Cat2Type { |
| public: |
| std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| virtual bool IsDoubleHi() const OVERRIDE { return true; } |
| static const DoubleHiType* CreateInstance(mirror::Class* klass, |
| const std::string& descriptor, |
| uint16_t cache_id) |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| static const DoubleHiType* GetInstance() PURE; |
| static void Destroy(); |
| |
| private: |
| DoubleHiType(mirror::Class* klass, const std::string& descriptor, |
| uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) |
| : Cat2Type(klass, descriptor, cache_id) {} |
| static const DoubleHiType* instance_; |
| }; |
| |
| class ConstantType : public RegType { |
| public: |
| ConstantType(uint32_t constant, uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) |
| : RegType(nullptr, "", cache_id), constant_(constant) { |
| } |
| |
| |
| // If this is a 32-bit constant, what is the value? This value may be |
| // imprecise in which case |
| // the value represents part of the integer range of values that may be held |
| // in the register. |
| int32_t ConstantValue() const { |
| DCHECK(IsConstantTypes()); |
| return constant_; |
| } |
| |
| int32_t ConstantValueLo() const { |
| DCHECK(IsConstantLo()); |
| return constant_; |
| } |
| |
| int32_t ConstantValueHi() const { |
| if (IsConstantHi() || IsPreciseConstantHi() || IsImpreciseConstantHi()) { |
| return constant_; |
| } else { |
| DCHECK(false); |
| return 0; |
| } |
| } |
| |
| bool IsZero() const OVERRIDE { |
| return IsPreciseConstant() && ConstantValue() == 0; |
| } |
| bool IsOne() const OVERRIDE { |
| return IsPreciseConstant() && ConstantValue() == 1; |
| } |
| |
| bool IsConstantChar() const OVERRIDE { |
| return IsConstant() && ConstantValue() >= 0 && |
| ConstantValue() <= std::numeric_limits<uint16_t>::max(); |
| } |
| bool IsConstantByte() const OVERRIDE { |
| return IsConstant() && |
| ConstantValue() >= std::numeric_limits<int8_t>::min() && |
| ConstantValue() <= std::numeric_limits<int8_t>::max(); |
| } |
| bool IsConstantShort() const OVERRIDE { |
| return IsConstant() && |
| ConstantValue() >= std::numeric_limits<int16_t>::min() && |
| ConstantValue() <= std::numeric_limits<int16_t>::max(); |
| } |
| virtual bool IsConstantTypes() const OVERRIDE { return true; } |
| |
| private: |
| const uint32_t constant_; |
| }; |
| |
| class PreciseConstType FINAL : public ConstantType { |
| public: |
| PreciseConstType(uint32_t constant, uint16_t cache_id) |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) |
| : ConstantType(constant, cache_id) {} |
| |
| bool IsPreciseConstant() const OVERRIDE { return true; } |
| |
| std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| }; |
| |
| class PreciseConstLoType FINAL : public ConstantType { |
| public: |
| PreciseConstLoType(uint32_t constant, uint16_t cache_id) |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) |
| : ConstantType(constant, cache_id) {} |
| bool IsPreciseConstantLo() const OVERRIDE { return true; } |
| std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| }; |
| |
| class PreciseConstHiType FINAL : public ConstantType { |
| public: |
| PreciseConstHiType(uint32_t constant, uint16_t cache_id) |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) |
| : ConstantType(constant, cache_id) {} |
| bool IsPreciseConstantHi() const OVERRIDE { return true; } |
| std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| }; |
| |
| class ImpreciseConstType FINAL : public ConstantType { |
| public: |
| ImpreciseConstType(uint32_t constat, uint16_t cache_id) |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) |
| : ConstantType(constat, cache_id) { |
| } |
| bool IsImpreciseConstant() const OVERRIDE { return true; } |
| std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| }; |
| |
| class ImpreciseConstLoType FINAL : public ConstantType { |
| public: |
| ImpreciseConstLoType(uint32_t constant, uint16_t cache_id) |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) |
| : ConstantType(constant, cache_id) {} |
| bool IsImpreciseConstantLo() const OVERRIDE { return true; } |
| std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| }; |
| |
| class ImpreciseConstHiType FINAL : public ConstantType { |
| public: |
| ImpreciseConstHiType(uint32_t constant, uint16_t cache_id) |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) |
| : ConstantType(constant, cache_id) {} |
| bool IsImpreciseConstantHi() const OVERRIDE { return true; } |
| std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| }; |
| |
| // Common parent of all uninitialized types. Uninitialized types are created by |
| // "new" dex |
| // instructions and must be passed to a constructor. |
| class UninitializedType : public RegType { |
| public: |
| UninitializedType(mirror::Class* klass, const std::string& descriptor, |
| uint32_t allocation_pc, uint16_t cache_id) |
| : RegType(klass, descriptor, cache_id), allocation_pc_(allocation_pc) {} |
| |
| bool IsUninitializedTypes() const OVERRIDE; |
| bool IsNonZeroReferenceTypes() const OVERRIDE; |
| |
| uint32_t GetAllocationPc() const { |
| DCHECK(IsUninitializedTypes()); |
| return allocation_pc_; |
| } |
| |
| private: |
| const uint32_t allocation_pc_; |
| }; |
| |
| // Similar to ReferenceType but not yet having been passed to a constructor. |
| class UninitializedReferenceType FINAL : public UninitializedType { |
| public: |
| UninitializedReferenceType(mirror::Class* klass, |
| const std::string& descriptor, |
| uint32_t allocation_pc, uint16_t cache_id) |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) |
| : UninitializedType(klass, descriptor, allocation_pc, cache_id) {} |
| |
| bool IsUninitializedReference() const OVERRIDE { return true; } |
| |
| bool HasClassVirtual() const OVERRIDE { return true; } |
| |
| std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| }; |
| |
| // Similar to UnresolvedReferenceType but not yet having been passed to a |
| // constructor. |
| class UnresolvedUninitializedRefType FINAL : public UninitializedType { |
| public: |
| UnresolvedUninitializedRefType(const std::string& descriptor, |
| uint32_t allocation_pc, uint16_t cache_id) |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) |
| : UninitializedType(nullptr, descriptor, allocation_pc, cache_id) { |
| if (kIsDebugBuild) { |
| CheckInvariants(); |
| } |
| } |
| |
| bool IsUnresolvedAndUninitializedReference() const OVERRIDE { return true; } |
| |
| bool IsUnresolvedTypes() const OVERRIDE { return true; } |
| |
| std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| |
| private: |
| void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| }; |
| |
| // Similar to UninitializedReferenceType but special case for the this argument |
| // of a constructor. |
| class UninitializedThisReferenceType FINAL : public UninitializedType { |
| public: |
| UninitializedThisReferenceType(mirror::Class* klass, |
| const std::string& descriptor, |
| uint16_t cache_id) |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) |
| : UninitializedType(klass, descriptor, 0, cache_id) { |
| if (kIsDebugBuild) { |
| CheckInvariants(); |
| } |
| } |
| |
| virtual bool IsUninitializedThisReference() const OVERRIDE { return true; } |
| |
| bool HasClassVirtual() const OVERRIDE { return true; } |
| |
| std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| |
| private: |
| void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| }; |
| |
| class UnresolvedUninitializedThisRefType FINAL : public UninitializedType { |
| public: |
| UnresolvedUninitializedThisRefType(const std::string& descriptor, |
| uint16_t cache_id) |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) |
| : UninitializedType(nullptr, descriptor, 0, cache_id) { |
| if (kIsDebugBuild) { |
| CheckInvariants(); |
| } |
| } |
| |
| bool IsUnresolvedAndUninitializedThisReference() const OVERRIDE { return true; } |
| |
| bool IsUnresolvedTypes() const OVERRIDE { return true; } |
| |
| std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| |
| private: |
| void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| }; |
| |
| // A type of register holding a reference to an Object of type GetClass or a |
| // sub-class. |
| class ReferenceType FINAL : public RegType { |
| public: |
| ReferenceType(mirror::Class* klass, const std::string& descriptor, |
| uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) |
| : RegType(klass, descriptor, cache_id) {} |
| |
| bool IsReference() const OVERRIDE { return true; } |
| |
| bool IsNonZeroReferenceTypes() const OVERRIDE { return true; } |
| |
| bool HasClassVirtual() const OVERRIDE { return true; } |
| |
| std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| }; |
| |
| // A type of register holding a reference to an Object of type GetClass and only |
| // an object of that |
| // type. |
| class PreciseReferenceType FINAL : public RegType { |
| public: |
| PreciseReferenceType(mirror::Class* klass, const std::string& descriptor, |
| uint16_t cache_id) |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| |
| bool IsPreciseReference() const OVERRIDE { return true; } |
| |
| bool IsNonZeroReferenceTypes() const OVERRIDE { return true; } |
| |
| bool HasClassVirtual() const OVERRIDE { return true; } |
| |
| std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| }; |
| |
| // Common parent of unresolved types. |
| class UnresolvedType : public RegType { |
| public: |
| UnresolvedType(const std::string& descriptor, uint16_t cache_id) |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) |
| : RegType(nullptr, descriptor, cache_id) {} |
| |
| bool IsNonZeroReferenceTypes() const OVERRIDE; |
| }; |
| |
| // Similar to ReferenceType except the Class couldn't be loaded. Assignability |
| // and other tests made |
| // of this type must be conservative. |
| class UnresolvedReferenceType FINAL : public UnresolvedType { |
| public: |
| UnresolvedReferenceType(const std::string& descriptor, uint16_t cache_id) |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) |
| : UnresolvedType(descriptor, cache_id) { |
| if (kIsDebugBuild) { |
| CheckInvariants(); |
| } |
| } |
| |
| bool IsUnresolvedReference() const OVERRIDE { return true; } |
| |
| bool IsUnresolvedTypes() const OVERRIDE { return true; } |
| |
| std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| |
| private: |
| void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| }; |
| |
| // Type representing the super-class of an unresolved type. |
| class UnresolvedSuperClass FINAL : public UnresolvedType { |
| public: |
| UnresolvedSuperClass(uint16_t child_id, RegTypeCache* reg_type_cache, |
| uint16_t cache_id) |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) |
| : UnresolvedType("", cache_id), |
| unresolved_child_id_(child_id), |
| reg_type_cache_(reg_type_cache) { |
| if (kIsDebugBuild) { |
| CheckInvariants(); |
| } |
| } |
| |
| bool IsUnresolvedSuperClass() const OVERRIDE { return true; } |
| |
| bool IsUnresolvedTypes() const OVERRIDE { return true; } |
| |
| uint16_t GetUnresolvedSuperClassChildId() const { |
| DCHECK(IsUnresolvedSuperClass()); |
| return static_cast<uint16_t>(unresolved_child_id_ & 0xFFFF); |
| } |
| |
| std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| |
| private: |
| void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| |
| const uint16_t unresolved_child_id_; |
| const RegTypeCache* const reg_type_cache_; |
| }; |
| |
| // A merge of two unresolved types. If the types were resolved this may be |
| // Conflict or another |
| // known ReferenceType. |
| class UnresolvedMergedType FINAL : public UnresolvedType { |
| public: |
| UnresolvedMergedType(uint16_t left_id, uint16_t right_id, |
| const RegTypeCache* reg_type_cache, uint16_t cache_id) |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) |
| : UnresolvedType("", cache_id), |
| reg_type_cache_(reg_type_cache), |
| merged_types_(left_id, right_id) { |
| if (kIsDebugBuild) { |
| CheckInvariants(); |
| } |
| } |
| |
| // The top of a tree of merged types. |
| std::pair<uint16_t, uint16_t> GetTopMergedTypes() const { |
| DCHECK(IsUnresolvedMergedReference()); |
| return merged_types_; |
| } |
| |
| // The complete set of merged types. |
| std::set<uint16_t> GetMergedTypes() const; |
| |
| bool IsUnresolvedMergedReference() const OVERRIDE { return true; } |
| |
| bool IsUnresolvedTypes() const OVERRIDE { return true; } |
| |
| std::string Dump() const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| |
| private: |
| void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| |
| const RegTypeCache* const reg_type_cache_; |
| const std::pair<uint16_t, uint16_t> merged_types_; |
| }; |
| |
| std::ostream& operator<<(std::ostream& os, const RegType& rhs) |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| |
| } // namespace verifier |
| } // namespace art |
| |
| #endif // ART_RUNTIME_VERIFIER_REG_TYPE_H_ |