blob: 61d590bd592e2cb44d1584c7de3f8ab84148230b [file] [log] [blame]
Igor Murashkinf31a00c2017-10-27 10:52:07 -07001/*
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.
24struct SubtypeCheckInfoTest;
25
26namespace 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
Hans Boehmb91f9c12017-12-19 15:01:28 -080093 * OF == False
Igor Murashkinf31a00c2017-10-27 10:52:07 -070094 * Initialized <=> StrLen(PathToRoot) < Depth
Hans Boehmb91f9c12017-12-19 15:01:28 -080095 * Next == 1
96 * OF == False
Igor Murashkinf31a00c2017-10-27 10:52:07 -070097 * Assigned <=> StrLen(PathToRoot) == Depth
Hans Boehmb91f9c12017-12-19 15:01:28 -080098 * Next >= 1
99 * OF == False
Igor Murashkinf31a00c2017-10-27 10:52:07 -0700100 * 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 */
125struct 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
Vladimir Marko38b8b252018-01-02 19:07:06 +0000141 // Get the raw depth.
142 size_t GetDepth() const {
143 return depth_;
144 }
145
Igor Murashkinf31a00c2017-10-27 10:52:07 -0700146 // Chop off the depth, returning only the bitstring+of state.
147 // (Used to store into memory, since storing the depth would be redundant.)
148 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.
155 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.
169 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.
198 static SubtypeCheckInfo CreateRoot() {
Igor Murashkin5573c372017-11-16 13:34:30 -0800199 SubtypeCheckInfo io{};
Igor Murashkinf31a00c2017-10-27 10:52:07 -0700200 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.
216 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
Hans Boehmb91f9c12017-12-19 15:01:28 -0800230 // Always clear the inherited Parent's next Value, i.e. the child's last path entry.
Igor Murashkin5573c372017-11-16 13:34:30 -0800231 OverwriteNextValueFromParent(/*inout*/&child, BitStringChar{});
Igor Murashkinf31a00c2017-10-27 10:52:07 -0700232
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_) {
Igor Murashkinf31a00c2017-10-27 10:52:07 -0700246 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.
269 State GetState() const {
Igor Murashkinf31a00c2017-10-27 10:52:07 -0700270 if (bitstring_and_of_.overflow_) {
271 // Overflowed if and only if the OF bit was set.
272 return kOverflowed;
273 }
274
Hans Boehmb91f9c12017-12-19 15:01:28 -0800275 if (GetBitString().IsEmpty()) {
276 // Empty bitstring (all 0s) -> uninitialized.
277 return kUninitialized;
278 }
279
Igor Murashkinf31a00c2017-10-27 10:52:07 -0700280 // Either Assigned or Initialized.
281 BitString path_to_root = GetPathToRoot();
282
Igor Murashkin86083f72017-10-27 10:59:04 -0700283 DCHECK(!HasNext() || GetNext() != 0u)
Igor Murashkinf31a00c2017-10-27 10:52:07 -0700284 << "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".
296 BitString::StorageType GetEncodedPathToRoot() const {
297 BitString::StorageType data = static_cast<BitString::StorageType>(GetPathToRoot());
298 // Bit strings are logically in the least-significant memory.
299 // Shift it so the bits are all most-significant.
300 return data << (BitSizeOf(data) - BitStructSizeOf<BitString>());
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".
305 BitString::StorageType GetEncodedPathToRootMask() const {
306 size_t num_bitchars = GetSafeDepth();
307 size_t bitlength = BitString::GetBitLengthTotalAtPosition(num_bitchars);
308
309 BitString::StorageType mask_all =
310 std::numeric_limits<BitString::StorageType>::max();
311 BitString::StorageType mask_lsb =
312 MaskLeastSignificant<BitString::StorageType>(
313 BitSizeOf<BitString::StorageType>() - bitlength);
314
315 BitString::StorageType result = mask_all & ~mask_lsb;
316
317 // TODO: refactor above code into MaskMostSignificant?
318 return result;
319 }
320
321 // Get the "Next" bitchar, assuming that there is one to get.
322 BitStringChar GetNext() const {
323 DCHECK(HasNext());
324 return GetBitString()[depth_];
325 }
326
327 // Try to get the Next value, if there is one.
328 // Returns: Whether or not there was a Next value.
329 bool MaybeGetNext(/*out*/BitStringChar* next) const {
330 DCHECK(next != nullptr);
331
332 if (HasNext()) {
333 *next = GetBitString()[depth_];
334 return true;
335 }
336 return false;
337 }
338
339 private:
340 // Constructor intended for testing. Runs all invariant checks.
341 SubtypeCheckInfo(BitString path_to_root, BitStringChar next, bool overflow, size_t depth) {
342 SubtypeCheckBits iod;
343 iod.bitstring_ = path_to_root;
344 iod.overflow_ = overflow;
345
346 bitstring_and_of_ = iod;
347 depth_ = depth;
348
349 // Len(Path-to-root) <= Depth.
350 DCHECK_GE(depth_, path_to_root.Length())
351 << "Path was too long for the depth, path: " << path_to_root;
352
353 bool did_overlap = false;
354 if (HasNext()) {
355 if (kIsDebugBuild) {
Igor Murashkin86083f72017-10-27 10:59:04 -0700356 did_overlap = (GetNext() != 0u);
Igor Murashkinf31a00c2017-10-27 10:52:07 -0700357 }
358
359 SetNext(next);
360
361 DCHECK_EQ(next, GetNext());
362 }
363 // "Next" must be set before we can check the invariants.
364 DcheckInvariants();
365 DCHECK(!did_overlap)
366 << "Path to root overlapped with Next value, path: " << path_to_root;
367 DCHECK_EQ(path_to_root, GetPathToRoot());
368 }
369
370 // Factory intended for testing. Skips DcheckInvariants.
371 static SubtypeCheckInfo MakeUnchecked(BitString bitstring, bool overflow, size_t depth) {
372 SubtypeCheckBits iod;
373 iod.bitstring_ = bitstring;
374 iod.overflow_ = overflow;
375
376 SubtypeCheckInfo io;
377 io.depth_ = depth;
378 io.bitstring_and_of_ = iod;
379
380 return io;
381 }
382
383 void SetNext(BitStringChar next) {
384 DCHECK(HasNext());
385 BitString bs = GetBitString();
386 bs.SetAt(depth_, next);
387 SetBitString(bs);
388 }
389
390 void SetNextUnchecked(BitStringChar next) {
391 BitString bs = GetBitString();
392 bs.SetAt(depth_, next);
393 SetBitStringUnchecked(bs);
394 }
395
Hans Boehmb91f9c12017-12-19 15:01:28 -0800396 // If there is a next field, set it to 1.
Igor Murashkinf31a00c2017-10-27 10:52:07 -0700397 void MaybeInitNext() {
398 if (HasNext()) {
399 // Clearing out the "Next" value like this
400 // is often an intermediate operation which temporarily
401 // violates the invariants. Do not do the extra dchecks.
Igor Murashkin5573c372017-11-16 13:34:30 -0800402 SetNextUnchecked(BitStringChar{});
Igor Murashkinf31a00c2017-10-27 10:52:07 -0700403 SetNextUnchecked(GetNext()+1u);
404 }
405 }
406
407 BitString GetPathToRoot() const {
408 size_t end = GetSafeDepth();
409 return GetBitString().Truncate(end);
410 }
411
412 bool HasNext() const {
413 return depth_ < BitString::kCapacity;
414 }
415
416 void MarkOverflowed() {
417 bitstring_and_of_.overflow_ = true;
418 }
419
420 static constexpr bool HasBitStringCharStorage(size_t idx) {
421 return idx < BitString::kCapacity;
422 }
423
424 size_t GetSafeDepth() const {
425 return GetSafeDepth(depth_);
426 }
427
428 // Get a "safe" depth, one that is truncated to the bitstring max capacity.
429 // Using a value larger than this will cause undefined behavior.
430 static size_t GetSafeDepth(size_t depth) {
431 return std::min(depth, BitString::kCapacity);
432 }
433
434 BitString GetBitString() const {
435 return bitstring_and_of_.bitstring_;
436 }
437
438 void SetBitString(const BitString& val) {
439 SetBitStringUnchecked(val);
440 DcheckInvariants();
441 }
442
443 void SetBitStringUnchecked(const BitString& val) {
444 bitstring_and_of_.bitstring_ = val;
445 }
446
447 void OverwriteNextValueFromParent(/*inout*/SubtypeCheckInfo* child, BitStringChar value) const {
448 // Helper function for CreateChild.
449 if (HasNext()) {
450 // When we copied the "Next" value, it is now our
451 // last path component in the child.
452 // Always overwrite it with either a cleared value or the parent's Next value.
453 BitString bs = child->GetBitString();
454
455 // Safe write. This.Next always occupies same slot as Child[Depth_].
456 DCHECK(child->HasBitStringCharStorage(depth_));
457
458 bs.SetAt(depth_, value);
459
460 // The child is temporarily in a bad state until it is fixed up further.
461 // Do not do the normal dchecks which do not allow transient badness.
462 child->SetBitStringUnchecked(bs);
463 }
464 }
465
466 void DcheckInvariants() const {
467 if (kIsDebugBuild) {
468 CHECK_GE(GetSafeDepth(depth_ + 1u), GetBitString().Length())
469 << "Bitstring too long for depth, bitstring: " << GetBitString() << ", depth: " << depth_;
470
471 BitString path_to_root = GetPathToRoot();
472
473 // A 'null' (\0) character in path-to-root must be followed only
474 // by other null characters.
475 size_t i;
476 for (i = 0; i < BitString::kCapacity; ++i) {
477 BitStringChar bc = path_to_root[i];
478 if (bc == 0u) {
479 break;
480 }
481 }
482
483 // All characters following a 0 must also be 0.
484 for (; i < BitString::kCapacity; ++i) {
485 BitStringChar bc = path_to_root[i];
486 if (bc != 0u) {
487 LOG(FATAL) << "Path to root had non-0s following 0s: " << path_to_root;
488 }
489 }
490
491 // Trigger any dchecks in GetState.
492 (void)GetState();
493 }
494 }
495
496 SubtypeCheckInfo() = default;
497 size_t depth_;
498 SubtypeCheckBits bitstring_and_of_;
499
500 friend struct ::SubtypeCheckInfoTest;
501 friend std::ostream& operator<<(std::ostream& os, const SubtypeCheckInfo& io);
502};
503
504// Prints the SubtypeCheckInfo::State, e.g. "kUnitialized".
505inline std::ostream& operator<<(std::ostream& os, const SubtypeCheckInfo::State& state) {
506 switch (state) {
507 case SubtypeCheckInfo::kUninitialized:
508 os << "kUninitialized";
509 break;
510 case SubtypeCheckInfo::kInitialized:
511 os << "kInitialized";
512 break;
513 case SubtypeCheckInfo::kAssigned:
514 os << "kAssigned";
515 break;
516 case SubtypeCheckInfo::kOverflowed:
517 os << "kOverflowed";
518 break;
519 default:
520 os << "(Invalid SubtypeCheckInfo::State " << static_cast<int>(state) << ")";
521 }
522 return os;
523}
524
525// Prints e.g. "SubtypeCheckInfo{BitString[1,2,3], depth: 3, of:1}"
526inline std::ostream& operator<<(std::ostream& os, const SubtypeCheckInfo& io) {
527 os << "SubtypeCheckInfo{" << io.GetBitString() << ", "
528 << "depth: " << io.depth_ << ", of:" << io.bitstring_and_of_.overflow_ << "}";
529 return os;
530}
531
532} // namespace art
533
534#endif // ART_RUNTIME_SUBTYPE_CHECK_INFO_H_