Add ClassIterator
Add a way to iterate over all of the classes in a Dex file. The
iterator returns a ClassAccessor for each class.
Added DexFile::GetClasses to return an iteration range for this new
iterator type.
Sample usage:
for (ClassAccessor accessor : dex_file.GetClasses()) {
Bug: 79758018
Bug: 77709234
Test: test-art-host
Change-Id: I66e000aa11f433e72f6857496f4e89a0b811f5a2
diff --git a/libdexfile/dex/class_accessor-inl.h b/libdexfile/dex/class_accessor-inl.h
index bcd0a7b..5cfbcaa 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 @@
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 @@
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 59a6b5d..835c4e2 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 @@
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 @@
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 @@
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 0000000..477c93b
--- /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 ba7c126..5786d3f 100644
--- a/libdexfile/dex/code_item_accessors.h
+++ b/libdexfile/dex/code_item_accessors.h
@@ -47,6 +47,11 @@
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 e78e8d7..f5dd374 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 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 87d2c48..f1f8b50 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 @@
// 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;