diff options
-rw-r--r-- | libdexfile/dex/class_accessor-inl.h | 101 | ||||
-rw-r--r-- | libdexfile/dex/class_accessor.h | 78 | ||||
-rw-r--r-- | libdexfile/dex/class_accessor_test.cc | 10 | ||||
-rw-r--r-- | libdexfile/dex/dex_file.cc | 17 | ||||
-rw-r--r-- | libdexfile/dex/dex_file.h | 4 | ||||
-rw-r--r-- | openjdkjvmti/fixed_up_dex_file.cc | 15 | ||||
-rw-r--r-- | runtime/art_method.cc | 23 | ||||
-rw-r--r-- | runtime/class_linker.cc | 290 | ||||
-rw-r--r-- | runtime/class_linker.h | 13 | ||||
-rw-r--r-- | runtime/native/dalvik_system_VMRuntime.cc | 29 | ||||
-rw-r--r-- | runtime/vdex_file.cc | 40 | ||||
-rw-r--r-- | runtime/verifier/method_verifier.cc | 164 | ||||
-rw-r--r-- | runtime/verifier/method_verifier.h | 17 |
13 files changed, 417 insertions, 384 deletions
diff --git a/libdexfile/dex/class_accessor-inl.h b/libdexfile/dex/class_accessor-inl.h index 3bb9e93e5a..49ca98d47f 100644 --- a/libdexfile/dex/class_accessor-inl.h +++ b/libdexfile/dex/class_accessor-inl.h @@ -37,26 +37,30 @@ inline ClassAccessor::ClassAccessor(const DexFile& dex_file, const DexFile::Clas num_direct_methods_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u), num_virtual_methods_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u) {} -inline void ClassAccessor::Method::Read() { - index_ += DecodeUnsignedLeb128(&ptr_pos_); - access_flags_ = DecodeUnsignedLeb128(&ptr_pos_); - code_off_ = DecodeUnsignedLeb128(&ptr_pos_); +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::Field::Read() { - index_ += DecodeUnsignedLeb128(&ptr_pos_); - access_flags_ = DecodeUnsignedLeb128(&ptr_pos_); +inline const uint8_t* ClassAccessor::Field::Read(const uint8_t* ptr) { + index_ += DecodeUnsignedLeb128(&ptr); + access_flags_ = DecodeUnsignedLeb128(&ptr); + return ptr; } template <typename DataType, typename Visitor> -inline void ClassAccessor::VisitMembers(size_t count, - const Visitor& visitor, - DataType* data) const { +inline const uint8_t* ClassAccessor::VisitMembers(size_t count, + const Visitor& visitor, + const uint8_t* ptr, + DataType* data) const { DCHECK(data != nullptr); for ( ; count != 0; --count) { - data->Read(); + ptr = data->Read(ptr); visitor(*data); } + return ptr; } template <typename StaticFieldVisitor, @@ -68,15 +72,15 @@ inline void ClassAccessor::VisitFieldsAndMethods( const InstanceFieldVisitor& instance_field_visitor, const DirectMethodVisitor& direct_method_visitor, const VirtualMethodVisitor& virtual_method_visitor) const { - Field field(dex_file_, ptr_pos_); - VisitMembers(num_static_fields_, static_field_visitor, &field); + Field field(dex_file_); + const uint8_t* ptr = VisitMembers(num_static_fields_, static_field_visitor, ptr_pos_, &field); field.NextSection(); - VisitMembers(num_instance_fields_, instance_field_visitor, &field); + ptr = VisitMembers(num_instance_fields_, instance_field_visitor, ptr, &field); - Method method(dex_file_, field.ptr_pos_, /*is_static_or_direct*/ true); - VisitMembers(num_direct_methods_, direct_method_visitor, &method); + Method method(dex_file_, /*is_static_or_direct*/ true); + ptr = VisitMembers(num_direct_methods_, direct_method_visitor, ptr, &method); method.NextSection(); - VisitMembers(num_virtual_methods_, virtual_method_visitor, &method); + ptr = VisitMembers(num_virtual_methods_, virtual_method_visitor, ptr, &method); } template <typename DirectMethodVisitor, @@ -115,64 +119,23 @@ inline const DexFile::CodeItem* ClassAccessor::Method::GetCodeItem() const { 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 { - 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() }; + 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_) }; } inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Method>> ClassAccessor::GetMethods() const { - 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); + // 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) }; } } // namespace art diff --git a/libdexfile/dex/class_accessor.h b/libdexfile/dex/class_accessor.h index 4f0fd32e31..dda6e1c1a6 100644 --- a/libdexfile/dex/class_accessor.h +++ b/libdexfile/dex/class_accessor.h @@ -20,7 +20,6 @@ #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" @@ -34,18 +33,12 @@ class ClassAccessor { 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 HiddenApiAccessFlags::RemoveFromDex(access_flags_); - } - - HiddenApiAccessFlags::ApiList DecodeHiddenAccessFlags() const { - return HiddenApiAccessFlags::DecodeFromDex(access_flags_); + return access_flags_; } bool IsFinal() const { @@ -53,8 +46,6 @@ class ClassAccessor { } protected: - // Internal data pointer for reading. - const uint8_t* ptr_pos_ = nullptr; uint32_t index_ = 0u; uint32_t access_flags_ = 0u; }; @@ -85,18 +76,13 @@ class ClassAccessor { 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) - : BaseItem(ptr_pos), - dex_file_(dex_file), + : dex_file_(dex_file), is_static_or_direct_(is_static_or_direct) {} - void Read(); + const uint8_t* Read(const uint8_t* ptr); InvokeType GetDirectMethodInvokeType() const { return (GetAccessFlags() & kAccStatic) != 0 ? kStatic : kDirect; @@ -113,7 +99,6 @@ class ClassAccessor { } } - // Move to virtual method section. void NextSection() { DCHECK(is_static_or_direct_) << "Already in the virtual methods section"; is_static_or_direct_ = false; @@ -130,31 +115,20 @@ class ClassAccessor { // A decoded version of the field of a class_data_item. class Field : public BaseItem { public: - explicit Field(const DexFile& dex_file, - const uint8_t* ptr_pos) : BaseItem(ptr_pos), dex_file_(dex_file) {} + explicit Field(const DexFile& dex_file) : dex_file_(dex_file) {} const DexFile& GetDexFile() const { return dex_file_; } - bool IsStatic() const { - return is_static_; - } - - // Unhide the hidden API access flags at the iterator position. TODO: Deprecate. - void UnHideAccessFlags() const; - private: - void Read(); + const uint8_t* Read(const uint8_t* ptr); - // Move to instance fields section. void NextSection() { index_ = 0u; - is_static_ = false; } const DexFile& dex_file_; - bool is_static_ = true; friend class ClassAccessor; }; @@ -170,10 +144,11 @@ class ClassAccessor { uint32_t partition_pos, uint32_t iterator_end, const uint8_t* ptr_pos) - : data_(dex_file, ptr_pos), + : data_(dex_file), position_(position), partition_pos_(partition_pos), - iterator_end_(iterator_end) { + iterator_end_(iterator_end), + ptr_pos_(ptr_pos) { ReadData(); } @@ -230,7 +205,8 @@ class ClassAccessor { if (position_ == partition_pos_) { data_.NextSection(); } - data_.Read(); + DCHECK(ptr_pos_ != nullptr); + ptr_pos_ = data_.Read(ptr_pos_); } } @@ -241,6 +217,8 @@ class ClassAccessor { 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. @@ -274,21 +252,9 @@ class ClassAccessor { // 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_; } @@ -297,10 +263,6 @@ class ClassAccessor { return num_instance_fields_; } - uint32_t NumFields() const { - return NumStaticFields() + NumInstanceFields(); - } - uint32_t NumDirectMethods() const { return num_direct_methods_; } @@ -323,22 +285,14 @@ class ClassAccessor { 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> - 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 uint8_t* VisitMembers(size_t count, + const Visitor& visitor, + const uint8_t* ptr, + DataType* data) const NO_THREAD_SAFETY_ANALYSIS; 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 d0533c1811..95380d8140 100644 --- a/libdexfile/dex/class_accessor_test.cc +++ b/libdexfile/dex/class_accessor_test.cc @@ -38,27 +38,18 @@ TEST_F(ClassAccessorTest, TestVisiting) { 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) { @@ -80,7 +71,6 @@ TEST_F(ClassAccessorTest, TestVisiting) { }); 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 f570158dfb..9de260c862 100644 --- a/libdexfile/dex/dex_file.cc +++ b/libdexfile/dex/dex_file.cc @@ -45,18 +45,19 @@ static_assert(std::is_trivially_copyable<dex::StringIndex>::value, "StringIndex 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(uint8_t* data_ptr, - uint32_t new_access_flags, - bool is_method) { +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(); // Go back 1 uleb to start. - data_ptr = ReverseSearchUnsignedLeb128(data_ptr); + data = ReverseSearchUnsignedLeb128(data); if (is_method) { // Methods have another uleb field before the access flags - data_ptr = ReverseSearchUnsignedLeb128(data_ptr); + data = ReverseSearchUnsignedLeb128(data); } - DCHECK_EQ(HiddenApiAccessFlags::RemoveFromDex(DecodeUnsignedLeb128WithoutMovingCursor(data_ptr)), - new_access_flags); - UpdateUnsignedLeb128(data_ptr, new_access_flags); + DCHECK_EQ(HiddenApiAccessFlags::RemoveFromDex(DecodeUnsignedLeb128WithoutMovingCursor(data)), + new_flag); + UpdateUnsignedLeb128(data, new_flag); } uint32_t DexFile::CalculateChecksum() const { diff --git a/libdexfile/dex/dex_file.h b/libdexfile/dex/dex_file.h index ed219808d2..f1f8b505bd 100644 --- a/libdexfile/dex/dex_file.h +++ b/libdexfile/dex/dex_file.h @@ -1010,8 +1010,8 @@ class DexFile { return container_.get(); } - // 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); + // Changes the dex file pointed to by class_it to not have any hiddenapi flags. + static void UnHideAccessFlags(ClassDataItemIterator& class_it); inline IterationRange<ClassIterator> GetClasses() const; diff --git a/openjdkjvmti/fixed_up_dex_file.cc b/openjdkjvmti/fixed_up_dex_file.cc index a660fb56c4..fcbafe7e71 100644 --- a/openjdkjvmti/fixed_up_dex_file.cc +++ b/openjdkjvmti/fixed_up_dex_file.cc @@ -31,7 +31,6 @@ #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" @@ -52,12 +51,14 @@ static void RecomputeDexChecksum(art::DexFile* dex_file) { } static void UnhideApis(const art::DexFile& target_dex_file) { - 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(); + 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); + } } } } diff --git a/runtime/art_method.cc b/runtime/art_method.cc index 4e9f3c52e2..151c36f3bc 100644 --- a/runtime/art_method.cc +++ b/runtime/art_method.cc @@ -26,7 +26,6 @@ #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" @@ -435,14 +434,28 @@ bool ArtMethod::IsPolymorphicSignature() { static uint32_t GetOatMethodIndexFromMethodIndex(const DexFile& dex_file, uint16_t class_def_idx, uint32_t 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) { + 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) { 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 d6ac3bad52..095272394a 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -56,7 +56,6 @@ #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" @@ -2735,50 +2734,52 @@ mirror::Class* ClassLinker::DefineClass(Thread* self, 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; - 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(); + 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(); + } } } return mirror::Class::ComputeClassSize(false, @@ -2876,15 +2877,17 @@ void ClassLinker::FixupStaticTrampolines(ObjPtr<mirror::Class> klass) { const DexFile& dex_file = klass->GetDexFile(); const DexFile::ClassDef* dex_class_def = klass->GetClassDef(); CHECK(dex_class_def != nullptr); - ClassAccessor accessor(dex_file, *dex_class_def); + const uint8_t* class_data = dex_file.GetClassData(*dex_class_def); // There should always be class data if there were direct methods. - CHECK(accessor.HasClassData()) << klass->PrettyDescriptor(); + CHECK(class_data != nullptr) << klass->PrettyDescriptor(); + ClassDataItemIterator it(dex_file, class_data); + it.SkipAllFields(); 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; method_index < accessor.NumDirectMethods(); ++method_index) { + for (size_t method_index = 0; it.HasNextDirectMethod(); ++method_index, it.Next()) { ArtMethod* method = klass->GetDirectMethod(method_index, image_pointer_size_); if (!method->IsStatic()) { // Only update static methods. @@ -2993,6 +2996,17 @@ void ClassLinker::SetupClass(const DexFile& dex_file, 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) { @@ -3051,15 +3065,10 @@ LinearAlloc* ClassLinker::GetOrCreateAllocatorForClassLoader(ObjPtr<mirror::Clas return allocator; } -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(); +void ClassLinker::LoadClassMembers(Thread* self, + const DexFile& dex_file, + const uint8_t* class_data, + Handle<mirror::Class> klass) { { // Note: We cannot have thread suspension until the field and method arrays are setup or else // Class::VisitFieldRoots may miss some fields or methods. @@ -3068,79 +3077,45 @@ void ClassLinker::LoadClass(Thread* self, // 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, - accessor.NumStaticFields()); + 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. LengthPrefixedArray<ArtField>* ifields = AllocArtFieldArray(self, allocator, - accessor.NumInstanceFields()); - size_t num_sfields = 0u; + it.NumInstanceFields()); size_t num_ifields = 0u; - uint32_t last_static_field_idx = 0u; - uint32_t last_instance_field_idx = 0u; - - // 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; + 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; + } + } - // 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())) { + if (UNLIKELY(num_sfields != it.NumStaticFields()) || + UNLIKELY(num_ifields != it.NumInstanceFields())) { LOG(WARNING) << "Duplicate fields in class " << klass->PrettyDescriptor() - << " (unique static fields: " << num_sfields << "/" << accessor.NumStaticFields() - << ", unique instance fields: " << num_ifields << "/" << accessor.NumInstanceFields() - << ")"; + << " (unique static fields: " << num_sfields << "/" << it.NumStaticFields() + << ", unique instance fields: " << num_ifields << "/" << it.NumInstanceFields() << ")"; // NOTE: Not shrinking the over-allocated sfields/ifields, just setting size. if (sfields != nullptr) { sfields->SetSize(num_sfields); @@ -3154,49 +3129,87 @@ void ClassLinker::LoadClass(Thread* self, 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 ClassAccessor::Field& field, +void ClassLinker::LoadField(const ClassDataItemIterator& it, Handle<mirror::Class> klass, ArtField* dst) { - const uint32_t field_idx = field.GetIndex(); + const uint32_t field_idx = it.GetMemberIndex(); 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 = field.GetAccessFlags(); + uint32_t access_flags = it.GetFieldAccessFlags(); if (klass->IsBootStrapClassLoaded()) { access_flags = - HiddenApiAccessFlags::EncodeForRuntime(access_flags, field.DecodeHiddenAccessFlags()); + HiddenApiAccessFlags::EncodeForRuntime(access_flags, it.DecodeHiddenAccessFlags()); } dst->SetAccessFlags(access_flags); } void ClassLinker::LoadMethod(const DexFile& dex_file, - const ClassAccessor::Method& method, + const ClassDataItemIterator& it, Handle<mirror::Class> klass, ArtMethod* dst) { - const uint32_t dex_method_idx = method.GetIndex(); + uint32_t dex_method_idx = it.GetMemberIndex(); 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(method.GetCodeItemOffset()); + dst->SetCodeItemOffset(it.GetMethodCodeItemOffset()); // 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 = method.GetAccessFlags(); + uint32_t access_flags = it.GetMethodAccessFlags(); if (klass->IsBootStrapClassLoaded()) { access_flags = - HiddenApiAccessFlags::EncodeForRuntime(access_flags, method.DecodeHiddenAccessFlags()); + HiddenApiAccessFlags::EncodeForRuntime(access_flags, it.DecodeHiddenAccessFlags()); } if (UNLIKELY(strcmp("finalize", method_name) == 0)) { @@ -4759,29 +4772,24 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, 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()) { - ClassAccessor accessor(dex_file, *dex_class_def); + DCHECK(field_it.HasNextStaticField()); CHECK(can_init_statics); - 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); + for ( ; value_it.HasNext(); value_it.Next(), field_it.Next()) { + ArtField* field = ResolveField( + field_it.GetMemberIndex(), dex_cache, class_loader, /* is_static */ true); if (Runtime::Current()->IsActiveTransaction()) { - value_it.ReadValueToField<true>(art_field); + value_it.ReadValueToField<true>(field); } else { - value_it.ReadValueToField<false>(art_field); + value_it.ReadValueToField<false>(field); } if (self->IsExceptionPending()) { break; } - value_it.Next(); + DCHECK(!value_it.HasNext() || field_it.HasNextStaticField()); } - DCHECK(self->IsExceptionPending() || !value_it.HasNext()); } } diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 1912d21d98..1f94c43408 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -27,7 +27,6 @@ #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" @@ -824,14 +823,18 @@ class ClassLinker { 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 ClassAccessor::Field& field, Handle<mirror::Class> klass, ArtField* dst) + void LoadField(const ClassDataItemIterator& it, Handle<mirror::Class> klass, ArtField* dst) REQUIRES_SHARED(Locks::mutator_lock_); void LoadMethod(const DexFile& dex_file, - const ClassAccessor::Method& method, - Handle<mirror::Class> klass, - ArtMethod* dst) + const ClassDataItemIterator& it, + 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 c9deb526c2..6c820190b4 100644 --- a/runtime/native/dalvik_system_VMRuntime.cc +++ b/runtime/native/dalvik_system_VMRuntime.cc @@ -32,7 +32,6 @@ extern "C" void android_set_application_target_sdk_version(uint32_t version); #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" @@ -574,12 +573,30 @@ static void VMRuntime_preloadDexCaches(JNIEnv* env, jobject) { } if (kPreloadDexCachesFieldsAndMethods) { - for (ClassAccessor accessor : dex_file->GetClasses()) { - for (const ClassAccessor::Field& field : accessor.GetFields()) { - PreloadDexCachesResolveField(dex_cache, field.GetIndex(), field.IsStatic()); + 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 (const ClassAccessor::Method& method : accessor.GetMethods()) { - PreloadDexCachesResolveMethod(dex_cache, method.GetIndex()); + 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); } } } diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc index e2f42c937d..838d7f14bc 100644 --- a/runtime/vdex_file.cc +++ b/runtime/vdex_file.cc @@ -28,7 +28,6 @@ #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" @@ -284,26 +283,31 @@ void VdexFile::UnquickenDexFile(const DexFile& target_dex_file, std::unordered_set<const DexFile::CodeItem*> unquickened_code_item; CompactOffsetTable::Accessor accessor(GetQuickenInfoOffsetTable(source_dex_begin, quickening_info)); - 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); + 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); + } + } } - method.UnHideAccessFlags(); + DexFile::UnHideAccessFlags(class_it); } } - 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 8169568413..cc71dc5f84 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -35,7 +35,6 @@ #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" @@ -191,6 +190,11 @@ FailureKind MethodVerifier::VerifyClass(Thread* self, 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, @@ -203,51 +207,45 @@ void MethodVerifier::FailureData::Merge(const MethodVerifier::FailureData& fd) { types |= fd.types; } -FailureKind MethodVerifier::VerifyClass(Thread* self, - const DexFile* dex_file, - Handle<mirror::DexCache> dex_cache, - Handle<mirror::ClassLoader> class_loader, - const DexFile::ClassDef& class_def, - CompilerCallbacks* callbacks, - bool allow_soft_failures, - HardFailLogMode log_level, - std::string* error) { - SCOPED_TRACE << "VerifyClass " << PrettyDescriptor(dex_file->GetClassDescriptor(class_def)); +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); - // A class must not be abstract and final. - if ((class_def.access_flags_ & (kAccAbstract | kAccFinal)) == (kAccAbstract | kAccFinal)) { - *error = "Verifier rejected class "; - *error += PrettyDescriptor(dex_file->GetClassDescriptor(class_def)); - *error += ": class is abstract and final."; - return FailureKind::kHardFailure; - } - - 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]; + int64_t previous_method_idx = -1; + while (HasNextMethod<kDirect>(it)) { self->AllowThreadSuspension(); - const uint32_t method_idx = method.GetIndex(); - if (method_idx == *previous_idx) { + 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_idx = method_idx; - const InvokeType type = method.GetInvokeType(class_def.access_flags_); - ArtMethod* resolved_method = linker->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>( + 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 (resolved_method == nullptr) { + if (method == nullptr) { DCHECK(self->IsExceptionPending()); // We couldn't resolve the method, but continue regardless. self->ClearException(); } else { - DCHECK(resolved_method->GetDeclaringClassUnchecked() != nullptr) << type; + DCHECK(method->GetDeclaringClassUnchecked() != nullptr) << type; } + StackHandleScope<1> hs(self); std::string hard_failure_msg; MethodVerifier::FailureData result = VerifyMethod(self, method_idx, @@ -255,39 +253,99 @@ FailureKind MethodVerifier::VerifyClass(Thread* self, dex_cache, class_loader, class_def, - method.GetCodeItem(), - resolved_method, - method.GetAccessFlags(), + it->GetMethodCodeItem(), + method, + it->GetMethodAccessFlags(), callbacks, allow_soft_failures, log_level, - /*need_precise_constants*/ false, + 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 += "\n"; + *error_string += "\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_string += "Verifier rejected class "; + *error_string += PrettyDescriptor(dex_file->GetClassDescriptor(class_def)); + *error_string += ":"; } - *error += " "; - *error += hard_failure_msg; + *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, + Handle<mirror::ClassLoader> class_loader, + const DexFile::ClassDef& class_def, + CompilerCallbacks* callbacks, + bool allow_soft_failures, + HardFailLogMode log_level, + std::string* error) { + SCOPED_TRACE << "VerifyClass " << PrettyDescriptor(dex_file->GetClassDescriptor(class_def)); + + // A class must not be abstract and final. + if ((class_def.access_flags_ & (kAccAbstract | kAccFinal)) == (kAccAbstract | kAccFinal)) { + *error = "Verifier rejected class "; + *error += PrettyDescriptor(dex_file->GetClassDescriptor(class_def)); + *error += ": class is abstract and final."; + return FailureKind::kHardFailure; } - if (failure_data.kind == FailureKind::kNoFailure) { + const uint8_t* class_data = dex_file->GetClassData(class_def); + if (class_data == nullptr) { + // empty class, probably a marker interface + return FailureKind::kNoFailure; + } + 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) { return FailureKind::kNoFailure; } else { - if ((failure_data.types & VERIFY_ERROR_LOCKING) != 0) { + if ((data1.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(accessor.GetDescriptor()).c_str()); + PrettyDescriptor(dex_file->GetClassDescriptor(class_def)).c_str()); if (!gPrintedDxMonitorText) { tmp = tmp + "\nCommon causes for lock verification issues are non-optimized dex code\n" "and incorrect proguard optimizations."; @@ -295,7 +353,7 @@ FailureKind MethodVerifier::VerifyClass(Thread* self, } LOG(WARNING) << tmp; } - return failure_data.kind; + return data1.kind; } } @@ -1866,11 +1924,15 @@ bool MethodVerifier::CodeFlowVerifyMethod() { 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); - ClassAccessor accessor(dex_file, *class_def); - for (const ClassAccessor::Field& field : accessor.GetInstanceFields()) { - if (field.IsFinal()) { - return field.GetIndex(); - } + 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(); + } + it.Next(); } return dex::kDexNoIndex; } diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h index c7368d7b39..b2adc62a97 100644 --- a/runtime/verifier/method_verifier.h +++ b/runtime/verifier/method_verifier.h @@ -275,6 +275,23 @@ class MethodVerifier { 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. * |