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