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