summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dex2oat/linker/oat_writer.cc10
-rw-r--r--libdexfile/dex/type_lookup_table.cc201
-rw-r--r--libdexfile/dex/type_lookup_table.h211
-rw-r--r--libdexfile/dex/type_lookup_table_test.cc14
-rw-r--r--runtime/oat.h4
-rw-r--r--runtime/oat_file.cc8
-rw-r--r--runtime/oat_file.h8
7 files changed, 247 insertions, 209 deletions
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index 4046dc101f..99516684e8 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -4032,13 +4032,13 @@ bool OatWriter::WriteTypeLookupTables(
// TypeLookupTable allocates its own and OatDexFile takes ownership.
const DexFile& dex_file = *opened_dex_files[i];
{
- std::unique_ptr<TypeLookupTable> type_lookup_table =
- TypeLookupTable::Create(dex_file, /* storage */ nullptr);
+ TypeLookupTable type_lookup_table = TypeLookupTable::Create(dex_file);
type_lookup_table_oat_dex_files_.push_back(
std::make_unique<art::OatDexFile>(std::move(type_lookup_table)));
dex_file.SetOatDexFile(type_lookup_table_oat_dex_files_.back().get());
}
- TypeLookupTable* const table = type_lookup_table_oat_dex_files_.back()->GetTypeLookupTable();
+ const TypeLookupTable& table = type_lookup_table_oat_dex_files_.back()->GetTypeLookupTable();
+ DCHECK(table.Valid());
// Type tables are required to be 4 byte aligned.
size_t initial_offset = oat_size_;
@@ -4057,9 +4057,9 @@ bool OatWriter::WriteTypeLookupTables(
DCHECK_EQ(oat_data_offset_ + rodata_offset,
static_cast<size_t>(oat_rodata->Seek(0u, kSeekCurrent)));
- DCHECK_EQ(table_size, table->RawDataLength());
+ DCHECK_EQ(table_size, table.RawDataLength());
- if (!oat_rodata->WriteFully(table->RawData(), table_size)) {
+ if (!oat_rodata->WriteFully(table.RawData(), table_size)) {
PLOG(ERROR) << "Failed to write lookup table."
<< " File: " << oat_dex_file->GetLocation()
<< " Output: " << oat_rodata->GetLocation();
diff --git a/libdexfile/dex/type_lookup_table.cc b/libdexfile/dex/type_lookup_table.cc
index ca5ec2f798..00ec358b02 100644
--- a/libdexfile/dex/type_lookup_table.cc
+++ b/libdexfile/dex/type_lookup_table.cc
@@ -20,72 +20,43 @@
#include <memory>
#include "base/bit_utils.h"
+#include "base/leb128.h"
#include "dex/dex_file-inl.h"
#include "dex/utf-inl.h"
namespace art {
-static uint16_t MakeData(uint16_t class_def_idx, uint32_t hash, uint32_t mask) {
- uint16_t hash_mask = static_cast<uint16_t>(~mask);
- return (static_cast<uint16_t>(hash) & hash_mask) | class_def_idx;
+static inline bool ModifiedUtf8StringEquals(const char* lhs, const char* rhs) {
+ return CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(lhs, rhs) == 0;
}
-TypeLookupTable::~TypeLookupTable() {
- if (!owns_entries_) {
- // We don't actually own the entries, don't let the unique_ptr release them.
- entries_.release();
+TypeLookupTable TypeLookupTable::Create(const DexFile& dex_file) {
+ uint32_t num_class_defs = dex_file.NumClassDefs();
+ if (UNLIKELY(!SupportedSize(num_class_defs))) {
+ return TypeLookupTable();
}
-}
-
-uint32_t TypeLookupTable::RawDataLength(uint32_t num_class_defs) {
- return SupportedSize(num_class_defs) ? RoundUpToPowerOfTwo(num_class_defs) * sizeof(Entry) : 0u;
-}
-
-uint32_t TypeLookupTable::CalculateMask(uint32_t num_class_defs) {
- return SupportedSize(num_class_defs) ? RoundUpToPowerOfTwo(num_class_defs) - 1u : 0u;
-}
-
-bool TypeLookupTable::SupportedSize(uint32_t num_class_defs) {
- return num_class_defs != 0u && num_class_defs <= std::numeric_limits<uint16_t>::max();
-}
-
-std::unique_ptr<TypeLookupTable> TypeLookupTable::Create(const DexFile& dex_file,
- uint8_t* storage) {
- const uint32_t num_class_defs = dex_file.NumClassDefs();
- return std::unique_ptr<TypeLookupTable>(SupportedSize(num_class_defs)
- ? new TypeLookupTable(dex_file, storage)
- : nullptr);
-}
-
-std::unique_ptr<TypeLookupTable> TypeLookupTable::Open(const uint8_t* dex_file_pointer,
- const uint8_t* raw_data,
- uint32_t num_class_defs) {
- return std::unique_ptr<TypeLookupTable>(
- new TypeLookupTable(dex_file_pointer, raw_data, num_class_defs));
-}
+ size_t mask_bits = CalculateMaskBits(num_class_defs);
+ size_t size = 1u << mask_bits;
+ std::unique_ptr<Entry[]> owned_entries(new Entry[size]);
+ Entry* entries = owned_entries.get();
-TypeLookupTable::TypeLookupTable(const DexFile& dex_file, uint8_t* storage)
- : dex_data_begin_(dex_file.DataBegin()),
- raw_data_length_(RawDataLength(dex_file.NumClassDefs())),
- mask_(CalculateMask(dex_file.NumClassDefs())),
- entries_(storage != nullptr ? reinterpret_cast<Entry*>(storage) : new Entry[mask_ + 1]),
- owns_entries_(storage == nullptr) {
static_assert(alignof(Entry) == 4u, "Expecting Entry to be 4-byte aligned.");
- DCHECK_ALIGNED(storage, alignof(Entry));
+ const uint32_t mask = Entry::GetMask(mask_bits);
std::vector<uint16_t> conflict_class_defs;
// The first stage. Put elements on their initial positions. If an initial position is already
// occupied then delay the insertion of the element to the second stage to reduce probing
// distance.
- for (size_t i = 0; i < dex_file.NumClassDefs(); ++i) {
- const DexFile::ClassDef& class_def = dex_file.GetClassDef(i);
+ for (size_t class_def_idx = 0; class_def_idx < dex_file.NumClassDefs(); ++class_def_idx) {
+ const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_idx);
const DexFile::TypeId& type_id = dex_file.GetTypeId(class_def.class_idx_);
const DexFile::StringId& str_id = dex_file.GetStringId(type_id.descriptor_idx_);
const uint32_t hash = ComputeModifiedUtf8Hash(dex_file.GetStringData(str_id));
- Entry entry;
- entry.str_offset = str_id.string_data_off_;
- entry.data = MakeData(i, hash, GetSizeMask());
- if (!SetOnInitialPos(entry, hash)) {
- conflict_class_defs.push_back(i);
+ const uint32_t pos = hash & mask;
+ if (entries[pos].IsEmpty()) {
+ entries[pos] = Entry(str_id.string_data_off_, hash, class_def_idx, mask_bits);
+ DCHECK(entries[pos].IsLast(mask_bits));
+ } else {
+ conflict_class_defs.push_back(class_def_idx);
}
}
// The second stage. The initial position of these elements had a collision. Put these elements
@@ -95,51 +66,111 @@ TypeLookupTable::TypeLookupTable(const DexFile& dex_file, uint8_t* storage)
const DexFile::TypeId& type_id = dex_file.GetTypeId(class_def.class_idx_);
const DexFile::StringId& str_id = dex_file.GetStringId(type_id.descriptor_idx_);
const uint32_t hash = ComputeModifiedUtf8Hash(dex_file.GetStringData(str_id));
- Entry entry;
- entry.str_offset = str_id.string_data_off_;
- entry.data = MakeData(class_def_idx, hash, GetSizeMask());
- Insert(entry, hash);
+ // Find the last entry in the chain.
+ uint32_t tail_pos = hash & mask;
+ DCHECK(!entries[tail_pos].IsEmpty());
+ while (!entries[tail_pos].IsLast(mask_bits)) {
+ tail_pos = (tail_pos + entries[tail_pos].GetNextPosDelta(mask_bits)) & mask;
+ DCHECK(!entries[tail_pos].IsEmpty());
+ }
+ // Find an empty entry for insertion.
+ uint32_t insert_pos = tail_pos;
+ do {
+ insert_pos = (insert_pos + 1) & mask;
+ } while (!entries[insert_pos].IsEmpty());
+ // Insert and chain the new entry.
+ entries[insert_pos] = Entry(str_id.string_data_off_, hash, class_def_idx, mask_bits);
+ entries[tail_pos].SetNextPosDelta((insert_pos - tail_pos) & mask, mask_bits);
+ DCHECK(entries[insert_pos].IsLast(mask_bits));
+ DCHECK(!entries[tail_pos].IsLast(mask_bits));
}
-}
-TypeLookupTable::TypeLookupTable(const uint8_t* dex_file_pointer,
- const uint8_t* raw_data,
- uint32_t num_class_defs)
- : dex_data_begin_(dex_file_pointer),
- raw_data_length_(RawDataLength(num_class_defs)),
- mask_(CalculateMask(num_class_defs)),
- entries_(reinterpret_cast<Entry*>(const_cast<uint8_t*>(raw_data))),
- owns_entries_(false) {}
-
-bool TypeLookupTable::SetOnInitialPos(const Entry& entry, uint32_t hash) {
- const uint32_t pos = hash & GetSizeMask();
- if (!entries_[pos].IsEmpty()) {
- return false;
- }
- entries_[pos] = entry;
- entries_[pos].next_pos_delta = 0;
- return true;
+ return TypeLookupTable(dex_file.DataBegin(), mask_bits, entries, std::move(owned_entries));
}
-void TypeLookupTable::Insert(const Entry& entry, uint32_t hash) {
- uint32_t pos = FindLastEntryInBucket(hash & GetSizeMask());
- uint32_t next_pos = (pos + 1) & GetSizeMask();
- while (!entries_[next_pos].IsEmpty()) {
- next_pos = (next_pos + 1) & GetSizeMask();
- }
- const uint32_t delta = (next_pos >= pos) ? (next_pos - pos) : (next_pos + Size() - pos);
- entries_[pos].next_pos_delta = delta;
- entries_[next_pos] = entry;
- entries_[next_pos].next_pos_delta = 0;
+TypeLookupTable TypeLookupTable::Open(const uint8_t* dex_data_pointer,
+ const uint8_t* raw_data,
+ uint32_t num_class_defs) {
+ DCHECK_ALIGNED(raw_data, alignof(Entry));
+ const Entry* entries = reinterpret_cast<const Entry*>(raw_data);
+ size_t mask_bits = CalculateMaskBits(num_class_defs);
+ return TypeLookupTable(dex_data_pointer, mask_bits, entries, /* owned_entries */ nullptr);
}
-uint32_t TypeLookupTable::FindLastEntryInBucket(uint32_t pos) const {
+uint32_t TypeLookupTable::Lookup(const char* str, uint32_t hash) const {
+ uint32_t mask = Entry::GetMask(mask_bits_);
+ uint32_t pos = hash & mask;
+ // Thanks to special insertion algorithm, the element at position pos can be empty
+ // or start of the right bucket, or anywhere in the wrong bucket's chain.
const Entry* entry = &entries_[pos];
- while (!entry->IsLast()) {
- pos = (pos + entry->next_pos_delta) & GetSizeMask();
+ if (entry->IsEmpty()) {
+ return dex::kDexNoIndex;
+ }
+ // Look for the partial hash match first, even if traversing the wrong bucket's chain.
+ uint32_t compared_hash_bits = (hash << mask_bits_) >> (2 * mask_bits_);
+ while (compared_hash_bits != entry->GetHashBits(mask_bits_)) {
+ if (entry->IsLast(mask_bits_)) {
+ return dex::kDexNoIndex;
+ }
+ pos = (pos + entry->GetNextPosDelta(mask_bits_)) & mask;
entry = &entries_[pos];
+ DCHECK(!entry->IsEmpty());
+ }
+ // Found partial hash match, compare strings (expecting this to succeed).
+ const char* first_checked_str = GetStringData(*entry);
+ if (ModifiedUtf8StringEquals(str, first_checked_str)) {
+ return entry->GetClassDefIdx(mask_bits_);
+ }
+ // If we're at the end of the chain, return before doing further expensive work.
+ if (entry->IsLast(mask_bits_)) {
+ return dex::kDexNoIndex;
+ }
+ // Check if we're traversing the right bucket. This is important if the compared
+ // partial hash has only a few bits (i.e. it can match frequently).
+ if (((ComputeModifiedUtf8Hash(first_checked_str) ^ hash) & mask) != 0u) {
+ return dex::kDexNoIndex; // Low hash bits mismatch.
}
- return pos;
+ // Continue looking for the string in the rest of the chain.
+ do {
+ pos = (pos + entry->GetNextPosDelta(mask_bits_)) & mask;
+ entry = &entries_[pos];
+ DCHECK(!entry->IsEmpty());
+ if (compared_hash_bits == entry->GetHashBits(mask_bits_) &&
+ ModifiedUtf8StringEquals(str, GetStringData(*entry))) {
+ return entry->GetClassDefIdx(mask_bits_);
+ }
+ } while (!entry->IsLast(mask_bits_));
+ // Not found.
+ return dex::kDexNoIndex;
+}
+
+uint32_t TypeLookupTable::RawDataLength(uint32_t num_class_defs) {
+ return SupportedSize(num_class_defs) ? RoundUpToPowerOfTwo(num_class_defs) * sizeof(Entry) : 0u;
+}
+
+uint32_t TypeLookupTable::CalculateMaskBits(uint32_t num_class_defs) {
+ return SupportedSize(num_class_defs) ? MinimumBitsToStore(num_class_defs - 1u) : 0u;
+}
+
+bool TypeLookupTable::SupportedSize(uint32_t num_class_defs) {
+ return num_class_defs != 0u && num_class_defs <= std::numeric_limits<uint16_t>::max();
+}
+
+TypeLookupTable::TypeLookupTable(const uint8_t* dex_data_pointer,
+ uint32_t mask_bits,
+ const Entry* entries,
+ std::unique_ptr<Entry[]> owned_entries)
+ : dex_data_begin_(dex_data_pointer),
+ mask_bits_(mask_bits),
+ entries_(entries),
+ owned_entries_(std::move(owned_entries)) {}
+
+const char* TypeLookupTable::GetStringData(const Entry& entry) const {
+ DCHECK(dex_data_begin_ != nullptr);
+ const uint8_t* ptr = dex_data_begin_ + entry.GetStringOffset();
+ // Skip string length.
+ DecodeUnsignedLeb128(&ptr);
+ return reinterpret_cast<const char*>(ptr);
}
} // namespace art
diff --git a/libdexfile/dex/type_lookup_table.h b/libdexfile/dex/type_lookup_table.h
index 0ba2b75dc6..7005d34b88 100644
--- a/libdexfile/dex/type_lookup_table.h
+++ b/libdexfile/dex/type_lookup_table.h
@@ -17,9 +17,8 @@
#ifndef ART_LIBDEXFILE_DEX_TYPE_LOOKUP_TABLE_H_
#define ART_LIBDEXFILE_DEX_TYPE_LOOKUP_TABLE_H_
-#include "base/leb128.h"
+#include "base/logging.h"
#include "dex/dex_file_types.h"
-#include "dex/utf.h"
namespace art {
@@ -34,140 +33,146 @@ class DexFile;
*/
class TypeLookupTable {
public:
- ~TypeLookupTable();
+ // Method creates lookup table for dex file.
+ static TypeLookupTable Create(const DexFile& dex_file);
+
+ // Method opens lookup table from binary data. Lookups will traverse strings and other
+ // data contained in dex_file as well. Lookup table does not own raw_data or dex_file.
+ static TypeLookupTable Open(const uint8_t* dex_data_pointer,
+ const uint8_t* raw_data,
+ uint32_t num_class_defs);
+
+ // Create an invalid lookup table.
+ TypeLookupTable()
+ : dex_data_begin_(nullptr),
+ mask_bits_(0u),
+ entries_(nullptr),
+ owned_entries_(nullptr) {}
+
+ TypeLookupTable(TypeLookupTable&& src) noexcept = default;
+ TypeLookupTable& operator=(TypeLookupTable&& src) noexcept = default;
+
+ ~TypeLookupTable() {
+ // Implicit deallocation by std::unique_ptr<> destructor.
+ }
+
+ // Returns whether the TypeLookupTable is valid.
+ bool Valid() const {
+ return entries_ != nullptr;
+ }
// Return the number of buckets in the lookup table.
uint32_t Size() const {
- return mask_ + 1;
+ DCHECK(Valid());
+ return 1u << mask_bits_;
}
// Method search class_def_idx by class descriptor and it's hash.
// If no data found then the method returns dex::kDexNoIndex.
- uint32_t Lookup(const char* str, uint32_t hash) const {
- uint32_t pos = hash & GetSizeMask();
- // Thanks to special insertion algorithm, the element at position pos can be empty or start of
- // bucket.
- const Entry* entry = &entries_[pos];
- while (!entry->IsEmpty()) {
- if (CmpHashBits(entry->data, hash) && IsStringsEquals(str, entry->str_offset)) {
- return GetClassDefIdx(entry->data);
- }
- if (entry->IsLast()) {
- return dex::kDexNoIndex;
- }
- pos = (pos + entry->next_pos_delta) & GetSizeMask();
- entry = &entries_[pos];
- }
- return dex::kDexNoIndex;
- }
-
- // Method creates lookup table for dex file
- static std::unique_ptr<TypeLookupTable> Create(const DexFile& dex_file,
- uint8_t* storage = nullptr);
-
- // Method opens lookup table from binary data. Lookups will traverse strings and other
- // data contained in dex_file as well. Lookup table does not own raw_data or dex_file.
- static std::unique_ptr<TypeLookupTable> Open(const uint8_t* dex_file_pointer,
- const uint8_t* raw_data,
- uint32_t num_class_defs);
+ uint32_t Lookup(const char* str, uint32_t hash) const;
// Method returns pointer to binary data of lookup table. Used by the oat writer.
const uint8_t* RawData() const {
- return reinterpret_cast<const uint8_t*>(entries_.get());
+ DCHECK(Valid());
+ return reinterpret_cast<const uint8_t*>(entries_);
}
// Method returns length of binary data. Used by the oat writer.
- uint32_t RawDataLength() const { return raw_data_length_; }
+ uint32_t RawDataLength() const {
+ DCHECK(Valid());
+ return Size() * sizeof(Entry);
+ }
// Method returns length of binary data for the specified number of class definitions.
static uint32_t RawDataLength(uint32_t num_class_defs);
private:
- /**
- * To find element we need to compare strings.
- * It is faster to compare first hashes and then strings itself.
- * But we have no full hash of element of table. But we can use 2 ideas.
- * 1. All minor bits of hash inside one bucket are equals.
- * 2. If dex file contains N classes and size of hash table is 2^n (where N <= 2^n)
- * then 16-n bits are free. So we can encode part of element's hash into these bits.
- * So hash of element can be divided on three parts:
- * XXXX XXXX XXXX YYYY YZZZ ZZZZ ZZZZZ
- * Z - a part of hash encoded in bucket (these bits of has are same for all elements in bucket) -
- * n bits
- * Y - a part of hash that we can write into free 16-n bits (because only n bits used to store
- * class_def_idx)
- * X - a part of has that we can't use without increasing increase
- * So the data element of Entry used to store class_def_idx and part of hash of the entry.
- */
- struct Entry {
- uint32_t str_offset;
- uint16_t data;
- uint16_t next_pos_delta;
-
- Entry() : str_offset(0), data(0), next_pos_delta(0) {}
+ /**
+ * To find element we need to compare strings.
+ * It is faster to compare first hashes and then strings itself.
+ * But we have no full hash of element of table. But we can use 2 ideas.
+ * 1. All minor bits of hash inside one bucket are equal.
+ * (TODO: We're not actually using this, are we?)
+ * 2. If the dex file contains N classes and the size of the hash table is 2^n (where N <= 2^n)
+ * then we need n bits for the class def index and n bits for the next position delta.
+ * So we can encode part of element's hash into the remaining 32-2*n (n <= 16) bits which
+ * would be otherwise wasted as a padding.
+ * So hash of element can be divided on three parts:
+ * XXXX XXXX XXXY YYYY YYYY YZZZ ZZZZ ZZZZ (example with n=11)
+ * Z - a part of hash encoded implicitly in the bucket index
+ * (these bits are same for all elements in bucket)
+ * Y - a part of hash that we can write into free 32-2*n bits
+ * X - a part of hash that we can't use without increasing the size of the entry
+ * So the `data` element of Entry is used to store the next position delta, class_def_index
+ * and a part of hash of the entry.
+ */
+ class Entry {
+ public:
+ Entry() : str_offset_(0u), data_(0u) {}
+ Entry(uint32_t str_offset, uint32_t hash, uint32_t class_def_index, uint32_t mask_bits)
+ : str_offset_(str_offset),
+ data_(((hash & ~GetMask(mask_bits)) | class_def_index) << mask_bits) {
+ DCHECK_EQ(class_def_index & ~GetMask(mask_bits), 0u);
+ }
+
+ void SetNextPosDelta(uint32_t next_pos_delta, uint32_t mask_bits) {
+ DCHECK_EQ(GetNextPosDelta(mask_bits), 0u);
+ DCHECK_EQ(next_pos_delta & ~GetMask(mask_bits), 0u);
+ DCHECK_NE(next_pos_delta, 0u);
+ data_ |= next_pos_delta;
+ }
bool IsEmpty() const {
- return str_offset == 0;
+ return str_offset_ == 0u;
}
- bool IsLast() const {
- return next_pos_delta == 0;
+ bool IsLast(uint32_t mask_bits) const {
+ return GetNextPosDelta(mask_bits) == 0u;
}
- };
- static uint32_t CalculateMask(uint32_t num_class_defs);
- static bool SupportedSize(uint32_t num_class_defs);
+ uint32_t GetStringOffset() const {
+ return str_offset_;
+ }
- // Construct from a dex file.
- explicit TypeLookupTable(const DexFile& dex_file, uint8_t* storage);
-
- // Construct from a dex file with existing data.
- TypeLookupTable(const uint8_t* dex_file_pointer,
- const uint8_t* raw_data,
- uint32_t num_class_defs);
-
- bool IsStringsEquals(const char* str, uint32_t str_offset) const {
- const uint8_t* ptr = dex_data_begin_ + str_offset;
- CHECK(dex_data_begin_ != nullptr);
- // Skip string length.
- DecodeUnsignedLeb128(&ptr);
- return CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(
- str, reinterpret_cast<const char*>(ptr)) == 0;
- }
+ uint32_t GetNextPosDelta(uint32_t mask_bits) const {
+ return data_ & GetMask(mask_bits);
+ }
- // Method extracts hash bits from element's data and compare them with
- // the corresponding bits of the specified hash
- bool CmpHashBits(uint32_t data, uint32_t hash) const {
- uint32_t mask = static_cast<uint16_t>(~GetSizeMask());
- return (hash & mask) == (data & mask);
- }
+ uint32_t GetClassDefIdx(uint32_t mask_bits) const {
+ return (data_ >> mask_bits) & GetMask(mask_bits);
+ }
- uint32_t GetClassDefIdx(uint32_t data) const {
- return data & mask_;
- }
+ uint32_t GetHashBits(uint32_t mask_bits) const {
+ DCHECK_LE(mask_bits, 16u);
+ return data_ >> (2u * mask_bits);
+ }
- uint32_t GetSizeMask() const {
- return mask_;
- }
+ static uint32_t GetMask(uint32_t mask_bits) {
+ DCHECK_LE(mask_bits, 16u);
+ return ~(std::numeric_limits<uint32_t>::max() << mask_bits);
+ }
- // Attempt to set an entry on its hash's slot. If there is already something there, return false.
- // Otherwise return true.
- bool SetOnInitialPos(const Entry& entry, uint32_t hash);
+ private:
+ uint32_t str_offset_;
+ uint32_t data_;
+ };
- // Insert an entry, probes until there is an empty slot.
- void Insert(const Entry& entry, uint32_t hash);
+ static uint32_t CalculateMaskBits(uint32_t num_class_defs);
+ static bool SupportedSize(uint32_t num_class_defs);
- // Find the last entry in a chain.
- uint32_t FindLastEntryInBucket(uint32_t cur_pos) const;
+ // Construct the TypeLookupTable.
+ TypeLookupTable(const uint8_t* dex_data_pointer,
+ uint32_t mask_bits,
+ const Entry* entries,
+ std::unique_ptr<Entry[]> owned_entries);
- const uint8_t* dex_data_begin_;
- const uint32_t raw_data_length_;
- const uint32_t mask_;
- std::unique_ptr<Entry[]> entries_;
- // owns_entries_ specifies if the lookup table owns the entries_ array.
- const bool owns_entries_;
+ const char* GetStringData(const Entry& entry) const;
- DISALLOW_IMPLICIT_CONSTRUCTORS(TypeLookupTable);
+ const uint8_t* dex_data_begin_;
+ uint32_t mask_bits_;
+ const Entry* entries_;
+ // `owned_entries_` is either null (not owning `entries_`) or same pointer as `entries_`.
+ std::unique_ptr<Entry[]> owned_entries_;
};
} // namespace art
diff --git a/libdexfile/dex/type_lookup_table_test.cc b/libdexfile/dex/type_lookup_table_test.cc
index 6c3d291332..4316be0bd6 100644
--- a/libdexfile/dex/type_lookup_table_test.cc
+++ b/libdexfile/dex/type_lookup_table_test.cc
@@ -30,20 +30,20 @@ class TypeLookupTableTest : public CommonArtTestWithParam<DescriptorClassDefIdxP
TEST_F(TypeLookupTableTest, CreateLookupTable) {
std::unique_ptr<const DexFile> dex_file(OpenTestDexFile("Lookup"));
- std::unique_ptr<TypeLookupTable> table(TypeLookupTable::Create(*dex_file));
- ASSERT_NE(nullptr, table.get());
- ASSERT_NE(nullptr, table->RawData());
- ASSERT_EQ(32U, table->RawDataLength());
+ TypeLookupTable table = TypeLookupTable::Create(*dex_file);
+ ASSERT_TRUE(table.Valid());
+ ASSERT_NE(nullptr, table.RawData());
+ ASSERT_EQ(32U, table.RawDataLength());
}
TEST_P(TypeLookupTableTest, Find) {
std::unique_ptr<const DexFile> dex_file(OpenTestDexFile("Lookup"));
- std::unique_ptr<TypeLookupTable> table(TypeLookupTable::Create(*dex_file));
- ASSERT_NE(nullptr, table.get());
+ TypeLookupTable table(TypeLookupTable::Create(*dex_file));
+ ASSERT_TRUE(table.Valid());
auto pair = GetParam();
const char* descriptor = pair.first;
size_t hash = ComputeModifiedUtf8Hash(descriptor);
- uint32_t class_def_idx = table->Lookup(descriptor, hash);
+ uint32_t class_def_idx = table.Lookup(descriptor, hash);
ASSERT_EQ(pair.second, class_def_idx);
}
diff --git a/runtime/oat.h b/runtime/oat.h
index e7e5848dd6..72eb27d69e 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,8 +32,8 @@ class InstructionSetFeatures;
class PACKED(4) OatHeader {
public:
static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' };
- // Last oat version changed reason: Rewrite dex register map encoding.
- static constexpr uint8_t kOatVersion[] = { '1', '4', '6', '\0' };
+ // Last oat version changed reason: Rewrite TypeLookupTable.
+ static constexpr uint8_t kOatVersion[] = { '1', '4', '7', '\0' };
static constexpr const char* kImageLocationKey = "image-location";
static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index ffbc26c647..2b05b0e3dd 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -1687,6 +1687,7 @@ OatFile::OatDexFile::OatDexFile(const OatFile* oat_file,
type_bss_mapping_(type_bss_mapping_data),
string_bss_mapping_(string_bss_mapping_data),
oat_class_offsets_pointer_(oat_class_offsets_pointer),
+ lookup_table_(),
dex_layout_sections_(dex_layout_sections) {
// Initialize TypeLookupTable.
if (lookup_table_data_ != nullptr) {
@@ -1706,7 +1707,7 @@ OatFile::OatDexFile::OatDexFile(const OatFile* oat_file,
}
}
-OatFile::OatDexFile::OatDexFile(std::unique_ptr<TypeLookupTable>&& lookup_table)
+OatFile::OatDexFile::OatDexFile(TypeLookupTable&& lookup_table)
: lookup_table_(std::move(lookup_table)) {}
OatFile::OatDexFile::~OatDexFile() {}
@@ -1783,9 +1784,9 @@ const DexFile::ClassDef* OatFile::OatDexFile::FindClassDef(const DexFile& dex_fi
DCHECK_EQ(ComputeModifiedUtf8Hash(descriptor), hash);
bool used_lookup_table = false;
const DexFile::ClassDef* lookup_table_classdef = nullptr;
- if (LIKELY((oat_dex_file != nullptr) && (oat_dex_file->GetTypeLookupTable() != nullptr))) {
+ if (LIKELY((oat_dex_file != nullptr) && oat_dex_file->GetTypeLookupTable().Valid())) {
used_lookup_table = true;
- const uint32_t class_def_idx = oat_dex_file->GetTypeLookupTable()->Lookup(descriptor, hash);
+ const uint32_t class_def_idx = oat_dex_file->GetTypeLookupTable().Lookup(descriptor, hash);
lookup_table_classdef = (class_def_idx != dex::kDexNoIndex)
? &dex_file.GetClassDef(class_def_idx)
: nullptr;
@@ -1796,6 +1797,7 @@ const DexFile::ClassDef* OatFile::OatDexFile::FindClassDef(const DexFile& dex_fi
// Fast path for rare no class defs case.
const uint32_t num_class_defs = dex_file.NumClassDefs();
if (num_class_defs == 0) {
+ DCHECK(!used_lookup_table);
return nullptr;
}
const DexFile::TypeId* type_id = dex_file.FindTypeId(descriptor);
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 8e18cee729..d72b6a8971 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -514,14 +514,14 @@ class OatDexFile FINAL {
// Madvise the dex file based on the state we are moving to.
static void MadviseDexFile(const DexFile& dex_file, MadviseState state);
- TypeLookupTable* GetTypeLookupTable() const {
- return lookup_table_.get();
+ const TypeLookupTable& GetTypeLookupTable() const {
+ return lookup_table_;
}
~OatDexFile();
// Create only with a type lookup table, used by the compiler to speed up compilation.
- explicit OatDexFile(std::unique_ptr<TypeLookupTable>&& lookup_table);
+ explicit OatDexFile(TypeLookupTable&& lookup_table);
// Return the dex layout sections.
const DexLayoutSections* GetDexLayoutSections() const {
@@ -553,7 +553,7 @@ class OatDexFile FINAL {
const IndexBssMapping* const type_bss_mapping_ = nullptr;
const IndexBssMapping* const string_bss_mapping_ = nullptr;
const uint32_t* const oat_class_offsets_pointer_ = 0u;
- mutable std::unique_ptr<TypeLookupTable> lookup_table_;
+ TypeLookupTable lookup_table_;
const DexLayoutSections* const dex_layout_sections_ = nullptr;
friend class OatFile;