// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. #ifndef RUNTIME_VM_STATIC_TYPE_EXACTNESS_STATE_H_ #define RUNTIME_VM_STATIC_TYPE_EXACTNESS_STATE_H_ #include "platform/allocation.h" #include "platform/utils.h" // This header defines the list of VM implementation classes and their ids. // // Note: we assume that all builds of Dart VM use exactly the same class ids // for these classes. namespace dart { class Instance; class Type; // Representation of a state of runtime tracking of static type exactness for // a particular location in the program (e.g. exactness of type annotation // on a field). // // Given the static type G we say that it is exact iff any // values that can be observed at this location has runtime type T such that // type arguments of T at G are exactly . // // Currently we only support tracking for locations that are also known // to be monomorphic with respect to the actual class of the values it contains. // // Important: locations should never switch from tracked (kIsTriviallyExact, // kHasExactSuperType, kHasExactSuperClass, kNotExact) to not tracked // (kNotTracking) or the other way around because that would affect unoptimized // graphs generated by graph builder and skew deopt ids. class StaticTypeExactnessState final { public: // Values stored in the location with static type G are all // instances of C and C at G has type parameters // . // // For trivially exact types we can simply compare type argument // vectors as pointers to check exactness. That's why we represent // trivially exact locations as offset in words to the type arguments of // class C. All other states are represented as non-positive values. // // Note: we are ignoring the type argument vector sharing optimization for // now. static inline StaticTypeExactnessState TriviallyExact( intptr_t type_arguments_offset_in_bytes) { ASSERT((type_arguments_offset_in_bytes > 0) && Utils::IsInt(8, type_arguments_offset_in_bytes)); return StaticTypeExactnessState(type_arguments_offset_in_bytes); } static inline bool CanRepresentAsTriviallyExact( intptr_t type_arguments_offset_in_bytes) { return Utils::IsInt(8, type_arguments_offset_in_bytes); } // Values stored in the location with static type G are all // instances of class C<...> and C at G has type // parameters for any - that is C<...> has a // supertype G. // // For such locations we can simply check if the value stored // is an instance of an expected class and we don't have to look at // type arguments carried by the instance. // // We distinguish situations where we know that G is a superclass of C from // situations where G might be superinterface of C - because in the first // type arguments of G give us constant prefix of type arguments of C. static inline StaticTypeExactnessState HasExactSuperType() { return StaticTypeExactnessState(kHasExactSuperType); } static inline StaticTypeExactnessState HasExactSuperClass() { return StaticTypeExactnessState(kHasExactSuperClass); } // Values stored in the location don't fall under either kIsTriviallyExact // or kHasExactSuperType categories. // // Note: that does not imply that static type annotation is not exact // according to a broader definition, e.g. location might simply be // polymorphic and store instances of multiple different types. // However for simplicity we don't track such cases yet. static inline StaticTypeExactnessState NotExact() { return StaticTypeExactnessState(kNotExact); } // The location does not track exactness of its static type at runtime. static inline StaticTypeExactnessState NotTracking() { return StaticTypeExactnessState(kNotTracking); } static inline StaticTypeExactnessState Uninitialized() { return StaticTypeExactnessState(kUninitialized); } static StaticTypeExactnessState Compute(const Type& static_type, const Instance& value, bool print_trace = false); bool IsTracking() const { return value_ != kNotTracking; } bool IsUninitialized() const { return value_ == kUninitialized; } bool IsHasExactSuperClass() const { return value_ == kHasExactSuperClass; } bool IsHasExactSuperType() const { return value_ == kHasExactSuperType; } bool IsTriviallyExact() const { return value_ > kUninitialized; } bool NeedsFieldGuard() const { return value_ >= kUninitialized; } bool IsExactOrUninitialized() const { return value_ > kNotExact; } bool IsExact() const { return IsTriviallyExact() || IsHasExactSuperType() || IsHasExactSuperClass(); } const char* ToCString() const; StaticTypeExactnessState CollapseSuperTypeExactness() const { return IsHasExactSuperClass() ? HasExactSuperType() : *this; } static inline StaticTypeExactnessState Decode(int8_t value) { return StaticTypeExactnessState(value); } int8_t Encode() const { return value_; } int8_t GetTypeArgumentsOffsetInWords() const { ASSERT(IsTriviallyExact()); return value_; } static constexpr int8_t kUninitialized = 0; private: static constexpr int8_t kNotTracking = -4; static constexpr int8_t kNotExact = -3; static constexpr int8_t kHasExactSuperType = -2; static constexpr int8_t kHasExactSuperClass = -1; explicit StaticTypeExactnessState(int8_t value) : value_(value) {} int8_t value_; DISALLOW_ALLOCATION(); }; } // namespace dart #endif // RUNTIME_VM_STATIC_TYPE_EXACTNESS_STATE_H_