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