summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Alex Light <allight@google.com> 2019-11-14 14:51:41 -0800
committer Treehugger Robot <treehugger-gerrit@google.com> 2019-11-15 19:17:23 +0000
commita9bbc08daad6d601c870c8493323f57b70373336 (patch)
tree8ca74373cac0fe52aced5f32cc6f6e1f9c3239b5
parent56f1332113c3b8b1844c04683b9cb9dc5a0bd346 (diff)
Implement STL iterators on ObjectArray and add helpers
Iterating over an ObjectArray is rather cumbersome, requiring manual for-loops. To improve ergonomics and STL standard-ness this implements std::iterator's for ObjectArray and converts code to use this (in simple situations). This should allow us to use standard STL functions in the future when dealing with ObjectArrays. Also adds some helpers such as ZipCount and ZipLeft. Test: ./test.py --host Change-Id: Ifd515b8321775424b3256a6faf47b2ba970177d3
-rw-r--r--libartbase/base/stl_util.h77
-rw-r--r--openjdkjvmti/ti_class.cc4
-rw-r--r--openjdkjvmti/ti_class_loader-inl.h4
-rw-r--r--openjdkjvmti/ti_field.cc4
-rw-r--r--openjdkjvmti/ti_heap.cc10
-rw-r--r--openjdkjvmti/ti_method.cc4
-rw-r--r--openjdkjvmti/ti_threadgroup.cc3
-rw-r--r--runtime/class_linker.cc30
-rw-r--r--runtime/class_loader_context.cc11
-rw-r--r--runtime/class_loader_utils.h4
-rw-r--r--runtime/handle.h21
-rw-r--r--runtime/mirror/object_array-inl.h44
-rw-r--r--runtime/mirror/object_array.h95
13 files changed, 268 insertions, 43 deletions
diff --git a/libartbase/base/stl_util.h b/libartbase/base/stl_util.h
index 1e071cee23..fbafd53e8e 100644
--- a/libartbase/base/stl_util.h
+++ b/libartbase/base/stl_util.h
@@ -18,10 +18,13 @@
#define ART_LIBARTBASE_BASE_STL_UTIL_H_
#include <algorithm>
+#include <iterator>
#include <sstream>
#include <android-base/logging.h>
+#include "base/iteration_range.h"
+
namespace art {
// STLDeleteContainerPointers()
@@ -146,6 +149,80 @@ static inline std::vector<T*> MakeNonOwningPointerVector(const std::vector<std::
return result;
}
+template <typename IterLeft, typename IterRight>
+class ZipLeftIter : public std::iterator<
+ std::forward_iterator_tag,
+ std::pair<typename IterLeft::value_type, typename IterRight::value_type>> {
+ public:
+ ZipLeftIter(IterLeft left, IterRight right) : left_iter_(left), right_iter_(right) {}
+ ZipLeftIter<IterLeft, IterRight>& operator++() {
+ ++left_iter_;
+ ++right_iter_;
+ return *this;
+ }
+ ZipLeftIter<IterLeft, IterRight> operator++(int) {
+ ZipLeftIter<IterLeft, IterRight> ret(left_iter_, right_iter_);
+ ++(*this);
+ return ret;
+ }
+ bool operator==(const ZipLeftIter<IterLeft, IterRight>& other) const {
+ return left_iter_ == other.left_iter_;
+ }
+ bool operator!=(const ZipLeftIter<IterLeft, IterRight>& other) const {
+ return !(*this == other);
+ }
+ std::pair<typename IterLeft::value_type, typename IterRight::value_type> operator*() const {
+ return std::make_pair(*left_iter_, *right_iter_);
+ }
+
+ private:
+ IterLeft left_iter_;
+ IterRight right_iter_;
+};
+
+class CountIter : public std::iterator<std::forward_iterator_tag, size_t, size_t, size_t, size_t> {
+ public:
+ CountIter() : count_(0) {}
+ explicit CountIter(size_t count) : count_(count) {}
+ CountIter& operator++() {
+ ++count_;
+ return *this;
+ }
+ CountIter operator++(int) {
+ size_t ret = count_;
+ ++count_;
+ return CountIter(ret);
+ }
+ bool operator==(const CountIter& other) const {
+ return count_ == other.count_;
+ }
+ bool operator!=(const CountIter& other) const {
+ return !(*this == other);
+ }
+ size_t operator*() const {
+ return count_;
+ }
+
+ private:
+ size_t count_;
+};
+
+// Make an iteration range that returns a pair of the element and the index of the element.
+template <typename Iter>
+static inline IterationRange<ZipLeftIter<Iter, CountIter>> ZipCount(IterationRange<Iter> iter) {
+ return IterationRange(ZipLeftIter(iter.begin(), CountIter(0)),
+ ZipLeftIter(iter.end(), CountIter(-1)));
+}
+
+// Make an iteration range that returns a pair of the outputs of two iterators. Stops when the first
+// (left) one is exhausted. The left iterator must be at least as long as the right one.
+template <typename IterLeft, typename IterRight>
+static inline IterationRange<ZipLeftIter<IterLeft, IterRight>> ZipLeft(
+ IterationRange<IterLeft> iter_left, IterationRange<IterRight> iter_right) {
+ return IterationRange(ZipLeftIter(iter_left.begin(), iter_right.begin()),
+ ZipLeftIter(iter_left.end(), iter_right.end()));
+}
+
} // namespace art
#endif // ART_LIBARTBASE_BASE_STL_UTIL_H_
diff --git a/openjdkjvmti/ti_class.cc b/openjdkjvmti/ti_class.cc
index 82ce916ccd..4d6b41a386 100644
--- a/openjdkjvmti/ti_class.cc
+++ b/openjdkjvmti/ti_class.cc
@@ -726,8 +726,8 @@ jvmtiError ClassUtil::GetClassSignature(jvmtiEnv* env,
art::annotations::GetSignatureAnnotationForClass(h_klass);
if (str_array != nullptr) {
std::ostringstream oss;
- for (int32_t i = 0; i != str_array->GetLength(); ++i) {
- oss << str_array->Get(i)->ToModifiedUtf8();
+ for (auto str : str_array->Iterate()) {
+ oss << str->ToModifiedUtf8();
}
std::string output_string = oss.str();
jvmtiError ret;
diff --git a/openjdkjvmti/ti_class_loader-inl.h b/openjdkjvmti/ti_class_loader-inl.h
index 9b04841eb3..29ea684779 100644
--- a/openjdkjvmti/ti_class_loader-inl.h
+++ b/openjdkjvmti/ti_class_loader-inl.h
@@ -57,10 +57,8 @@ inline void ClassLoaderHelper::VisitDexFileObjects(art::Thread* self,
return;
}
- size_t num_elements = dex_elements_list->GetLength();
// Iterate over the DexPathList$Element to find the right one
- for (size_t i = 0; i < num_elements; i++) {
- art::ObjPtr<art::mirror::Object> current_element = dex_elements_list->Get(i);
+ for (auto current_element : dex_elements_list.Iterate<art::mirror::Object>()) {
CHECK(!current_element.IsNull());
art::ObjPtr<art::mirror::Object> dex_file(element_dex_file_field->GetObject(current_element));
if (!dex_file.IsNull()) {
diff --git a/openjdkjvmti/ti_field.cc b/openjdkjvmti/ti_field.cc
index e5b96374b0..d4c0ec830b 100644
--- a/openjdkjvmti/ti_field.cc
+++ b/openjdkjvmti/ti_field.cc
@@ -176,8 +176,8 @@ jvmtiError FieldUtil::GetFieldName(jvmtiEnv* env,
art::annotations::GetSignatureAnnotationForField(art_field);
if (str_array != nullptr) {
std::ostringstream oss;
- for (int32_t i = 0; i != str_array->GetLength(); ++i) {
- oss << str_array->Get(i)->ToModifiedUtf8();
+ for (auto str : str_array->Iterate()) {
+ oss << str->ToModifiedUtf8();
}
std::string output_string = oss.str();
jvmtiError ret;
diff --git a/openjdkjvmti/ti_heap.cc b/openjdkjvmti/ti_heap.cc
index 702a1c462b..1d1839014a 100644
--- a/openjdkjvmti/ti_heap.cc
+++ b/openjdkjvmti/ti_heap.cc
@@ -1166,16 +1166,14 @@ class FollowReferencesHelper final {
if (array->IsObjectArray()) {
art::ObjPtr<art::mirror::ObjectArray<art::mirror::Object>> obj_array =
array->AsObjectArray<art::mirror::Object>();
- int32_t length = obj_array->GetLength();
- for (int32_t i = 0; i != length; ++i) {
- art::ObjPtr<art::mirror::Object> elem = obj_array->GetWithoutChecks(i);
- if (elem != nullptr) {
+ for (auto elem_pair : art::ZipCount(obj_array->Iterate())) {
+ if (elem_pair.first != nullptr) {
jvmtiHeapReferenceInfo reference_info;
- reference_info.array.index = i;
+ reference_info.array.index = elem_pair.second;
stop_reports_ = !ReportReferenceMaybeEnqueue(JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT,
&reference_info,
array,
- elem.Ptr());
+ elem_pair.first.Ptr());
if (stop_reports_) {
break;
}
diff --git a/openjdkjvmti/ti_method.cc b/openjdkjvmti/ti_method.cc
index d36e2c9932..e7f071fac8 100644
--- a/openjdkjvmti/ti_method.cc
+++ b/openjdkjvmti/ti_method.cc
@@ -354,8 +354,8 @@ jvmtiError MethodUtil::GetMethodName(jvmtiEnv* env,
art::annotations::GetSignatureAnnotationForMethod(art_method);
if (str_array != nullptr) {
std::ostringstream oss;
- for (int32_t i = 0; i != str_array->GetLength(); ++i) {
- oss << str_array->Get(i)->ToModifiedUtf8();
+ for (auto str : str_array->Iterate()) {
+ oss << str->ToModifiedUtf8();
}
std::string output_string = oss.str();
jvmtiError ret;
diff --git a/openjdkjvmti/ti_threadgroup.cc b/openjdkjvmti/ti_threadgroup.cc
index f2e5c90c75..bc912cf6a5 100644
--- a/openjdkjvmti/ti_threadgroup.cc
+++ b/openjdkjvmti/ti_threadgroup.cc
@@ -207,8 +207,7 @@ static void GetChildThreadGroups(art::Handle<art::mirror::Object> thread_group,
groups_array->AsObjectArray<art::mirror::Object>();
// Copy all non-null elements.
- for (int32_t i = 0; i < groups_array_as_array->GetLength(); ++i) {
- art::ObjPtr<art::mirror::Object> entry = groups_array_as_array->Get(i);
+ for (auto entry : groups_array_as_array->Iterate()) {
if (entry != nullptr) {
thread_groups->push_back(entry);
}
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 04455847cd..b813117af0 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -113,6 +113,7 @@
#include "mirror/method_type.h"
#include "mirror/object-inl.h"
#include "mirror/object-refvisitor-inl.h"
+#include "mirror/object.h"
#include "mirror/object_array-alloc-inl.h"
#include "mirror/object_array-inl.h"
#include "mirror/object_reference.h"
@@ -1468,11 +1469,11 @@ static bool CompareClassLoaders(ScopedObjectAccessUnchecked& soa,
return false;
}
- for (int32_t i = 0; i < array1->GetLength(); ++i) {
+ for (auto clp : ZipLeft(array1->Iterate(), array2->Iterate())) {
// Do a full comparison of the class loaders, including comparing their dex files.
if (!CompareClassLoaders(soa,
- array1->Get(i),
- array2->Get(i),
+ clp.first,
+ clp.second,
/*check_dex_file_names=*/ true,
error_msg)) {
return false;
@@ -1774,9 +1775,7 @@ void AppImageLoadingHelper::Update(
{
// Register dex caches with the class loader.
WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
- const size_t num_dex_caches = dex_caches->GetLength();
- for (size_t i = 0; i < num_dex_caches; i++) {
- ObjPtr<mirror::DexCache> dex_cache = dex_caches->Get(i);
+ for (auto dex_cache : dex_caches.Iterate<mirror::DexCache>()) {
const DexFile* const dex_file = dex_cache->GetDexFile();
{
WriterMutexLock mu2(self, *Locks::dex_lock_);
@@ -1968,8 +1967,7 @@ bool ClassLinker::OpenImageDexFiles(gc::space::ImageSpace* space,
ObjPtr<mirror::ObjectArray<mirror::DexCache>> dex_caches =
dex_caches_object->AsObjectArray<mirror::DexCache>();
const OatFile* oat_file = space->GetOatFile();
- for (int32_t i = 0, length = dex_caches->GetLength(); i != length; ++i) {
- ObjPtr<mirror::DexCache> dex_cache = dex_caches->Get(i);
+ for (auto dex_cache : dex_caches->Iterate()) {
std::string dex_file_location(dex_cache->GetLocation()->ToModifiedUtf8());
std::unique_ptr<const DexFile> dex_file = OpenOatDexFile(oat_file,
dex_file_location.c_str(),
@@ -2158,8 +2156,7 @@ static void VerifyAppImage(const ImageHeader& header,
}
}
// Check that all non-primitive classes in dex caches are also in the class table.
- for (int32_t i = 0; i < dex_caches->GetLength(); i++) {
- ObjPtr<mirror::DexCache> dex_cache = dex_caches->Get(i);
+ for (auto dex_cache : dex_caches.ConstIterate<mirror::DexCache>()) {
mirror::TypeDexCacheType* const types = dex_cache->GetResolvedTypes();
for (int32_t j = 0, num_types = dex_cache->NumResolvedTypes(); j < num_types; j++) {
ObjPtr<mirror::Class> klass = types[j].load(std::memory_order_relaxed).object.Read();
@@ -2233,8 +2230,7 @@ bool ClassLinker::AddImageSpace(
return false;
}
- for (int32_t i = 0; i < dex_caches->GetLength(); i++) {
- ObjPtr<mirror::DexCache> dex_cache = dex_caches->Get(i);
+ for (auto dex_cache : dex_caches.Iterate<mirror::DexCache>()) {
std::string dex_file_location = dex_cache->GetLocation()->ToModifiedUtf8();
if (class_loader == nullptr) {
// For app images, we'll see the relative location. b/130666977.
@@ -2292,8 +2288,7 @@ bool ClassLinker::AddImageSpace(
// comparisons for their shared libraries and parent.
auto elements = soa.Decode<mirror::ObjectArray<mirror::Object>>(dex_elements);
std::list<ObjPtr<mirror::String>> loader_dex_file_names;
- for (size_t i = 0, num_elems = elements->GetLength(); i < num_elems; ++i) {
- ObjPtr<mirror::Object> element = elements->GetWithoutChecks(i);
+ for (auto element : elements->Iterate()) {
if (element != nullptr) {
// If we are somewhere in the middle of the array, there may be nulls at the end.
ObjPtr<mirror::String> name;
@@ -2329,8 +2324,7 @@ bool ClassLinker::AddImageSpace(
}
if (kSanityCheckObjects) {
- for (int32_t i = 0; i < dex_caches->GetLength(); i++) {
- ObjPtr<mirror::DexCache> dex_cache = dex_caches->Get(i);
+ for (auto dex_cache : dex_caches.Iterate<mirror::DexCache>()) {
for (size_t j = 0; j < dex_cache->NumResolvedFields(); ++j) {
auto* field = dex_cache->GetResolvedField(j, image_pointer_size_);
if (field != nullptr) {
@@ -2983,8 +2977,8 @@ bool ClassLinker::FindClassInSharedLibraries(ScopedObjectAccessAlreadyRunnable&
Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries(
hs.NewHandle(raw_shared_libraries->AsObjectArray<mirror::ClassLoader>()));
MutableHandle<mirror::ClassLoader> temp_loader = hs.NewHandle<mirror::ClassLoader>(nullptr);
- for (int32_t i = 0; i < shared_libraries->GetLength(); ++i) {
- temp_loader.Assign(shared_libraries->Get(i));
+ for (auto loader : shared_libraries.Iterate<mirror::ClassLoader>()) {
+ temp_loader.Assign(loader);
if (!FindClassInBaseDexClassLoader(soa, self, descriptor, hash, temp_loader, result)) {
return false; // One of the shared libraries is not supported.
}
diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc
index 7b571aab8e..b5b156e064 100644
--- a/runtime/class_loader_context.cc
+++ b/runtime/class_loader_context.cc
@@ -33,6 +33,7 @@
#include "handle_scope-inl.h"
#include "jni/jni_internal.h"
#include "mirror/class_loader-inl.h"
+#include "mirror/object.h"
#include "mirror/object_array-alloc-inl.h"
#include "nativehelper/scoped_local_ref.h"
#include "oat_file_assistant.h"
@@ -940,8 +941,7 @@ static bool CollectDexFilesFromSupportedClassLoader(ScopedObjectAccessAlreadyRun
StackHandleScope<1> hs(soa.Self());
Handle<mirror::ObjectArray<mirror::Object>> dex_elements(
hs.NewHandle(dex_elements_obj->AsObjectArray<mirror::Object>()));
- for (int32_t i = 0; i < dex_elements->GetLength(); ++i) {
- ObjPtr<mirror::Object> element = dex_elements->GetWithoutChecks(i);
+ for (auto element : dex_elements.Iterate<mirror::Object>()) {
if (element == nullptr) {
// Should never happen, log an error and break.
// TODO(calin): It's unclear if we should just assert here.
@@ -975,8 +975,7 @@ static bool GetDexFilesFromDexElementsArray(
const ObjPtr<mirror::Class> dexfile_class = soa.Decode<mirror::Class>(
WellKnownClasses::dalvik_system_DexFile);
- for (int32_t i = 0; i < dex_elements->GetLength(); ++i) {
- ObjPtr<mirror::Object> element = dex_elements->GetWithoutChecks(i);
+ for (auto element : dex_elements.Iterate<mirror::Object>()) {
// We can hit a null element here because this is invoked with a partially filled dex_elements
// array from DexPathList. DexPathList will open each dex sequentially, each time passing the
// list of dex files which were opened before.
@@ -1086,8 +1085,8 @@ bool ClassLoaderContext::CreateInfoFromClassLoader(
Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries =
hs.NewHandle(raw_shared_libraries->AsObjectArray<mirror::ClassLoader>());
MutableHandle<mirror::ClassLoader> temp_loader = hs.NewHandle<mirror::ClassLoader>(nullptr);
- for (int32_t i = 0; i < shared_libraries->GetLength(); ++i) {
- temp_loader.Assign(shared_libraries->Get(i));
+ for (auto library : shared_libraries.Iterate<mirror::ClassLoader>()) {
+ temp_loader.Assign(library);
if (!CreateInfoFromClassLoader(
soa, temp_loader, null_dex_elements, info, /*is_shared_library=*/ true)) {
return false;
diff --git a/runtime/class_loader_utils.h b/runtime/class_loader_utils.h
index 2e8504391a..1c353604fa 100644
--- a/runtime/class_loader_utils.h
+++ b/runtime/class_loader_utils.h
@@ -23,6 +23,7 @@
#include "jni/jni_internal.h"
#include "mirror/class_loader.h"
#include "mirror/object-inl.h"
+#include "mirror/object.h"
#include "native/dalvik_system_DexFile.h"
#include "scoped_thread_state_change-inl.h"
#include "well_known_classes.h"
@@ -86,8 +87,7 @@ inline RetType VisitClassLoaderDexElements(ScopedObjectAccessAlreadyRunnable& so
StackHandleScope<1> hs(self);
Handle<mirror::ObjectArray<mirror::Object>> dex_elements =
hs.NewHandle(dex_elements_obj->AsObjectArray<mirror::Object>());
- for (int32_t i = 0; i < dex_elements->GetLength(); ++i) {
- ObjPtr<mirror::Object> element = dex_elements->GetWithoutChecks(i);
+ for (auto element : dex_elements.Iterate<mirror::Object>()) {
if (element == nullptr) {
// Should never happen, fail.
break;
diff --git a/runtime/handle.h b/runtime/handle.h
index f6ed17321f..6de4e88c2f 100644
--- a/runtime/handle.h
+++ b/runtime/handle.h
@@ -32,6 +32,14 @@ namespace art {
class Thread;
template<class T> class Handle;
+template<typename T> class IterationRange;
+
+namespace mirror {
+template<typename T> class ObjectArray;
+template<typename T, typename C> class ArrayIter;
+template<typename T> using HandleArrayIter = ArrayIter<T, Handle<ObjectArray<T>>>;
+template<typename T> using ConstHandleArrayIter = ArrayIter<T, const Handle<ObjectArray<T>>>;
+} // namespace mirror
// Handles are memory locations that contain GC roots. As the mirror::Object*s within a handle are
// GC visible then the GC may move the references within them, something that couldn't be done with
@@ -67,6 +75,19 @@ class Handle : public ValueObject {
return down_cast<T*>(reference_->AsMirrorPtr());
}
+ template <typename Type,
+ typename = typename std::enable_if_t<std::is_same_v<mirror::ObjectArray<Type>, T>>>
+ ALWAYS_INLINE IterationRange<mirror::ConstHandleArrayIter<Type>> ConstIterate() const
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ return T::ConstIterate(*this);
+ }
+ template <typename Type,
+ typename = typename std::enable_if_t<std::is_same_v<mirror::ObjectArray<Type>, T>>>
+ ALWAYS_INLINE IterationRange<mirror::HandleArrayIter<Type>> Iterate()
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ return T::Iterate(*this);
+ }
+
ALWAYS_INLINE bool IsNull() const {
// It's safe to null-check it without a read barrier.
return reference_->IsNull();
diff --git a/runtime/mirror/object_array-inl.h b/runtime/mirror/object_array-inl.h
index 154302e0e8..57bd191ce2 100644
--- a/runtime/mirror/object_array-inl.h
+++ b/runtime/mirror/object_array-inl.h
@@ -17,6 +17,7 @@
#ifndef ART_RUNTIME_MIRROR_OBJECT_ARRAY_INL_H_
#define ART_RUNTIME_MIRROR_OBJECT_ARRAY_INL_H_
+#include "base/globals.h"
#include "object_array.h"
#include <string>
@@ -330,6 +331,49 @@ inline void ObjectArray<T>::VisitReferences(const Visitor& visitor) {
}
}
+template <class T>
+inline ConstObjPtrArrayIter<T> ObjectArray<T>::cbegin() const {
+ return ConstObjPtrArrayIter<T>(this, 0);
+}
+template <class T>
+inline ConstObjPtrArrayIter<T> ObjectArray<T>::cend() const {
+ return ConstObjPtrArrayIter<T>(this, GetLength());
+}
+template <class T>
+inline ConstHandleArrayIter<T> ObjectArray<T>::cbegin(const Handle<ObjectArray<T>>& h_this) {
+ return ConstHandleArrayIter<T>(h_this, 0);
+}
+template <class T>
+inline ConstHandleArrayIter<T> ObjectArray<T>::cend(const Handle<ObjectArray<T>>& h_this) {
+ return ConstHandleArrayIter<T>(h_this, h_this->GetLength());
+}
+
+template <class T>
+inline ObjPtrArrayIter<T> ObjectArray<T>::begin() {
+ return ObjPtrArrayIter<T>(this, 0);
+}
+template <class T>
+inline ObjPtrArrayIter<T> ObjectArray<T>::end() {
+ return ObjPtrArrayIter<T>(this, GetLength());
+}
+template <class T>
+inline HandleArrayIter<T> ObjectArray<T>::begin(Handle<ObjectArray<T>>& h_this) {
+ return HandleArrayIter<T>(h_this, 0);
+}
+template <class T>
+inline HandleArrayIter<T> ObjectArray<T>::end(Handle<ObjectArray<T>>& h_this) {
+ return HandleArrayIter<T>(h_this, h_this->GetLength());
+}
+
+template<typename T, typename C>
+inline void ArrayIter<T, C>::CheckIdx() const {
+ if (kIsDebugBuild) {
+ Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
+ }
+ DCHECK_LE(0, idx_);
+ DCHECK_LE(idx_, array_->GetLength());
+}
+
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/object_array.h b/runtime/mirror/object_array.h
index 7f43cd2393..20362b2ffc 100644
--- a/runtime/mirror/object_array.h
+++ b/runtime/mirror/object_array.h
@@ -17,12 +17,20 @@
#ifndef ART_RUNTIME_MIRROR_OBJECT_ARRAY_H_
#define ART_RUNTIME_MIRROR_OBJECT_ARRAY_H_
+#include <iterator>
#include "array.h"
+#include "base/iteration_range.h"
#include "obj_ptr.h"
namespace art {
namespace mirror {
+template<typename T, typename Container> class ArrayIter;
+template <typename T> using ConstObjPtrArrayIter = ArrayIter<T, const ObjPtr<ObjectArray<T>>>;
+template <typename T> using ConstHandleArrayIter = ArrayIter<T, const Handle<ObjectArray<T>>>;
+template <typename T> using ObjPtrArrayIter = ArrayIter<T, ObjPtr<ObjectArray<T>>>;
+template <typename T> using HandleArrayIter = ArrayIter<T, Handle<ObjectArray<T>>>;
+
template<class T>
class MANAGED ObjectArray: public Array {
public:
@@ -107,6 +115,34 @@ class MANAGED ObjectArray: public Array {
static MemberOffset OffsetOfElement(int32_t i);
+ inline ConstObjPtrArrayIter<T> cbegin() const REQUIRES_SHARED(Locks::mutator_lock_);
+ inline ConstObjPtrArrayIter<T> cend() const REQUIRES_SHARED(Locks::mutator_lock_);
+ inline IterationRange<ConstObjPtrArrayIter<T>> ConstIterate() const REQUIRES_SHARED(Locks::mutator_lock_) {
+ return IterationRange(cbegin(), cend());
+ }
+ inline ObjPtrArrayIter<T> begin() REQUIRES_SHARED(Locks::mutator_lock_);
+ inline ObjPtrArrayIter<T> end() REQUIRES_SHARED(Locks::mutator_lock_);
+ inline IterationRange<ObjPtrArrayIter<T>> Iterate() REQUIRES_SHARED(Locks::mutator_lock_) {
+ return IterationRange(begin(), end());
+ }
+
+ static inline ConstHandleArrayIter<T> cbegin(const Handle<ObjectArray<T>>& h_this)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+ static inline ConstHandleArrayIter<T> cend(const Handle<ObjectArray<T>>& h_this)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+ static inline IterationRange<ConstHandleArrayIter<T>> ConstIterate(
+ const Handle<ObjectArray<T>>& h_this) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return IterationRange(cbegin(h_this), cend(h_this));
+ }
+ static inline HandleArrayIter<T> begin(Handle<ObjectArray<T>>& h_this)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+ static inline HandleArrayIter<T> end(Handle<ObjectArray<T>>& h_this)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+ static inline IterationRange<HandleArrayIter<T>> Iterate(Handle<ObjectArray<T>>& h_this)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ return IterationRange(begin(h_this), end(h_this));
+ }
+
private:
// TODO fix thread safety analysis broken by the use of template. This should be
// REQUIRES_SHARED(Locks::mutator_lock_).
@@ -117,6 +153,65 @@ class MANAGED ObjectArray: public Array {
DISALLOW_IMPLICIT_CONSTRUCTORS(ObjectArray);
};
+// Everything is NO_THREAD_SAFETY_ANALYSIS to work-around STL incompat with thread-annotations.
+// Everything should have REQUIRES_SHARED(Locks::mutator_lock_).
+template <typename T, typename Container>
+class ArrayIter : public std::iterator<std::forward_iterator_tag, ObjPtr<T>> {
+ private:
+ using Iter = ArrayIter<T, Container>;
+
+ public:
+ ArrayIter(Container array, int32_t idx) NO_THREAD_SAFETY_ANALYSIS : array_(array), idx_(idx) {
+ CheckIdx();
+ }
+
+ ArrayIter(const Iter& other) = default; // NOLINT(runtime/explicit)
+ Iter& operator=(const Iter& other) = default;
+
+ bool operator!=(const Iter& other) const NO_THREAD_SAFETY_ANALYSIS {
+ CheckIdx();
+ return !(*this == other);
+ }
+ bool operator==(const Iter& other) const NO_THREAD_SAFETY_ANALYSIS {
+ return Ptr(other.array_) == Ptr(array_) && other.idx_ == idx_;
+ }
+ Iter& operator++() NO_THREAD_SAFETY_ANALYSIS {
+ idx_++;
+ CheckIdx();
+ return *this;
+ }
+ Iter operator++(int) const NO_THREAD_SAFETY_ANALYSIS {
+ Iter res(this);
+ idx_++;
+ CheckIdx();
+ return res;
+ }
+ ObjPtr<T> operator->() const NO_THREAD_SAFETY_ANALYSIS {
+ CheckIdx();
+ return array_->GetWithoutChecks(idx_);
+ }
+ ObjPtr<T> operator*() const NO_THREAD_SAFETY_ANALYSIS {
+ CheckIdx();
+ return array_->GetWithoutChecks(idx_);
+ }
+
+ private:
+ // Checks current index and that locks are properly held.
+ void CheckIdx() const REQUIRES_SHARED(Locks::mutator_lock_);
+
+ static ObjectArray<T>* Ptr(const Handle<ObjectArray<T>>& p)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ return p.Get();
+ }
+ static ObjectArray<T>* Ptr(const ObjPtr<ObjectArray<T>>& p)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ return p.Ptr();
+ }
+
+ Container array_;
+ int32_t idx_;
+};
+
} // namespace mirror
} // namespace art