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