| /* | 
 |  * Copyright (C) 2013 The Android Open Source Project | 
 |  * | 
 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 |  * you may not use this file except in compliance with the License. | 
 |  * You may obtain a copy of the License at | 
 |  * | 
 |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
 |  * | 
 |  * Unless required by applicable law or agreed to in writing, software | 
 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 |  * See the License for the specific language governing permissions and | 
 |  * limitations under the License. | 
 |  */ | 
 |  | 
 | #ifndef ART_RUNTIME_MAPPING_TABLE_H_ | 
 | #define ART_RUNTIME_MAPPING_TABLE_H_ | 
 |  | 
 | #include "base/logging.h" | 
 | #include "leb128.h" | 
 |  | 
 | namespace art { | 
 |  | 
 | // A utility for processing the raw uleb128 encoded mapping table created by the quick compiler. | 
 | class MappingTable { | 
 |  public: | 
 |   explicit MappingTable(const uint8_t* encoded_map) : encoded_table_(encoded_map) { | 
 |   } | 
 |  | 
 |   uint32_t TotalSize() const PURE { | 
 |     const uint8_t* table = encoded_table_; | 
 |     if (table == nullptr) { | 
 |       return 0; | 
 |     } else { | 
 |       return DecodeUnsignedLeb128(&table); | 
 |     } | 
 |   } | 
 |  | 
 |   uint32_t DexToPcSize() const PURE { | 
 |     const uint8_t* table = encoded_table_; | 
 |     if (table == nullptr) { | 
 |       return 0; | 
 |     } else { | 
 |       uint32_t total_size = DecodeUnsignedLeb128(&table); | 
 |       uint32_t pc_to_dex_size = DecodeUnsignedLeb128(&table); | 
 |       return total_size - pc_to_dex_size; | 
 |     } | 
 |   } | 
 |  | 
 |   const uint8_t* FirstDexToPcPtr() const { | 
 |     const uint8_t* table = encoded_table_; | 
 |     if (table != nullptr) { | 
 |       uint32_t total_size = DecodeUnsignedLeb128(&table); | 
 |       uint32_t pc_to_dex_size = DecodeUnsignedLeb128(&table); | 
 |       // We must have dex to pc entries or else the loop will go beyond the end of the table. | 
 |       DCHECK_GT(total_size, pc_to_dex_size); | 
 |       for (uint32_t i = 0; i < pc_to_dex_size; ++i) { | 
 |         DecodeUnsignedLeb128(&table);  // Move ptr past native PC delta. | 
 |         DecodeSignedLeb128(&table);  // Move ptr past dex PC delta. | 
 |       } | 
 |     } | 
 |     return table; | 
 |   } | 
 |  | 
 |   class DexToPcIterator { | 
 |    public: | 
 |     DexToPcIterator(const MappingTable* table, uint32_t element) : | 
 |         table_(table), element_(element), end_(table_->DexToPcSize()), encoded_table_ptr_(nullptr), | 
 |         native_pc_offset_(0), dex_pc_(0) { | 
 |       if (element == 0) {  // An iterator wanted from the start. | 
 |         if (end_ > 0) { | 
 |           encoded_table_ptr_ = table_->FirstDexToPcPtr(); | 
 |           native_pc_offset_ = DecodeUnsignedLeb128(&encoded_table_ptr_); | 
 |           // First delta is always positive. | 
 |           dex_pc_ = static_cast<uint32_t>(DecodeSignedLeb128(&encoded_table_ptr_)); | 
 |         } | 
 |       } else {  // An iterator wanted from the end. | 
 |         DCHECK_EQ(table_->DexToPcSize(), element); | 
 |       } | 
 |     } | 
 |     uint32_t NativePcOffset() const { | 
 |       return native_pc_offset_; | 
 |     } | 
 |     uint32_t DexPc() const { | 
 |       return dex_pc_; | 
 |     } | 
 |     void operator++() { | 
 |       ++element_; | 
 |       if (element_ != end_) {  // Avoid reading beyond the end of the table. | 
 |         native_pc_offset_ += DecodeUnsignedLeb128(&encoded_table_ptr_); | 
 |         // For negative delta, unsigned overflow after static_cast does exactly what we need. | 
 |         dex_pc_ += static_cast<uint32_t>(DecodeSignedLeb128(&encoded_table_ptr_)); | 
 |       } | 
 |     } | 
 |     bool operator==(const DexToPcIterator& rhs) const { | 
 |       CHECK(table_ == rhs.table_); | 
 |       return element_ == rhs.element_; | 
 |     } | 
 |     bool operator!=(const DexToPcIterator& rhs) const { | 
 |       CHECK(table_ == rhs.table_); | 
 |       return element_ != rhs.element_; | 
 |     } | 
 |  | 
 |    private: | 
 |     const MappingTable* const table_;  // The original table. | 
 |     uint32_t element_;  // A value in the range 0 to end_. | 
 |     const uint32_t end_;  // Equal to table_->DexToPcSize(). | 
 |     const uint8_t* encoded_table_ptr_;  // Either nullptr or points to encoded data after this entry. | 
 |     uint32_t native_pc_offset_;  // The current value of native pc offset. | 
 |     uint32_t dex_pc_;  // The current value of dex pc. | 
 |   }; | 
 |  | 
 |   DexToPcIterator DexToPcBegin() const { | 
 |     return DexToPcIterator(this, 0); | 
 |   } | 
 |  | 
 |   DexToPcIterator DexToPcEnd() const { | 
 |     uint32_t size = DexToPcSize(); | 
 |     return DexToPcIterator(this, size); | 
 |   } | 
 |  | 
 |   uint32_t PcToDexSize() const PURE { | 
 |     const uint8_t* table = encoded_table_; | 
 |     if (table == nullptr) { | 
 |       return 0; | 
 |     } else { | 
 |       DecodeUnsignedLeb128(&table);  // Total_size, unused. | 
 |       uint32_t pc_to_dex_size = DecodeUnsignedLeb128(&table); | 
 |       return pc_to_dex_size; | 
 |     } | 
 |   } | 
 |  | 
 |   const uint8_t* FirstPcToDexPtr() const { | 
 |     const uint8_t* table = encoded_table_; | 
 |     if (table != nullptr) { | 
 |       DecodeUnsignedLeb128(&table);  // Total_size, unused. | 
 |       DecodeUnsignedLeb128(&table);  // PC to Dex size, unused. | 
 |     } | 
 |     return table; | 
 |   } | 
 |  | 
 |   class PcToDexIterator { | 
 |    public: | 
 |     PcToDexIterator(const MappingTable* table, uint32_t element) : | 
 |         table_(table), element_(element), end_(table_->PcToDexSize()), encoded_table_ptr_(nullptr), | 
 |         native_pc_offset_(0), dex_pc_(0) { | 
 |       if (element == 0) {  // An iterator wanted from the start. | 
 |         if (end_ > 0) { | 
 |           encoded_table_ptr_ = table_->FirstPcToDexPtr(); | 
 |           native_pc_offset_ = DecodeUnsignedLeb128(&encoded_table_ptr_); | 
 |           // First delta is always positive. | 
 |           dex_pc_ = static_cast<uint32_t>(DecodeSignedLeb128(&encoded_table_ptr_)); | 
 |         } | 
 |       } else {  // An iterator wanted from the end. | 
 |         DCHECK_EQ(table_->PcToDexSize(), element); | 
 |       } | 
 |     } | 
 |     uint32_t NativePcOffset() const { | 
 |       return native_pc_offset_; | 
 |     } | 
 |     uint32_t DexPc() const { | 
 |       return dex_pc_; | 
 |     } | 
 |     void operator++() { | 
 |       ++element_; | 
 |       if (element_ != end_) {  // Avoid reading beyond the end of the table. | 
 |         native_pc_offset_ += DecodeUnsignedLeb128(&encoded_table_ptr_); | 
 |         // For negative delta, unsigned overflow after static_cast does exactly what we need. | 
 |         dex_pc_ += static_cast<uint32_t>(DecodeSignedLeb128(&encoded_table_ptr_)); | 
 |       } | 
 |     } | 
 |     bool operator==(const PcToDexIterator& rhs) const { | 
 |       CHECK(table_ == rhs.table_); | 
 |       return element_ == rhs.element_; | 
 |     } | 
 |     bool operator!=(const PcToDexIterator& rhs) const { | 
 |       CHECK(table_ == rhs.table_); | 
 |       return element_ != rhs.element_; | 
 |     } | 
 |  | 
 |    private: | 
 |     const MappingTable* const table_;  // The original table. | 
 |     uint32_t element_;  // A value in the range 0 to PcToDexSize. | 
 |     const uint32_t end_;  // Equal to table_->PcToDexSize(). | 
 |     const uint8_t* encoded_table_ptr_;  // Either null or points to encoded data after this entry. | 
 |     uint32_t native_pc_offset_;  // The current value of native pc offset. | 
 |     uint32_t dex_pc_;  // The current value of dex pc. | 
 |   }; | 
 |  | 
 |   PcToDexIterator PcToDexBegin() const { | 
 |     return PcToDexIterator(this, 0); | 
 |   } | 
 |  | 
 |   PcToDexIterator PcToDexEnd() const { | 
 |     uint32_t size = PcToDexSize(); | 
 |     return PcToDexIterator(this, size); | 
 |   } | 
 |  | 
 |  private: | 
 |   const uint8_t* const encoded_table_; | 
 | }; | 
 |  | 
 | }  // namespace art | 
 |  | 
 | #endif  // ART_RUNTIME_MAPPING_TABLE_H_ |