diff options
-rw-r--r-- | libdexfile/dex/class_accessor-inl.h | 59 | ||||
-rw-r--r-- | libdexfile/dex/class_accessor.h | 24 | ||||
-rw-r--r-- | libdexfile/dex/class_iterator.h | 101 | ||||
-rw-r--r-- | libdexfile/dex/code_item_accessors.h | 5 | ||||
-rw-r--r-- | libdexfile/dex/dex_file-inl.h | 5 | ||||
-rw-r--r-- | libdexfile/dex/dex_file.h | 3 | ||||
-rw-r--r-- | tools/dexanalyze/dexanalyze_experiments.cc | 21 |
7 files changed, 176 insertions, 42 deletions
diff --git a/libdexfile/dex/class_accessor-inl.h b/libdexfile/dex/class_accessor-inl.h index bcd0a7b66c..5cfbcaa359 100644 --- a/libdexfile/dex/class_accessor-inl.h +++ b/libdexfile/dex/class_accessor-inl.h @@ -20,19 +20,22 @@ #include "class_accessor.h" #include "base/leb128.h" +#include "class_iterator.h" +#include "code_item_accessors-inl.h" namespace art { -inline ClassAccessor::ClassAccessor(const DexFile& dex_file, const DexFile::ClassDef& class_def) - : ClassAccessor(dex_file, dex_file.GetClassData(class_def)) {} +inline ClassAccessor::ClassAccessor(const ClassIteratorData& data) + : ClassAccessor(data.dex_file_, data.dex_file_.GetClassDef(data.class_def_idx_)) {} -inline ClassAccessor::ClassAccessor(const DexFile& dex_file, const uint8_t* class_data) +inline ClassAccessor::ClassAccessor(const DexFile& dex_file, const DexFile::ClassDef& class_def) : dex_file_(dex_file), - ptr_pos_(class_data), - num_static_fields_(class_data != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u), - num_instance_fields_(class_data != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u), - num_direct_methods_(class_data != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u), - num_virtual_methods_(class_data != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u) {} + descriptor_index_(class_def.class_idx_), + ptr_pos_(dex_file.GetClassData(class_def)), + num_static_fields_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u), + num_instance_fields_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u), + 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) { method_idx_ += DecodeUnsignedLeb128(&ptr); @@ -57,25 +60,33 @@ inline void ClassAccessor::VisitMethodsAndFields( const DirectMethodVisitor& direct_method_visitor, const VirtualMethodVisitor& virtual_method_visitor) const { const uint8_t* ptr = ptr_pos_; - for (size_t i = 0; i < num_static_fields_; ++i) { + { Field data; - ptr = data.Read(ptr); - static_field_visitor(data); + for (size_t i = 0; i < num_static_fields_; ++i) { + ptr = data.Read(ptr); + static_field_visitor(data); + } } - for (size_t i = 0; i < num_instance_fields_; ++i) { + { Field data; - ptr = data.Read(ptr); - instance_field_visitor(data); + for (size_t i = 0; i < num_instance_fields_; ++i) { + ptr = data.Read(ptr); + instance_field_visitor(data); + } } - for (size_t i = 0; i < num_direct_methods_; ++i) { - Method data; - ptr = data.Read(ptr); - direct_method_visitor(data); + { + Method data(dex_file_); + for (size_t i = 0; i < num_direct_methods_; ++i) { + ptr = data.Read(ptr); + direct_method_visitor(data); + } } - for (size_t i = 0; i < num_virtual_methods_; ++i) { - Method data; - ptr = data.Read(ptr); - virtual_method_visitor(data); + { + Method data(dex_file_); + for (size_t i = 0; i < num_virtual_methods_; ++i) { + ptr = data.Read(ptr); + virtual_method_visitor(data); + } } } @@ -99,6 +110,10 @@ inline const DexFile::CodeItem* ClassAccessor::GetCodeItem(const Method& method) return dex_file_.GetCodeItem(method.GetCodeItemOffset()); } +inline CodeItemInstructionAccessor ClassAccessor::Method::GetInstructions() const { + return CodeItemInstructionAccessor(dex_file_, dex_file_.GetCodeItem(GetCodeItemOffset())); +} + } // namespace art #endif // ART_LIBDEXFILE_DEX_CLASS_ACCESSOR_INL_H_ diff --git a/libdexfile/dex/class_accessor.h b/libdexfile/dex/class_accessor.h index 59a6b5dfa5..835c4e2eb7 100644 --- a/libdexfile/dex/class_accessor.h +++ b/libdexfile/dex/class_accessor.h @@ -18,10 +18,13 @@ #define ART_LIBDEXFILE_DEX_CLASS_ACCESSOR_H_ #include "base/utils.h" +#include "code_item_accessors.h" #include "dex_file.h" namespace art { +class ClassIteratorData; + // Classes to access Dex data. class ClassAccessor { public: @@ -40,10 +43,15 @@ class ClassAccessor { return code_off_; } + CodeItemInstructionAccessor GetInstructions() const; + private: + explicit Method(const DexFile& dex_file) : dex_file_(dex_file) {} + const uint8_t* Read(const uint8_t* ptr); // A decoded version of the method of a class_data_item. + const DexFile& dex_file_; uint32_t method_idx_ = 0u; uint32_t access_flags_ = 0u; uint32_t code_off_ = 0u; @@ -72,7 +80,10 @@ class ClassAccessor { friend class ClassAccessor; }; - ALWAYS_INLINE ClassAccessor(const DexFile& dex_file, const DexFile::ClassDef& class_def); + // Not explicit specifically for range-based loops. + ALWAYS_INLINE ClassAccessor(const ClassIteratorData& data); + + ClassAccessor(const DexFile& dex_file, const DexFile::ClassDef& class_def); // Return the code item for a method. const DexFile::CodeItem* GetCodeItem(const Method& method) const; @@ -112,18 +123,19 @@ class ClassAccessor { return num_virtual_methods_; } - protected: - ALWAYS_INLINE ClassAccessor(const DexFile& dex_file, const uint8_t* class_data); + // TODO: Deprecate + dex::TypeIndex GetDescriptorIndex() const { + return descriptor_index_; + } + protected: const DexFile& dex_file_; + const dex::TypeIndex descriptor_index_ = {}; const uint8_t* ptr_pos_ = nullptr; // Pointer into stream of class_data_item. const uint32_t num_static_fields_ = 0u; const uint32_t num_instance_fields_ = 0u; const uint32_t num_direct_methods_ = 0u; const uint32_t num_virtual_methods_ = 0u; - // Only cache descriptor. - const void* class_def_ = nullptr; - const void* class_data_ = nullptr; }; } // namespace art diff --git a/libdexfile/dex/class_iterator.h b/libdexfile/dex/class_iterator.h new file mode 100644 index 0000000000..477c93b508 --- /dev/null +++ b/libdexfile/dex/class_iterator.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_LIBDEXFILE_DEX_CLASS_ITERATOR_H_ +#define ART_LIBDEXFILE_DEX_CLASS_ITERATOR_H_ + +#include "base/logging.h" + +namespace art { + +class ClassAccessor; +class ClassIterator; +class DexFile; + +// Holder class, used to construct ClassAccessors. +class ClassIteratorData { + public: + ClassIteratorData(const DexFile& dex_file, uint32_t class_def_idx) + : dex_file_(dex_file), + class_def_idx_(class_def_idx) {} + + private: + const DexFile& dex_file_; + uint32_t class_def_idx_ = 0u; + + friend class ClassAccessor; + friend class ClassIterator; +}; + +// Iterator for visiting classes in a Dex file. +class ClassIterator : public std::iterator<std::forward_iterator_tag, ClassIteratorData> { + public: + using value_type = std::iterator<std::forward_iterator_tag, ClassIteratorData>::value_type; + using difference_type = std::iterator<std::forward_iterator_tag, value_type>::difference_type; + + ClassIterator(const DexFile& dex_file, uint32_t class_def_idx) + : data_(dex_file, class_def_idx) {} + + // Value after modification. + ClassIterator& operator++() { + ++data_.class_def_idx_; + return *this; + } + + // Value before modification. + ClassIterator operator++(int) { + ClassIterator temp = *this; + ++*this; + return temp; + } + + const value_type& operator*() const { + return data_; + } + + bool operator==(const ClassIterator& rhs) const { + DCHECK_EQ(&data_.dex_file_, &rhs.data_.dex_file_) << "Comparing different dex files."; + return data_.class_def_idx_ == rhs.data_.class_def_idx_; + } + + bool operator!=(const ClassIterator& rhs) const { + return !(*this == rhs); + } + + bool operator<(const ClassIterator& rhs) const { + DCHECK_EQ(&data_.dex_file_, &rhs.data_.dex_file_) << "Comparing different dex files."; + return data_.class_def_idx_ < rhs.data_.class_def_idx_; + } + + bool operator>(const ClassIterator& rhs) const { + return rhs < *this; + } + + bool operator<=(const ClassIterator& rhs) const { + return !(rhs < *this); + } + + bool operator>=(const ClassIterator& rhs) const { + return !(*this < rhs); + } + + protected: + ClassIteratorData data_; +}; + +} // namespace art + +#endif // ART_LIBDEXFILE_DEX_CLASS_ITERATOR_H_ diff --git a/libdexfile/dex/code_item_accessors.h b/libdexfile/dex/code_item_accessors.h index ba7c126ed8..5786d3f611 100644 --- a/libdexfile/dex/code_item_accessors.h +++ b/libdexfile/dex/code_item_accessors.h @@ -47,6 +47,11 @@ class CodeItemInstructionAccessor { return insns_size_in_code_units_; } + uint32_t InsnsSizeInBytes() const { + static constexpr uint32_t kCodeUnitSizeInBytes = 2u; + return insns_size_in_code_units_ * kCodeUnitSizeInBytes; + } + const uint16_t* Insns() const { return insns_; } diff --git a/libdexfile/dex/dex_file-inl.h b/libdexfile/dex/dex_file-inl.h index e78e8d7a44..f5dd374253 100644 --- a/libdexfile/dex/dex_file-inl.h +++ b/libdexfile/dex/dex_file-inl.h @@ -20,6 +20,7 @@ #include "base/casts.h" #include "base/leb128.h" #include "base/stringpiece.h" +#include "class_iterator.h" #include "compact_dex_file.h" #include "dex_file.h" #include "invoke_type.h" @@ -527,6 +528,10 @@ inline void DexFile::ClassDef::VisitMethods(const DexFile* dex_file, const Visit } } +inline IterationRange<ClassIterator> DexFile::GetClasses() const { + return { ClassIterator(*this, 0u), ClassIterator(*this, NumClassDefs()) }; +} + } // namespace art #endif // ART_LIBDEXFILE_DEX_DEX_FILE_INL_H_ diff --git a/libdexfile/dex/dex_file.h b/libdexfile/dex/dex_file.h index 87d2c48ff1..f1f8b505bd 100644 --- a/libdexfile/dex/dex_file.h +++ b/libdexfile/dex/dex_file.h @@ -27,6 +27,7 @@ #include "base/iteration_range.h" #include "base/macros.h" #include "base/value_object.h" +#include "class_iterator.h" #include "dex_file_types.h" #include "dex_instruction_iterator.h" #include "hidden_api_access_flags.h" @@ -1012,6 +1013,8 @@ class DexFile { // 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; + protected: // First Dex format version supporting default methods. static const uint32_t kDefaultMethodsVersion = 37; diff --git a/tools/dexanalyze/dexanalyze_experiments.cc b/tools/dexanalyze/dexanalyze_experiments.cc index f9bf45da4f..427a465caf 100644 --- a/tools/dexanalyze/dexanalyze_experiments.cc +++ b/tools/dexanalyze/dexanalyze_experiments.cc @@ -24,6 +24,7 @@ #include "android-base/stringprintf.h" #include "dex/class_accessor-inl.h" +#include "dex/class_iterator.h" #include "dex/code_item_accessors-inl.h" #include "dex/dex_instruction-inl.h" #include "dex/standard_dex_file.h" @@ -125,20 +126,12 @@ void CountDexIndices::ProcessDexFile(const DexFile& dex_file) { num_field_ids_ += dex_file.NumFieldIds(); num_type_ids_ += dex_file.NumTypeIds(); num_class_defs_ += dex_file.NumClassDefs(); - 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); - ClassAccessor accessor(dex_file, class_def); + for (ClassAccessor accessor : dex_file.GetClasses()) { std::set<size_t> unique_method_ids; std::set<size_t> unique_string_ids; accessor.VisitMethods([&](const ClassAccessor::Method& method) { - const DexFile::CodeItem* code_item = accessor.GetCodeItem(method); - if (code_item == nullptr) { - return; - } - CodeItemInstructionAccessor instructions(dex_file, code_item); - const uint16_t* code_ptr = instructions.Insns(); - dex_code_bytes_ += instructions.InsnsSizeInCodeUnits() * sizeof(code_ptr[0]); - for (const DexInstructionPcPair& inst : instructions) { + dex_code_bytes_ += method.GetInstructions().InsnsSizeInBytes(); + for (const DexInstructionPcPair& inst : method.GetInstructions()) { switch (inst->Opcode()) { case Instruction::CONST_STRING: { const dex::StringIndex string_index(inst->VRegB_21c()); @@ -157,7 +150,7 @@ void CountDexIndices::ProcessDexFile(const DexFile& dex_file) { case Instruction::INVOKE_VIRTUAL_RANGE: { bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE); uint32_t method_idx = is_range ? inst->VRegB_3rc() : inst->VRegB_35c(); - if (dex_file.GetMethodId(method_idx).class_idx_ == class_def.class_idx_) { + if (dex_file.GetMethodId(method_idx).class_idx_ == accessor.GetDescriptorIndex()) { ++same_class_virtual_; } else { ++other_class_virtual_; @@ -169,7 +162,7 @@ void CountDexIndices::ProcessDexFile(const DexFile& dex_file) { case Instruction::INVOKE_DIRECT_RANGE: { bool is_range = (inst->Opcode() == Instruction::INVOKE_DIRECT_RANGE); uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c(); - if (dex_file.GetMethodId(method_idx).class_idx_ == class_def.class_idx_) { + if (dex_file.GetMethodId(method_idx).class_idx_ == accessor.GetDescriptorIndex()) { ++same_class_direct_; } else { ++other_class_direct_; @@ -181,7 +174,7 @@ void CountDexIndices::ProcessDexFile(const DexFile& dex_file) { case Instruction::INVOKE_STATIC_RANGE: { bool is_range = (inst->Opcode() == Instruction::INVOKE_STATIC_RANGE); uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c(); - if (dex_file.GetMethodId(method_idx).class_idx_ == class_def.class_idx_) { + if (dex_file.GetMethodId(method_idx).class_idx_ == accessor.GetDescriptorIndex()) { ++same_class_static_; } else { ++other_class_static_; |