diff options
author | 2018-01-03 15:47:24 +0000 | |
---|---|---|
committer | 2018-01-03 15:47:24 +0000 | |
commit | b0ddceb337f614dc2600d19b82fb4a6596aa7d4c (patch) | |
tree | ed9d3cb8668c54b0274653de2bbd7c90b08fa3ea | |
parent | 00359cd27da40020e0a539515590fac3a46be1e4 (diff) | |
parent | 38b8b25b7deff92627586405c80182a19e7c18f9 (diff) |
Merge changes Idd405a2c,I7052da55
* changes:
ART: Faster type check bitstring initialization.
Replace TypeStaticIf<> with std::conditional<> (C++11).
-rw-r--r-- | oatdump/oatdump.cc | 4 | ||||
-rw-r--r-- | runtime/base/allocator.h | 9 | ||||
-rw-r--r-- | runtime/base/type_static_if.h | 32 | ||||
-rw-r--r-- | runtime/class_linker.cc | 12 | ||||
-rw-r--r-- | runtime/subtype_check.h | 64 | ||||
-rw-r--r-- | runtime/subtype_check_info.h | 5 | ||||
-rw-r--r-- | runtime/subtype_check_test.cc | 6 |
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 |