207 lines
6.9 KiB
C++
207 lines
6.9 KiB
C++
/*
|
|
* 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_
|