blob: 08db77030e0c400540f1296b882c27ff01a3fc3d [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.
Vladimir Markodc682aa2018-01-04 18:42:57 +0000299 return data;
Igor Murashkinf31a00c2017-10-27 10:52:07 -0700300 }
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".
304 BitString::StorageType GetEncodedPathToRootMask() const {
305 size_t num_bitchars = GetSafeDepth();
306 size_t bitlength = BitString::GetBitLengthTotalAtPosition(num_bitchars);
Vladimir Markodc682aa2018-01-04 18:42:57 +0000307 return MaskLeastSignificant<BitString::StorageType>(bitlength);
Igor Murashkinf31a00c2017-10-27 10:52:07 -0700308 }
309
310 // Get the "Next" bitchar, assuming that there is one to get.
311 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.
318 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.
330 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) {
Igor Murashkin86083f72017-10-27 10:59:04 -0700345 did_overlap = (GetNext() != 0u);
Igor Murashkinf31a00c2017-10-27 10:52:07 -0700346 }
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.
360 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
372 void SetNext(BitStringChar next) {
373 DCHECK(HasNext());
374 BitString bs = GetBitString();
375 bs.SetAt(depth_, next);
376 SetBitString(bs);
377 }
378
379 void SetNextUnchecked(BitStringChar next) {
380 BitString bs = GetBitString();
381 bs.SetAt(depth_, next);
382 SetBitStringUnchecked(bs);
383 }
384
Hans Boehmb91f9c12017-12-19 15:01:28 -0800385 // If there is a next field, set it to 1.
Igor Murashkinf31a00c2017-10-27 10:52:07 -0700386 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.
Igor Murashkin5573c372017-11-16 13:34:30 -0800391 SetNextUnchecked(BitStringChar{});
Igor Murashkinf31a00c2017-10-27 10:52:07 -0700392 SetNextUnchecked(GetNext()+1u);
393 }
394 }
395
396 BitString GetPathToRoot() const {
397 size_t end = GetSafeDepth();
398 return GetBitString().Truncate(end);
399 }
400
401 bool HasNext() const {
402 return depth_ < BitString::kCapacity;
403 }
404
405 void MarkOverflowed() {
406 bitstring_and_of_.overflow_ = true;
407 }
408
409 static constexpr bool HasBitStringCharStorage(size_t idx) {
410 return idx < BitString::kCapacity;
411 }
412
413 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.
419 static size_t GetSafeDepth(size_t depth) {
420 return std::min(depth, BitString::kCapacity);
421 }
422
423 BitString GetBitString() const {
424 return bitstring_and_of_.bitstring_;
425 }
426
427 void SetBitString(const BitString& val) {
428 SetBitStringUnchecked(val);
429 DcheckInvariants();
430 }
431
432 void SetBitStringUnchecked(const BitString& val) {
433 bitstring_and_of_.bitstring_ = val;
434 }
435
436 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
455 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".
494inline 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}"
515inline 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_