From 5ae4d897ebb4574b9d96b69a3ee8eb0e777fc7c7 Mon Sep 17 00:00:00 2001 From: Tess Strickland Date: Fri, 2 Jul 2021 14:27:34 +0000 Subject: [PATCH] [vm] Move UntaggedObject::Tags -> AtomicBitFieldContainer. Now that this class is used for more than wrapping Object tags, move it to be alongside the BitField class and change its name to something more representative of its role. Also remove the need to change BitField declarations if the source type of the bitfield is decltype(field) and the declaration of field is changed from type T to type AtomicBitFieldContainer. TEST=Refactoring, so existing tests. Cq-Include-Trybots: luci.dart.try:vm-kernel-tsan-linux-release-x64-try,vm-kernel-precomp-tsan-linux-release-x64-try,vm-kernel-precomp-linux-release-simarm_x64-try Change-Id: If2f48ed4e209d71461c1b1ec81769e1485fbd6b0 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/205782 Commit-Queue: Tess Strickland Reviewed-by: Alexander Aprelev Reviewed-by: Martin Kustermann --- runtime/vm/bitfield.h | 158 +++++++++++++++++++++++++++++++++++++++- runtime/vm/raw_object.h | 139 ++++------------------------------- 2 files changed, 171 insertions(+), 126 deletions(-) diff --git a/runtime/vm/bitfield.h b/runtime/vm/bitfield.h index b982d834470..f96a34e3539 100644 --- a/runtime/vm/bitfield.h +++ b/runtime/vm/bitfield.h @@ -7,10 +7,121 @@ #include +#include "platform/atomic.h" #include "platform/globals.h" +#include "platform/thread_sanitizer.h" namespace dart { +class AtomicBitFieldContainerBase { + private: + AtomicBitFieldContainerBase() = delete; // Only used for std::is_base_of. +}; + +template +class AtomicBitFieldContainer : AtomicBitFieldContainerBase { + static_assert(sizeof(std::atomic) == sizeof(T), + "Size of type changes when made atomic"); + + public: + using ContainedType = T; + + AtomicBitFieldContainer() : field_(0) {} + + operator T() const { return field_.load(std::memory_order_relaxed); } + T operator=(T tags) { + field_.store(tags, std::memory_order_relaxed); + return tags; + } + + T load(std::memory_order order) const { return field_.load(order); } + void store(T value, std::memory_order order) { field_.store(value, order); } + + bool compare_exchange_weak(T old_tags, T new_tags, std::memory_order order) { + return field_.compare_exchange_weak(old_tags, new_tags, order); + } + + template + typename TargetBitField::Type Read() const { + return TargetBitField::decode(field_.load(order)); + } + + template + NO_SANITIZE_THREAD typename TargetBitField::Type ReadIgnoreRace() const { + return TargetBitField::decode(*reinterpret_cast(&field_)); + } + + template + void UpdateBool(bool value) { + if (value) { + field_.fetch_or(TargetBitField::encode(true), order); + } else { + field_.fetch_and(~TargetBitField::encode(true), order); + } + } + + template + void FetchOr(typename TargetBitField::Type value) { + field_.fetch_or(TargetBitField::encode(value), std::memory_order_relaxed); + } + + template + void Update(typename TargetBitField::Type value) { + T old_field = field_.load(std::memory_order_relaxed); + T new_field; + do { + new_field = TargetBitField::update(value, old_field); + } while (!field_.compare_exchange_weak(old_field, new_field, + std::memory_order_relaxed)); + } + + template + void UpdateUnsynchronized(typename TargetBitField::Type value) { + field_.store( + TargetBitField::update(value, field_.load(std::memory_order_relaxed)), + std::memory_order_relaxed); + } + + template + typename TargetBitField::Type UpdateConditional( + typename TargetBitField::Type value_to_be_set, + typename TargetBitField::Type conditional_old_value) { + T old_field = field_.load(std::memory_order_relaxed); + while (true) { + // This operation is only performed if the condition is met. + auto old_value = TargetBitField::decode(old_field); + if (old_value != conditional_old_value) { + return old_value; + } + T new_tags = TargetBitField::update(value_to_be_set, old_field); + if (field_.compare_exchange_weak(old_field, new_tags, + std::memory_order_relaxed)) { + return value_to_be_set; + } + // [old_tags] was updated to it's current value. + } + } + + template + bool TryAcquire() { + T mask = TargetBitField::encode(true); + T old_field = field_.fetch_or(mask, std::memory_order_relaxed); + return !TargetBitField::decode(old_field); + } + + template + bool TryClear() { + T mask = ~TargetBitField::encode(true); + T old_field = field_.fetch_and(mask, std::memory_order_relaxed); + return TargetBitField::decode(old_field); + } + + private: + std::atomic field_; +}; + static const uword kUwordOne = 1U; // BitField is a template for encoding and decoding a value of type T @@ -19,7 +130,8 @@ template + bool sign_extend = false, + typename Enable = void> class BitField { public: typedef T Type; @@ -86,6 +198,50 @@ class BitField { } }; +// Partial instantiations to avoid having to change BitField declarations if +// S is decltype(field_) and the type of field_ is changed to be wrapped in an +// AtomicBitFieldContainer. +template +class BitField::value, + void>::type> : public BitField {}; + +template +class BitField::value, + void>::type> + : public BitField {}; + +template +class BitField::value, + void>::type> + : public BitField {}; + } // namespace dart #endif // RUNTIME_VM_BITFIELD_H_ diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h index b4542b90077..fbbce4cded8 100644 --- a/runtime/vm/raw_object.h +++ b/runtime/vm/raw_object.h @@ -10,8 +10,6 @@ #endif #include "platform/assert.h" -#include "platform/atomic.h" -#include "platform/thread_sanitizer.h" #include "vm/class_id.h" #include "vm/compiler/method_recognizer.h" #include "vm/compiler/runtime_api.h" @@ -260,110 +258,6 @@ class UntaggedObject { class ReservedBits : public BitField {}; - template - class Tags { - public: - Tags() : tags_(0) {} - - using ContentType = T; - - operator T() const { return tags_.load(std::memory_order_relaxed); } - T operator=(T tags) { - tags_.store(tags, std::memory_order_relaxed); - return tags; - } - - T load(std::memory_order order) const { return tags_.load(order); } - void store(T value, std::memory_order order) { tags_.store(value, order); } - - bool compare_exchange_weak(T old_tags, - T new_tags, - std::memory_order order) { - return tags_.compare_exchange_weak(old_tags, new_tags, order); - } - - template - typename TagBitField::Type Read() const { - return TagBitField::decode(tags_.load(order)); - } - - template - NO_SANITIZE_THREAD typename TagBitField::Type ReadIgnoreRace() const { - return TagBitField::decode(*reinterpret_cast(&tags_)); - } - - template - void UpdateBool(bool value) { - if (value) { - tags_.fetch_or(TagBitField::encode(true), order); - } else { - tags_.fetch_and(~TagBitField::encode(true), order); - } - } - - template - void FetchOr(typename TagBitField::Type value) { - tags_.fetch_or(TagBitField::encode(value), std::memory_order_relaxed); - } - - template - void Update(typename TagBitField::Type value) { - T old_tags = tags_.load(std::memory_order_relaxed); - T new_tags; - do { - new_tags = TagBitField::update(value, old_tags); - } while (!tags_.compare_exchange_weak(old_tags, new_tags, - std::memory_order_relaxed)); - } - - template - void UpdateUnsynchronized(typename TagBitField::Type value) { - tags_.store( - TagBitField::update(value, tags_.load(std::memory_order_relaxed)), - std::memory_order_relaxed); - } - - template - typename TagBitField::Type UpdateConditional( - typename TagBitField::Type value_to_be_set, - typename TagBitField::Type conditional_old_value) { - T old_tags = tags_.load(std::memory_order_relaxed); - while (true) { - // This operation is only performed if the condition is met. - auto old_value = TagBitField::decode(old_tags); - if (old_value != conditional_old_value) { - return old_value; - } - T new_tags = TagBitField::update(value_to_be_set, old_tags); - if (tags_.compare_exchange_weak(old_tags, new_tags, - std::memory_order_relaxed)) { - return value_to_be_set; - } - // [old_tags] was updated to it's current value. - } - } - - template - bool TryAcquire() { - T mask = TagBitField::encode(true); - T old_tags = tags_.fetch_or(mask, std::memory_order_relaxed); - return !TagBitField::decode(old_tags); - } - - template - bool TryClear() { - T mask = ~TagBitField::encode(true); - T old_tags = tags_.fetch_and(mask, std::memory_order_relaxed); - return TagBitField::decode(old_tags); - } - - private: - std::atomic tags_; - COMPILE_ASSERT(sizeof(std::atomic) == sizeof(T)); - }; - // Assumes this is a heap object. bool IsNewObject() const { uword addr = reinterpret_cast(this); @@ -604,7 +498,7 @@ class UntaggedObject { } private: - Tags tags_; // Various object tags (bits). + AtomicBitFieldContainer tags_; // Various object tags (bits). intptr_t VisitPointersPredefined(ObjectPointerVisitor* visitor, intptr_t class_id); @@ -1399,7 +1293,7 @@ class UntaggedFunction : public UntaggedObject { TokenPosition end_token_pos_; #endif - Tags kind_tag_; // See Function::KindTagBits. + AtomicBitFieldContainer kind_tag_; // See Function::KindTagBits. #define JIT_FUNCTION_COUNTERS(F) \ F(intptr_t, int32_t, usage_counter) \ @@ -1418,14 +1312,12 @@ class UntaggedFunction : public UntaggedObject { #endif // !defined(DART_PRECOMPILED_RUNTIME) - Tags packed_fields_; + AtomicBitFieldContainer packed_fields_; static constexpr intptr_t kMaxOptimizableBits = 1; - using PackedOptimizable = BitField; + using PackedOptimizable = + BitField; }; class UntaggedClosureData : public UntaggedObject { @@ -2446,7 +2338,7 @@ class UntaggedICData : public UntaggedCallSiteData { } NOT_IN_PRECOMPILED(int32_t deopt_id_); // Number of arguments tested in IC, deopt reasons. - Tags state_bits_; + AtomicBitFieldContainer state_bits_; }; class UntaggedMegamorphicCache : public UntaggedCallSiteData { @@ -2662,8 +2554,8 @@ class UntaggedFunctionType : public UntaggedAbstractType { COMPRESSED_POINTER_FIELD(ArrayPtr, named_parameter_names); COMPRESSED_POINTER_FIELD(SmiPtr, hash) VISIT_TO(hash) - Tags packed_parameter_counts_; - Tags packed_type_parameter_counts_; + AtomicBitFieldContainer packed_parameter_counts_; + AtomicBitFieldContainer packed_type_parameter_counts_; uint8_t type_state_; uint8_t nullability_; @@ -2671,31 +2563,28 @@ class UntaggedFunctionType : public UntaggedAbstractType { public: // For packed_type_parameter_counts_. using PackedNumParentTypeArguments = - BitField; + BitField; using PackedNumTypeParameters = - BitField; // For packed_parameter_counts_. using PackedNumImplicitParameters = - BitField; + BitField; using PackedHasNamedOptionalParameters = - BitField; using PackedNumFixedParameters = - BitField; using PackedNumOptionalParameters = - BitField;