Move runtime/ to ClassAccessor
Added more iterator helpers, added logic for dealing with hidden API
flags.
Bug: 77709234
Bug: 79758018
Test: test-art-host
Change-Id: I3e6d34dd3fe61f1a3256a1cc4c74b63a6bdf514c
diff --git a/libdexfile/dex/class_accessor-inl.h b/libdexfile/dex/class_accessor-inl.h
index 49ca98d..3bb9e93 100644
--- a/libdexfile/dex/class_accessor-inl.h
+++ b/libdexfile/dex/class_accessor-inl.h
@@ -37,30 +37,26 @@
num_direct_methods_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u),
num_virtual_methods_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u) {}
-inline const uint8_t* ClassAccessor::Method::Read(const uint8_t* ptr) {
- index_ += DecodeUnsignedLeb128(&ptr);
- access_flags_ = DecodeUnsignedLeb128(&ptr);
- code_off_ = DecodeUnsignedLeb128(&ptr);
- return ptr;
+inline void ClassAccessor::Method::Read() {
+ index_ += DecodeUnsignedLeb128(&ptr_pos_);
+ access_flags_ = DecodeUnsignedLeb128(&ptr_pos_);
+ code_off_ = DecodeUnsignedLeb128(&ptr_pos_);
}
-inline const uint8_t* ClassAccessor::Field::Read(const uint8_t* ptr) {
- index_ += DecodeUnsignedLeb128(&ptr);
- access_flags_ = DecodeUnsignedLeb128(&ptr);
- return ptr;
+inline void ClassAccessor::Field::Read() {
+ index_ += DecodeUnsignedLeb128(&ptr_pos_);
+ access_flags_ = DecodeUnsignedLeb128(&ptr_pos_);
}
template <typename DataType, typename Visitor>
-inline const uint8_t* ClassAccessor::VisitMembers(size_t count,
- const Visitor& visitor,
- const uint8_t* ptr,
- DataType* data) const {
+inline void ClassAccessor::VisitMembers(size_t count,
+ const Visitor& visitor,
+ DataType* data) const {
DCHECK(data != nullptr);
for ( ; count != 0; --count) {
- ptr = data->Read(ptr);
+ data->Read();
visitor(*data);
}
- return ptr;
}
template <typename StaticFieldVisitor,
@@ -72,15 +68,15 @@
const InstanceFieldVisitor& instance_field_visitor,
const DirectMethodVisitor& direct_method_visitor,
const VirtualMethodVisitor& virtual_method_visitor) const {
- Field field(dex_file_);
- const uint8_t* ptr = VisitMembers(num_static_fields_, static_field_visitor, ptr_pos_, &field);
+ Field field(dex_file_, ptr_pos_);
+ VisitMembers(num_static_fields_, static_field_visitor, &field);
field.NextSection();
- ptr = VisitMembers(num_instance_fields_, instance_field_visitor, ptr, &field);
+ VisitMembers(num_instance_fields_, instance_field_visitor, &field);
- Method method(dex_file_, /*is_static_or_direct*/ true);
- ptr = VisitMembers(num_direct_methods_, direct_method_visitor, ptr, &method);
+ Method method(dex_file_, field.ptr_pos_, /*is_static_or_direct*/ true);
+ VisitMembers(num_direct_methods_, direct_method_visitor, &method);
method.NextSection();
- ptr = VisitMembers(num_virtual_methods_, virtual_method_visitor, ptr, &method);
+ VisitMembers(num_virtual_methods_, virtual_method_visitor, &method);
}
template <typename DirectMethodVisitor,
@@ -119,23 +115,64 @@
return dex_file_.GetCodeItem(code_off_);
}
+inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Field>>
+ ClassAccessor::GetFieldsInternal(size_t count) const {
+ return { DataIterator<Field>(dex_file_, 0u, num_static_fields_, count, ptr_pos_),
+ DataIterator<Field>(dex_file_, count, num_static_fields_, count, ptr_pos_) };
+}
+
+// Return an iteration range for the first <count> methods.
+inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Method>>
+ ClassAccessor::GetMethodsInternal(size_t count) const {
+ // Skip over the fields.
+ Field field(dex_file_, ptr_pos_);
+ VisitMembers(NumFields(), VoidFunctor(), &field);
+ // Return the iterator pair.
+ return { DataIterator<Method>(dex_file_, 0u, num_direct_methods_, count, field.ptr_pos_),
+ DataIterator<Method>(dex_file_, count, num_direct_methods_, count, field.ptr_pos_) };
+}
+
inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Field>> ClassAccessor::GetFields()
const {
- const uint32_t limit = num_static_fields_ + num_instance_fields_;
- return { DataIterator<Field>(dex_file_, 0u, num_static_fields_, limit, ptr_pos_),
- DataIterator<Field>(dex_file_, limit, num_static_fields_, limit, ptr_pos_) };
+ return GetFieldsInternal(num_static_fields_ + num_instance_fields_);
+}
+
+inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Field>>
+ ClassAccessor::GetStaticFields() const {
+ return GetFieldsInternal(num_static_fields_);
+}
+
+
+inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Field>>
+ ClassAccessor::GetInstanceFields() const {
+ IterationRange<ClassAccessor::DataIterator<ClassAccessor::Field>> fields = GetFields();
+ // Skip the static fields.
+ return { std::next(fields.begin(), NumStaticFields()), fields.end() };
}
inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Method>>
ClassAccessor::GetMethods() const {
- // Skip over the fields.
- Field field(dex_file_);
- const size_t skip_count = num_static_fields_ + num_instance_fields_;
- const uint8_t* ptr_pos = VisitMembers(skip_count, VoidFunctor(), ptr_pos_, &field);
- // Return the iterator pair for all the methods.
- const uint32_t limit = num_direct_methods_ + num_virtual_methods_;
- return { DataIterator<Method>(dex_file_, 0u, num_direct_methods_, limit, ptr_pos),
- DataIterator<Method>(dex_file_, limit, num_direct_methods_, limit, ptr_pos) };
+ return GetMethodsInternal(NumMethods());
+}
+
+inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Method>>
+ ClassAccessor::GetDirectMethods() const {
+ return GetMethodsInternal(NumDirectMethods());
+}
+
+inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Method>>
+ ClassAccessor::GetVirtualMethods() const {
+ IterationRange<DataIterator<Method>> methods = GetMethods();
+ // Skip the direct fields.
+ return { std::next(methods.begin(), NumDirectMethods()), methods.end() };
+}
+
+inline void ClassAccessor::Field::UnHideAccessFlags() const {
+ DexFile::UnHideAccessFlags(const_cast<uint8_t*>(ptr_pos_), GetAccessFlags(), /*is_method*/ false);
+}
+
+inline void ClassAccessor::Method::UnHideAccessFlags() const {
+ DexFile::UnHideAccessFlags(const_cast<uint8_t*>(ptr_pos_), GetAccessFlags(), /*is_method*/ true);
}
} // namespace art
diff --git a/libdexfile/dex/class_accessor.h b/libdexfile/dex/class_accessor.h
index dda6e1c..4f0fd32 100644
--- a/libdexfile/dex/class_accessor.h
+++ b/libdexfile/dex/class_accessor.h
@@ -20,6 +20,7 @@
#include "base/utils.h"
#include "code_item_accessors.h"
#include "dex_file.h"
+#include "hidden_api_access_flags.h"
#include "invoke_type.h"
#include "method_reference.h"
#include "modifiers.h"
@@ -33,12 +34,18 @@
private:
class BaseItem {
public:
+ explicit BaseItem(const uint8_t* ptr_pos) : ptr_pos_(ptr_pos) {}
+
uint32_t GetIndex() const {
return index_;
}
uint32_t GetAccessFlags() const {
- return access_flags_;
+ return HiddenApiAccessFlags::RemoveFromDex(access_flags_);
+ }
+
+ HiddenApiAccessFlags::ApiList DecodeHiddenAccessFlags() const {
+ return HiddenApiAccessFlags::DecodeFromDex(access_flags_);
}
bool IsFinal() const {
@@ -46,6 +53,8 @@
}
protected:
+ // Internal data pointer for reading.
+ const uint8_t* ptr_pos_ = nullptr;
uint32_t index_ = 0u;
uint32_t access_flags_ = 0u;
};
@@ -76,13 +85,18 @@
return is_static_or_direct_;
}
+ // Unhide the hidden API access flags at the iterator position. TODO: Deprecate.
+ void UnHideAccessFlags() const;
+
private:
explicit Method(const DexFile& dex_file,
+ const uint8_t* ptr_pos,
bool is_static_or_direct = true)
- : dex_file_(dex_file),
+ : BaseItem(ptr_pos),
+ dex_file_(dex_file),
is_static_or_direct_(is_static_or_direct) {}
- const uint8_t* Read(const uint8_t* ptr);
+ void Read();
InvokeType GetDirectMethodInvokeType() const {
return (GetAccessFlags() & kAccStatic) != 0 ? kStatic : kDirect;
@@ -99,6 +113,7 @@
}
}
+ // Move to virtual method section.
void NextSection() {
DCHECK(is_static_or_direct_) << "Already in the virtual methods section";
is_static_or_direct_ = false;
@@ -115,20 +130,31 @@
// A decoded version of the field of a class_data_item.
class Field : public BaseItem {
public:
- explicit Field(const DexFile& dex_file) : dex_file_(dex_file) {}
+ explicit Field(const DexFile& dex_file,
+ const uint8_t* ptr_pos) : BaseItem(ptr_pos), dex_file_(dex_file) {}
const DexFile& GetDexFile() const {
return dex_file_;
}
- private:
- const uint8_t* Read(const uint8_t* ptr);
+ bool IsStatic() const {
+ return is_static_;
+ }
+ // Unhide the hidden API access flags at the iterator position. TODO: Deprecate.
+ void UnHideAccessFlags() const;
+
+ private:
+ void Read();
+
+ // Move to instance fields section.
void NextSection() {
index_ = 0u;
+ is_static_ = false;
}
const DexFile& dex_file_;
+ bool is_static_ = true;
friend class ClassAccessor;
};
@@ -144,11 +170,10 @@
uint32_t partition_pos,
uint32_t iterator_end,
const uint8_t* ptr_pos)
- : data_(dex_file),
+ : data_(dex_file, ptr_pos),
position_(position),
partition_pos_(partition_pos),
- iterator_end_(iterator_end),
- ptr_pos_(ptr_pos) {
+ iterator_end_(iterator_end) {
ReadData();
}
@@ -205,8 +230,7 @@
if (position_ == partition_pos_) {
data_.NextSection();
}
- DCHECK(ptr_pos_ != nullptr);
- ptr_pos_ = data_.Read(ptr_pos_);
+ data_.Read();
}
}
@@ -217,8 +241,6 @@
const uint32_t partition_pos_;
// At iterator_end_, the iterator is no longer valid.
const uint32_t iterator_end_;
- // Internal data pointer.
- const uint8_t* ptr_pos_;
};
// Not explicit specifically for range-based loops.
@@ -252,9 +274,21 @@
// Return the iteration range for all the fields.
IterationRange<DataIterator<Field>> GetFields() const;
+ // Return the iteration range for all the static fields.
+ IterationRange<DataIterator<Field>> GetStaticFields() const;
+
+ // Return the iteration range for all the instance fields.
+ IterationRange<DataIterator<Field>> GetInstanceFields() const;
+
// Return the iteration range for all the methods.
IterationRange<DataIterator<Method>> GetMethods() const;
+ // Return the iteration range for the direct methods.
+ IterationRange<DataIterator<Method>> GetDirectMethods() const;
+
+ // Return the iteration range for the virtual methods.
+ IterationRange<DataIterator<Method>> GetVirtualMethods() const;
+
uint32_t NumStaticFields() const {
return num_static_fields_;
}
@@ -263,6 +297,10 @@
return num_instance_fields_;
}
+ uint32_t NumFields() const {
+ return NumStaticFields() + NumInstanceFields();
+ }
+
uint32_t NumDirectMethods() const {
return num_direct_methods_;
}
@@ -285,14 +323,22 @@
return dex_file_;
}
+ bool HasClassData() const {
+ return ptr_pos_ != nullptr;
+ }
+
protected:
// Template visitor to reduce copy paste for visiting elements.
// No thread safety analysis since the visitor may require capabilities.
template <typename DataType, typename Visitor>
- const uint8_t* VisitMembers(size_t count,
- const Visitor& visitor,
- const uint8_t* ptr,
- DataType* data) const NO_THREAD_SAFETY_ANALYSIS;
+ void VisitMembers(size_t count, const Visitor& visitor, DataType* data) const
+ NO_THREAD_SAFETY_ANALYSIS;
+
+ // Return an iteration range for the first <count> fields.
+ IterationRange<DataIterator<Field>> GetFieldsInternal(size_t count) const;
+
+ // Return an iteration range for the first <count> methods.
+ IterationRange<DataIterator<Method>> GetMethodsInternal(size_t count) const;
const DexFile& dex_file_;
const dex::TypeIndex descriptor_index_ = {};
diff --git a/libdexfile/dex/class_accessor_test.cc b/libdexfile/dex/class_accessor_test.cc
index 95380d8..d0533c1 100644
--- a/libdexfile/dex/class_accessor_test.cc
+++ b/libdexfile/dex/class_accessor_test.cc
@@ -38,18 +38,27 @@
auto fields = accessor.GetFields();
auto method_it = methods.begin();
auto field_it = fields.begin();
+ auto instance_fields = accessor.GetInstanceFields();
+ auto instance_field_it = instance_fields.begin();
accessor.VisitFieldsAndMethods(
// Static fields.
[&](const ClassAccessor::Field& field) {
+ EXPECT_TRUE(field.IsStatic());
+ EXPECT_TRUE(field_it->IsStatic());
EXPECT_EQ(field.GetIndex(), field_it->GetIndex());
EXPECT_EQ(field.GetAccessFlags(), field_it->GetAccessFlags());
++field_it;
},
// Instance fields.
[&](const ClassAccessor::Field& field) {
+ EXPECT_FALSE(field.IsStatic());
+ EXPECT_FALSE(field_it->IsStatic());
EXPECT_EQ(field.GetIndex(), field_it->GetIndex());
EXPECT_EQ(field.GetAccessFlags(), field_it->GetAccessFlags());
+ EXPECT_EQ(field.GetIndex(), instance_field_it->GetIndex());
+ EXPECT_EQ(field.GetAccessFlags(), instance_field_it->GetAccessFlags());
++field_it;
+ ++instance_field_it;
},
// Direct methods.
[&](const ClassAccessor::Method& method) {
@@ -71,6 +80,7 @@
});
ASSERT_TRUE(field_it == fields.end());
ASSERT_TRUE(method_it == methods.end());
+ ASSERT_TRUE(instance_field_it == instance_fields.end());
}
EXPECT_EQ(class_def_idx, dex_file->NumClassDefs());
}
diff --git a/libdexfile/dex/dex_file.cc b/libdexfile/dex/dex_file.cc
index 9de260c..f570158 100644
--- a/libdexfile/dex/dex_file.cc
+++ b/libdexfile/dex/dex_file.cc
@@ -45,19 +45,18 @@
static_assert(sizeof(dex::TypeIndex) == sizeof(uint16_t), "TypeIndex size is wrong");
static_assert(std::is_trivially_copyable<dex::TypeIndex>::value, "TypeIndex not trivial");
-void DexFile::UnHideAccessFlags(ClassDataItemIterator& class_it) {
- uint8_t* data = const_cast<uint8_t*>(class_it.DataPointer());
- uint32_t new_flag = class_it.GetMemberAccessFlags();
- bool is_method = class_it.IsAtMethod();
+void DexFile::UnHideAccessFlags(uint8_t* data_ptr,
+ uint32_t new_access_flags,
+ bool is_method) {
// Go back 1 uleb to start.
- data = ReverseSearchUnsignedLeb128(data);
+ data_ptr = ReverseSearchUnsignedLeb128(data_ptr);
if (is_method) {
// Methods have another uleb field before the access flags
- data = ReverseSearchUnsignedLeb128(data);
+ data_ptr = ReverseSearchUnsignedLeb128(data_ptr);
}
- DCHECK_EQ(HiddenApiAccessFlags::RemoveFromDex(DecodeUnsignedLeb128WithoutMovingCursor(data)),
- new_flag);
- UpdateUnsignedLeb128(data, new_flag);
+ DCHECK_EQ(HiddenApiAccessFlags::RemoveFromDex(DecodeUnsignedLeb128WithoutMovingCursor(data_ptr)),
+ new_access_flags);
+ UpdateUnsignedLeb128(data_ptr, new_access_flags);
}
uint32_t DexFile::CalculateChecksum() const {
diff --git a/libdexfile/dex/dex_file.h b/libdexfile/dex/dex_file.h
index f1f8b50..ed21980 100644
--- a/libdexfile/dex/dex_file.h
+++ b/libdexfile/dex/dex_file.h
@@ -1010,8 +1010,8 @@
return container_.get();
}
- // Changes the dex file pointed to by class_it to not have any hiddenapi flags.
- static void UnHideAccessFlags(ClassDataItemIterator& class_it);
+ // Changes the dex class data pointed to by data_ptr it to not have any hiddenapi flags.
+ static void UnHideAccessFlags(uint8_t* data_ptr, uint32_t new_access_flags, bool is_method);
inline IterationRange<ClassIterator> GetClasses() const;
diff --git a/openjdkjvmti/fixed_up_dex_file.cc b/openjdkjvmti/fixed_up_dex_file.cc
index fcbafe7..a660fb5 100644
--- a/openjdkjvmti/fixed_up_dex_file.cc
+++ b/openjdkjvmti/fixed_up_dex_file.cc
@@ -31,6 +31,7 @@
#include "base/leb128.h"
#include "fixed_up_dex_file.h"
+#include "dex/class_accessor-inl.h"
#include "dex/dex_file-inl.h"
#include "dex/dex_file_loader.h"
#include "dex/dex_file_verifier.h"
@@ -51,14 +52,12 @@
}
static void UnhideApis(const art::DexFile& target_dex_file) {
- for (uint32_t i = 0; i < target_dex_file.NumClassDefs(); ++i) {
- const uint8_t* class_data = target_dex_file.GetClassData(target_dex_file.GetClassDef(i));
- if (class_data != nullptr) {
- for (art::ClassDataItemIterator class_it(target_dex_file, class_data);
- class_it.HasNext();
- class_it.Next()) {
- art::DexFile::UnHideAccessFlags(class_it);
- }
+ for (art::ClassAccessor accessor : target_dex_file.GetClasses()) {
+ for (const art::ClassAccessor::Field& field : accessor.GetFields()) {
+ field.UnHideAccessFlags();
+ }
+ for (const art::ClassAccessor::Method& method : accessor.GetMethods()) {
+ method.UnHideAccessFlags();
}
}
}
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index 151c36f..4e9f3c5 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -26,6 +26,7 @@
#include "class_linker-inl.h"
#include "class_root.h"
#include "debugger.h"
+#include "dex/class_accessor-inl.h"
#include "dex/descriptors_names.h"
#include "dex/dex_file-inl.h"
#include "dex/dex_file_exception_helpers.h"
@@ -434,28 +435,14 @@
static uint32_t GetOatMethodIndexFromMethodIndex(const DexFile& dex_file,
uint16_t class_def_idx,
uint32_t method_idx) {
- const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_idx);
- const uint8_t* class_data = dex_file.GetClassData(class_def);
- CHECK(class_data != nullptr);
- ClassDataItemIterator it(dex_file, class_data);
- it.SkipAllFields();
- // Process methods
- size_t class_def_method_index = 0;
- while (it.HasNextDirectMethod()) {
- if (it.GetMemberIndex() == method_idx) {
+ ClassAccessor accessor(dex_file, dex_file.GetClassDef(class_def_idx));
+ uint32_t class_def_method_index = 0u;
+ for (const ClassAccessor::Method& method : accessor.GetMethods()) {
+ if (method.GetIndex() == method_idx) {
return class_def_method_index;
}
class_def_method_index++;
- it.Next();
}
- while (it.HasNextVirtualMethod()) {
- if (it.GetMemberIndex() == method_idx) {
- return class_def_method_index;
- }
- class_def_method_index++;
- it.Next();
- }
- DCHECK(!it.HasNext());
LOG(FATAL) << "Failed to find method index " << method_idx << " in " << dex_file.GetLocation();
UNREACHABLE();
}
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 0952723..d6ac3ba 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -56,6 +56,7 @@
#include "compiler_callbacks.h"
#include "debug_print.h"
#include "debugger.h"
+#include "dex/class_accessor-inl.h"
#include "dex/descriptors_names.h"
#include "dex/dex_file-inl.h"
#include "dex/dex_file_exception_helpers.h"
@@ -2734,52 +2735,50 @@
uint32_t ClassLinker::SizeOfClassWithoutEmbeddedTables(const DexFile& dex_file,
const DexFile::ClassDef& dex_class_def) {
- const uint8_t* class_data = dex_file.GetClassData(dex_class_def);
size_t num_ref = 0;
size_t num_8 = 0;
size_t num_16 = 0;
size_t num_32 = 0;
size_t num_64 = 0;
- if (class_data != nullptr) {
- // We allow duplicate definitions of the same field in a class_data_item
- // but ignore the repeated indexes here, b/21868015.
- uint32_t last_field_idx = dex::kDexNoIndex;
- for (ClassDataItemIterator it(dex_file, class_data); it.HasNextStaticField(); it.Next()) {
- uint32_t field_idx = it.GetMemberIndex();
- // Ordering enforced by DexFileVerifier.
- DCHECK(last_field_idx == dex::kDexNoIndex || last_field_idx <= field_idx);
- if (UNLIKELY(field_idx == last_field_idx)) {
- continue;
- }
- last_field_idx = field_idx;
- const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx);
- const char* descriptor = dex_file.GetFieldTypeDescriptor(field_id);
- char c = descriptor[0];
- switch (c) {
- case 'L':
- case '[':
- num_ref++;
- break;
- case 'J':
- case 'D':
- num_64++;
- break;
- case 'I':
- case 'F':
- num_32++;
- break;
- case 'S':
- case 'C':
- num_16++;
- break;
- case 'B':
- case 'Z':
- num_8++;
- break;
- default:
- LOG(FATAL) << "Unknown descriptor: " << c;
- UNREACHABLE();
- }
+ ClassAccessor accessor(dex_file, dex_class_def);
+ // We allow duplicate definitions of the same field in a class_data_item
+ // but ignore the repeated indexes here, b/21868015.
+ uint32_t last_field_idx = dex::kDexNoIndex;
+ for (const ClassAccessor::Field& field : accessor.GetStaticFields()) {
+ uint32_t field_idx = field.GetIndex();
+ // Ordering enforced by DexFileVerifier.
+ DCHECK(last_field_idx == dex::kDexNoIndex || last_field_idx <= field_idx);
+ if (UNLIKELY(field_idx == last_field_idx)) {
+ continue;
+ }
+ last_field_idx = field_idx;
+ const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx);
+ const char* descriptor = dex_file.GetFieldTypeDescriptor(field_id);
+ char c = descriptor[0];
+ switch (c) {
+ case 'L':
+ case '[':
+ num_ref++;
+ break;
+ case 'J':
+ case 'D':
+ num_64++;
+ break;
+ case 'I':
+ case 'F':
+ num_32++;
+ break;
+ case 'S':
+ case 'C':
+ num_16++;
+ break;
+ case 'B':
+ case 'Z':
+ num_8++;
+ break;
+ default:
+ LOG(FATAL) << "Unknown descriptor: " << c;
+ UNREACHABLE();
}
}
return mirror::Class::ComputeClassSize(false,
@@ -2877,17 +2876,15 @@
const DexFile& dex_file = klass->GetDexFile();
const DexFile::ClassDef* dex_class_def = klass->GetClassDef();
CHECK(dex_class_def != nullptr);
- const uint8_t* class_data = dex_file.GetClassData(*dex_class_def);
+ ClassAccessor accessor(dex_file, *dex_class_def);
// There should always be class data if there were direct methods.
- CHECK(class_data != nullptr) << klass->PrettyDescriptor();
- ClassDataItemIterator it(dex_file, class_data);
- it.SkipAllFields();
+ CHECK(accessor.HasClassData()) << klass->PrettyDescriptor();
bool has_oat_class;
OatFile::OatClass oat_class = OatFile::FindOatClass(dex_file,
klass->GetDexClassDefIndex(),
&has_oat_class);
// Link the code of methods skipped by LinkCode.
- for (size_t method_index = 0; it.HasNextDirectMethod(); ++method_index, it.Next()) {
+ for (size_t method_index = 0; method_index < accessor.NumDirectMethods(); ++method_index) {
ArtMethod* method = klass->GetDirectMethod(method_index, image_pointer_size_);
if (!method->IsStatic()) {
// Only update static methods.
@@ -2996,17 +2993,6 @@
klass->SetDexTypeIndex(dex_class_def.class_idx_);
}
-void ClassLinker::LoadClass(Thread* self,
- const DexFile& dex_file,
- const DexFile::ClassDef& dex_class_def,
- Handle<mirror::Class> klass) {
- const uint8_t* class_data = dex_file.GetClassData(dex_class_def);
- if (class_data == nullptr) {
- return; // no fields or methods - for example a marker interface
- }
- LoadClassMembers(self, dex_file, class_data, klass);
-}
-
LengthPrefixedArray<ArtField>* ClassLinker::AllocArtFieldArray(Thread* self,
LinearAlloc* allocator,
size_t length) {
@@ -3065,10 +3051,15 @@
return allocator;
}
-void ClassLinker::LoadClassMembers(Thread* self,
- const DexFile& dex_file,
- const uint8_t* class_data,
- Handle<mirror::Class> klass) {
+void ClassLinker::LoadClass(Thread* self,
+ const DexFile& dex_file,
+ const DexFile::ClassDef& dex_class_def,
+ Handle<mirror::Class> klass) {
+ ClassAccessor accessor(dex_file, dex_class_def);
+ if (!accessor.HasClassData()) {
+ return;
+ }
+ Runtime* const runtime = Runtime::Current();
{
// Note: We cannot have thread suspension until the field and method arrays are setup or else
// Class::VisitFieldRoots may miss some fields or methods.
@@ -3077,45 +3068,79 @@
// We allow duplicate definitions of the same field in a class_data_item
// but ignore the repeated indexes here, b/21868015.
LinearAlloc* const allocator = GetAllocatorForClassLoader(klass->GetClassLoader());
- ClassDataItemIterator it(dex_file, class_data);
LengthPrefixedArray<ArtField>* sfields = AllocArtFieldArray(self,
allocator,
- it.NumStaticFields());
- size_t num_sfields = 0;
- uint32_t last_field_idx = 0u;
- for (; it.HasNextStaticField(); it.Next()) {
- uint32_t field_idx = it.GetMemberIndex();
- DCHECK_GE(field_idx, last_field_idx); // Ordering enforced by DexFileVerifier.
- if (num_sfields == 0 || LIKELY(field_idx > last_field_idx)) {
- DCHECK_LT(num_sfields, it.NumStaticFields());
- LoadField(it, klass, &sfields->At(num_sfields));
- ++num_sfields;
- last_field_idx = field_idx;
- }
- }
-
- // Load instance fields.
+ accessor.NumStaticFields());
LengthPrefixedArray<ArtField>* ifields = AllocArtFieldArray(self,
allocator,
- it.NumInstanceFields());
+ accessor.NumInstanceFields());
+ size_t num_sfields = 0u;
size_t num_ifields = 0u;
- last_field_idx = 0u;
- for (; it.HasNextInstanceField(); it.Next()) {
- uint32_t field_idx = it.GetMemberIndex();
- DCHECK_GE(field_idx, last_field_idx); // Ordering enforced by DexFileVerifier.
- if (num_ifields == 0 || LIKELY(field_idx > last_field_idx)) {
- DCHECK_LT(num_ifields, it.NumInstanceFields());
- LoadField(it, klass, &ifields->At(num_ifields));
- ++num_ifields;
- last_field_idx = field_idx;
- }
- }
+ uint32_t last_static_field_idx = 0u;
+ uint32_t last_instance_field_idx = 0u;
- if (UNLIKELY(num_sfields != it.NumStaticFields()) ||
- UNLIKELY(num_ifields != it.NumInstanceFields())) {
+ // Methods
+ bool has_oat_class = false;
+ const OatFile::OatClass oat_class = (runtime->IsStarted() && !runtime->IsAotCompiler())
+ ? OatFile::FindOatClass(dex_file, klass->GetDexClassDefIndex(), &has_oat_class)
+ : OatFile::OatClass::Invalid();
+ const OatFile::OatClass* oat_class_ptr = has_oat_class ? &oat_class : nullptr;
+ klass->SetMethodsPtr(
+ AllocArtMethodArray(self, allocator, accessor.NumMethods()),
+ accessor.NumDirectMethods(),
+ accessor.NumVirtualMethods());
+ size_t class_def_method_index = 0;
+ uint32_t last_dex_method_index = dex::kDexNoIndex;
+ size_t last_class_def_method_index = 0;
+
+ // Use the visitor since the ranged based loops are bit slower from seeking. Seeking to the
+ // methods needs to decode all of the fields.
+ accessor.VisitFieldsAndMethods([&](
+ const ClassAccessor::Field& field) REQUIRES_SHARED(Locks::mutator_lock_) {
+ uint32_t field_idx = field.GetIndex();
+ DCHECK_GE(field_idx, last_static_field_idx); // Ordering enforced by DexFileVerifier.
+ if (num_sfields == 0 || LIKELY(field_idx > last_static_field_idx)) {
+ LoadField(field, klass, &sfields->At(num_sfields));
+ ++num_sfields;
+ last_static_field_idx = field_idx;
+ }
+ }, [&](const ClassAccessor::Field& field) REQUIRES_SHARED(Locks::mutator_lock_) {
+ uint32_t field_idx = field.GetIndex();
+ DCHECK_GE(field_idx, last_instance_field_idx); // Ordering enforced by DexFileVerifier.
+ if (num_ifields == 0 || LIKELY(field_idx > last_instance_field_idx)) {
+ LoadField(field, klass, &ifields->At(num_ifields));
+ ++num_ifields;
+ last_instance_field_idx = field_idx;
+ }
+ }, [&](const ClassAccessor::Method& method) REQUIRES_SHARED(Locks::mutator_lock_) {
+ ArtMethod* art_method = klass->GetDirectMethodUnchecked(class_def_method_index,
+ image_pointer_size_);
+ LoadMethod(dex_file, method, klass, art_method);
+ LinkCode(this, art_method, oat_class_ptr, class_def_method_index);
+ uint32_t it_method_index = method.GetIndex();
+ if (last_dex_method_index == it_method_index) {
+ // duplicate case
+ art_method->SetMethodIndex(last_class_def_method_index);
+ } else {
+ art_method->SetMethodIndex(class_def_method_index);
+ last_dex_method_index = it_method_index;
+ last_class_def_method_index = class_def_method_index;
+ }
+ ++class_def_method_index;
+ }, [&](const ClassAccessor::Method& method) REQUIRES_SHARED(Locks::mutator_lock_) {
+ ArtMethod* art_method = klass->GetVirtualMethodUnchecked(
+ class_def_method_index - accessor.NumDirectMethods(),
+ image_pointer_size_);
+ LoadMethod(dex_file, method, klass, art_method);
+ LinkCode(this, art_method, oat_class_ptr, class_def_method_index);
+ ++class_def_method_index;
+ });
+
+ if (UNLIKELY(num_ifields + num_sfields != accessor.NumFields())) {
LOG(WARNING) << "Duplicate fields in class " << klass->PrettyDescriptor()
- << " (unique static fields: " << num_sfields << "/" << it.NumStaticFields()
- << ", unique instance fields: " << num_ifields << "/" << it.NumInstanceFields() << ")";
+ << " (unique static fields: " << num_sfields << "/" << accessor.NumStaticFields()
+ << ", unique instance fields: " << num_ifields << "/" << accessor.NumInstanceFields()
+ << ")";
// NOTE: Not shrinking the over-allocated sfields/ifields, just setting size.
if (sfields != nullptr) {
sfields->SetSize(num_sfields);
@@ -3129,87 +3154,49 @@
DCHECK_EQ(klass->NumStaticFields(), num_sfields);
klass->SetIFieldsPtr(ifields);
DCHECK_EQ(klass->NumInstanceFields(), num_ifields);
- // Load methods.
- bool has_oat_class = false;
- const OatFile::OatClass oat_class =
- (Runtime::Current()->IsStarted() && !Runtime::Current()->IsAotCompiler())
- ? OatFile::FindOatClass(dex_file, klass->GetDexClassDefIndex(), &has_oat_class)
- : OatFile::OatClass::Invalid();
- const OatFile::OatClass* oat_class_ptr = has_oat_class ? &oat_class : nullptr;
- klass->SetMethodsPtr(
- AllocArtMethodArray(self, allocator, it.NumDirectMethods() + it.NumVirtualMethods()),
- it.NumDirectMethods(),
- it.NumVirtualMethods());
- size_t class_def_method_index = 0;
- uint32_t last_dex_method_index = dex::kDexNoIndex;
- size_t last_class_def_method_index = 0;
- // TODO These should really use the iterators.
- for (size_t i = 0; it.HasNextDirectMethod(); i++, it.Next()) {
- ArtMethod* method = klass->GetDirectMethodUnchecked(i, image_pointer_size_);
- LoadMethod(dex_file, it, klass, method);
- LinkCode(this, method, oat_class_ptr, class_def_method_index);
- uint32_t it_method_index = it.GetMemberIndex();
- if (last_dex_method_index == it_method_index) {
- // duplicate case
- method->SetMethodIndex(last_class_def_method_index);
- } else {
- method->SetMethodIndex(class_def_method_index);
- last_dex_method_index = it_method_index;
- last_class_def_method_index = class_def_method_index;
- }
- class_def_method_index++;
- }
- for (size_t i = 0; it.HasNextVirtualMethod(); i++, it.Next()) {
- ArtMethod* method = klass->GetVirtualMethodUnchecked(i, image_pointer_size_);
- LoadMethod(dex_file, it, klass, method);
- DCHECK_EQ(class_def_method_index, it.NumDirectMethods() + i);
- LinkCode(this, method, oat_class_ptr, class_def_method_index);
- class_def_method_index++;
- }
- DCHECK(!it.HasNext());
}
// Ensure that the card is marked so that remembered sets pick up native roots.
Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(klass.Get());
self->AllowThreadSuspension();
}
-void ClassLinker::LoadField(const ClassDataItemIterator& it,
+void ClassLinker::LoadField(const ClassAccessor::Field& field,
Handle<mirror::Class> klass,
ArtField* dst) {
- const uint32_t field_idx = it.GetMemberIndex();
+ const uint32_t field_idx = field.GetIndex();
dst->SetDexFieldIndex(field_idx);
dst->SetDeclaringClass(klass.Get());
// Get access flags from the DexFile. If this is a boot class path class,
// also set its runtime hidden API access flags.
- uint32_t access_flags = it.GetFieldAccessFlags();
+ uint32_t access_flags = field.GetAccessFlags();
if (klass->IsBootStrapClassLoaded()) {
access_flags =
- HiddenApiAccessFlags::EncodeForRuntime(access_flags, it.DecodeHiddenAccessFlags());
+ HiddenApiAccessFlags::EncodeForRuntime(access_flags, field.DecodeHiddenAccessFlags());
}
dst->SetAccessFlags(access_flags);
}
void ClassLinker::LoadMethod(const DexFile& dex_file,
- const ClassDataItemIterator& it,
+ const ClassAccessor::Method& method,
Handle<mirror::Class> klass,
ArtMethod* dst) {
- uint32_t dex_method_idx = it.GetMemberIndex();
+ const uint32_t dex_method_idx = method.GetIndex();
const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method_idx);
const char* method_name = dex_file.StringDataByIdx(method_id.name_idx_);
ScopedAssertNoThreadSuspension ants("LoadMethod");
dst->SetDexMethodIndex(dex_method_idx);
dst->SetDeclaringClass(klass.Get());
- dst->SetCodeItemOffset(it.GetMethodCodeItemOffset());
+ dst->SetCodeItemOffset(method.GetCodeItemOffset());
// Get access flags from the DexFile. If this is a boot class path class,
// also set its runtime hidden API access flags.
- uint32_t access_flags = it.GetMethodAccessFlags();
+ uint32_t access_flags = method.GetAccessFlags();
if (klass->IsBootStrapClassLoaded()) {
access_flags =
- HiddenApiAccessFlags::EncodeForRuntime(access_flags, it.DecodeHiddenAccessFlags());
+ HiddenApiAccessFlags::EncodeForRuntime(access_flags, method.DecodeHiddenAccessFlags());
}
if (UNLIKELY(strcmp("finalize", method_name) == 0)) {
@@ -4772,24 +4759,29 @@
this,
*dex_class_def);
const DexFile& dex_file = *dex_cache->GetDexFile();
- const uint8_t* class_data = dex_file.GetClassData(*dex_class_def);
- ClassDataItemIterator field_it(dex_file, class_data);
+
if (value_it.HasNext()) {
- DCHECK(field_it.HasNextStaticField());
+ ClassAccessor accessor(dex_file, *dex_class_def);
CHECK(can_init_statics);
- for ( ; value_it.HasNext(); value_it.Next(), field_it.Next()) {
- ArtField* field = ResolveField(
- field_it.GetMemberIndex(), dex_cache, class_loader, /* is_static */ true);
+ for (const ClassAccessor::Field& field : accessor.GetStaticFields()) {
+ if (!value_it.HasNext()) {
+ break;
+ }
+ ArtField* art_field = ResolveField(field.GetIndex(),
+ dex_cache,
+ class_loader,
+ /* is_static */ true);
if (Runtime::Current()->IsActiveTransaction()) {
- value_it.ReadValueToField<true>(field);
+ value_it.ReadValueToField<true>(art_field);
} else {
- value_it.ReadValueToField<false>(field);
+ value_it.ReadValueToField<false>(art_field);
}
if (self->IsExceptionPending()) {
break;
}
- DCHECK(!value_it.HasNext() || field_it.HasNextStaticField());
+ value_it.Next();
}
+ DCHECK(self->IsExceptionPending() || !value_it.HasNext());
}
}
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 1f94c43..1912d21 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -27,6 +27,7 @@
#include "base/enums.h"
#include "base/macros.h"
#include "base/mutex.h"
+#include "dex/class_accessor.h"
#include "dex/dex_cache_resolved_classes.h"
#include "dex/dex_file.h"
#include "dex/dex_file_types.h"
@@ -823,18 +824,14 @@
const DexFile::ClassDef& dex_class_def,
Handle<mirror::Class> klass)
REQUIRES_SHARED(Locks::mutator_lock_);
- void LoadClassMembers(Thread* self,
- const DexFile& dex_file,
- const uint8_t* class_data,
- Handle<mirror::Class> klass)
- REQUIRES_SHARED(Locks::mutator_lock_);
- void LoadField(const ClassDataItemIterator& it, Handle<mirror::Class> klass, ArtField* dst)
+ void LoadField(const ClassAccessor::Field& field, Handle<mirror::Class> klass, ArtField* dst)
REQUIRES_SHARED(Locks::mutator_lock_);
void LoadMethod(const DexFile& dex_file,
- const ClassDataItemIterator& it,
- Handle<mirror::Class> klass, ArtMethod* dst)
+ const ClassAccessor::Method& method,
+ Handle<mirror::Class> klass,
+ ArtMethod* dst)
REQUIRES_SHARED(Locks::mutator_lock_);
void FixupStaticTrampolines(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index 6c82019..c9deb52 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -32,6 +32,7 @@
#include "class_linker-inl.h"
#include "common_throws.h"
#include "debugger.h"
+#include "dex/class_accessor-inl.h"
#include "dex/dex_file-inl.h"
#include "dex/dex_file_types.h"
#include "gc/accounting/card_table-inl.h"
@@ -573,30 +574,12 @@
}
if (kPreloadDexCachesFieldsAndMethods) {
- for (size_t class_def_index = 0;
- class_def_index < dex_file->NumClassDefs();
- class_def_index++) {
- const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
- const uint8_t* class_data = dex_file->GetClassData(class_def);
- if (class_data == nullptr) {
- continue;
+ for (ClassAccessor accessor : dex_file->GetClasses()) {
+ for (const ClassAccessor::Field& field : accessor.GetFields()) {
+ PreloadDexCachesResolveField(dex_cache, field.GetIndex(), field.IsStatic());
}
- ClassDataItemIterator it(*dex_file, class_data);
- for (; it.HasNextStaticField(); it.Next()) {
- uint32_t field_idx = it.GetMemberIndex();
- PreloadDexCachesResolveField(dex_cache, field_idx, true);
- }
- for (; it.HasNextInstanceField(); it.Next()) {
- uint32_t field_idx = it.GetMemberIndex();
- PreloadDexCachesResolveField(dex_cache, field_idx, false);
- }
- for (; it.HasNextDirectMethod(); it.Next()) {
- uint32_t method_idx = it.GetMemberIndex();
- PreloadDexCachesResolveMethod(dex_cache, method_idx);
- }
- for (; it.HasNextVirtualMethod(); it.Next()) {
- uint32_t method_idx = it.GetMemberIndex();
- PreloadDexCachesResolveMethod(dex_cache, method_idx);
+ for (const ClassAccessor::Method& method : accessor.GetMethods()) {
+ PreloadDexCachesResolveMethod(dex_cache, method.GetIndex());
}
}
}
diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc
index 838d7f1..e2f42c9 100644
--- a/runtime/vdex_file.cc
+++ b/runtime/vdex_file.cc
@@ -28,6 +28,7 @@
#include "base/stl_util.h"
#include "base/unix_file/fd_file.h"
#include "dex/art_dex_file_loader.h"
+#include "dex/class_accessor-inl.h"
#include "dex/dex_file.h"
#include "dex/dex_file_loader.h"
#include "dex/hidden_api_access_flags.h"
@@ -283,31 +284,26 @@
std::unordered_set<const DexFile::CodeItem*> unquickened_code_item;
CompactOffsetTable::Accessor accessor(GetQuickenInfoOffsetTable(source_dex_begin,
quickening_info));
- for (uint32_t i = 0; i < target_dex_file.NumClassDefs(); ++i) {
- const DexFile::ClassDef& class_def = target_dex_file.GetClassDef(i);
- const uint8_t* class_data = target_dex_file.GetClassData(class_def);
- if (class_data != nullptr) {
- for (ClassDataItemIterator class_it(target_dex_file, class_data);
- class_it.HasNext();
- class_it.Next()) {
- if (class_it.IsAtMethod()) {
- const DexFile::CodeItem* code_item = class_it.GetMethodCodeItem();
- if (code_item != nullptr && unquickened_code_item.emplace(code_item).second) {
- const uint32_t offset = accessor.GetOffset(class_it.GetMemberIndex());
- // Offset being 0 means not quickened.
- if (offset != 0u) {
- ArrayRef<const uint8_t> quicken_data = GetQuickeningInfoAt(quickening_info, offset);
- optimizer::ArtDecompileDEX(
- target_dex_file,
- *code_item,
- quicken_data,
- decompile_return_instruction);
- }
- }
+ for (ClassAccessor class_accessor : target_dex_file.GetClasses()) {
+ for (const ClassAccessor::Method& method : class_accessor.GetMethods()) {
+ const DexFile::CodeItem* code_item = method.GetCodeItem();
+ if (code_item != nullptr && unquickened_code_item.emplace(code_item).second) {
+ const uint32_t offset = accessor.GetOffset(method.GetIndex());
+ // Offset being 0 means not quickened.
+ if (offset != 0u) {
+ ArrayRef<const uint8_t> quicken_data = GetQuickeningInfoAt(quickening_info, offset);
+ optimizer::ArtDecompileDEX(
+ target_dex_file,
+ *code_item,
+ quicken_data,
+ decompile_return_instruction);
}
- DexFile::UnHideAccessFlags(class_it);
+ method.UnHideAccessFlags();
}
}
+ for (const ClassAccessor::Field& field : class_accessor.GetFields()) {
+ field.UnHideAccessFlags();
+ }
}
}
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index cc71dc5..8169568 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -35,6 +35,7 @@
#include "class_linker.h"
#include "class_root.h"
#include "compiler_callbacks.h"
+#include "dex/class_accessor-inl.h"
#include "dex/descriptors_names.h"
#include "dex/dex_file-inl.h"
#include "dex/dex_file_exception_helpers.h"
@@ -190,11 +191,6 @@
error);
}
-template <bool kDirect>
-static bool HasNextMethod(ClassDataItemIterator* it) {
- return kDirect ? it->HasNextDirectMethod() : it->HasNextVirtualMethod();
-}
-
static FailureKind FailureKindMax(FailureKind fk1, FailureKind fk2) {
static_assert(FailureKind::kNoFailure < FailureKind::kSoftFailure
&& FailureKind::kSoftFailure < FailureKind::kHardFailure,
@@ -207,80 +203,6 @@
types |= fd.types;
}
-template <bool kDirect>
-MethodVerifier::FailureData MethodVerifier::VerifyMethods(Thread* self,
- ClassLinker* linker,
- const DexFile* dex_file,
- const DexFile::ClassDef& class_def,
- ClassDataItemIterator* it,
- Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader,
- CompilerCallbacks* callbacks,
- bool allow_soft_failures,
- HardFailLogMode log_level,
- bool need_precise_constants,
- std::string* error_string) {
- DCHECK(it != nullptr);
-
- MethodVerifier::FailureData failure_data;
-
- int64_t previous_method_idx = -1;
- while (HasNextMethod<kDirect>(it)) {
- self->AllowThreadSuspension();
- uint32_t method_idx = it->GetMemberIndex();
- if (method_idx == previous_method_idx) {
- // smali can create dex files with two encoded_methods sharing the same method_idx
- // http://code.google.com/p/smali/issues/detail?id=119
- it->Next();
- continue;
- }
- previous_method_idx = method_idx;
- InvokeType type = it->GetMethodInvokeType(class_def);
- ArtMethod* method = linker->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
- method_idx, dex_cache, class_loader, /* referrer */ nullptr, type);
- if (method == nullptr) {
- DCHECK(self->IsExceptionPending());
- // We couldn't resolve the method, but continue regardless.
- self->ClearException();
- } else {
- DCHECK(method->GetDeclaringClassUnchecked() != nullptr) << type;
- }
- StackHandleScope<1> hs(self);
- std::string hard_failure_msg;
- MethodVerifier::FailureData result = VerifyMethod(self,
- method_idx,
- dex_file,
- dex_cache,
- class_loader,
- class_def,
- it->GetMethodCodeItem(),
- method,
- it->GetMethodAccessFlags(),
- callbacks,
- allow_soft_failures,
- log_level,
- need_precise_constants,
- &hard_failure_msg);
- if (result.kind == FailureKind::kHardFailure) {
- if (failure_data.kind == FailureKind::kHardFailure) {
- // If we logged an error before, we need a newline.
- *error_string += "\n";
- } else {
- // If we didn't log a hard failure before, print the header of the message.
- *error_string += "Verifier rejected class ";
- *error_string += PrettyDescriptor(dex_file->GetClassDescriptor(class_def));
- *error_string += ":";
- }
- *error_string += " ";
- *error_string += hard_failure_msg;
- }
- failure_data.Merge(result);
- it->Next();
- }
-
- return failure_data;
-}
-
FailureKind MethodVerifier::VerifyClass(Thread* self,
const DexFile* dex_file,
Handle<mirror::DexCache> dex_cache,
@@ -300,52 +222,72 @@
return FailureKind::kHardFailure;
}
- const uint8_t* class_data = dex_file->GetClassData(class_def);
- if (class_data == nullptr) {
- // empty class, probably a marker interface
- return FailureKind::kNoFailure;
+ ClassAccessor accessor(*dex_file, class_def);
+
+ int64_t previous_method_idx[2] = { -1, -1 };
+ MethodVerifier::FailureData failure_data;
+ ClassLinker* const linker = Runtime::Current()->GetClassLinker();
+
+ for (const ClassAccessor::Method& method : accessor.GetMethods()) {
+ int64_t* previous_idx = &previous_method_idx[method.IsStaticOrDirect() ? 0u : 1u];
+ self->AllowThreadSuspension();
+ const uint32_t method_idx = method.GetIndex();
+ if (method_idx == *previous_idx) {
+ // smali can create dex files with two encoded_methods sharing the same method_idx
+ // http://code.google.com/p/smali/issues/detail?id=119
+ continue;
+ }
+ *previous_idx = method_idx;
+ const InvokeType type = method.GetInvokeType(class_def.access_flags_);
+ ArtMethod* resolved_method = linker->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
+ method_idx, dex_cache, class_loader, /* referrer */ nullptr, type);
+ if (resolved_method == nullptr) {
+ DCHECK(self->IsExceptionPending());
+ // We couldn't resolve the method, but continue regardless.
+ self->ClearException();
+ } else {
+ DCHECK(resolved_method->GetDeclaringClassUnchecked() != nullptr) << type;
+ }
+ std::string hard_failure_msg;
+ MethodVerifier::FailureData result = VerifyMethod(self,
+ method_idx,
+ dex_file,
+ dex_cache,
+ class_loader,
+ class_def,
+ method.GetCodeItem(),
+ resolved_method,
+ method.GetAccessFlags(),
+ callbacks,
+ allow_soft_failures,
+ log_level,
+ /*need_precise_constants*/ false,
+ &hard_failure_msg);
+ if (result.kind == FailureKind::kHardFailure) {
+ if (failure_data.kind == FailureKind::kHardFailure) {
+ // If we logged an error before, we need a newline.
+ *error += "\n";
+ } else {
+ // If we didn't log a hard failure before, print the header of the message.
+ *error += "Verifier rejected class ";
+ *error += PrettyDescriptor(dex_file->GetClassDescriptor(class_def));
+ *error += ":";
+ }
+ *error += " ";
+ *error += hard_failure_msg;
+ }
+ failure_data.Merge(result);
}
- ClassDataItemIterator it(*dex_file, class_data);
- it.SkipAllFields();
- ClassLinker* linker = Runtime::Current()->GetClassLinker();
- // Direct methods.
- MethodVerifier::FailureData data1 = VerifyMethods<true>(self,
- linker,
- dex_file,
- class_def,
- &it,
- dex_cache,
- class_loader,
- callbacks,
- allow_soft_failures,
- log_level,
- false /* need precise constants */,
- error);
- // Virtual methods.
- MethodVerifier::FailureData data2 = VerifyMethods<false>(self,
- linker,
- dex_file,
- class_def,
- &it,
- dex_cache,
- class_loader,
- callbacks,
- allow_soft_failures,
- log_level,
- false /* need precise constants */,
- error);
- data1.Merge(data2);
-
- if (data1.kind == FailureKind::kNoFailure) {
+ if (failure_data.kind == FailureKind::kNoFailure) {
return FailureKind::kNoFailure;
} else {
- if ((data1.types & VERIFY_ERROR_LOCKING) != 0) {
+ if ((failure_data.types & VERIFY_ERROR_LOCKING) != 0) {
// Print a warning about expected slow-down. Use a string temporary to print one contiguous
// warning.
std::string tmp =
StringPrintf("Class %s failed lock verification and will run slower.",
- PrettyDescriptor(dex_file->GetClassDescriptor(class_def)).c_str());
+ PrettyDescriptor(accessor.GetDescriptor()).c_str());
if (!gPrintedDxMonitorText) {
tmp = tmp + "\nCommon causes for lock verification issues are non-optimized dex code\n"
"and incorrect proguard optimizations.";
@@ -353,7 +295,7 @@
}
LOG(WARNING) << tmp;
}
- return data1.kind;
+ return failure_data.kind;
}
}
@@ -1924,15 +1866,11 @@
static uint32_t GetFirstFinalInstanceFieldIndex(const DexFile& dex_file, dex::TypeIndex type_idx) {
const DexFile::ClassDef* class_def = dex_file.FindClassDef(type_idx);
DCHECK(class_def != nullptr);
- const uint8_t* class_data = dex_file.GetClassData(*class_def);
- DCHECK(class_data != nullptr);
- ClassDataItemIterator it(dex_file, class_data);
- it.SkipStaticFields();
- while (it.HasNextInstanceField()) {
- if ((it.GetFieldAccessFlags() & kAccFinal) != 0) {
- return it.GetMemberIndex();
+ ClassAccessor accessor(dex_file, *class_def);
+ for (const ClassAccessor::Field& field : accessor.GetInstanceFields()) {
+ if (field.IsFinal()) {
+ return field.GetIndex();
}
- it.Next();
}
return dex::kDexNoIndex;
}
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index b2adc62..c7368d7 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -275,23 +275,6 @@
void Merge(const FailureData& src);
};
- // Verify all direct or virtual methods of a class. The method assumes that the iterator is
- // positioned correctly, and the iterator will be updated.
- template <bool kDirect>
- static FailureData VerifyMethods(Thread* self,
- ClassLinker* linker,
- const DexFile* dex_file,
- const DexFile::ClassDef& class_def,
- ClassDataItemIterator* it,
- Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader,
- CompilerCallbacks* callbacks,
- bool allow_soft_failures,
- HardFailLogMode log_level,
- bool need_precise_constants,
- std::string* error_string)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
/*
* Perform verification on a single method.
*