summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Vladimir Marko <vmarko@google.com> 2018-01-03 15:47:24 +0000
committer Gerrit Code Review <noreply-gerritcodereview@google.com> 2018-01-03 15:47:24 +0000
commitb0ddceb337f614dc2600d19b82fb4a6596aa7d4c (patch)
treeed9d3cb8668c54b0274653de2bbd7c90b08fa3ea
parent00359cd27da40020e0a539515590fac3a46be1e4 (diff)
parent38b8b25b7deff92627586405c80182a19e7c18f9 (diff)
Merge changes Idd405a2c,I7052da55
* changes: ART: Faster type check bitstring initialization. Replace TypeStaticIf<> with std::conditional<> (C++11).
-rw-r--r--oatdump/oatdump.cc4
-rw-r--r--runtime/base/allocator.h9
-rw-r--r--runtime/base/type_static_if.h32
-rw-r--r--runtime/class_linker.cc12
-rw-r--r--runtime/subtype_check.h64
-rw-r--r--runtime/subtype_check_info.h5
-rw-r--r--runtime/subtype_check_test.cc6
7 files changed, 53 insertions, 79 deletions
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index b2e19a89d6..a97dd2a3dc 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -2375,10 +2375,10 @@ class ImageDumper {
PrettyObjectValue(os, value_class, value);
}
} else if (obj->IsClass()) {
- mirror::Class* klass = obj->AsClass();
+ ObjPtr<mirror::Class> klass = obj->AsClass();
os << "SUBTYPE_CHECK_BITS: ";
- SubtypeCheck<mirror::Class*>::Dump(klass, os);
+ SubtypeCheck<ObjPtr<mirror::Class>>::Dump(klass, os);
os << "\n";
if (klass->NumStaticFields() != 0) {
diff --git a/runtime/base/allocator.h b/runtime/base/allocator.h
index 99cdb49984..3cedb66abe 100644
--- a/runtime/base/allocator.h
+++ b/runtime/base/allocator.h
@@ -17,10 +17,11 @@
#ifndef ART_RUNTIME_BASE_ALLOCATOR_H_
#define ART_RUNTIME_BASE_ALLOCATOR_H_
+#include <type_traits>
+
#include "atomic.h"
#include "base/macros.h"
#include "base/mutex.h"
-#include "base/type_static_if.h"
namespace art {
@@ -147,9 +148,9 @@ class TrackingAllocatorImpl : public std::allocator<T> {
template<class T, AllocatorTag kTag>
// C++ doesn't allow template typedefs. This is a workaround template typedef which is
// TrackingAllocatorImpl<T> if kEnableTrackingAllocator is true, std::allocator<T> otherwise.
-using TrackingAllocator = typename TypeStaticIf<kEnableTrackingAllocator,
- TrackingAllocatorImpl<T, kTag>,
- std::allocator<T>>::type;
+using TrackingAllocator = typename std::conditional<kEnableTrackingAllocator,
+ TrackingAllocatorImpl<T, kTag>,
+ std::allocator<T>>::type;
} // namespace art
diff --git a/runtime/base/type_static_if.h b/runtime/base/type_static_if.h
deleted file mode 100644
index a74d79a665..0000000000
--- a/runtime/base/type_static_if.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2014 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_RUNTIME_BASE_TYPE_STATIC_IF_H_
-#define ART_RUNTIME_BASE_TYPE_STATIC_IF_H_
-
-// A static if which determines whether to return type A or B based on the condition boolean.
-template <bool condition, typename A, typename B>
-struct TypeStaticIf {
- typedef A type;
-};
-
-// Specialization to handle the false case.
-template <typename A, typename B>
-struct TypeStaticIf<false, A, B> {
- typedef B type;
-};
-
-#endif // ART_RUNTIME_BASE_TYPE_STATIC_IF_H_
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 192517fc5d..727dd14d6a 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -462,10 +462,8 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b
//
// We take the lock here to avoid using NO_THREAD_SAFETY_ANALYSIS.
MutexLock subtype_check_lock(Thread::Current(), *Locks::subtype_check_lock_);
- mirror::Class* java_lang_Object_ptr = java_lang_Object.Get();
- SubtypeCheck<mirror::Class*>::EnsureInitialized(java_lang_Object_ptr);
- mirror::Class* java_lang_Class_ptr = java_lang_Class.Get();
- SubtypeCheck<mirror::Class*>::EnsureInitialized(java_lang_Class_ptr);
+ SubtypeCheck<ObjPtr<mirror::Class>>::EnsureInitialized(java_lang_Object.Get());
+ SubtypeCheck<ObjPtr<mirror::Class>>::EnsureInitialized(java_lang_Class.Get());
}
// Object[] next to hold class roots.
@@ -1872,8 +1870,7 @@ bool ClassLinker::AddImageSpace(
ScopedTrace trace("Recalculate app image SubtypeCheck bitstrings");
MutexLock subtype_check_lock(Thread::Current(), *Locks::subtype_check_lock_);
for (const ClassTable::TableSlot& root : temp_set) {
- mirror::Class* root_klass = root.Read();
- SubtypeCheck<mirror::Class*>::EnsureInitialized(root_klass);
+ SubtypeCheck<ObjPtr<mirror::Class>>::EnsureInitialized(root.Read());
}
}
}
@@ -5220,8 +5217,7 @@ bool ClassLinker::EnsureInitialized(Thread* self,
// or Overflowed (can be used as a source for IsSubClass check).
{
MutexLock subtype_check_lock(Thread::Current(), *Locks::subtype_check_lock_);
- ObjPtr<mirror::Class> c_ptr(c.Get());
- SubtypeCheck<ObjPtr<mirror::Class>>::EnsureInitialized(c_ptr);
+ SubtypeCheck<ObjPtr<mirror::Class>>::EnsureInitialized(c.Get());
// TODO: Avoid taking subtype_check_lock_ if SubtypeCheck is already initialized.
}
const bool success = InitializeClass(self, c, can_init_fields, can_init_parents);
diff --git a/runtime/subtype_check.h b/runtime/subtype_check.h
index 1556abe67f..54d2f00106 100644
--- a/runtime/subtype_check.h
+++ b/runtime/subtype_check.h
@@ -216,12 +216,13 @@
* All node targets (in `src <: target`) get Assigned, and any parent of an Initialized
* node also gets Assigned.
*/
-struct MockSubtypeCheck; // Forward declaration for testing.
namespace art {
-// This is class is using a template parameter to enable testability without losing performance.
-// KlassT is almost always `mirror::Class*` or `ObjPtr<mirror::Class>`.
-template <typename KlassT /* Pointer-like type to Class */>
+struct MockSubtypeCheck; // Forward declaration for testing.
+
+// This class is using a template parameter to enable testability without losing performance.
+// ClassPtr is almost always `mirror::Class*` or `ObjPtr<mirror::Class>`.
+template <typename ClassPtr /* Pointer-like type to Class */>
struct SubtypeCheck {
// Force this class's SubtypeCheckInfo state into at least Initialized.
// As a side-effect, all parent classes also become Assigned|Overflowed.
@@ -230,7 +231,7 @@ struct SubtypeCheck {
//
// Post-condition: State is >= Initialized.
// Returns: The precise SubtypeCheckInfo::State.
- static SubtypeCheckInfo::State EnsureInitialized(KlassT& klass)
+ static SubtypeCheckInfo::State EnsureInitialized(ClassPtr klass)
REQUIRES(Locks::subtype_check_lock_)
REQUIRES_SHARED(Locks::mutator_lock_) {
return InitializeOrAssign(klass, /*assign*/false).GetState();
@@ -243,7 +244,7 @@ struct SubtypeCheck {
//
// Post-condition: State is Assigned|Overflowed.
// Returns: The precise SubtypeCheckInfo::State.
- static SubtypeCheckInfo::State EnsureAssigned(KlassT& klass)
+ static SubtypeCheckInfo::State EnsureAssigned(ClassPtr klass)
REQUIRES(Locks::subtype_check_lock_)
REQUIRES_SHARED(Locks::mutator_lock_) {
return InitializeOrAssign(klass, /*assign*/true).GetState();
@@ -258,7 +259,7 @@ struct SubtypeCheck {
// Cost: O(1).
//
// Returns: A state that is always Uninitialized.
- static SubtypeCheckInfo::State ForceUninitialize(KlassT& klass)
+ static SubtypeCheckInfo::State ForceUninitialize(ClassPtr klass)
REQUIRES(Locks::subtype_check_lock_)
REQUIRES_SHARED(Locks::mutator_lock_) {
// Trying to do this in a real runtime will break thread safety invariants
@@ -288,7 +289,7 @@ struct SubtypeCheck {
// Cost: O(Depth(Class)).
//
// Returns the encoded_src value. Must be >= Initialized (EnsureInitialized).
- static BitString::StorageType GetEncodedPathToRootForSource(const KlassT& klass)
+ static BitString::StorageType GetEncodedPathToRootForSource(ClassPtr klass)
REQUIRES(Locks::subtype_check_lock_)
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK_NE(SubtypeCheckInfo::kUninitialized, GetSubtypeCheckInfo(klass).GetState());
@@ -301,7 +302,7 @@ struct SubtypeCheck {
// Cost: O(Depth(Class)).
//
// Returns the encoded_target value. Must be Assigned (EnsureAssigned).
- static BitString::StorageType GetEncodedPathToRootForTarget(const KlassT& klass)
+ static BitString::StorageType GetEncodedPathToRootForTarget(ClassPtr klass)
REQUIRES(Locks::subtype_check_lock_)
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK_EQ(SubtypeCheckInfo::kAssigned, GetSubtypeCheckInfo(klass).GetState());
@@ -314,7 +315,7 @@ struct SubtypeCheck {
// Cost: O(Depth(Class)).
//
// Returns the mask_target value. Must be Assigned (EnsureAssigned).
- static BitString::StorageType GetEncodedPathToRootMask(const KlassT& klass)
+ static BitString::StorageType GetEncodedPathToRootMask(ClassPtr klass)
REQUIRES(Locks::subtype_check_lock_)
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK_EQ(SubtypeCheckInfo::kAssigned, GetSubtypeCheckInfo(klass).GetState());
@@ -333,7 +334,7 @@ struct SubtypeCheck {
// Runtime cost: O(Depth(Class)), but would be O(1) if depth was known.
//
// If the result is known, return kSubtypeOf or kNotSubtypeOf.
- static SubtypeCheckInfo::Result IsSubtypeOf(const KlassT& source, const KlassT& target)
+ static SubtypeCheckInfo::Result IsSubtypeOf(ClassPtr source, ClassPtr target)
REQUIRES_SHARED(Locks::mutator_lock_) {
SubtypeCheckInfo sci = GetSubtypeCheckInfo(source);
SubtypeCheckInfo target_sci = GetSubtypeCheckInfo(target);
@@ -342,24 +343,24 @@ struct SubtypeCheck {
}
// Print SubtypeCheck bitstring and overflow to a stream (e.g. for oatdump).
- static std::ostream& Dump(const KlassT& klass, std::ostream& os)
+ static std::ostream& Dump(ClassPtr klass, std::ostream& os)
REQUIRES_SHARED(Locks::mutator_lock_) {
return os << GetSubtypeCheckInfo(klass);
}
- static void WriteStatus(const KlassT& klass, ClassStatus status)
+ static void WriteStatus(ClassPtr klass, ClassStatus status)
REQUIRES_SHARED(Locks::mutator_lock_) {
WriteStatusImpl(klass, status);
}
private:
- static KlassT GetParentClass(const KlassT& klass)
+ static ClassPtr GetParentClass(ClassPtr klass)
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(klass->HasSuperClass());
- return KlassT(klass->GetSuperClass());
+ return ClassPtr(klass->GetSuperClass());
}
- static SubtypeCheckInfo InitializeOrAssign(KlassT& klass, bool assign)
+ static SubtypeCheckInfo InitializeOrAssign(ClassPtr klass, bool assign)
REQUIRES(Locks::subtype_check_lock_)
REQUIRES_SHARED(Locks::mutator_lock_) {
if (UNLIKELY(!klass->HasSuperClass())) {
@@ -380,8 +381,8 @@ struct SubtypeCheck {
}
// Force all ancestors to Assigned | Overflowed.
- KlassT parent_klass = GetParentClass(klass);
- EnsureAssigned(parent_klass);
+ ClassPtr parent_klass = GetParentClass(klass);
+ size_t parent_depth = InitializeOrAssign(parent_klass, /*assign*/true).GetDepth();
if (kIsDebugBuild) {
SubtypeCheckInfo::State parent_state = GetSubtypeCheckInfo(parent_klass).GetState();
DCHECK(parent_state == SubtypeCheckInfo::kAssigned ||
@@ -390,8 +391,8 @@ struct SubtypeCheck {
}
// Read.
- SubtypeCheckInfo sci = GetSubtypeCheckInfo(klass);
- SubtypeCheckInfo parent_sci = GetSubtypeCheckInfo(parent_klass);
+ SubtypeCheckInfo sci = GetSubtypeCheckInfo(klass, parent_depth + 1u);
+ SubtypeCheckInfo parent_sci = GetSubtypeCheckInfo(parent_klass, parent_depth);
// Modify.
const SubtypeCheckInfo::State sci_state = sci.GetState();
@@ -426,7 +427,7 @@ struct SubtypeCheck {
return sci;
}
- static SubtypeCheckBitsAndStatus ReadField(const KlassT& klass)
+ static SubtypeCheckBitsAndStatus ReadField(ClassPtr klass)
REQUIRES_SHARED(Locks::mutator_lock_) {
SubtypeCheckBitsAndStatus current_bits_and_status;
@@ -441,7 +442,7 @@ struct SubtypeCheck {
return current_bits_and_status;
}
- static void WriteSubtypeCheckBits(const KlassT& klass, const SubtypeCheckBits& new_bits)
+ static void WriteSubtypeCheckBits(ClassPtr klass, const SubtypeCheckBits& new_bits)
REQUIRES(Locks::subtype_check_lock_)
REQUIRES_SHARED(Locks::mutator_lock_) {
// Use a "CAS" to write the SubtypeCheckBits in the class.
@@ -490,7 +491,7 @@ struct SubtypeCheck {
}
}
- static void WriteStatusImpl(const KlassT& klass, ClassStatus status)
+ static void WriteStatusImpl(ClassPtr klass, ClassStatus status)
REQUIRES_SHARED(Locks::mutator_lock_) {
// Despite not having a lock annotation, this is done with mutual exclusion.
// See Class::SetStatus for more details.
@@ -519,7 +520,7 @@ struct SubtypeCheck {
}
}
- static bool CasFieldWeakSequentiallyConsistent32(const KlassT& klass,
+ static bool CasFieldWeakSequentiallyConsistent32(ClassPtr klass,
MemberOffset offset,
int32_t old_value,
int32_t new_value)
@@ -541,18 +542,23 @@ struct SubtypeCheck {
// it also requires calling klass->Depth.
//
// Anything calling this function will also be O(Depth(Class)).
- static SubtypeCheckInfo GetSubtypeCheckInfo(const KlassT& klass)
+ static SubtypeCheckInfo GetSubtypeCheckInfo(ClassPtr klass)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ return GetSubtypeCheckInfo(klass, klass->Depth());
+ }
+
+ // Get the SubtypeCheckInfo for a klass with known depth.
+ static SubtypeCheckInfo GetSubtypeCheckInfo(ClassPtr klass, size_t depth)
REQUIRES_SHARED(Locks::mutator_lock_) {
+ DCHECK_EQ(depth, klass->Depth());
SubtypeCheckBitsAndStatus current_bits_and_status = ReadField(klass);
- size_t depth = klass->Depth();
const SubtypeCheckInfo current =
SubtypeCheckInfo::Create(current_bits_and_status.subtype_check_info_, depth);
return current;
}
- static void SetSubtypeCheckInfo(KlassT& klass,
- const SubtypeCheckInfo& new_sci)
+ static void SetSubtypeCheckInfo(ClassPtr klass, const SubtypeCheckInfo& new_sci)
REQUIRES(Locks::subtype_check_lock_)
REQUIRES_SHARED(Locks::mutator_lock_) {
SubtypeCheckBits new_bits = new_sci.GetSubtypeCheckBits();
@@ -565,7 +571,7 @@ struct SubtypeCheck {
SubtypeCheck(SubtypeCheck&& other) = default;
~SubtypeCheck() = default;
- friend struct ::MockSubtypeCheck;
+ friend struct MockSubtypeCheck;
};
} // namespace art
diff --git a/runtime/subtype_check_info.h b/runtime/subtype_check_info.h
index 8320fb35a9..61d590bd59 100644
--- a/runtime/subtype_check_info.h
+++ b/runtime/subtype_check_info.h
@@ -138,6 +138,11 @@ struct SubtypeCheckInfo {
kSubtypeOf // Enough data. src is a subchild of the target.
};
+ // Get the raw depth.
+ size_t GetDepth() const {
+ return depth_;
+ }
+
// Chop off the depth, returning only the bitstring+of state.
// (Used to store into memory, since storing the depth would be redundant.)
SubtypeCheckBits GetSubtypeCheckBits() const {
diff --git a/runtime/subtype_check_test.cc b/runtime/subtype_check_test.cc
index dd51c18eff..e297d0beb4 100644
--- a/runtime/subtype_check_test.cc
+++ b/runtime/subtype_check_test.cc
@@ -24,10 +24,6 @@ namespace art {
constexpr size_t BitString::kBitSizeAtPosition[BitString::kCapacity];
constexpr size_t BitString::kCapacity;
-}; // namespace art
-
-using namespace art; // NOLINT
-
struct MockClass {
explicit MockClass(MockClass* parent, size_t x = 0, size_t y = 0) {
parent_ = parent;
@@ -1061,3 +1057,5 @@ TEST_F(SubtypeCheckTest, EnsureInitialized_TooWide_TooDeep) {
}
// TODO: add dcheck for child-parent invariants (e.g. child < parent.next) and death tests
+
+} // namespace art