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