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 "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 
     27 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 
     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 
     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 
     73 void RegisterLine::SetResultTypeToUnknown() {
     74   result_[0] = verifier_->GetRegTypeCache()->Undefined().GetId();
     75   result_[1] = result_[0];
     76 }
     77 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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  */
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    449 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 
    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 
    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   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