diff options
| author | 2018-05-22 16:49:41 +0000 | |
|---|---|---|
| committer | 2018-05-22 16:49:41 +0000 | |
| commit | 438918b2f37e11684fa1e80bbbfe3a8f657b79a9 (patch) | |
| tree | b77443efb26d5a18a5f5f7d853223dfb3c6ab919 | |
| parent | f31343f1eab771010b3f293366149d2524f30902 (diff) | |
| parent | c2b4db61e5d0d9ec40b87b9a051aa1ac15ed1294 (diff) | |
Merge "Add ClassAccessor"
| -rw-r--r-- | compiler/dex/dex_to_dex_decompiler_test.cc | 24 | ||||
| -rw-r--r-- | dexdump/dexdump.cc | 19 | ||||
| -rw-r--r-- | libdexfile/dex/class_accessor-inl.h | 104 | ||||
| -rw-r--r-- | libdexfile/dex/class_accessor.h | 131 | ||||
| -rw-r--r-- | tools/dexanalyze/dexanalyze_experiments.cc | 125 |
5 files changed, 309 insertions, 94 deletions
diff --git a/compiler/dex/dex_to_dex_decompiler_test.cc b/compiler/dex/dex_to_dex_decompiler_test.cc index 19b190093f..082e6091d2 100644 --- a/compiler/dex/dex_to_dex_decompiler_test.cc +++ b/compiler/dex/dex_to_dex_decompiler_test.cc @@ -20,6 +20,7 @@ #include "common_compiler_test.h" #include "compiled_method-inl.h" #include "compiler_callbacks.h" +#include "dex/class_accessor-inl.h" #include "dex/dex_file.h" #include "driver/compiler_driver.h" #include "driver/compiler_options.h" @@ -82,30 +83,21 @@ class DexToDexDecompilerTest : public CommonCompilerTest { // Unquicken the dex file. for (uint32_t i = 0; i < updated_dex_file->NumClassDefs(); ++i) { - const DexFile::ClassDef& class_def = updated_dex_file->GetClassDef(i); - const uint8_t* class_data = updated_dex_file->GetClassData(class_def); - if (class_data == nullptr) { - continue; - } - ClassDataItemIterator it(*updated_dex_file, class_data); - it.SkipAllFields(); - // Unquicken each method. - while (it.HasNextMethod()) { - uint32_t method_idx = it.GetMemberIndex(); - CompiledMethod* compiled_method = - compiler_driver_->GetCompiledMethod(MethodReference(updated_dex_file, method_idx)); + ClassAccessor accessor(*updated_dex_file, updated_dex_file->GetClassDef(i)); + accessor.VisitMethods([&](const ClassAccessor::Method& method) { + CompiledMethod* compiled_method = compiler_driver_->GetCompiledMethod( + MethodReference(updated_dex_file, + method.GetIndex())); ArrayRef<const uint8_t> table; if (compiled_method != nullptr) { table = compiled_method->GetVmapTable(); } optimizer::ArtDecompileDEX(*updated_dex_file, - *it.GetMethodCodeItem(), + *accessor.GetCodeItem(method), table, /* decompile_return_instruction */ true); - it.Next(); - } - DCHECK(!it.HasNext()); + }); } // Make sure after unquickening we go back to the same contents as the original dex file. diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc index e72d49e05f..f5a13f0920 100644 --- a/dexdump/dexdump.cc +++ b/dexdump/dexdump.cc @@ -45,6 +45,7 @@ #include "android-base/logging.h" #include "android-base/stringprintf.h" +#include "dex/class_accessor-inl.h" #include "dex/code_item_accessors-inl.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_exception_helpers.h" @@ -611,19 +612,11 @@ static void dumpClassDef(const DexFile* pDexFile, int idx) { pClassDef.class_data_off_, pClassDef.class_data_off_); // Fields and methods. - const u1* pEncodedData = pDexFile->GetClassData(pClassDef); - if (pEncodedData != nullptr) { - ClassDataItemIterator pClassData(*pDexFile, pEncodedData); - fprintf(gOutFile, "static_fields_size : %d\n", pClassData.NumStaticFields()); - fprintf(gOutFile, "instance_fields_size: %d\n", pClassData.NumInstanceFields()); - fprintf(gOutFile, "direct_methods_size : %d\n", pClassData.NumDirectMethods()); - fprintf(gOutFile, "virtual_methods_size: %d\n", pClassData.NumVirtualMethods()); - } else { - fprintf(gOutFile, "static_fields_size : 0\n"); - fprintf(gOutFile, "instance_fields_size: 0\n"); - fprintf(gOutFile, "direct_methods_size : 0\n"); - fprintf(gOutFile, "virtual_methods_size: 0\n"); - } + ClassAccessor accessor(*pDexFile, pClassDef); + fprintf(gOutFile, "static_fields_size : %d\n", accessor.NumStaticFields()); + fprintf(gOutFile, "instance_fields_size: %d\n", accessor.NumInstanceFields()); + fprintf(gOutFile, "direct_methods_size : %d\n", accessor.NumDirectMethods()); + fprintf(gOutFile, "virtual_methods_size: %d\n", accessor.NumVirtualMethods()); fprintf(gOutFile, "\n"); } diff --git a/libdexfile/dex/class_accessor-inl.h b/libdexfile/dex/class_accessor-inl.h new file mode 100644 index 0000000000..bcd0a7b66c --- /dev/null +++ b/libdexfile/dex/class_accessor-inl.h @@ -0,0 +1,104 @@ +/* + * 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_ACCESSOR_INL_H_ +#define ART_LIBDEXFILE_DEX_CLASS_ACCESSOR_INL_H_ + +#include "class_accessor.h" + +#include "base/leb128.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 DexFile& dex_file, const uint8_t* class_data) + : 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) {} + +inline const uint8_t* ClassAccessor::Method::Read(const uint8_t* ptr) { + method_idx_ += DecodeUnsignedLeb128(&ptr); + access_flags_ = DecodeUnsignedLeb128(&ptr); + code_off_ = DecodeUnsignedLeb128(&ptr); + return ptr; +} + +inline const uint8_t* ClassAccessor::Field::Read(const uint8_t* ptr) { + field_idx_ += DecodeUnsignedLeb128(&ptr); + access_flags_ = DecodeUnsignedLeb128(&ptr); + return ptr; +} + +template <typename StaticFieldVisitor, + typename InstanceFieldVisitor, + typename DirectMethodVisitor, + typename VirtualMethodVisitor> +inline void ClassAccessor::VisitMethodsAndFields( + const StaticFieldVisitor& static_field_visitor, + const InstanceFieldVisitor& instance_field_visitor, + 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_instance_fields_; ++i) { + Field data; + 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); + } + for (size_t i = 0; i < num_virtual_methods_; ++i) { + Method data; + ptr = data.Read(ptr); + virtual_method_visitor(data); + } +} + +template <typename DirectMethodVisitor, + typename VirtualMethodVisitor> +inline void ClassAccessor::VisitMethods(const DirectMethodVisitor& direct_method_visitor, + const VirtualMethodVisitor& virtual_method_visitor) const { + VisitMethodsAndFields(VoidFunctor(), + VoidFunctor(), + direct_method_visitor, + virtual_method_visitor); +} + +// Visit direct and virtual methods. +template <typename MethodVisitor> +inline void ClassAccessor::VisitMethods(const MethodVisitor& method_visitor) const { + VisitMethods(method_visitor, method_visitor); +} + +inline const DexFile::CodeItem* ClassAccessor::GetCodeItem(const Method& method) const { + return dex_file_.GetCodeItem(method.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 new file mode 100644 index 0000000000..59a6b5dfa5 --- /dev/null +++ b/libdexfile/dex/class_accessor.h @@ -0,0 +1,131 @@ +/* + * 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_ACCESSOR_H_ +#define ART_LIBDEXFILE_DEX_CLASS_ACCESSOR_H_ + +#include "base/utils.h" +#include "dex_file.h" + +namespace art { + +// Classes to access Dex data. +class ClassAccessor { + public: + // Class method data. + class Method { + public: + uint32_t GetIndex() const { + return method_idx_; + } + + uint32_t GetAccessFlags() const { + return access_flags_; + } + + uint32_t GetCodeItemOffset() const { + return code_off_; + } + + private: + const uint8_t* Read(const uint8_t* ptr); + + // A decoded version of the method of a class_data_item. + uint32_t method_idx_ = 0u; + uint32_t access_flags_ = 0u; + uint32_t code_off_ = 0u; + + friend class ClassAccessor; + }; + + // Class field data. + class Field { + public: + uint32_t GetIndex() const { + return field_idx_; + } + + uint32_t GetAccessFlags() const { + return access_flags_; + } + + private: + const uint8_t* Read(const uint8_t* ptr); + + // A decoded version of the field of a class_data_item. + uint32_t field_idx_ = 0u; + uint32_t access_flags_ = 0u; + + friend class ClassAccessor; + }; + + ALWAYS_INLINE 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; + + // Iterator data is not very iterator friendly, use visitors to get around this. + template <typename StaticFieldVisitor, + typename InstanceFieldVisitor, + typename DirectMethodVisitor, + typename VirtualMethodVisitor> + void VisitMethodsAndFields(const StaticFieldVisitor& static_field_visitor, + const InstanceFieldVisitor& instance_field_visitor, + const DirectMethodVisitor& direct_method_visitor, + const VirtualMethodVisitor& virtual_method_visitor) const; + + template <typename DirectMethodVisitor, + typename VirtualMethodVisitor> + void VisitMethods(const DirectMethodVisitor& direct_method_visitor, + const VirtualMethodVisitor& virtual_method_visitor) const; + + // Visit direct and virtual methods. + template <typename MethodVisitor> + void VisitMethods(const MethodVisitor& method_visitor) const; + + uint32_t NumStaticFields() const { + return num_static_fields_; + } + + uint32_t NumInstanceFields() const { + return num_instance_fields_; + } + + uint32_t NumDirectMethods() const { + return num_direct_methods_; + } + + uint32_t NumVirtualMethods() const { + return num_virtual_methods_; + } + + protected: + ALWAYS_INLINE ClassAccessor(const DexFile& dex_file, const uint8_t* class_data); + + const DexFile& dex_file_; + 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 + +#endif // ART_LIBDEXFILE_DEX_CLASS_ACCESSOR_H_ diff --git a/tools/dexanalyze/dexanalyze_experiments.cc b/tools/dexanalyze/dexanalyze_experiments.cc index adc515472d..f9bf45da4f 100644 --- a/tools/dexanalyze/dexanalyze_experiments.cc +++ b/tools/dexanalyze/dexanalyze_experiments.cc @@ -23,6 +23,7 @@ #include <vector> #include "android-base/stringprintf.h" +#include "dex/class_accessor-inl.h" #include "dex/code_item_accessors-inl.h" #include "dex/dex_instruction-inl.h" #include "dex/standard_dex_file.h" @@ -126,79 +127,73 @@ void CountDexIndices::ProcessDexFile(const DexFile& dex_file) { 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); - const uint8_t* class_data = dex_file.GetClassData(class_def); - if (class_data == nullptr) { - continue; - } - ClassDataItemIterator it(dex_file, class_data); - it.SkipAllFields(); + ClassAccessor accessor(dex_file, class_def); std::set<size_t> unique_method_ids; std::set<size_t> unique_string_ids; - while (it.HasNextMethod()) { - const DexFile::CodeItem* code_item = it.GetMethodCodeItem(); - if (code_item != nullptr) { - 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) { - switch (inst->Opcode()) { - case Instruction::CONST_STRING: { - const dex::StringIndex string_index(inst->VRegB_21c()); - unique_string_ids.insert(string_index.index_); - ++num_string_ids_from_code_; - break; - } - case Instruction::CONST_STRING_JUMBO: { - const dex::StringIndex string_index(inst->VRegB_31c()); - unique_string_ids.insert(string_index.index_); - ++num_string_ids_from_code_; - break; - } - // Invoke cases. - case Instruction::INVOKE_VIRTUAL: - 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_) { - ++same_class_virtual_; - } else { - ++other_class_virtual_; - unique_method_ids.insert(method_idx); - } - break; + 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) { + switch (inst->Opcode()) { + case Instruction::CONST_STRING: { + const dex::StringIndex string_index(inst->VRegB_21c()); + unique_string_ids.insert(string_index.index_); + ++num_string_ids_from_code_; + break; + } + case Instruction::CONST_STRING_JUMBO: { + const dex::StringIndex string_index(inst->VRegB_31c()); + unique_string_ids.insert(string_index.index_); + ++num_string_ids_from_code_; + break; + } + // Invoke cases. + case Instruction::INVOKE_VIRTUAL: + 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_) { + ++same_class_virtual_; + } else { + ++other_class_virtual_; + unique_method_ids.insert(method_idx); } - case Instruction::INVOKE_DIRECT: - 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_) { - ++same_class_direct_; - } else { - ++other_class_direct_; - unique_method_ids.insert(method_idx); - } - break; + break; + } + case Instruction::INVOKE_DIRECT: + 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_) { + ++same_class_direct_; + } else { + ++other_class_direct_; + unique_method_ids.insert(method_idx); } - case Instruction::INVOKE_STATIC: - 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_) { - ++same_class_static_; - } else { - ++other_class_static_; - unique_method_ids.insert(method_idx); - } - break; + break; + } + case Instruction::INVOKE_STATIC: + 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_) { + ++same_class_static_; + } else { + ++other_class_static_; + unique_method_ids.insert(method_idx); } - default: - break; + break; } + default: + break; } } - it.Next(); - } - DCHECK(!it.HasNext()); + }); total_unique_method_idx_ += unique_method_ids.size(); total_unique_string_ids_ += unique_string_ids.size(); } |