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.h"
22 #include "register_line-inl.h"
23 
24 namespace art {
25 namespace verifier {
26 
CheckConstructorReturn() const27 bool RegisterLine::CheckConstructorReturn() const {
28   for (size_t i = 0; i < num_regs_; i++) {
29     if (GetRegisterType(i).IsUninitializedThisReference() ||
30         GetRegisterType(i).IsUnresolvedAndUninitializedThisReference()) {
31       verifier_->Fail(VERIFY_ERROR_BAD_CLASS_SOFT)
32           << "Constructor returning without calling superclass constructor";
33       return false;
34     }
35   }
36   return true;
37 }
38 
SetRegisterType(uint32_t vdst,RegType & new_type)39 bool RegisterLine::SetRegisterType(uint32_t vdst, RegType& new_type) {
40   DCHECK_LT(vdst, num_regs_);
41   if (new_type.IsLowHalf() || new_type.IsHighHalf()) {
42     verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Expected category1 register type not '"
43         << new_type << "'";
44     return false;
45   } else if (new_type.IsConflict()) {  // should only be set during a merge
46     verifier_->Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "Set register to unknown type " << new_type;
47     return false;
48   } else {
49     line_[vdst] = new_type.GetId();
50   }
51   // Clear the monitor entry bits for this register.
52   ClearAllRegToLockDepths(vdst);
53   return true;
54 }
55 
SetRegisterTypeWide(uint32_t vdst,RegType & new_type1,RegType & new_type2)56 bool RegisterLine::SetRegisterTypeWide(uint32_t vdst, RegType& new_type1,
57                                        RegType& new_type2) {
58   DCHECK_LT(vdst + 1, num_regs_);
59   if (!new_type1.CheckWidePair(new_type2)) {
60     verifier_->Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "Invalid wide pair '"
61         << new_type1 << "' '" << new_type2 << "'";
62     return false;
63   } else {
64     line_[vdst] = new_type1.GetId();
65     line_[vdst + 1] = new_type2.GetId();
66   }
67   // Clear the monitor entry bits for this register.
68   ClearAllRegToLockDepths(vdst);
69   ClearAllRegToLockDepths(vdst + 1);
70   return true;
71 }
72 
SetResultTypeToUnknown()73 void RegisterLine::SetResultTypeToUnknown() {
74   result_[0] = verifier_->GetRegTypeCache()->Undefined().GetId();
75   result_[1] = result_[0];
76 }
77 
SetResultRegisterType(RegType & new_type)78 void RegisterLine::SetResultRegisterType(RegType& new_type) {
79   DCHECK(!new_type.IsLowHalf());
80   DCHECK(!new_type.IsHighHalf());
81   result_[0] = new_type.GetId();
82   result_[1] = verifier_->GetRegTypeCache()->Undefined().GetId();
83 }
84 
SetResultRegisterTypeWide(RegType & new_type1,RegType & new_type2)85 void RegisterLine::SetResultRegisterTypeWide(RegType& new_type1,
86                                              RegType& new_type2) {
87   DCHECK(new_type1.CheckWidePair(new_type2));
88   result_[0] = new_type1.GetId();
89   result_[1] = new_type2.GetId();
90 }
91 
GetInvocationThis(const Instruction * inst,bool is_range)92 RegType& RegisterLine::GetInvocationThis(const Instruction* inst, bool is_range) {
93   const size_t args_count = is_range ? inst->VRegA_3rc() : inst->VRegA_35c();
94   if (args_count < 1) {
95     verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invoke lacks 'this'";
96     return verifier_->GetRegTypeCache()->Conflict();
97   }
98   /* Get the element type of the array held in vsrc */
99   const uint32_t this_reg = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c();
100   RegType& this_type = GetRegisterType(this_reg);
101   if (!this_type.IsReferenceTypes()) {
102     verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "tried to get class from non-reference register v"
103                                                  << this_reg << " (type=" << this_type << ")";
104     return verifier_->GetRegTypeCache()->Conflict();
105   }
106   return this_type;
107 }
108 
VerifyRegisterType(uint32_t vsrc,RegType & check_type)109 bool RegisterLine::VerifyRegisterType(uint32_t vsrc,
110                                       RegType& check_type) {
111   // Verify the src register type against the check type refining the type of the register
112   RegType& src_type = GetRegisterType(vsrc);
113   if (!(check_type.IsAssignableFrom(src_type))) {
114     enum VerifyError fail_type;
115     if (!check_type.IsNonZeroReferenceTypes() || !src_type.IsNonZeroReferenceTypes()) {
116       // Hard fail if one of the types is primitive, since they are concretely known.
117       fail_type = VERIFY_ERROR_BAD_CLASS_HARD;
118     } else if (check_type.IsUnresolvedTypes() || src_type.IsUnresolvedTypes()) {
119       fail_type = VERIFY_ERROR_NO_CLASS;
120     } else {
121       fail_type = VERIFY_ERROR_BAD_CLASS_SOFT;
122     }
123     verifier_->Fail(fail_type) << "register v" << vsrc << " has type "
124                                << src_type << " but expected " << check_type;
125     return false;
126   }
127   if (check_type.IsLowHalf()) {
128     RegType& src_type_h = GetRegisterType(vsrc + 1);
129     if (!src_type.CheckWidePair(src_type_h)) {
130       verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "wide register v" << vsrc << " has type "
131                                                    << src_type << "/" << src_type_h;
132       return false;
133     }
134   }
135   // The register at vsrc has a defined type, we know the lower-upper-bound, but this is less
136   // precise than the subtype in vsrc so leave it for reference types. For primitive types
137   // if they are a defined type then they are as precise as we can get, however, for constant
138   // types we may wish to refine them. Unfortunately constant propagation has rendered this useless.
139   return true;
140 }
141 
VerifyRegisterTypeWide(uint32_t vsrc,RegType & check_type1,RegType & check_type2)142 bool RegisterLine::VerifyRegisterTypeWide(uint32_t vsrc, RegType& check_type1,
143                                           RegType& check_type2) {
144   DCHECK(check_type1.CheckWidePair(check_type2));
145   // Verify the src register type against the check type refining the type of the register
146   RegType& src_type = GetRegisterType(vsrc);
147   if (!check_type1.IsAssignableFrom(src_type)) {
148     verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "register v" << vsrc << " has type " << src_type
149                                << " but expected " << check_type1;
150     return false;
151   }
152   RegType& src_type_h = GetRegisterType(vsrc + 1);
153   if (!src_type.CheckWidePair(src_type_h)) {
154     verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "wide register v" << vsrc << " has type "
155         << src_type << "/" << src_type_h;
156     return false;
157   }
158   // The register at vsrc has a defined type, we know the lower-upper-bound, but this is less
159   // precise than the subtype in vsrc so leave it for reference types. For primitive types
160   // if they are a defined type then they are as precise as we can get, however, for constant
161   // types we may wish to refine them. Unfortunately constant propagation has rendered this useless.
162   return true;
163 }
164 
MarkRefsAsInitialized(RegType & uninit_type)165 void RegisterLine::MarkRefsAsInitialized(RegType& uninit_type) {
166   DCHECK(uninit_type.IsUninitializedTypes());
167   RegType& init_type = verifier_->GetRegTypeCache()->FromUninitialized(uninit_type);
168   size_t changed = 0;
169   for (uint32_t i = 0; i < num_regs_; i++) {
170     if (GetRegisterType(i).Equals(uninit_type)) {
171       line_[i] = init_type.GetId();
172       changed++;
173     }
174   }
175   DCHECK_GT(changed, 0u);
176 }
177 
MarkAllRegistersAsConflicts()178 void RegisterLine::MarkAllRegistersAsConflicts() {
179   uint16_t conflict_type_id = verifier_->GetRegTypeCache()->Conflict().GetId();
180   for (uint32_t i = 0; i < num_regs_; i++) {
181     line_[i] = conflict_type_id;
182   }
183 }
184 
MarkAllRegistersAsConflictsExcept(uint32_t vsrc)185 void RegisterLine::MarkAllRegistersAsConflictsExcept(uint32_t vsrc) {
186   uint16_t conflict_type_id = verifier_->GetRegTypeCache()->Conflict().GetId();
187   for (uint32_t i = 0; i < num_regs_; i++) {
188     if (i != vsrc) {
189       line_[i] = conflict_type_id;
190     }
191   }
192 }
193 
MarkAllRegistersAsConflictsExceptWide(uint32_t vsrc)194 void RegisterLine::MarkAllRegistersAsConflictsExceptWide(uint32_t vsrc) {
195   uint16_t conflict_type_id = verifier_->GetRegTypeCache()->Conflict().GetId();
196   for (uint32_t i = 0; i < num_regs_; i++) {
197     if ((i != vsrc) && (i != (vsrc + 1))) {
198       line_[i] = conflict_type_id;
199     }
200   }
201 }
202 
Dump()203 std::string RegisterLine::Dump() {
204   std::string result;
205   for (size_t i = 0; i < num_regs_; i++) {
206     result += StringPrintf("%zd:[", i);
207     result += GetRegisterType(i).Dump();
208     result += "],";
209   }
210   for (const auto& monitor : monitors_) {
211     result += StringPrintf("{%d},", monitor);
212   }
213   return result;
214 }
215 
MarkUninitRefsAsInvalid(RegType & uninit_type)216 void RegisterLine::MarkUninitRefsAsInvalid(RegType& uninit_type) {
217   for (size_t i = 0; i < num_regs_; i++) {
218     if (GetRegisterType(i).Equals(uninit_type)) {
219       line_[i] = verifier_->GetRegTypeCache()->Conflict().GetId();
220       ClearAllRegToLockDepths(i);
221     }
222   }
223 }
224 
CopyRegister1(uint32_t vdst,uint32_t vsrc,TypeCategory cat)225 void RegisterLine::CopyRegister1(uint32_t vdst, uint32_t vsrc, TypeCategory cat) {
226   DCHECK(cat == kTypeCategory1nr || cat == kTypeCategoryRef);
227   RegType& type = GetRegisterType(vsrc);
228   if (!SetRegisterType(vdst, type)) {
229     return;
230   }
231   if ((cat == kTypeCategory1nr && !type.IsCategory1Types()) ||
232       (cat == kTypeCategoryRef && !type.IsReferenceTypes())) {
233     verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "copy1 v" << vdst << "<-v" << vsrc << " type=" << type
234                                                  << " cat=" << static_cast<int>(cat);
235   } else if (cat == kTypeCategoryRef) {
236     CopyRegToLockDepth(vdst, vsrc);
237   }
238 }
239 
CopyRegister2(uint32_t vdst,uint32_t vsrc)240 void RegisterLine::CopyRegister2(uint32_t vdst, uint32_t vsrc) {
241   RegType& type_l = GetRegisterType(vsrc);
242   RegType& type_h = GetRegisterType(vsrc + 1);
243 
244   if (!type_l.CheckWidePair(type_h)) {
245     verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "copy2 v" << vdst << "<-v" << vsrc
246                                                  << " type=" << type_l << "/" << type_h;
247   } else {
248     SetRegisterTypeWide(vdst, type_l, type_h);
249   }
250 }
251 
CopyResultRegister1(uint32_t vdst,bool is_reference)252 void RegisterLine::CopyResultRegister1(uint32_t vdst, bool is_reference) {
253   RegType& type = verifier_->GetRegTypeCache()->GetFromId(result_[0]);
254   if ((!is_reference && !type.IsCategory1Types()) ||
255       (is_reference && !type.IsReferenceTypes())) {
256     verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD)
257         << "copyRes1 v" << vdst << "<- result0"  << " type=" << type;
258   } else {
259     DCHECK(verifier_->GetRegTypeCache()->GetFromId(result_[1]).IsUndefined());
260     SetRegisterType(vdst, type);
261     result_[0] = verifier_->GetRegTypeCache()->Undefined().GetId();
262   }
263 }
264 
265 /*
266  * Implement "move-result-wide". Copy the category-2 value from the result
267  * register to another register, and reset the result register.
268  */
CopyResultRegister2(uint32_t vdst)269 void RegisterLine::CopyResultRegister2(uint32_t vdst) {
270   RegType& type_l = verifier_->GetRegTypeCache()->GetFromId(result_[0]);
271   RegType& type_h = verifier_->GetRegTypeCache()->GetFromId(result_[1]);
272   if (!type_l.IsCategory2Types()) {
273     verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD)
274         << "copyRes2 v" << vdst << "<- result0"  << " type=" << type_l;
275   } else {
276     DCHECK(type_l.CheckWidePair(type_h));  // Set should never allow this case
277     SetRegisterTypeWide(vdst, type_l, type_h);  // also sets the high
278     result_[0] = verifier_->GetRegTypeCache()->Undefined().GetId();
279     result_[1] = verifier_->GetRegTypeCache()->Undefined().GetId();
280   }
281 }
282 
CheckUnaryOp(const Instruction * inst,RegType & dst_type,RegType & src_type)283 void RegisterLine::CheckUnaryOp(const Instruction* inst,
284                                 RegType& dst_type,
285                                 RegType& src_type) {
286   if (VerifyRegisterType(inst->VRegB_12x(), src_type)) {
287     SetRegisterType(inst->VRegA_12x(), dst_type);
288   }
289 }
290 
CheckUnaryOpWide(const Instruction * inst,RegType & dst_type1,RegType & dst_type2,RegType & src_type1,RegType & src_type2)291 void RegisterLine::CheckUnaryOpWide(const Instruction* inst,
292                                     RegType& dst_type1, RegType& dst_type2,
293                                     RegType& src_type1, RegType& src_type2) {
294   if (VerifyRegisterTypeWide(inst->VRegB_12x(), src_type1, src_type2)) {
295     SetRegisterTypeWide(inst->VRegA_12x(), dst_type1, dst_type2);
296   }
297 }
298 
CheckUnaryOpToWide(const Instruction * inst,RegType & dst_type1,RegType & dst_type2,RegType & src_type)299 void RegisterLine::CheckUnaryOpToWide(const Instruction* inst,
300                                       RegType& dst_type1, RegType& dst_type2,
301                                       RegType& src_type) {
302   if (VerifyRegisterType(inst->VRegB_12x(), src_type)) {
303     SetRegisterTypeWide(inst->VRegA_12x(), dst_type1, dst_type2);
304   }
305 }
306 
CheckUnaryOpFromWide(const Instruction * inst,RegType & dst_type,RegType & src_type1,RegType & src_type2)307 void RegisterLine::CheckUnaryOpFromWide(const Instruction* inst,
308                                         RegType& dst_type,
309                                         RegType& src_type1, RegType& src_type2) {
310   if (VerifyRegisterTypeWide(inst->VRegB_12x(), src_type1, src_type2)) {
311     SetRegisterType(inst->VRegA_12x(), dst_type);
312   }
313 }
314 
CheckBinaryOp(const Instruction * inst,RegType & dst_type,RegType & src_type1,RegType & src_type2,bool check_boolean_op)315 void RegisterLine::CheckBinaryOp(const Instruction* inst,
316                                  RegType& dst_type,
317                                  RegType& src_type1, RegType& src_type2,
318                                  bool check_boolean_op) {
319   const uint32_t vregB = inst->VRegB_23x();
320   const uint32_t vregC = inst->VRegC_23x();
321   if (VerifyRegisterType(vregB, src_type1) &&
322       VerifyRegisterType(vregC, src_type2)) {
323     if (check_boolean_op) {
324       DCHECK(dst_type.IsInteger());
325       if (GetRegisterType(vregB).IsBooleanTypes() &&
326           GetRegisterType(vregC).IsBooleanTypes()) {
327         SetRegisterType(inst->VRegA_23x(), verifier_->GetRegTypeCache()->Boolean());
328         return;
329       }
330     }
331     SetRegisterType(inst->VRegA_23x(), dst_type);
332   }
333 }
334 
CheckBinaryOpWide(const Instruction * inst,RegType & dst_type1,RegType & dst_type2,RegType & src_type1_1,RegType & src_type1_2,RegType & src_type2_1,RegType & src_type2_2)335 void RegisterLine::CheckBinaryOpWide(const Instruction* inst,
336                                      RegType& dst_type1, RegType& dst_type2,
337                                      RegType& src_type1_1, RegType& src_type1_2,
338                                      RegType& src_type2_1, RegType& src_type2_2) {
339   if (VerifyRegisterTypeWide(inst->VRegB_23x(), src_type1_1, src_type1_2) &&
340       VerifyRegisterTypeWide(inst->VRegC_23x(), src_type2_1, src_type2_2)) {
341     SetRegisterTypeWide(inst->VRegA_23x(), dst_type1, dst_type2);
342   }
343 }
344 
CheckBinaryOpWideShift(const Instruction * inst,RegType & long_lo_type,RegType & long_hi_type,RegType & int_type)345 void RegisterLine::CheckBinaryOpWideShift(const Instruction* inst,
346                                           RegType& long_lo_type, RegType& long_hi_type,
347                                           RegType& int_type) {
348   if (VerifyRegisterTypeWide(inst->VRegB_23x(), long_lo_type, long_hi_type) &&
349       VerifyRegisterType(inst->VRegC_23x(), int_type)) {
350     SetRegisterTypeWide(inst->VRegA_23x(), long_lo_type, long_hi_type);
351   }
352 }
353 
CheckBinaryOp2addr(const Instruction * inst,RegType & dst_type,RegType & src_type1,RegType & src_type2,bool check_boolean_op)354 void RegisterLine::CheckBinaryOp2addr(const Instruction* inst,
355                                       RegType& dst_type, RegType& src_type1,
356                                       RegType& src_type2, bool check_boolean_op) {
357   const uint32_t vregA = inst->VRegA_12x();
358   const uint32_t vregB = inst->VRegB_12x();
359   if (VerifyRegisterType(vregA, src_type1) &&
360       VerifyRegisterType(vregB, src_type2)) {
361     if (check_boolean_op) {
362       DCHECK(dst_type.IsInteger());
363       if (GetRegisterType(vregA).IsBooleanTypes() &&
364           GetRegisterType(vregB).IsBooleanTypes()) {
365         SetRegisterType(vregA, verifier_->GetRegTypeCache()->Boolean());
366         return;
367       }
368     }
369     SetRegisterType(vregA, dst_type);
370   }
371 }
372 
CheckBinaryOp2addrWide(const Instruction * inst,RegType & dst_type1,RegType & dst_type2,RegType & src_type1_1,RegType & src_type1_2,RegType & src_type2_1,RegType & src_type2_2)373 void RegisterLine::CheckBinaryOp2addrWide(const Instruction* inst,
374                                           RegType& dst_type1, RegType& dst_type2,
375                                           RegType& src_type1_1, RegType& src_type1_2,
376                                           RegType& src_type2_1, RegType& src_type2_2) {
377   const uint32_t vregA = inst->VRegA_12x();
378   const uint32_t vregB = inst->VRegB_12x();
379   if (VerifyRegisterTypeWide(vregA, src_type1_1, src_type1_2) &&
380       VerifyRegisterTypeWide(vregB, src_type2_1, src_type2_2)) {
381     SetRegisterTypeWide(vregA, dst_type1, dst_type2);
382   }
383 }
384 
CheckBinaryOp2addrWideShift(const Instruction * inst,RegType & long_lo_type,RegType & long_hi_type,RegType & int_type)385 void RegisterLine::CheckBinaryOp2addrWideShift(const Instruction* inst,
386                                                RegType& long_lo_type, RegType& long_hi_type,
387                                                RegType& int_type) {
388   const uint32_t vregA = inst->VRegA_12x();
389   const uint32_t vregB = inst->VRegB_12x();
390   if (VerifyRegisterTypeWide(vregA, long_lo_type, long_hi_type) &&
391       VerifyRegisterType(vregB, int_type)) {
392     SetRegisterTypeWide(vregA, long_lo_type, long_hi_type);
393   }
394 }
395 
CheckLiteralOp(const Instruction * inst,RegType & dst_type,RegType & src_type,bool check_boolean_op,bool is_lit16)396 void RegisterLine::CheckLiteralOp(const Instruction* inst,
397                                   RegType& dst_type, RegType& src_type,
398                                   bool check_boolean_op, bool is_lit16) {
399   const uint32_t vregA = is_lit16 ? inst->VRegA_22s() : inst->VRegA_22b();
400   const uint32_t vregB = is_lit16 ? inst->VRegB_22s() : inst->VRegB_22b();
401   if (VerifyRegisterType(vregB, src_type)) {
402     if (check_boolean_op) {
403       DCHECK(dst_type.IsInteger());
404       /* check vB with the call, then check the constant manually */
405       const uint32_t val = is_lit16 ? inst->VRegC_22s() : inst->VRegC_22b();
406       if (GetRegisterType(vregB).IsBooleanTypes() && (val == 0 || val == 1)) {
407         SetRegisterType(vregA, verifier_->GetRegTypeCache()->Boolean());
408         return;
409       }
410     }
411     SetRegisterType(vregA, dst_type);
412   }
413 }
414 
PushMonitor(uint32_t reg_idx,int32_t insn_idx)415 void RegisterLine::PushMonitor(uint32_t reg_idx, int32_t insn_idx) {
416   RegType& reg_type = GetRegisterType(reg_idx);
417   if (!reg_type.IsReferenceTypes()) {
418     verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "monitor-enter on non-object (" << reg_type << ")";
419   } else if (monitors_.size() >= 32) {
420     verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "monitor-enter stack overflow: " << monitors_.size();
421   } else {
422     SetRegToLockDepth(reg_idx, monitors_.size());
423     monitors_.push_back(insn_idx);
424   }
425 }
426 
PopMonitor(uint32_t reg_idx)427 void RegisterLine::PopMonitor(uint32_t reg_idx) {
428   RegType& reg_type = GetRegisterType(reg_idx);
429   if (!reg_type.IsReferenceTypes()) {
430     verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "monitor-exit on non-object (" << reg_type << ")";
431   } else if (monitors_.empty()) {
432     verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "monitor-exit stack underflow";
433   } else {
434     monitors_.pop_back();
435     if (!IsSetLockDepth(reg_idx, monitors_.size())) {
436       // Bug 3215458: Locks and unlocks are on objects, if that object is a literal then before
437       // format "036" the constant collector may create unlocks on the same object but referenced
438       // via different registers.
439       ((verifier_->DexFileVersion() >= 36) ? verifier_->Fail(VERIFY_ERROR_BAD_CLASS_SOFT)
440                                            : verifier_->LogVerifyInfo())
441             << "monitor-exit not unlocking the top of the monitor stack";
442     } else {
443       // Record the register was unlocked
444       ClearRegToLockDepth(reg_idx, monitors_.size());
445     }
446   }
447 }
448 
VerifyMonitorStackEmpty() const449 bool RegisterLine::VerifyMonitorStackEmpty() const {
450   if (MonitorStackDepth() != 0) {
451     verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected empty monitor stack";
452     return false;
453   } else {
454     return true;
455   }
456 }
457 
MergeRegisters(const RegisterLine * incoming_line)458 bool RegisterLine::MergeRegisters(const RegisterLine* incoming_line) {
459   bool changed = false;
460   DCHECK(incoming_line != nullptr);
461   for (size_t idx = 0; idx < num_regs_; idx++) {
462     if (line_[idx] != incoming_line->line_[idx]) {
463       RegType& incoming_reg_type = incoming_line->GetRegisterType(idx);
464       RegType& cur_type = GetRegisterType(idx);
465       RegType& new_type = cur_type.Merge(incoming_reg_type, verifier_->GetRegTypeCache());
466       changed = changed || !cur_type.Equals(new_type);
467       line_[idx] = new_type.GetId();
468     }
469   }
470   if (monitors_.size() != incoming_line->monitors_.size()) {
471     LOG(WARNING) << "mismatched stack depths (depth=" << MonitorStackDepth()
472                  << ", incoming depth=" << incoming_line->MonitorStackDepth() << ")";
473   } else if (reg_to_lock_depths_ != incoming_line->reg_to_lock_depths_) {
474     for (uint32_t idx = 0; idx < num_regs_; idx++) {
475       size_t depths = reg_to_lock_depths_.count(idx);
476       size_t incoming_depths = incoming_line->reg_to_lock_depths_.count(idx);
477       if (depths != incoming_depths) {
478         if (depths == 0 || incoming_depths == 0) {
479           reg_to_lock_depths_.erase(idx);
480         } else {
481           LOG(WARNING) << "mismatched stack depths for register v" << idx
482                        << ": " << depths  << " != " << incoming_depths;
483           break;
484         }
485       }
486     }
487   }
488   return changed;
489 }
490 
WriteReferenceBitMap(std::vector<uint8_t> & data,size_t max_bytes)491 void RegisterLine::WriteReferenceBitMap(std::vector<uint8_t>& data, size_t max_bytes) {
492   for (size_t i = 0; i < num_regs_; i += 8) {
493     uint8_t val = 0;
494     for (size_t j = 0; j < 8 && (i + j) < num_regs_; j++) {
495       // Note: we write 1 for a Reference but not for Null
496       if (GetRegisterType(i + j).IsNonZeroReferenceTypes()) {
497         val |= 1 << j;
498       }
499     }
500     if ((i / 8) >= max_bytes) {
501       DCHECK_EQ(0, val);
502       continue;
503     }
504     DCHECK_LT(i / 8, max_bytes) << "val=" << static_cast<uint32_t>(val);
505     data.push_back(val);
506   }
507 }
508 
operator <<(std::ostream & os,const RegisterLine & rhs)509 std::ostream& operator<<(std::ostream& os, const RegisterLine& rhs)
510     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
511   RegisterLine& rhs_non_const = const_cast<RegisterLine&>(rhs);
512   os << rhs_non_const.Dump();
513   return os;
514 }
515 
516 }  // namespace verifier
517 }  // namespace art
518