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