xref: /aosp_15_r20/art/runtime/verifier/register_line.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2012 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #include "register_line.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include "android-base/stringprintf.h"
20*795d594fSAndroid Build Coastguard Worker 
21*795d594fSAndroid Build Coastguard Worker #include "dex/dex_instruction-inl.h"
22*795d594fSAndroid Build Coastguard Worker #include "method_verifier-inl.h"
23*795d594fSAndroid Build Coastguard Worker #include "reg_type-inl.h"
24*795d594fSAndroid Build Coastguard Worker #include "register_line-inl.h"
25*795d594fSAndroid Build Coastguard Worker 
26*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
27*795d594fSAndroid Build Coastguard Worker namespace verifier {
28*795d594fSAndroid Build Coastguard Worker 
29*795d594fSAndroid Build Coastguard Worker using android::base::StringPrintf;
30*795d594fSAndroid Build Coastguard Worker 
CheckConstructorReturn(MethodVerifier * verifier) const31*795d594fSAndroid Build Coastguard Worker bool RegisterLine::CheckConstructorReturn(MethodVerifier* verifier) const {
32*795d594fSAndroid Build Coastguard Worker   if (kIsDebugBuild && this_initialized_) {
33*795d594fSAndroid Build Coastguard Worker     // Ensure that there is no UninitializedThisReference type anymore if this_initialized_ is true.
34*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0; i < num_regs_; i++) {
35*795d594fSAndroid Build Coastguard Worker       const RegType& type = GetRegisterType(verifier, i);
36*795d594fSAndroid Build Coastguard Worker       CHECK(!type.IsUninitializedThisReference() &&
37*795d594fSAndroid Build Coastguard Worker             !type.IsUnresolvedUninitializedThisReference())
38*795d594fSAndroid Build Coastguard Worker           << i << ": " << type.IsUninitializedThisReference() << " in "
39*795d594fSAndroid Build Coastguard Worker           << verifier->GetMethodReference().PrettyMethod();
40*795d594fSAndroid Build Coastguard Worker     }
41*795d594fSAndroid Build Coastguard Worker   }
42*795d594fSAndroid Build Coastguard Worker   if (!this_initialized_) {
43*795d594fSAndroid Build Coastguard Worker     verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD)
44*795d594fSAndroid Build Coastguard Worker         << "Constructor returning without calling superclass constructor";
45*795d594fSAndroid Build Coastguard Worker   }
46*795d594fSAndroid Build Coastguard Worker   return this_initialized_;
47*795d594fSAndroid Build Coastguard Worker }
48*795d594fSAndroid Build Coastguard Worker 
CopyFromLine(const RegisterLine * src)49*795d594fSAndroid Build Coastguard Worker void RegisterLine::CopyFromLine(const RegisterLine* src) {
50*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(num_regs_, src->num_regs_);
51*795d594fSAndroid Build Coastguard Worker   memcpy(&line_, &src->line_, num_regs_ * sizeof(uint16_t));
52*795d594fSAndroid Build Coastguard Worker   // Copy `allocation_dex_pcs_`. Note that if the `src` does not have `allocation_dex_pcs_`
53*795d594fSAndroid Build Coastguard Worker   // allocated, we retain the array allocated for this register line to avoid wasting
54*795d594fSAndroid Build Coastguard Worker   // memory by allocating a new array later. This means that the `allocation_dex_pcs_` can
55*795d594fSAndroid Build Coastguard Worker   // be filled with bogus values not tied to a `new-instance` uninitialized type.
56*795d594fSAndroid Build Coastguard Worker   if (src->allocation_dex_pcs_ != nullptr) {
57*795d594fSAndroid Build Coastguard Worker     EnsureAllocationDexPcsAvailable();
58*795d594fSAndroid Build Coastguard Worker     memcpy(allocation_dex_pcs_, src->allocation_dex_pcs_, num_regs_ * sizeof(uint32_t));
59*795d594fSAndroid Build Coastguard Worker   }
60*795d594fSAndroid Build Coastguard Worker   monitors_ = src->monitors_;
61*795d594fSAndroid Build Coastguard Worker   reg_to_lock_depths_ = src->reg_to_lock_depths_;
62*795d594fSAndroid Build Coastguard Worker   this_initialized_ = src->this_initialized_;
63*795d594fSAndroid Build Coastguard Worker }
64*795d594fSAndroid Build Coastguard Worker 
MarkRefsAsInitialized(MethodVerifier * verifier,uint32_t vsrc)65*795d594fSAndroid Build Coastguard Worker void RegisterLine::MarkRefsAsInitialized(MethodVerifier* verifier, uint32_t vsrc) {
66*795d594fSAndroid Build Coastguard Worker   const RegType& uninit_type = GetRegisterType(verifier, vsrc);
67*795d594fSAndroid Build Coastguard Worker   DCHECK(uninit_type.IsUninitializedTypes());
68*795d594fSAndroid Build Coastguard Worker   const RegType& init_type = verifier->GetRegTypeCache()->FromUninitialized(uninit_type);
69*795d594fSAndroid Build Coastguard Worker   size_t changed = 0;
70*795d594fSAndroid Build Coastguard Worker   // Is this initializing "this"?
71*795d594fSAndroid Build Coastguard Worker   if (uninit_type.IsUninitializedThisReference() ||
72*795d594fSAndroid Build Coastguard Worker       uninit_type.IsUnresolvedUninitializedThisReference()) {
73*795d594fSAndroid Build Coastguard Worker     this_initialized_ = true;
74*795d594fSAndroid Build Coastguard Worker     for (uint32_t i = 0; i < num_regs_; i++) {
75*795d594fSAndroid Build Coastguard Worker       if (GetRegisterType(verifier, i).Equals(uninit_type)) {
76*795d594fSAndroid Build Coastguard Worker         line_[i] = init_type.GetId();
77*795d594fSAndroid Build Coastguard Worker         changed++;
78*795d594fSAndroid Build Coastguard Worker       }
79*795d594fSAndroid Build Coastguard Worker     }
80*795d594fSAndroid Build Coastguard Worker   } else {
81*795d594fSAndroid Build Coastguard Worker     DCHECK(NeedsAllocationDexPc(uninit_type));
82*795d594fSAndroid Build Coastguard Worker     DCHECK(allocation_dex_pcs_ != nullptr);
83*795d594fSAndroid Build Coastguard Worker     uint32_t dex_pc = allocation_dex_pcs_[vsrc];
84*795d594fSAndroid Build Coastguard Worker     for (uint32_t i = 0; i < num_regs_; i++) {
85*795d594fSAndroid Build Coastguard Worker       if (GetRegisterType(verifier, i).Equals(uninit_type) && allocation_dex_pcs_[i] == dex_pc) {
86*795d594fSAndroid Build Coastguard Worker         line_[i] = init_type.GetId();
87*795d594fSAndroid Build Coastguard Worker         changed++;
88*795d594fSAndroid Build Coastguard Worker       }
89*795d594fSAndroid Build Coastguard Worker     }
90*795d594fSAndroid Build Coastguard Worker   }
91*795d594fSAndroid Build Coastguard Worker   DCHECK_GT(changed, 0u);
92*795d594fSAndroid Build Coastguard Worker }
93*795d594fSAndroid Build Coastguard Worker 
MarkAllRegistersAsConflicts(MethodVerifier * verifier)94*795d594fSAndroid Build Coastguard Worker void RegisterLine::MarkAllRegistersAsConflicts(MethodVerifier* verifier) {
95*795d594fSAndroid Build Coastguard Worker   uint16_t conflict_type_id = verifier->GetRegTypeCache()->Conflict().GetId();
96*795d594fSAndroid Build Coastguard Worker   for (uint32_t i = 0; i < num_regs_; i++) {
97*795d594fSAndroid Build Coastguard Worker     line_[i] = conflict_type_id;
98*795d594fSAndroid Build Coastguard Worker   }
99*795d594fSAndroid Build Coastguard Worker }
100*795d594fSAndroid Build Coastguard Worker 
MarkAllRegistersAsConflictsExcept(MethodVerifier * verifier,uint32_t vsrc)101*795d594fSAndroid Build Coastguard Worker void RegisterLine::MarkAllRegistersAsConflictsExcept(MethodVerifier* verifier, uint32_t vsrc) {
102*795d594fSAndroid Build Coastguard Worker   uint16_t conflict_type_id = verifier->GetRegTypeCache()->Conflict().GetId();
103*795d594fSAndroid Build Coastguard Worker   for (uint32_t i = 0; i < num_regs_; i++) {
104*795d594fSAndroid Build Coastguard Worker     if (i != vsrc) {
105*795d594fSAndroid Build Coastguard Worker       line_[i] = conflict_type_id;
106*795d594fSAndroid Build Coastguard Worker     }
107*795d594fSAndroid Build Coastguard Worker   }
108*795d594fSAndroid Build Coastguard Worker }
109*795d594fSAndroid Build Coastguard Worker 
MarkAllRegistersAsConflictsExceptWide(MethodVerifier * verifier,uint32_t vsrc)110*795d594fSAndroid Build Coastguard Worker void RegisterLine::MarkAllRegistersAsConflictsExceptWide(MethodVerifier* verifier, uint32_t vsrc) {
111*795d594fSAndroid Build Coastguard Worker   uint16_t conflict_type_id = verifier->GetRegTypeCache()->Conflict().GetId();
112*795d594fSAndroid Build Coastguard Worker   for (uint32_t i = 0; i < num_regs_; i++) {
113*795d594fSAndroid Build Coastguard Worker     if ((i != vsrc) && (i != (vsrc + 1))) {
114*795d594fSAndroid Build Coastguard Worker       line_[i] = conflict_type_id;
115*795d594fSAndroid Build Coastguard Worker     }
116*795d594fSAndroid Build Coastguard Worker   }
117*795d594fSAndroid Build Coastguard Worker }
118*795d594fSAndroid Build Coastguard Worker 
Dump(MethodVerifier * verifier) const119*795d594fSAndroid Build Coastguard Worker std::string RegisterLine::Dump(MethodVerifier* verifier) const {
120*795d594fSAndroid Build Coastguard Worker   std::string result;
121*795d594fSAndroid Build Coastguard Worker   for (size_t i = 0; i < num_regs_; i++) {
122*795d594fSAndroid Build Coastguard Worker     result += StringPrintf("%zd:[", i);
123*795d594fSAndroid Build Coastguard Worker     result += GetRegisterType(verifier, i).Dump();
124*795d594fSAndroid Build Coastguard Worker     result += "],";
125*795d594fSAndroid Build Coastguard Worker   }
126*795d594fSAndroid Build Coastguard Worker   for (const auto& monitor : monitors_) {
127*795d594fSAndroid Build Coastguard Worker     result += StringPrintf("{%d},", monitor);
128*795d594fSAndroid Build Coastguard Worker   }
129*795d594fSAndroid Build Coastguard Worker   for (auto& pairs : reg_to_lock_depths_) {
130*795d594fSAndroid Build Coastguard Worker     result += StringPrintf("<%d -> %" PRIx64 ">",
131*795d594fSAndroid Build Coastguard Worker                            pairs.first,
132*795d594fSAndroid Build Coastguard Worker                            static_cast<uint64_t>(pairs.second));
133*795d594fSAndroid Build Coastguard Worker   }
134*795d594fSAndroid Build Coastguard Worker   return result;
135*795d594fSAndroid Build Coastguard Worker }
136*795d594fSAndroid Build Coastguard Worker 
CopyResultRegister1(MethodVerifier * verifier,uint32_t vdst,bool is_reference)137*795d594fSAndroid Build Coastguard Worker void RegisterLine::CopyResultRegister1(MethodVerifier* verifier, uint32_t vdst, bool is_reference) {
138*795d594fSAndroid Build Coastguard Worker   const RegType& type = verifier->GetRegTypeCache()->GetFromId(result_[0]);
139*795d594fSAndroid Build Coastguard Worker   if ((!is_reference && !type.IsCategory1Types()) ||
140*795d594fSAndroid Build Coastguard Worker       (is_reference && !type.IsReferenceTypes())) {
141*795d594fSAndroid Build Coastguard Worker     verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD)
142*795d594fSAndroid Build Coastguard Worker         << "copyRes1 v" << vdst << "<- result0"  << " type=" << type;
143*795d594fSAndroid Build Coastguard Worker   } else {
144*795d594fSAndroid Build Coastguard Worker     DCHECK(verifier->GetRegTypeCache()->GetFromId(result_[1]).IsUndefined());
145*795d594fSAndroid Build Coastguard Worker     SetRegisterType<LockOp::kClear>(vdst, type);
146*795d594fSAndroid Build Coastguard Worker     result_[0] = verifier->GetRegTypeCache()->Undefined().GetId();
147*795d594fSAndroid Build Coastguard Worker   }
148*795d594fSAndroid Build Coastguard Worker }
149*795d594fSAndroid Build Coastguard Worker 
150*795d594fSAndroid Build Coastguard Worker /*
151*795d594fSAndroid Build Coastguard Worker  * Implement "move-result-wide". Copy the category-2 value from the result
152*795d594fSAndroid Build Coastguard Worker  * register to another register, and reset the result register.
153*795d594fSAndroid Build Coastguard Worker  */
CopyResultRegister2(MethodVerifier * verifier,uint32_t vdst)154*795d594fSAndroid Build Coastguard Worker void RegisterLine::CopyResultRegister2(MethodVerifier* verifier, uint32_t vdst) {
155*795d594fSAndroid Build Coastguard Worker   const RegType& type_l = verifier->GetRegTypeCache()->GetFromId(result_[0]);
156*795d594fSAndroid Build Coastguard Worker   const RegType& type_h = verifier->GetRegTypeCache()->GetFromId(result_[1]);
157*795d594fSAndroid Build Coastguard Worker   if (!type_l.IsCategory2Types()) {
158*795d594fSAndroid Build Coastguard Worker     verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD)
159*795d594fSAndroid Build Coastguard Worker         << "copyRes2 v" << vdst << "<- result0"  << " type=" << type_l;
160*795d594fSAndroid Build Coastguard Worker   } else {
161*795d594fSAndroid Build Coastguard Worker     DCHECK(type_l.CheckWidePair(type_h));  // Set should never allow this case
162*795d594fSAndroid Build Coastguard Worker     SetRegisterTypeWide(vdst, type_l, type_h);  // also sets the high
163*795d594fSAndroid Build Coastguard Worker     result_[0] = verifier->GetRegTypeCache()->Undefined().GetId();
164*795d594fSAndroid Build Coastguard Worker     result_[1] = verifier->GetRegTypeCache()->Undefined().GetId();
165*795d594fSAndroid Build Coastguard Worker   }
166*795d594fSAndroid Build Coastguard Worker }
167*795d594fSAndroid Build Coastguard Worker 
168*795d594fSAndroid Build Coastguard Worker static constexpr uint32_t kVirtualNullRegister = std::numeric_limits<uint32_t>::max();
169*795d594fSAndroid Build Coastguard Worker 
PushMonitor(MethodVerifier * verifier,uint32_t reg_idx,int32_t insn_idx)170*795d594fSAndroid Build Coastguard Worker void RegisterLine::PushMonitor(MethodVerifier* verifier, uint32_t reg_idx, int32_t insn_idx) {
171*795d594fSAndroid Build Coastguard Worker   const RegType& reg_type = GetRegisterType(verifier, reg_idx);
172*795d594fSAndroid Build Coastguard Worker   if (!reg_type.IsReferenceTypes()) {
173*795d594fSAndroid Build Coastguard Worker     verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "monitor-enter on non-object ("
174*795d594fSAndroid Build Coastguard Worker         << reg_type << ")";
175*795d594fSAndroid Build Coastguard Worker   } else if (monitors_.size() >= kMaxMonitorStackDepth) {
176*795d594fSAndroid Build Coastguard Worker     verifier->Fail(VERIFY_ERROR_LOCKING);
177*795d594fSAndroid Build Coastguard Worker     if (kDumpLockFailures) {
178*795d594fSAndroid Build Coastguard Worker       VLOG(verifier) << "monitor-enter stack overflow while verifying "
179*795d594fSAndroid Build Coastguard Worker                      << verifier->GetMethodReference().PrettyMethod();
180*795d594fSAndroid Build Coastguard Worker     }
181*795d594fSAndroid Build Coastguard Worker   } else {
182*795d594fSAndroid Build Coastguard Worker     if (SetRegToLockDepth(reg_idx, monitors_.size())) {
183*795d594fSAndroid Build Coastguard Worker       // Null literals can establish aliases that we can't easily track. As such, handle the zero
184*795d594fSAndroid Build Coastguard Worker       // case as the 2^32-1 register (which isn't available in dex bytecode).
185*795d594fSAndroid Build Coastguard Worker       if (reg_type.IsZero()) {
186*795d594fSAndroid Build Coastguard Worker         SetRegToLockDepth(kVirtualNullRegister, monitors_.size());
187*795d594fSAndroid Build Coastguard Worker       }
188*795d594fSAndroid Build Coastguard Worker 
189*795d594fSAndroid Build Coastguard Worker       monitors_.push_back(insn_idx);
190*795d594fSAndroid Build Coastguard Worker     } else {
191*795d594fSAndroid Build Coastguard Worker       verifier->Fail(VERIFY_ERROR_LOCKING);
192*795d594fSAndroid Build Coastguard Worker       if (kDumpLockFailures) {
193*795d594fSAndroid Build Coastguard Worker         VLOG(verifier) << "unexpected monitor-enter on register v" <<  reg_idx << " in "
194*795d594fSAndroid Build Coastguard Worker                        << verifier->GetMethodReference().PrettyMethod();
195*795d594fSAndroid Build Coastguard Worker       }
196*795d594fSAndroid Build Coastguard Worker     }
197*795d594fSAndroid Build Coastguard Worker   }
198*795d594fSAndroid Build Coastguard Worker }
199*795d594fSAndroid Build Coastguard Worker 
PopMonitor(MethodVerifier * verifier,uint32_t reg_idx)200*795d594fSAndroid Build Coastguard Worker void RegisterLine::PopMonitor(MethodVerifier* verifier, uint32_t reg_idx) {
201*795d594fSAndroid Build Coastguard Worker   const RegType& reg_type = GetRegisterType(verifier, reg_idx);
202*795d594fSAndroid Build Coastguard Worker   if (!reg_type.IsReferenceTypes()) {
203*795d594fSAndroid Build Coastguard Worker     verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "monitor-exit on non-object (" << reg_type << ")";
204*795d594fSAndroid Build Coastguard Worker   } else if (monitors_.empty()) {
205*795d594fSAndroid Build Coastguard Worker     verifier->Fail(VERIFY_ERROR_LOCKING);
206*795d594fSAndroid Build Coastguard Worker     if (kDumpLockFailures) {
207*795d594fSAndroid Build Coastguard Worker       VLOG(verifier) << "monitor-exit stack underflow while verifying "
208*795d594fSAndroid Build Coastguard Worker                      << verifier->GetMethodReference().PrettyMethod();
209*795d594fSAndroid Build Coastguard Worker     }
210*795d594fSAndroid Build Coastguard Worker   } else {
211*795d594fSAndroid Build Coastguard Worker     monitors_.pop_back();
212*795d594fSAndroid Build Coastguard Worker 
213*795d594fSAndroid Build Coastguard Worker     bool success = IsSetLockDepth(reg_idx, monitors_.size());
214*795d594fSAndroid Build Coastguard Worker 
215*795d594fSAndroid Build Coastguard Worker     if (!success && reg_type.IsZero()) {
216*795d594fSAndroid Build Coastguard Worker       // Null literals can establish aliases that we can't easily track. As such, handle the zero
217*795d594fSAndroid Build Coastguard Worker       // case as the 2^32-1 register (which isn't available in dex bytecode).
218*795d594fSAndroid Build Coastguard Worker       success = IsSetLockDepth(kVirtualNullRegister, monitors_.size());
219*795d594fSAndroid Build Coastguard Worker       if (success) {
220*795d594fSAndroid Build Coastguard Worker         reg_idx = kVirtualNullRegister;
221*795d594fSAndroid Build Coastguard Worker       }
222*795d594fSAndroid Build Coastguard Worker     }
223*795d594fSAndroid Build Coastguard Worker 
224*795d594fSAndroid Build Coastguard Worker     if (!success) {
225*795d594fSAndroid Build Coastguard Worker       verifier->Fail(VERIFY_ERROR_LOCKING);
226*795d594fSAndroid Build Coastguard Worker       if (kDumpLockFailures) {
227*795d594fSAndroid Build Coastguard Worker         VLOG(verifier) << "monitor-exit not unlocking the top of the monitor stack while verifying "
228*795d594fSAndroid Build Coastguard Worker                        << verifier->GetMethodReference().PrettyMethod();
229*795d594fSAndroid Build Coastguard Worker       }
230*795d594fSAndroid Build Coastguard Worker     } else {
231*795d594fSAndroid Build Coastguard Worker       // Record the register was unlocked. This clears all aliases, thus it will also clear the
232*795d594fSAndroid Build Coastguard Worker       // null lock, if necessary.
233*795d594fSAndroid Build Coastguard Worker       ClearRegToLockDepth(reg_idx, monitors_.size());
234*795d594fSAndroid Build Coastguard Worker     }
235*795d594fSAndroid Build Coastguard Worker   }
236*795d594fSAndroid Build Coastguard Worker }
237*795d594fSAndroid Build Coastguard Worker 
FindLockAliasedRegister(uint32_t src,const RegisterLine::RegToLockDepthsMap & src_map,const RegisterLine::RegToLockDepthsMap & search_map)238*795d594fSAndroid Build Coastguard Worker bool FindLockAliasedRegister(uint32_t src,
239*795d594fSAndroid Build Coastguard Worker                              const RegisterLine::RegToLockDepthsMap& src_map,
240*795d594fSAndroid Build Coastguard Worker                              const RegisterLine::RegToLockDepthsMap& search_map) {
241*795d594fSAndroid Build Coastguard Worker   auto it = src_map.find(src);
242*795d594fSAndroid Build Coastguard Worker   if (it == src_map.end()) {
243*795d594fSAndroid Build Coastguard Worker     // "Not locked" is trivially aliased.
244*795d594fSAndroid Build Coastguard Worker     return true;
245*795d594fSAndroid Build Coastguard Worker   }
246*795d594fSAndroid Build Coastguard Worker   uint32_t src_lock_levels = it->second;
247*795d594fSAndroid Build Coastguard Worker   if (src_lock_levels == 0) {
248*795d594fSAndroid Build Coastguard Worker     // "Not locked" is trivially aliased.
249*795d594fSAndroid Build Coastguard Worker     return true;
250*795d594fSAndroid Build Coastguard Worker   }
251*795d594fSAndroid Build Coastguard Worker 
252*795d594fSAndroid Build Coastguard Worker   // Scan the map for the same value.
253*795d594fSAndroid Build Coastguard Worker   for (const std::pair<const uint32_t, uint32_t>& pair : search_map) {
254*795d594fSAndroid Build Coastguard Worker     if (pair.first != src && pair.second == src_lock_levels) {
255*795d594fSAndroid Build Coastguard Worker       return true;
256*795d594fSAndroid Build Coastguard Worker     }
257*795d594fSAndroid Build Coastguard Worker   }
258*795d594fSAndroid Build Coastguard Worker 
259*795d594fSAndroid Build Coastguard Worker   // Nothing found, no alias.
260*795d594fSAndroid Build Coastguard Worker   return false;
261*795d594fSAndroid Build Coastguard Worker }
262*795d594fSAndroid Build Coastguard Worker 
MergeRegisters(MethodVerifier * verifier,const RegisterLine * incoming_line)263*795d594fSAndroid Build Coastguard Worker bool RegisterLine::MergeRegisters(MethodVerifier* verifier, const RegisterLine* incoming_line) {
264*795d594fSAndroid Build Coastguard Worker   bool changed = false;
265*795d594fSAndroid Build Coastguard Worker   DCHECK(incoming_line != nullptr);
266*795d594fSAndroid Build Coastguard Worker   for (size_t idx = 0; idx < num_regs_; idx++) {
267*795d594fSAndroid Build Coastguard Worker     if (line_[idx] != incoming_line->line_[idx]) {
268*795d594fSAndroid Build Coastguard Worker       const RegType& incoming_reg_type = incoming_line->GetRegisterType(verifier, idx);
269*795d594fSAndroid Build Coastguard Worker       const RegType& cur_type = GetRegisterType(verifier, idx);
270*795d594fSAndroid Build Coastguard Worker       const RegType& new_type = cur_type.Merge(
271*795d594fSAndroid Build Coastguard Worker           incoming_reg_type, verifier->GetRegTypeCache(), verifier);
272*795d594fSAndroid Build Coastguard Worker       changed = changed || !cur_type.Equals(new_type);
273*795d594fSAndroid Build Coastguard Worker       line_[idx] = new_type.GetId();
274*795d594fSAndroid Build Coastguard Worker     } else {
275*795d594fSAndroid Build Coastguard Worker       auto needs_allocation_dex_pc = [&]() {
276*795d594fSAndroid Build Coastguard Worker         return NeedsAllocationDexPc(verifier->GetRegTypeCache()->GetFromId(line_[idx]));
277*795d594fSAndroid Build Coastguard Worker       };
278*795d594fSAndroid Build Coastguard Worker       DCHECK_IMPLIES(needs_allocation_dex_pc(), allocation_dex_pcs_ != nullptr);
279*795d594fSAndroid Build Coastguard Worker       DCHECK_IMPLIES(needs_allocation_dex_pc(), incoming_line->allocation_dex_pcs_ != nullptr);
280*795d594fSAndroid Build Coastguard Worker       // Check for allocation dex pc mismatch first to try and avoid costly virtual calls.
281*795d594fSAndroid Build Coastguard Worker       // For methods without any `new-instance` instructions, the `allocation_dex_pcs_` is null.
282*795d594fSAndroid Build Coastguard Worker       if (allocation_dex_pcs_ != nullptr &&
283*795d594fSAndroid Build Coastguard Worker           incoming_line->allocation_dex_pcs_ != nullptr &&
284*795d594fSAndroid Build Coastguard Worker           allocation_dex_pcs_[idx] != incoming_line->allocation_dex_pcs_[idx] &&
285*795d594fSAndroid Build Coastguard Worker           needs_allocation_dex_pc()) {
286*795d594fSAndroid Build Coastguard Worker         line_[idx] = verifier->GetRegTypeCache()->Conflict().GetId();
287*795d594fSAndroid Build Coastguard Worker       }
288*795d594fSAndroid Build Coastguard Worker     }
289*795d594fSAndroid Build Coastguard Worker   }
290*795d594fSAndroid Build Coastguard Worker   if (monitors_.size() > 0 || incoming_line->monitors_.size() > 0) {
291*795d594fSAndroid Build Coastguard Worker     if (monitors_.size() != incoming_line->monitors_.size()) {
292*795d594fSAndroid Build Coastguard Worker       verifier->Fail(VERIFY_ERROR_LOCKING, /*pending_exc=*/ false);
293*795d594fSAndroid Build Coastguard Worker       if (kDumpLockFailures) {
294*795d594fSAndroid Build Coastguard Worker         VLOG(verifier) << "mismatched stack depths (depth=" << MonitorStackDepth()
295*795d594fSAndroid Build Coastguard Worker                        << ", incoming depth=" << incoming_line->MonitorStackDepth() << ") in "
296*795d594fSAndroid Build Coastguard Worker                        << verifier->GetMethodReference().PrettyMethod();
297*795d594fSAndroid Build Coastguard Worker       }
298*795d594fSAndroid Build Coastguard Worker     } else if (reg_to_lock_depths_ != incoming_line->reg_to_lock_depths_) {
299*795d594fSAndroid Build Coastguard Worker       for (uint32_t idx = 0; idx < num_regs_; idx++) {
300*795d594fSAndroid Build Coastguard Worker         size_t depths = reg_to_lock_depths_.count(idx);
301*795d594fSAndroid Build Coastguard Worker         size_t incoming_depths = incoming_line->reg_to_lock_depths_.count(idx);
302*795d594fSAndroid Build Coastguard Worker         if (depths != incoming_depths) {
303*795d594fSAndroid Build Coastguard Worker           // Stack levels aren't matching. This is potentially bad, as we don't do a
304*795d594fSAndroid Build Coastguard Worker           // flow-sensitive analysis.
305*795d594fSAndroid Build Coastguard Worker           // However, this could be an alias of something locked in one path, and the alias was
306*795d594fSAndroid Build Coastguard Worker           // destroyed in another path. It is fine to drop this as long as there's another alias
307*795d594fSAndroid Build Coastguard Worker           // for the lock around. The last vanishing alias will then report that things would be
308*795d594fSAndroid Build Coastguard Worker           // left unlocked. We need to check for aliases for both lock levels.
309*795d594fSAndroid Build Coastguard Worker           //
310*795d594fSAndroid Build Coastguard Worker           // Example (lock status in curly braces as pair of register and lock leels):
311*795d594fSAndroid Build Coastguard Worker           //
312*795d594fSAndroid Build Coastguard Worker           //                            lock v1 {v1=1}
313*795d594fSAndroid Build Coastguard Worker           //                        |                    |
314*795d594fSAndroid Build Coastguard Worker           //              v0 = v1 {v0=1, v1=1}       v0 = v2 {v1=1}
315*795d594fSAndroid Build Coastguard Worker           //                        |                    |
316*795d594fSAndroid Build Coastguard Worker           //                                 {v1=1}
317*795d594fSAndroid Build Coastguard Worker           //                                         // Dropping v0, as the status can't be merged
318*795d594fSAndroid Build Coastguard Worker           //                                         // but the lock info ("locked at depth 1" and)
319*795d594fSAndroid Build Coastguard Worker           //                                         // "not locked at all") is available.
320*795d594fSAndroid Build Coastguard Worker           if (!FindLockAliasedRegister(idx,
321*795d594fSAndroid Build Coastguard Worker                                        reg_to_lock_depths_,
322*795d594fSAndroid Build Coastguard Worker                                        reg_to_lock_depths_) ||
323*795d594fSAndroid Build Coastguard Worker               !FindLockAliasedRegister(idx,
324*795d594fSAndroid Build Coastguard Worker                                        incoming_line->reg_to_lock_depths_,
325*795d594fSAndroid Build Coastguard Worker                                        reg_to_lock_depths_)) {
326*795d594fSAndroid Build Coastguard Worker             verifier->Fail(VERIFY_ERROR_LOCKING, /*pending_exc=*/ false);
327*795d594fSAndroid Build Coastguard Worker             if (kDumpLockFailures) {
328*795d594fSAndroid Build Coastguard Worker               VLOG(verifier) << "mismatched stack depths for register v" << idx
329*795d594fSAndroid Build Coastguard Worker                              << ": " << depths  << " != " << incoming_depths << " in "
330*795d594fSAndroid Build Coastguard Worker                              << verifier->GetMethodReference().PrettyMethod();
331*795d594fSAndroid Build Coastguard Worker             }
332*795d594fSAndroid Build Coastguard Worker             break;
333*795d594fSAndroid Build Coastguard Worker           }
334*795d594fSAndroid Build Coastguard Worker           // We found aliases, set this to zero.
335*795d594fSAndroid Build Coastguard Worker           reg_to_lock_depths_.erase(idx);
336*795d594fSAndroid Build Coastguard Worker         } else if (depths > 0) {
337*795d594fSAndroid Build Coastguard Worker           // Check whether they're actually the same levels.
338*795d594fSAndroid Build Coastguard Worker           uint32_t locked_levels = reg_to_lock_depths_.find(idx)->second;
339*795d594fSAndroid Build Coastguard Worker           uint32_t incoming_locked_levels = incoming_line->reg_to_lock_depths_.find(idx)->second;
340*795d594fSAndroid Build Coastguard Worker           if (locked_levels != incoming_locked_levels) {
341*795d594fSAndroid Build Coastguard Worker             // Lock levels aren't matching. This is potentially bad, as we don't do a
342*795d594fSAndroid Build Coastguard Worker             // flow-sensitive analysis.
343*795d594fSAndroid Build Coastguard Worker             // However, this could be an alias of something locked in one path, and the alias was
344*795d594fSAndroid Build Coastguard Worker             // destroyed in another path. It is fine to drop this as long as there's another alias
345*795d594fSAndroid Build Coastguard Worker             // for the lock around. The last vanishing alias will then report that things would be
346*795d594fSAndroid Build Coastguard Worker             // left unlocked. We need to check for aliases for both lock levels.
347*795d594fSAndroid Build Coastguard Worker             //
348*795d594fSAndroid Build Coastguard Worker             // Example (lock status in curly braces as pair of register and lock leels):
349*795d594fSAndroid Build Coastguard Worker             //
350*795d594fSAndroid Build Coastguard Worker             //                          lock v1 {v1=1}
351*795d594fSAndroid Build Coastguard Worker             //                          lock v2 {v1=1, v2=2}
352*795d594fSAndroid Build Coastguard Worker             //                        |                      |
353*795d594fSAndroid Build Coastguard Worker             //         v0 = v1 {v0=1, v1=1, v2=2}  v0 = v2 {v0=2, v1=1, v2=2}
354*795d594fSAndroid Build Coastguard Worker             //                        |                      |
355*795d594fSAndroid Build Coastguard Worker             //                             {v1=1, v2=2}
356*795d594fSAndroid Build Coastguard Worker             //                                           // Dropping v0, as the status can't be
357*795d594fSAndroid Build Coastguard Worker             //                                           // merged but the lock info ("locked at
358*795d594fSAndroid Build Coastguard Worker             //                                           // depth 1" and "locked at depth 2") is
359*795d594fSAndroid Build Coastguard Worker             //                                           // available.
360*795d594fSAndroid Build Coastguard Worker             if (!FindLockAliasedRegister(idx,
361*795d594fSAndroid Build Coastguard Worker                                          reg_to_lock_depths_,
362*795d594fSAndroid Build Coastguard Worker                                          reg_to_lock_depths_) ||
363*795d594fSAndroid Build Coastguard Worker                 !FindLockAliasedRegister(idx,
364*795d594fSAndroid Build Coastguard Worker                                          incoming_line->reg_to_lock_depths_,
365*795d594fSAndroid Build Coastguard Worker                                          reg_to_lock_depths_)) {
366*795d594fSAndroid Build Coastguard Worker               // No aliases for both current and incoming, we'll lose information.
367*795d594fSAndroid Build Coastguard Worker               verifier->Fail(VERIFY_ERROR_LOCKING, /*pending_exc=*/ false);
368*795d594fSAndroid Build Coastguard Worker               if (kDumpLockFailures) {
369*795d594fSAndroid Build Coastguard Worker                 VLOG(verifier) << "mismatched lock levels for register v" << idx << ": "
370*795d594fSAndroid Build Coastguard Worker                                << std::hex << locked_levels << std::dec  << " != "
371*795d594fSAndroid Build Coastguard Worker                                << std::hex << incoming_locked_levels << std::dec << " in "
372*795d594fSAndroid Build Coastguard Worker                                << verifier->GetMethodReference().PrettyMethod();
373*795d594fSAndroid Build Coastguard Worker               }
374*795d594fSAndroid Build Coastguard Worker               break;
375*795d594fSAndroid Build Coastguard Worker             }
376*795d594fSAndroid Build Coastguard Worker             // We found aliases, set this to zero.
377*795d594fSAndroid Build Coastguard Worker             reg_to_lock_depths_.erase(idx);
378*795d594fSAndroid Build Coastguard Worker           }
379*795d594fSAndroid Build Coastguard Worker         }
380*795d594fSAndroid Build Coastguard Worker       }
381*795d594fSAndroid Build Coastguard Worker     }
382*795d594fSAndroid Build Coastguard Worker   }
383*795d594fSAndroid Build Coastguard Worker 
384*795d594fSAndroid Build Coastguard Worker   // Check whether "this" was initialized in both paths.
385*795d594fSAndroid Build Coastguard Worker   if (this_initialized_ && !incoming_line->this_initialized_) {
386*795d594fSAndroid Build Coastguard Worker     this_initialized_ = false;
387*795d594fSAndroid Build Coastguard Worker     changed = true;
388*795d594fSAndroid Build Coastguard Worker   }
389*795d594fSAndroid Build Coastguard Worker   return changed;
390*795d594fSAndroid Build Coastguard Worker }
391*795d594fSAndroid Build Coastguard Worker 
392*795d594fSAndroid Build Coastguard Worker }  // namespace verifier
393*795d594fSAndroid Build Coastguard Worker }  // namespace art
394