• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ART_RUNTIME_SUBTYPE_CHECK_INFO_H_
18 #define ART_RUNTIME_SUBTYPE_CHECK_INFO_H_
19 
20 #include "base/bit_string.h"
21 #include "base/logging.h"
22 #include "base/macros.h"
23 #include "subtype_check_bits.h"
24 
25 // Forward-declare for testing purposes.
26 struct SubtypeCheckInfoTest;
27 
28 namespace art HIDDEN {
29 
30 /**
31  * SubtypeCheckInfo is a logical label for the class SubtypeCheck data, which is necessary to
32  * perform efficient O(1) subtype comparison checks. See also subtype_check.h
33  * for the more general explanation of how the labels are used overall.
34  *
35  * For convenience, we also store the class depth within an SubtypeCheckInfo, since nearly all
36  * calculations are dependent on knowing the depth of the class.
37  *
38  * A SubtypeCheckInfo logically has:
39  *          * Depth - How many levels up to the root (j.l.Object)?
40  *          * PathToRoot - Possibly truncated BitString that encodes path to root
41  *          * Next - The value a newly inserted Child would get appended to its path.
42  *          * Overflow - If this path can never become a full path.
43  *
44  * Depending on the values of the above, it can be in one of these logical states,
45  * which are introduced in subtype_check.h:
46  *
47  *               Transient States                         Terminal States
48  *
49  *  +-----------------+     +--------------------+     +-------------------+
50  *  |                 |     |                    |     |                   |
51  *  |  Uninitialized  | +--->    Initialized     | +--->     Assigned      |
52  *  |                 |     |                    |     |                   |
53  *  +--------+--------+     +---------+----------+     +-------------------+
54  *           |                        |
55  *           |                        |
56  *           |                        |                +-------------------+
57  *           |                        +---------------->                   |
58  *           |                                         |     Overflowed    |
59  *           +----------------------------------------->                   |
60  *                                                     +-------------------+
61  *
62  * Invariants:
63  *
64  *   Initialized      => Parent >= Initialized
65  *
66  *   Assigned         => Parent == Assigned
67  *
68  *   Overflowed       => Parent == Overflowed || Parent.Next == Overflowed
69  *
70  * Thread-safety invariants:
71  *
72  *   Initialized      => Parent == Assigned
73  *   // For a class that has an Initialized bitstring, its superclass needs to have an
74  *   // Assigned bitstring since if its super class's bitstring is not Assigned yet,
75  *   // once it becomes Assigned, we cannot update its children's bitstrings to maintain
76  *   // all the tree invariants (below) atomically.
77  *
78  * --------------------------------------------------------------------------------------------
79  * Knowing these transitions above, we can more closely define the various terms and operations:
80  *
81  * Definitions:
82  *   (see also base/bit_string.h definitions).
83  *
84  *           Depth :=  Distance(Root, Class)
85  *     Safe(Depth) :=  Min(Depth, MaxBitstringLen)
86  *      PathToRoot :=  Bitstring[0..Safe(Depth))
87  *           Next  :=  Bitstring[Depth]
88  *           OF    ∈   {False, True}
89  *    TruncPath(D) :=  PathToRoot[0..D)
90  *
91  * Local Invariants:
92  *
93  *   Uninitialized <=> StrLen(PathToRoot) == 0
94  *                     Next == 0
95  *                     OF == False
96  *   Initialized   <=> StrLen(PathToRoot) < Depth
97  *                     Next == 1
98  *                     OF == False
99  *   Assigned      <=> StrLen(PathToRoot) == Depth
100  *                     Next >= 1
101  *                     OF == False
102  *   Overflowed    <=> OF == True
103  *
104  * Tree Invariants:
105  *
106  *   Uninitialized =>
107  *     forall child ∈ Children(Class):
108  *       child.State == Uninitialized
109  *
110  *   Assigned       =>
111  *     forall child ∈ Children(Class):
112  *       Next > Child.PathToRoot[Child.Depth-1]
113  *
114  *   ! Uninitialized =>
115  *     forall ancestor ∈ Ancestors(Class):
116  *       TruncPath(ancestor.Depth) == ancestor.PathToRoot
117  *     forall unrelated ∈ (Classes - Ancestors(Class))
118  *         s.t. unrelated.State == Assigned:
119  *       TruncPath(unrelated.Depth) != unrelated.PathToRoot
120  *
121  * Thread-safety invariants:
122  *
123  *   Initialized   <=> StrLen(PathToRoot) == Safe(Depth - 1)
124  *   // Initialized State corresponds to exactly 1 bitstring.
125  *   // Cannot transition from Initialized to Initialized.
126  */
127 struct SubtypeCheckInfo {
128   // See above documentation for possible state transitions.
129   enum State {
130     kUninitialized,
131     kInitialized,
132     kAssigned,
133     kOverflowed
134   };
135 
136   // The result of a "src IsSubType target" check:
137   enum Result {
138     kUnknownSubtypeOf,  // Not enough data. Operand states weren't high enough.
139     kNotSubtypeOf,      // Enough data. src is not a subchild of the target.
140     kSubtypeOf          // Enough data. src is a subchild of the target.
141   };
142 
143   // Get the raw depth.
GetDepthSubtypeCheckInfo144   size_t GetDepth() const {
145     return depth_;
146   }
147 
148   // Chop off the depth, returning only the bitstring+of state.
149   // (Used to store into memory, since storing the depth would be redundant.)
GetSubtypeCheckBitsSubtypeCheckInfo150   SubtypeCheckBits GetSubtypeCheckBits() const {
151     return bitstring_and_of_;
152   }
153 
154   // Create from the depth and the bitstring+of state.
155   // This is done for convenience to avoid passing in "depth" everywhere,
156   // since our current state is almost always a function of depth.
CreateSubtypeCheckInfo157   static SubtypeCheckInfo Create(const SubtypeCheckBits& compressed_value, size_t depth) {
158     SubtypeCheckInfo io;
159     io.depth_ = depth;
160     io.bitstring_and_of_ = compressed_value;
161     io.DcheckInvariants();
162     return io;
163   }
164 
165   // Is this a subtype of the target?
166   //
167   // The current state must be at least Initialized, and the target state
168   // must be Assigned, otherwise the result will return kUnknownSubtypeOf.
169   //
170   // Normally, return kSubtypeOf or kNotSubtypeOf.
IsSubtypeOfSubtypeCheckInfo171   Result IsSubtypeOf(const SubtypeCheckInfo& target) {
172     if (target.GetState() != SubtypeCheckInfo::kAssigned ||
173         GetState() == SubtypeCheckInfo::kUninitialized) {
174       return Result::kUnknownSubtypeOf;
175     }
176 
177     BitString::StorageType source_value = GetEncodedPathToRoot();
178     BitString::StorageType target_value = target.GetEncodedPathToRoot();
179     BitString::StorageType target_mask = target.GetEncodedPathToRootMask();
180 
181     bool result = (source_value & target_mask) == (target_value);
182     if (result) {
183       DCHECK_EQ(GetPathToRoot().Truncate(target.GetSafeDepth()), target.GetPathToRoot())
184           << "Source: " << *this << ", Target: " << target;
185     } else {
186       DCHECK_NE(GetPathToRoot().Truncate(target.GetSafeDepth()), target.GetPathToRoot())
187           << "Source: " << *this << ", Target: " << target;
188     }
189 
190     // Note: We could've also used shifts here, as described in subtype_check_bits.h,
191     // but it doesn't make much of a difference in the Runtime since we aren't trying to optimize
192     // for code size.
193 
194     return result ? Result::kSubtypeOf : Result::kNotSubtypeOf;
195   }
196 
197   // Returns a new root SubtypeCheckInfo with a blank PathToRoot.
198   // Post-condition: The return valued has an Assigned state.
CreateRootSubtypeCheckInfo199   static SubtypeCheckInfo CreateRoot() {
200     SubtypeCheckInfo io{};
201     io.depth_ = 0u;
202     io.SetNext(io.GetNext() + 1u);
203 
204     // The root is always considered assigned once it is no longer Initialized.
205     DCHECK_EQ(SubtypeCheckInfo::kAssigned, io.GetState());
206     return io;
207   }
208 
209   // Copies the current PathToRoot into the child.
210   //
211   // If assign_next is true, then also assign a new SubtypeCheckInfo for a child by
212   // assigning the current Next value to its PathToRoot[Depth] component.
213   // Updates the current Next value as a side effect.
214   //
215   // Preconditions: State is either Assigned or Overflowed.
216   // Returns: A new child >= Initialized state.
CreateChildSubtypeCheckInfo217   SubtypeCheckInfo CreateChild(bool assign_next) {
218     SubtypeCheckInfo child = *this;  // Copy everything (path, next, of).
219     child.depth_ = depth_ + 1u;
220 
221     // Must be Assigned or Overflowed in order to create a subchild.
222     DCHECK(GetState() == kAssigned || GetState() == kOverflowed)
223         << "Unexpected bitstring state: " << GetState();
224 
225     // Begin transition to >= Initialized.
226 
227     // Always attempt to re-initialize Child's Next value.
228     // Next must be non-0 to disambiguate it from Uninitialized.
229     child.MaybeInitNext();
230 
231     // Always clear the inherited Parent's next Value, i.e. the child's last path entry.
232     OverwriteNextValueFromParent(/*inout*/&child, BitStringChar{});
233 
234     // The state is now Initialized | Overflowed.
235     DCHECK_NE(kAssigned, child.GetState()) << child.GetBitString();
236     DCHECK_NE(kUninitialized, child.GetState()) << child.GetBitString();
237 
238     if (assign_next == false) {
239       child.DcheckInvariants();
240       return child;
241     }
242 
243     // Begin transition to >= Assigned.
244 
245     // Assign attempt.
246     if (HasNext() && !bitstring_and_of_.overflow_) {
247       BitStringChar next = GetNext();
248       if (next != next.MaximumValue()) {
249         // The parent's "next" value is now the child's latest path element.
250         OverwriteNextValueFromParent(/*inout*/&child, next);
251         // Update self next value, so that future CreateChild calls
252         // do not get the same path value.
253         SetNext(next + 1u);
254       } else {
255         child.MarkOverflowed();  // Too wide.
256       }
257     } else {
258       child.MarkOverflowed();  // Too deep, or parent was already overflowed.
259     }
260 
261     // The state is now Assigned | Overflowed.
262     DCHECK(child.GetState() == kAssigned || child.GetState() == kOverflowed);
263 
264     child.DcheckInvariants();
265     return child;
266   }
267 
268   // Get the current state (Uninitialized, Initialized, Assigned, or Overflowed).
269   // See the "SubtypeCheckInfo" documentation above which explains how a state is determined.
GetStateSubtypeCheckInfo270   State GetState() const {
271     if (bitstring_and_of_.overflow_) {
272       // Overflowed if and only if the OF bit was set.
273       return kOverflowed;
274     }
275 
276     if (GetBitString().IsEmpty()) {
277       // Empty bitstring (all 0s) -> uninitialized.
278       return kUninitialized;
279     }
280 
281     // Either Assigned or Initialized.
282     BitString path_to_root = GetPathToRoot();
283 
284     DCHECK_IMPLIES(HasNext(), GetNext() != 0u)
285         << "Expected (Assigned|Initialized) state to have >0 Next value: " << GetNext()
286         << " path: " << path_to_root;
287 
288     if (path_to_root.Length() == depth_) {
289       return kAssigned;
290     }
291 
292     return kInitialized;
293   }
294 
295   // Retrieve the path to root bitstring as a plain uintN_t value that is amenable to
296   // be used by a fast check "encoded_src & mask_target == encoded_target".
GetEncodedPathToRootSubtypeCheckInfo297   BitString::StorageType GetEncodedPathToRoot() const {
298     BitString::StorageType data = static_cast<BitString::StorageType>(GetPathToRoot());
299     // Bit strings are logically in the least-significant memory.
300     return data;
301   }
302 
303   // Retrieve the path to root bitstring mask as a plain uintN_t that is amenable to
304   // be used by a fast check "encoded_src & mask_target == encoded_target".
GetEncodedPathToRootMaskSubtypeCheckInfo305   BitString::StorageType GetEncodedPathToRootMask() const {
306     size_t num_bitchars = GetSafeDepth();
307     size_t bitlength = BitString::GetBitLengthTotalAtPosition(num_bitchars);
308     return MaskLeastSignificant<BitString::StorageType>(bitlength);
309   }
310 
311   // Get the "Next" bitchar, assuming that there is one to get.
GetNextSubtypeCheckInfo312   BitStringChar GetNext() const {
313     DCHECK(HasNext());
314     return GetBitString()[depth_];
315   }
316 
317   // Try to get the Next value, if there is one.
318   // Returns: Whether or not there was a Next value.
MaybeGetNextSubtypeCheckInfo319   bool MaybeGetNext(/*out*/BitStringChar* next) const {
320     DCHECK(next != nullptr);
321 
322     if (HasNext()) {
323       *next = GetBitString()[depth_];
324       return true;
325     }
326     return false;
327   }
328 
329  private:
330   // Constructor intended for testing. Runs all invariant checks.
SubtypeCheckInfoSubtypeCheckInfo331   SubtypeCheckInfo(BitString path_to_root, BitStringChar next, bool overflow, size_t depth) {
332     SubtypeCheckBits iod;
333     iod.bitstring_ = path_to_root;
334     iod.overflow_ = overflow;
335 
336     bitstring_and_of_ = iod;
337     depth_ = depth;
338 
339     // Len(Path-to-root) <= Depth.
340     DCHECK_GE(depth_, path_to_root.Length())
341         << "Path was too long for the depth, path: " << path_to_root;
342 
343     bool did_overlap = false;
344     if (HasNext()) {
345       if (kIsDebugBuild) {
346         did_overlap = (GetNext() != 0u);
347       }
348 
349       SetNext(next);
350 
351       DCHECK_EQ(next, GetNext());
352     }
353     // "Next" must be set before we can check the invariants.
354     DcheckInvariants();
355     DCHECK(!did_overlap)
356           << "Path to root overlapped with Next value, path: " << path_to_root;
357     DCHECK_EQ(path_to_root, GetPathToRoot());
358   }
359 
360   // Factory intended for testing. Skips DcheckInvariants.
MakeUncheckedSubtypeCheckInfo361   static SubtypeCheckInfo MakeUnchecked(BitString bitstring, bool overflow, size_t depth) {
362     SubtypeCheckBits iod;
363     iod.bitstring_ = bitstring;
364     iod.overflow_ = overflow;
365 
366     SubtypeCheckInfo io;
367     io.depth_ = depth;
368     io.bitstring_and_of_ = iod;
369 
370     return io;
371   }
372 
SetNextSubtypeCheckInfo373   void SetNext(BitStringChar next) {
374     DCHECK(HasNext());
375     BitString bs = GetBitString();
376     bs.SetAt(depth_, next);
377     SetBitString(bs);
378   }
379 
SetNextUncheckedSubtypeCheckInfo380   void SetNextUnchecked(BitStringChar next) {
381     BitString bs = GetBitString();
382     bs.SetAt(depth_, next);
383     SetBitStringUnchecked(bs);
384   }
385 
386   // If there is a next field, set it to 1.
MaybeInitNextSubtypeCheckInfo387   void MaybeInitNext() {
388     if (HasNext()) {
389       // Clearing out the "Next" value like this
390       // is often an intermediate operation which temporarily
391       // violates the invariants. Do not do the extra dchecks.
392       SetNextUnchecked(BitStringChar{});
393       SetNextUnchecked(GetNext()+1u);
394     }
395   }
396 
GetPathToRootSubtypeCheckInfo397   BitString GetPathToRoot() const {
398     size_t end = GetSafeDepth();
399     return GetBitString().Truncate(end);
400   }
401 
HasNextSubtypeCheckInfo402   bool HasNext() const {
403     return depth_ < BitString::kCapacity;
404   }
405 
MarkOverflowedSubtypeCheckInfo406   void MarkOverflowed() {
407     bitstring_and_of_.overflow_ = true;
408   }
409 
HasBitStringCharStorageSubtypeCheckInfo410   static constexpr bool HasBitStringCharStorage(size_t idx) {
411     return idx < BitString::kCapacity;
412   }
413 
GetSafeDepthSubtypeCheckInfo414   size_t GetSafeDepth() const {
415     return GetSafeDepth(depth_);
416   }
417 
418   // Get a "safe" depth, one that is truncated to the bitstring max capacity.
419   // Using a value larger than this will cause undefined behavior.
GetSafeDepthSubtypeCheckInfo420   static size_t GetSafeDepth(size_t depth) {
421     return std::min(depth, BitString::kCapacity);
422   }
423 
GetBitStringSubtypeCheckInfo424   BitString GetBitString() const {
425     return bitstring_and_of_.bitstring_;
426   }
427 
SetBitStringSubtypeCheckInfo428   void SetBitString(const BitString& val) {
429     SetBitStringUnchecked(val);
430     DcheckInvariants();
431   }
432 
SetBitStringUncheckedSubtypeCheckInfo433   void SetBitStringUnchecked(const BitString& val) {
434     bitstring_and_of_.bitstring_ = val;
435   }
436 
OverwriteNextValueFromParentSubtypeCheckInfo437   void OverwriteNextValueFromParent(/*inout*/SubtypeCheckInfo* child, BitStringChar value) const {
438     // Helper function for CreateChild.
439     if (HasNext()) {
440       // When we copied the "Next" value, it is now our
441       // last path component in the child.
442       // Always overwrite it with either a cleared value or the parent's Next value.
443       BitString bs = child->GetBitString();
444 
445       // Safe write. This.Next always occupies same slot as Child[Depth_].
446       DCHECK(child->HasBitStringCharStorage(depth_));
447 
448       bs.SetAt(depth_, value);
449 
450       // The child is temporarily in a bad state until it is fixed up further.
451       // Do not do the normal dchecks which do not allow transient badness.
452       child->SetBitStringUnchecked(bs);
453     }
454   }
455 
DcheckInvariantsSubtypeCheckInfo456   void DcheckInvariants() const {
457     if (kIsDebugBuild) {
458       CHECK_GE(GetSafeDepth(depth_ + 1u), GetBitString().Length())
459           << "Bitstring too long for depth, bitstring: " << GetBitString() << ", depth: " << depth_;
460 
461       BitString path_to_root = GetPathToRoot();
462 
463       // A 'null' (\0) character in path-to-root must be followed only
464       // by other null characters.
465       size_t i;
466       for (i = 0; i < BitString::kCapacity; ++i) {
467         BitStringChar bc = path_to_root[i];
468         if (bc == 0u) {
469           break;
470         }
471       }
472 
473       // All characters following a 0 must also be 0.
474       for (; i < BitString::kCapacity; ++i) {
475         BitStringChar bc = path_to_root[i];
476         if (bc != 0u) {
477           LOG(FATAL) << "Path to root had non-0s following 0s: " << path_to_root;
478         }
479       }
480 
481        // Trigger any dchecks in GetState.
482       (void)GetState();
483     }
484   }
485 
486   SubtypeCheckInfo() = default;
487   size_t depth_;
488   SubtypeCheckBits bitstring_and_of_;
489 
490   friend struct ::SubtypeCheckInfoTest;
491   friend std::ostream& operator<<(std::ostream& os, const SubtypeCheckInfo& io);
492 };
493 
494 // Prints the SubtypeCheckInfo::State, e.g. "kUnitialized".
495 inline std::ostream& operator<<(std::ostream& os, const SubtypeCheckInfo::State& state) {
496   switch (state) {
497     case SubtypeCheckInfo::kUninitialized:
498       os << "kUninitialized";
499       break;
500     case SubtypeCheckInfo::kInitialized:
501       os << "kInitialized";
502       break;
503     case SubtypeCheckInfo::kAssigned:
504       os << "kAssigned";
505       break;
506     case SubtypeCheckInfo::kOverflowed:
507       os << "kOverflowed";
508       break;
509     default:
510       os << "(Invalid SubtypeCheckInfo::State " << static_cast<int>(state) << ")";
511   }
512   return os;
513 }
514 
515 // Prints e.g. "SubtypeCheckInfo{BitString[1,2,3], depth: 3, of:1}"
516 inline std::ostream& operator<<(std::ostream& os, const SubtypeCheckInfo& io) {
517   os << "SubtypeCheckInfo{" << io.GetBitString() << ", "
518      << "depth: " << io.depth_ << ", of:" << io.bitstring_and_of_.overflow_ << "}";
519   return os;
520 }
521 
522 }  // namespace art
523 
524 #endif  // ART_RUNTIME_SUBTYPE_CHECK_INFO_H_
525