Add ClassAccessor
Aims to replace ClassDataItemIterator with a cleaner and simpler
abstraction.
Bug: 77709234
Bug: 79758018
Test: test-art-host
Change-Id: I871a3e1cf213e0d81bfe4bb77790fbab2d13e44c
diff --git a/compiler/dex/dex_to_dex_decompiler_test.cc b/compiler/dex/dex_to_dex_decompiler_test.cc
index 19b1900..082e609 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 @@
// 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 e72d49e..f5a13f0 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 @@
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 0000000..bcd0a7b
--- /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 0000000..59a6b5d
--- /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 adc5154..f9bf45d 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 @@
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;
- }
- 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;
- }
- 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;
- }
- default:
- 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);
+ }
+ 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);
+ }
+ 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);
+ }
+ break;
+ }
+ default:
+ break;
}
}
- it.Next();
- }
- DCHECK(!it.HasNext());
+ });
total_unique_method_idx_ += unique_method_ids.size();
total_unique_string_ids_ += unique_string_ids.size();
}