1 /* 2 * Copyright (C) 2012 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 #include "register_line.h" 18 19 #include "android-base/stringprintf.h" 20 21 #include "dex_instruction-inl.h" 22 #include "method_verifier-inl.h" 23 #include "register_line-inl.h" 24 #include "reg_type-inl.h" 25 26 namespace art { 27 namespace verifier { 28 29 using android::base::StringPrintf; 30 31 bool RegisterLine::CheckConstructorReturn(MethodVerifier* verifier) const { 32 if (kIsDebugBuild && this_initialized_) { 33 // Ensure that there is no UninitializedThisReference type anymore if this_initialized_ is true. 34 for (size_t i = 0; i < num_regs_; i++) { 35 const RegType& type = GetRegisterType(verifier, i); 36 CHECK(!type.IsUninitializedThisReference() && 37 !type.IsUnresolvedAndUninitializedThisReference()) 38 << i << ": " << type.IsUninitializedThisReference() << " in " 39 << verifier->GetMethodReference().PrettyMethod(); 40 } 41 } 42 if (!this_initialized_) { 43 verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) 44 << "Constructor returning without calling superclass constructor"; 45 } 46 return this_initialized_; 47 } 48 49 const RegType& RegisterLine::GetInvocationThis(MethodVerifier* verifier, const Instruction* inst, 50 bool allow_failure) { 51 DCHECK(inst->IsInvoke()); 52 const size_t args_count = inst->VRegA(); 53 if (args_count < 1) { 54 if (!allow_failure) { 55 verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invoke lacks 'this'"; 56 } 57 return verifier->GetRegTypeCache()->Conflict(); 58 } 59 /* Get the element type of the array held in vsrc */ 60 const uint32_t this_reg = inst->VRegC(); 61 const RegType& this_type = GetRegisterType(verifier, this_reg); 62 if (!this_type.IsReferenceTypes()) { 63 if (!allow_failure) { 64 verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) 65 << "tried to get class from non-reference register v" << this_reg 66 << " (type=" << this_type << ")"; 67 } 68 return verifier->GetRegTypeCache()->Conflict(); 69 } 70 return this_type; 71 } 72 73 bool RegisterLine::VerifyRegisterTypeWide(MethodVerifier* verifier, uint32_t vsrc, 74 const RegType& check_type1, 75 const RegType& check_type2) { 76 DCHECK(check_type1.CheckWidePair(check_type2)); 77 // Verify the src register type against the check type refining the type of the register 78 const RegType& src_type = GetRegisterType(verifier, vsrc); 79 if (!check_type1.IsAssignableFrom(src_type, verifier)) { 80 verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "register v" << vsrc << " has type " << src_type 81 << " but expected " << check_type1; 82 return false; 83 } 84 const RegType& src_type_h = GetRegisterType(verifier, vsrc + 1); 85 if (!src_type.CheckWidePair(src_type_h)) { 86 verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "wide register v" << vsrc << " has type " 87 << src_type << "/" << src_type_h; 88 return false; 89 } 90 // The register at vsrc has a defined type, we know the lower-upper-bound, but this is less 91 // precise than the subtype in vsrc so leave it for reference types. For primitive types 92 // if they are a defined type then they are as precise as we can get, however, for constant 93 // types we may wish to refine them. Unfortunately constant propagation has rendered this useless. 94 return true; 95 } 96 97 void RegisterLine::MarkRefsAsInitialized(MethodVerifier* verifier, const RegType& uninit_type) { 98 DCHECK(uninit_type.IsUninitializedTypes()); 99 const RegType& init_type = verifier->GetRegTypeCache()->FromUninitialized(uninit_type); 100 size_t changed = 0; 101 for (uint32_t i = 0; i < num_regs_; i++) { 102 if (GetRegisterType(verifier, i).Equals(uninit_type)) { 103 line_[i] = init_type.GetId(); 104 changed++; 105 } 106 } 107 // Is this initializing "this"? 108 if (uninit_type.IsUninitializedThisReference() || 109 uninit_type.IsUnresolvedAndUninitializedThisReference()) { 110 this_initialized_ = true; 111 } 112 DCHECK_GT(changed, 0u); 113 } 114 115 void RegisterLine::MarkAllRegistersAsConflicts(MethodVerifier* verifier) { 116 uint16_t conflict_type_id = verifier->GetRegTypeCache()->Conflict().GetId(); 117 for (uint32_t i = 0; i < num_regs_; i++) { 118 line_[i] = conflict_type_id; 119 } 120 } 121 122 void RegisterLine::MarkAllRegistersAsConflictsExcept(MethodVerifier* verifier, uint32_t vsrc) { 123 uint16_t conflict_type_id = verifier->GetRegTypeCache()->Conflict().GetId(); 124 for (uint32_t i = 0; i < num_regs_; i++) { 125 if (i != vsrc) { 126 line_[i] = conflict_type_id; 127 } 128 } 129 } 130 131 void RegisterLine::MarkAllRegistersAsConflictsExceptWide(MethodVerifier* verifier, uint32_t vsrc) { 132 uint16_t conflict_type_id = verifier->GetRegTypeCache()->Conflict().GetId(); 133 for (uint32_t i = 0; i < num_regs_; i++) { 134 if ((i != vsrc) && (i != (vsrc + 1))) { 135 line_[i] = conflict_type_id; 136 } 137 } 138 } 139 140 std::string RegisterLine::Dump(MethodVerifier* verifier) const { 141 std::string result; 142 for (size_t i = 0; i < num_regs_; i++) { 143 result += StringPrintf("%zd:[", i); 144 result += GetRegisterType(verifier, i).Dump(); 145 result += "],"; 146 } 147 for (const auto& monitor : monitors_) { 148 result += StringPrintf("{%d},", monitor); 149 } 150 for (auto& pairs : reg_to_lock_depths_) { 151 result += StringPrintf("<%d -> %x>", pairs.first, pairs.second); 152 } 153 return result; 154 } 155 156 void RegisterLine::MarkUninitRefsAsInvalid(MethodVerifier* verifier, const RegType& uninit_type) { 157 for (size_t i = 0; i < num_regs_; i++) { 158 if (GetRegisterType(verifier, i).Equals(uninit_type)) { 159 line_[i] = verifier->GetRegTypeCache()->Conflict().GetId(); 160 ClearAllRegToLockDepths(i); 161 } 162 } 163 } 164 165 void RegisterLine::CopyResultRegister1(MethodVerifier* verifier, uint32_t vdst, bool is_reference) { 166 const RegType& type = verifier->GetRegTypeCache()->GetFromId(result_[0]); 167 if ((!is_reference && !type.IsCategory1Types()) || 168 (is_reference && !type.IsReferenceTypes())) { 169 verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) 170 << "copyRes1 v" << vdst << "<- result0" << " type=" << type; 171 } else { 172 DCHECK(verifier->GetRegTypeCache()->GetFromId(result_[1]).IsUndefined()); 173 SetRegisterType<LockOp::kClear>(verifier, vdst, type); 174 result_[0] = verifier->GetRegTypeCache()->Undefined().GetId(); 175 } 176 } 177 178 /* 179 * Implement "move-result-wide". Copy the category-2 value from the result 180 * register to another register, and reset the result register. 181 */ 182 void RegisterLine::CopyResultRegister2(MethodVerifier* verifier, uint32_t vdst) { 183 const RegType& type_l = verifier->GetRegTypeCache()->GetFromId(result_[0]); 184 const RegType& type_h = verifier->GetRegTypeCache()->GetFromId(result_[1]); 185 if (!type_l.IsCategory2Types()) { 186 verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) 187 << "copyRes2 v" << vdst << "<- result0" << " type=" << type_l; 188 } else { 189 DCHECK(type_l.CheckWidePair(type_h)); // Set should never allow this case 190 SetRegisterTypeWide(verifier, vdst, type_l, type_h); // also sets the high 191 result_[0] = verifier->GetRegTypeCache()->Undefined().GetId(); 192 result_[1] = verifier->GetRegTypeCache()->Undefined().GetId(); 193 } 194 } 195 196 void RegisterLine::CheckUnaryOp(MethodVerifier* verifier, const Instruction* inst, 197 const RegType& dst_type, const RegType& src_type) { 198 if (VerifyRegisterType(verifier, inst->VRegB_12x(), src_type)) { 199 SetRegisterType<LockOp::kClear>(verifier, inst->VRegA_12x(), dst_type); 200 } 201 } 202 203 void RegisterLine::CheckUnaryOpWide(MethodVerifier* verifier, const Instruction* inst, 204 const RegType& dst_type1, const RegType& dst_type2, 205 const RegType& src_type1, const RegType& src_type2) { 206 if (VerifyRegisterTypeWide(verifier, inst->VRegB_12x(), src_type1, src_type2)) { 207 SetRegisterTypeWide(verifier, inst->VRegA_12x(), dst_type1, dst_type2); 208 } 209 } 210 211 void RegisterLine::CheckUnaryOpToWide(MethodVerifier* verifier, const Instruction* inst, 212 const RegType& dst_type1, const RegType& dst_type2, 213 const RegType& src_type) { 214 if (VerifyRegisterType(verifier, inst->VRegB_12x(), src_type)) { 215 SetRegisterTypeWide(verifier, inst->VRegA_12x(), dst_type1, dst_type2); 216 } 217 } 218 219 void RegisterLine::CheckUnaryOpFromWide(MethodVerifier* verifier, const Instruction* inst, 220 const RegType& dst_type, 221 const RegType& src_type1, const RegType& src_type2) { 222 if (VerifyRegisterTypeWide(verifier, inst->VRegB_12x(), src_type1, src_type2)) { 223 SetRegisterType<LockOp::kClear>(verifier, inst->VRegA_12x(), dst_type); 224 } 225 } 226 227 void RegisterLine::CheckBinaryOp(MethodVerifier* verifier, const Instruction* inst, 228 const RegType& dst_type, 229 const RegType& src_type1, const RegType& src_type2, 230 bool check_boolean_op) { 231 const uint32_t vregB = inst->VRegB_23x(); 232 const uint32_t vregC = inst->VRegC_23x(); 233 if (VerifyRegisterType(verifier, vregB, src_type1) && 234 VerifyRegisterType(verifier, vregC, src_type2)) { 235 if (check_boolean_op) { 236 DCHECK(dst_type.IsInteger()); 237 if (GetRegisterType(verifier, vregB).IsBooleanTypes() && 238 GetRegisterType(verifier, vregC).IsBooleanTypes()) { 239 SetRegisterType<LockOp::kClear>(verifier, 240 inst->VRegA_23x(), 241 verifier->GetRegTypeCache()->Boolean()); 242 return; 243 } 244 } 245 SetRegisterType<LockOp::kClear>(verifier, inst->VRegA_23x(), dst_type); 246 } 247 } 248 249 void RegisterLine::CheckBinaryOpWide(MethodVerifier* verifier, const Instruction* inst, 250 const RegType& dst_type1, const RegType& dst_type2, 251 const RegType& src_type1_1, const RegType& src_type1_2, 252 const RegType& src_type2_1, const RegType& src_type2_2) { 253 if (VerifyRegisterTypeWide(verifier, inst->VRegB_23x(), src_type1_1, src_type1_2) && 254 VerifyRegisterTypeWide(verifier, inst->VRegC_23x(), src_type2_1, src_type2_2)) { 255 SetRegisterTypeWide(verifier, inst->VRegA_23x(), dst_type1, dst_type2); 256 } 257 } 258 259 void RegisterLine::CheckBinaryOpWideShift(MethodVerifier* verifier, const Instruction* inst, 260 const RegType& long_lo_type, const RegType& long_hi_type, 261 const RegType& int_type) { 262 if (VerifyRegisterTypeWide(verifier, inst->VRegB_23x(), long_lo_type, long_hi_type) && 263 VerifyRegisterType(verifier, inst->VRegC_23x(), int_type)) { 264 SetRegisterTypeWide(verifier, inst->VRegA_23x(), long_lo_type, long_hi_type); 265 } 266 } 267 268 void RegisterLine::CheckBinaryOp2addr(MethodVerifier* verifier, const Instruction* inst, 269 const RegType& dst_type, const RegType& src_type1, 270 const RegType& src_type2, bool check_boolean_op) { 271 const uint32_t vregA = inst->VRegA_12x(); 272 const uint32_t vregB = inst->VRegB_12x(); 273 if (VerifyRegisterType(verifier, vregA, src_type1) && 274 VerifyRegisterType(verifier, vregB, src_type2)) { 275 if (check_boolean_op) { 276 DCHECK(dst_type.IsInteger()); 277 if (GetRegisterType(verifier, vregA).IsBooleanTypes() && 278 GetRegisterType(verifier, vregB).IsBooleanTypes()) { 279 SetRegisterType<LockOp::kClear>(verifier, 280 vregA, 281 verifier->GetRegTypeCache()->Boolean()); 282 return; 283 } 284 } 285 SetRegisterType<LockOp::kClear>(verifier, vregA, dst_type); 286 } 287 } 288 289 void RegisterLine::CheckBinaryOp2addrWide(MethodVerifier* verifier, const Instruction* inst, 290 const RegType& dst_type1, const RegType& dst_type2, 291 const RegType& src_type1_1, const RegType& src_type1_2, 292 const RegType& src_type2_1, const RegType& src_type2_2) { 293 const uint32_t vregA = inst->VRegA_12x(); 294 const uint32_t vregB = inst->VRegB_12x(); 295 if (VerifyRegisterTypeWide(verifier, vregA, src_type1_1, src_type1_2) && 296 VerifyRegisterTypeWide(verifier, vregB, src_type2_1, src_type2_2)) { 297 SetRegisterTypeWide(verifier, vregA, dst_type1, dst_type2); 298 } 299 } 300 301 void RegisterLine::CheckBinaryOp2addrWideShift(MethodVerifier* verifier, const Instruction* inst, 302 const RegType& long_lo_type, const RegType& long_hi_type, 303 const RegType& int_type) { 304 const uint32_t vregA = inst->VRegA_12x(); 305 const uint32_t vregB = inst->VRegB_12x(); 306 if (VerifyRegisterTypeWide(verifier, vregA, long_lo_type, long_hi_type) && 307 VerifyRegisterType(verifier, vregB, int_type)) { 308 SetRegisterTypeWide(verifier, vregA, long_lo_type, long_hi_type); 309 } 310 } 311 312 void RegisterLine::CheckLiteralOp(MethodVerifier* verifier, const Instruction* inst, 313 const RegType& dst_type, const RegType& src_type, 314 bool check_boolean_op, bool is_lit16) { 315 const uint32_t vregA = is_lit16 ? inst->VRegA_22s() : inst->VRegA_22b(); 316 const uint32_t vregB = is_lit16 ? inst->VRegB_22s() : inst->VRegB_22b(); 317 if (VerifyRegisterType(verifier, vregB, src_type)) { 318 if (check_boolean_op) { 319 DCHECK(dst_type.IsInteger()); 320 /* check vB with the call, then check the constant manually */ 321 const uint32_t val = is_lit16 ? inst->VRegC_22s() : inst->VRegC_22b(); 322 if (GetRegisterType(verifier, vregB).IsBooleanTypes() && (val == 0 || val == 1)) { 323 SetRegisterType<LockOp::kClear>(verifier, 324 vregA, 325 verifier->GetRegTypeCache()->Boolean()); 326 return; 327 } 328 } 329 SetRegisterType<LockOp::kClear>(verifier, vregA, dst_type); 330 } 331 } 332 333 static constexpr uint32_t kVirtualNullRegister = std::numeric_limits<uint32_t>::max(); 334 335 void RegisterLine::PushMonitor(MethodVerifier* verifier, uint32_t reg_idx, int32_t insn_idx) { 336 const RegType& reg_type = GetRegisterType(verifier, reg_idx); 337 if (!reg_type.IsReferenceTypes()) { 338 verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "monitor-enter on non-object (" 339 << reg_type << ")"; 340 } else if (monitors_.size() >= 32) { 341 verifier->Fail(VERIFY_ERROR_LOCKING); 342 if (kDumpLockFailures) { 343 VLOG(verifier) << "monitor-enter stack overflow while verifying " 344 << verifier->GetMethodReference().PrettyMethod(); 345 } 346 } else { 347 if (SetRegToLockDepth(reg_idx, monitors_.size())) { 348 // Null literals can establish aliases that we can't easily track. As such, handle the zero 349 // case as the 2^32-1 register (which isn't available in dex bytecode). 350 if (reg_type.IsZero()) { 351 SetRegToLockDepth(kVirtualNullRegister, monitors_.size()); 352 } 353 354 monitors_.push_back(insn_idx); 355 } else { 356 verifier->Fail(VERIFY_ERROR_LOCKING); 357 if (kDumpLockFailures) { 358 VLOG(verifier) << "unexpected monitor-enter on register v" << reg_idx << " in " 359 << verifier->GetMethodReference().PrettyMethod(); 360 } 361 } 362 } 363 } 364 365 void RegisterLine::PopMonitor(MethodVerifier* verifier, uint32_t reg_idx) { 366 const RegType& reg_type = GetRegisterType(verifier, reg_idx); 367 if (!reg_type.IsReferenceTypes()) { 368 verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "monitor-exit on non-object (" << reg_type << ")"; 369 } else if (monitors_.empty()) { 370 verifier->Fail(VERIFY_ERROR_LOCKING); 371 if (kDumpLockFailures) { 372 VLOG(verifier) << "monitor-exit stack underflow while verifying " 373 << verifier->GetMethodReference().PrettyMethod(); 374 } 375 } else { 376 monitors_.pop_back(); 377 378 bool success = IsSetLockDepth(reg_idx, monitors_.size()); 379 380 if (!success && reg_type.IsZero()) { 381 // Null literals can establish aliases that we can't easily track. As such, handle the zero 382 // case as the 2^32-1 register (which isn't available in dex bytecode). 383 success = IsSetLockDepth(kVirtualNullRegister, monitors_.size()); 384 if (success) { 385 reg_idx = kVirtualNullRegister; 386 } 387 } 388 389 if (!success) { 390 verifier->Fail(VERIFY_ERROR_LOCKING); 391 if (kDumpLockFailures) { 392 VLOG(verifier) << "monitor-exit not unlocking the top of the monitor stack while verifying " 393 << verifier->GetMethodReference().PrettyMethod(); 394 } 395 } else { 396 // Record the register was unlocked. This clears all aliases, thus it will also clear the 397 // null lock, if necessary. 398 ClearRegToLockDepth(reg_idx, monitors_.size()); 399 } 400 } 401 } 402 403 bool FindLockAliasedRegister(uint32_t src, 404 const RegisterLine::RegToLockDepthsMap& src_map, 405 const RegisterLine::RegToLockDepthsMap& search_map) { 406 auto it = src_map.find(src); 407 if (it == src_map.end()) { 408 // "Not locked" is trivially aliased. 409 return true; 410 } 411 uint32_t src_lock_levels = it->second; 412 if (src_lock_levels == 0) { 413 // "Not locked" is trivially aliased. 414 return true; 415 } 416 417 // Scan the map for the same value. 418 for (const std::pair<const uint32_t, uint32_t>& pair : search_map) { 419 if (pair.first != src && pair.second == src_lock_levels) { 420 return true; 421 } 422 } 423 424 // Nothing found, no alias. 425 return false; 426 } 427 428 bool RegisterLine::MergeRegisters(MethodVerifier* verifier, const RegisterLine* incoming_line) { 429 bool changed = false; 430 DCHECK(incoming_line != nullptr); 431 for (size_t idx = 0; idx < num_regs_; idx++) { 432 if (line_[idx] != incoming_line->line_[idx]) { 433 const RegType& incoming_reg_type = incoming_line->GetRegisterType(verifier, idx); 434 const RegType& cur_type = GetRegisterType(verifier, idx); 435 const RegType& new_type = cur_type.Merge( 436 incoming_reg_type, verifier->GetRegTypeCache(), verifier); 437 changed = changed || !cur_type.Equals(new_type); 438 line_[idx] = new_type.GetId(); 439 } 440 } 441 if (monitors_.size() > 0 || incoming_line->monitors_.size() > 0) { 442 if (monitors_.size() != incoming_line->monitors_.size()) { 443 verifier->Fail(VERIFY_ERROR_LOCKING); 444 if (kDumpLockFailures) { 445 VLOG(verifier) << "mismatched stack depths (depth=" << MonitorStackDepth() 446 << ", incoming depth=" << incoming_line->MonitorStackDepth() << ") in " 447 << verifier->GetMethodReference().PrettyMethod(); 448 } 449 } else if (reg_to_lock_depths_ != incoming_line->reg_to_lock_depths_) { 450 for (uint32_t idx = 0; idx < num_regs_; idx++) { 451 size_t depths = reg_to_lock_depths_.count(idx); 452 size_t incoming_depths = incoming_line->reg_to_lock_depths_.count(idx); 453 if (depths != incoming_depths) { 454 // Stack levels aren't matching. This is potentially bad, as we don't do a 455 // flow-sensitive analysis. 456 // However, this could be an alias of something locked in one path, and the alias was 457 // destroyed in another path. It is fine to drop this as long as there's another alias 458 // for the lock around. The last vanishing alias will then report that things would be 459 // left unlocked. We need to check for aliases for both lock levels. 460 // 461 // Example (lock status in curly braces as pair of register and lock leels): 462 // 463 // lock v1 {v1=1} 464 // | | 465 // v0 = v1 {v0=1, v1=1} v0 = v2 {v1=1} 466 // | | 467 // {v1=1} 468 // // Dropping v0, as the status can't be merged 469 // // but the lock info ("locked at depth 1" and) 470 // // "not locked at all") is available. 471 if (!FindLockAliasedRegister(idx, 472 reg_to_lock_depths_, 473 reg_to_lock_depths_) || 474 !FindLockAliasedRegister(idx, 475 incoming_line->reg_to_lock_depths_, 476 reg_to_lock_depths_)) { 477 verifier->Fail(VERIFY_ERROR_LOCKING); 478 if (kDumpLockFailures) { 479 VLOG(verifier) << "mismatched stack depths for register v" << idx 480 << ": " << depths << " != " << incoming_depths << " in " 481 << verifier->GetMethodReference().PrettyMethod(); 482 } 483 break; 484 } 485 // We found aliases, set this to zero. 486 reg_to_lock_depths_.erase(idx); 487 } else if (depths > 0) { 488 // Check whether they're actually the same levels. 489 uint32_t locked_levels = reg_to_lock_depths_.find(idx)->second; 490 uint32_t incoming_locked_levels = incoming_line->reg_to_lock_depths_.find(idx)->second; 491 if (locked_levels != incoming_locked_levels) { 492 // Lock levels aren't matching. This is potentially bad, as we don't do a 493 // flow-sensitive analysis. 494 // However, this could be an alias of something locked in one path, and the alias was 495 // destroyed in another path. It is fine to drop this as long as there's another alias 496 // for the lock around. The last vanishing alias will then report that things would be 497 // left unlocked. We need to check for aliases for both lock levels. 498 // 499 // Example (lock status in curly braces as pair of register and lock leels): 500 // 501 // lock v1 {v1=1} 502 // lock v2 {v1=1, v2=2} 503 // | | 504 // v0 = v1 {v0=1, v1=1, v2=2} v0 = v2 {v0=2, v1=1, v2=2} 505 // | | 506 // {v1=1, v2=2} 507 // // Dropping v0, as the status can't be 508 // // merged but the lock info ("locked at 509 // // depth 1" and "locked at depth 2") is 510 // // available. 511 if (!FindLockAliasedRegister(idx, 512 reg_to_lock_depths_, 513 reg_to_lock_depths_) || 514 !FindLockAliasedRegister(idx, 515 incoming_line->reg_to_lock_depths_, 516 reg_to_lock_depths_)) { 517 // No aliases for both current and incoming, we'll lose information. 518 verifier->Fail(VERIFY_ERROR_LOCKING); 519 if (kDumpLockFailures) { 520 VLOG(verifier) << "mismatched lock levels for register v" << idx << ": " 521 << std::hex << locked_levels << std::dec << " != " 522 << std::hex << incoming_locked_levels << std::dec << " in " 523 << verifier->GetMethodReference().PrettyMethod(); 524 } 525 break; 526 } 527 // We found aliases, set this to zero. 528 reg_to_lock_depths_.erase(idx); 529 } 530 } 531 } 532 } 533 } 534 535 // Check whether "this" was initialized in both paths. 536 if (this_initialized_ && !incoming_line->this_initialized_) { 537 this_initialized_ = false; 538 changed = true; 539 } 540 return changed; 541 } 542 543 } // namespace verifier 544 } // namespace art 545