| /* | |
| * 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_ |