| /* |
| * 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/leb128.h" |
| #include "base/logging.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 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. |
| }; |
| |
| 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_ |