1 | // Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file |
2 | // for details. All rights reserved. Use of this source code is governed by a |
3 | // BSD-style license that can be found in the LICENSE file. |
4 | |
5 | #ifndef RUNTIME_VM_STATIC_TYPE_EXACTNESS_STATE_H_ |
6 | #define RUNTIME_VM_STATIC_TYPE_EXACTNESS_STATE_H_ |
7 | |
8 | #include "platform/allocation.h" |
9 | #include "platform/utils.h" |
10 | |
11 | // This header defines the list of VM implementation classes and their ids. |
12 | // |
13 | // Note: we assume that all builds of Dart VM use exactly the same class ids |
14 | // for these classes. |
15 | |
16 | namespace dart { |
17 | |
18 | class Instance; |
19 | class Type; |
20 | |
21 | // Representation of a state of runtime tracking of static type exactness for |
22 | // a particular location in the program (e.g. exactness of type annotation |
23 | // on a field). |
24 | // |
25 | // Given the static type G<T0, ..., Tn> we say that it is exact iff any |
26 | // values that can be observed at this location has runtime type T such that |
27 | // type arguments of T at G are exactly <T0, ..., Tn>. |
28 | // |
29 | // Currently we only support tracking for locations that are also known |
30 | // to be monomorphic with respect to the actual class of the values it contains. |
31 | // |
32 | // Important: locations should never switch from tracked (kIsTriviallyExact, |
33 | // kHasExactSuperType, kHasExactSuperClass, kNotExact) to not tracked |
34 | // (kNotTracking) or the other way around because that would affect unoptimized |
35 | // graphs generated by graph builder and skew deopt ids. |
36 | class StaticTypeExactnessState final { |
37 | public: |
38 | // Values stored in the location with static type G<T0, ..., Tn> are all |
39 | // instances of C<T0, ..., Tn> and C<U0, ..., Un> at G has type parameters |
40 | // <U0, ..., Un>. |
41 | // |
42 | // For trivially exact types we can simply compare type argument |
43 | // vectors as pointers to check exactness. That's why we represent |
44 | // trivially exact locations as offset in words to the type arguments of |
45 | // class C. All other states are represented as non-positive values. |
46 | // |
47 | // Note: we are ignoring the type argument vector sharing optimization for |
48 | // now. |
49 | static inline StaticTypeExactnessState TriviallyExact( |
50 | intptr_t type_arguments_offset_in_bytes) { |
51 | ASSERT((type_arguments_offset_in_bytes > 0) && |
52 | Utils::IsInt(8, type_arguments_offset_in_bytes)); |
53 | return StaticTypeExactnessState(type_arguments_offset_in_bytes); |
54 | } |
55 | |
56 | static inline bool CanRepresentAsTriviallyExact( |
57 | intptr_t type_arguments_offset_in_bytes) { |
58 | return Utils::IsInt(8, type_arguments_offset_in_bytes); |
59 | } |
60 | |
61 | // Values stored in the location with static type G<T0, ..., Tn> are all |
62 | // instances of class C<...> and C<U0, ..., Un> at G has type |
63 | // parameters <T0, ..., Tn> for any <U0, ..., Un> - that is C<...> has a |
64 | // supertype G<T0, ..., Tn>. |
65 | // |
66 | // For such locations we can simply check if the value stored |
67 | // is an instance of an expected class and we don't have to look at |
68 | // type arguments carried by the instance. |
69 | // |
70 | // We distinguish situations where we know that G is a superclass of C from |
71 | // situations where G might be superinterface of C - because in the first |
72 | // type arguments of G give us constant prefix of type arguments of C. |
73 | static inline StaticTypeExactnessState HasExactSuperType() { |
74 | return StaticTypeExactnessState(kHasExactSuperType); |
75 | } |
76 | |
77 | static inline StaticTypeExactnessState HasExactSuperClass() { |
78 | return StaticTypeExactnessState(kHasExactSuperClass); |
79 | } |
80 | |
81 | // Values stored in the location don't fall under either kIsTriviallyExact |
82 | // or kHasExactSuperType categories. |
83 | // |
84 | // Note: that does not imply that static type annotation is not exact |
85 | // according to a broader definition, e.g. location might simply be |
86 | // polymorphic and store instances of multiple different types. |
87 | // However for simplicity we don't track such cases yet. |
88 | static inline StaticTypeExactnessState NotExact() { |
89 | return StaticTypeExactnessState(kNotExact); |
90 | } |
91 | |
92 | // The location does not track exactness of its static type at runtime. |
93 | static inline StaticTypeExactnessState NotTracking() { |
94 | return StaticTypeExactnessState(kNotTracking); |
95 | } |
96 | |
97 | static inline StaticTypeExactnessState Uninitialized() { |
98 | return StaticTypeExactnessState(kUninitialized); |
99 | } |
100 | |
101 | static StaticTypeExactnessState Compute(const Type& static_type, |
102 | const Instance& value, |
103 | bool print_trace = false); |
104 | |
105 | bool IsTracking() const { return value_ != kNotTracking; } |
106 | bool IsUninitialized() const { return value_ == kUninitialized; } |
107 | bool IsHasExactSuperClass() const { return value_ == kHasExactSuperClass; } |
108 | bool IsHasExactSuperType() const { return value_ == kHasExactSuperType; } |
109 | bool IsTriviallyExact() const { return value_ > kUninitialized; } |
110 | bool NeedsFieldGuard() const { return value_ >= kUninitialized; } |
111 | bool IsExactOrUninitialized() const { return value_ > kNotExact; } |
112 | bool IsExact() const { |
113 | return IsTriviallyExact() || IsHasExactSuperType() || |
114 | IsHasExactSuperClass(); |
115 | } |
116 | |
117 | const char* ToCString() const; |
118 | |
119 | StaticTypeExactnessState CollapseSuperTypeExactness() const { |
120 | return IsHasExactSuperClass() ? HasExactSuperType() : *this; |
121 | } |
122 | |
123 | static inline StaticTypeExactnessState Decode(int8_t value) { |
124 | return StaticTypeExactnessState(value); |
125 | } |
126 | |
127 | int8_t Encode() const { return value_; } |
128 | int8_t GetTypeArgumentsOffsetInWords() const { |
129 | ASSERT(IsTriviallyExact()); |
130 | return value_; |
131 | } |
132 | |
133 | static constexpr int8_t kUninitialized = 0; |
134 | |
135 | private: |
136 | static constexpr int8_t kNotTracking = -4; |
137 | static constexpr int8_t kNotExact = -3; |
138 | static constexpr int8_t kHasExactSuperType = -2; |
139 | static constexpr int8_t kHasExactSuperClass = -1; |
140 | |
141 | explicit StaticTypeExactnessState(int8_t value) : value_(value) {} |
142 | |
143 | int8_t value_; |
144 | |
145 | DISALLOW_ALLOCATION(); |
146 | }; |
147 | |
148 | } // namespace dart |
149 | |
150 | #endif // RUNTIME_VM_STATIC_TYPE_EXACTNESS_STATE_H_ |
151 | |