ART: Change direct-method overlap detection
Avoid allocations in a hash set when trying to ensure that there are no
method-ids denoting both direct and virtual methods. Instead use a copy
of the item iterator, as the methods are guaranteed to be sorted.
Saves 1% of instructions for a compiler-filter=extract compact-dex-level=none
compile:
Before After
Small app 545,345,563 540,654,732
Large app 8,040,713,801 7,956,413,657
Bug: 78568168
Test: m test-art-host
Change-Id: Ia2a0fbb82dad5d9fa781cbab46fe543d1dd0645e
diff --git a/libdexfile/dex/dex_file.h b/libdexfile/dex/dex_file.h
index 4098b42..4ca735a 100644
--- a/libdexfile/dex/dex_file.h
+++ b/libdexfile/dex/dex_file.h
@@ -1346,9 +1346,6 @@
uint32_t field_idx_delta_; // delta of index into the field_ids array for FieldId
uint32_t access_flags_; // access flags for the field
ClassDataField() : field_idx_delta_(0), access_flags_(0) {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ClassDataField);
};
ClassDataField field_;
@@ -1361,9 +1358,6 @@
uint32_t access_flags_;
uint32_t code_off_;
ClassDataMethod() : method_idx_delta_(0), access_flags_(0), code_off_(0) {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ClassDataMethod);
};
ClassDataMethod method_;
@@ -1374,7 +1368,6 @@
size_t pos_; // integral number of items passed
const uint8_t* ptr_pos_; // pointer into stream of class_data_item
uint32_t last_idx_; // last read field or method index to apply delta to
- DISALLOW_IMPLICIT_CONSTRUCTORS(ClassDataItemIterator);
};
class EncodedArrayValueIterator {
diff --git a/libdexfile/dex/dex_file_verifier.cc b/libdexfile/dex/dex_file_verifier.cc
index 68bd19e..e0bfdcf 100644
--- a/libdexfile/dex/dex_file_verifier.cc
+++ b/libdexfile/dex/dex_file_verifier.cc
@@ -674,9 +674,9 @@
uint32_t class_access_flags,
dex::TypeIndex class_type_index,
uint32_t code_offset,
- std::unordered_set<uint32_t>* direct_method_indexes,
+ ClassDataItemIterator* direct_it,
bool expect_direct) {
- DCHECK(direct_method_indexes != nullptr);
+ DCHECK(expect_direct || direct_it != nullptr);
// Check for overflow.
if (!CheckIndex(idx, header_->method_ids_size_, "class_data_item method_idx")) {
return false;
@@ -694,11 +694,19 @@
}
// Check that it's not defined as both direct and virtual.
- if (expect_direct) {
- direct_method_indexes->insert(idx);
- } else if (direct_method_indexes->find(idx) != direct_method_indexes->end()) {
- ErrorStringPrintf("Found virtual method with same index as direct method: %d", idx);
- return false;
+ if (!expect_direct) {
+ // The direct methods are already known to be in ascending index order. So just keep up
+ // with the current index.
+ for (; direct_it->HasNextDirectMethod(); direct_it->Next()) {
+ uint32_t direct_idx = direct_it->GetMemberIndex();
+ if (direct_idx > idx) {
+ break;
+ }
+ if (direct_idx == idx) {
+ ErrorStringPrintf("Found virtual method with same index as direct method: %d", idx);
+ return false;
+ }
+ }
}
std::string error_msg;
@@ -1146,7 +1154,7 @@
template <bool kDirect>
bool DexFileVerifier::CheckIntraClassDataItemMethods(
ClassDataItemIterator* it,
- std::unordered_set<uint32_t>* direct_method_indexes,
+ ClassDataItemIterator* direct_it,
bool* have_class,
dex::TypeIndex* class_type_index,
const DexFile::ClassDef** class_def) {
@@ -1168,7 +1176,7 @@
(*class_def)->access_flags_,
*class_type_index,
it->GetMethodCodeItemOffset(),
- direct_method_indexes,
+ direct_it,
kDirect)) {
return false;
}
@@ -1181,7 +1189,6 @@
bool DexFileVerifier::CheckIntraClassDataItem() {
ClassDataItemIterator it(*dex_file_, ptr_);
- std::unordered_set<uint32_t> direct_method_indexes;
// This code is complicated by the fact that we don't directly know which class this belongs to.
// So we need to explicitly search with the first item we find (either field or method), and then,
@@ -1205,15 +1212,17 @@
}
// Check methods.
+ ClassDataItemIterator direct_it = it;
+
if (!CheckIntraClassDataItemMethods<true>(&it,
- &direct_method_indexes,
+ nullptr /* direct_it */,
&have_class,
&class_type_index,
&class_def)) {
return false;
}
if (!CheckIntraClassDataItemMethods<false>(&it,
- &direct_method_indexes,
+ &direct_it,
&have_class,
&class_type_index,
&class_def)) {
diff --git a/libdexfile/dex/dex_file_verifier.h b/libdexfile/dex/dex_file_verifier.h
index a80a9d5..3bddc77 100644
--- a/libdexfile/dex/dex_file_verifier.h
+++ b/libdexfile/dex/dex_file_verifier.h
@@ -85,7 +85,7 @@
uint32_t class_access_flags,
dex::TypeIndex class_type_index,
uint32_t code_offset,
- std::unordered_set<uint32_t>* direct_method_indexes,
+ ClassDataItemIterator* direct_it,
bool expect_direct);
bool CheckOrderAndGetClassDef(bool is_field,
const char* type_descr,
@@ -113,7 +113,7 @@
// method, if necessary (and return it), or use the given values.
template <bool kDirect>
bool CheckIntraClassDataItemMethods(ClassDataItemIterator* it,
- std::unordered_set<uint32_t>* direct_method_indexes,
+ ClassDataItemIterator* direct_it,
bool* have_class,
dex::TypeIndex* class_type_index,
const DexFile::ClassDef** class_def);