diff options
| -rw-r--r-- | dex2oat/linker/oat_writer.cc | 10 | ||||
| -rw-r--r-- | libdexfile/dex/type_lookup_table.cc | 201 | ||||
| -rw-r--r-- | libdexfile/dex/type_lookup_table.h | 211 | ||||
| -rw-r--r-- | libdexfile/dex/type_lookup_table_test.cc | 14 | ||||
| -rw-r--r-- | runtime/oat.h | 4 | ||||
| -rw-r--r-- | runtime/oat_file.cc | 8 | ||||
| -rw-r--r-- | runtime/oat_file.h | 8 |
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; |