Commit 2509e67f authored by Omer Katz's avatar Omer Katz Committed by Commit Bot

heap: Reduce atomics in IsInConstruction checks

When this check is called from the mutator thread it does not need
to be atomic. Adding a template layer between MarkingVisitorBase and
(Concurrent)MarkingVisitor to choose the right access mode to use

Evaluated this change on the regressed metrics from
https://crbug.com/1005476. The metric
rendering.mobile/queueing_durations/balls_css_key_frame_animations
was reduced from 5.9 to 4.5 and jank dropped by 2 (see
pinpoint job 1644ff41c20000).

Bug: 986235, 1005476
Change-Id: I767f1be9a3d387d63d49ec4643e90f3022c608b0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1872100
Commit-Queue: Omer Katz <omerkatz@chromium.org>
Reviewed-by: default avatarMichael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#708987}
parent 6cfae4e6
...@@ -1133,7 +1133,7 @@ NO_SANITIZE_ADDRESS inline bool HeapObjectHeader::IsInConstruction() const { ...@@ -1133,7 +1133,7 @@ NO_SANITIZE_ADDRESS inline bool HeapObjectHeader::IsInConstruction() const {
template <HeapObjectHeader::AccessMode mode> template <HeapObjectHeader::AccessMode mode>
NO_SANITIZE_ADDRESS inline void HeapObjectHeader::MarkFullyConstructed() { NO_SANITIZE_ADDRESS inline void HeapObjectHeader::MarkFullyConstructed() {
DCHECK(IsInConstruction<mode>()); DCHECK(IsInConstruction());
StoreEncoded<mode, EncodedHalf::kHigh>(kHeaderIsInConstructionMask, StoreEncoded<mode, EncodedHalf::kHigh>(kHeaderIsInConstructionMask,
kHeaderIsInConstructionMask); kHeaderIsInConstructionMask);
} }
......
...@@ -18,9 +18,9 @@ ALWAYS_INLINE bool IsHashTableDeleteValue(const void* value) { ...@@ -18,9 +18,9 @@ ALWAYS_INLINE bool IsHashTableDeleteValue(const void* value) {
} // namespace } // namespace
MarkingVisitorBase::MarkingVisitorBase(ThreadState* state, MarkingVisitorCommon::MarkingVisitorCommon(ThreadState* state,
MarkingMode marking_mode, MarkingMode marking_mode,
int task_id) int task_id)
: Visitor(state), : Visitor(state),
marking_worklist_(Heap().GetMarkingWorklist(), task_id), marking_worklist_(Heap().GetMarkingWorklist(), task_id),
not_fully_constructed_worklist_(Heap().GetNotFullyConstructedWorklist(), not_fully_constructed_worklist_(Heap().GetNotFullyConstructedWorklist(),
...@@ -34,17 +34,17 @@ MarkingVisitorBase::MarkingVisitorBase(ThreadState* state, ...@@ -34,17 +34,17 @@ MarkingVisitorBase::MarkingVisitorBase(ThreadState* state,
marking_mode_(marking_mode), marking_mode_(marking_mode),
task_id_(task_id) {} task_id_(task_id) {}
void MarkingVisitorBase::FlushCompactionWorklists() { void MarkingVisitorCommon::FlushCompactionWorklists() {
movable_reference_worklist_.FlushToGlobal(); movable_reference_worklist_.FlushToGlobal();
backing_store_callback_worklist_.FlushToGlobal(); backing_store_callback_worklist_.FlushToGlobal();
} }
void MarkingVisitorBase::RegisterWeakCallback(void* object, void MarkingVisitorCommon::RegisterWeakCallback(void* object,
WeakCallback callback) { WeakCallback callback) {
weak_callback_worklist_.Push({object, callback}); weak_callback_worklist_.Push({object, callback});
} }
void MarkingVisitorBase::RegisterBackingStoreReference(void** slot) { void MarkingVisitorCommon::RegisterBackingStoreReference(void** slot) {
if (marking_mode_ != kGlobalMarkingWithCompaction) if (marking_mode_ != kGlobalMarkingWithCompaction)
return; return;
MovableReference* movable_reference = MovableReference* movable_reference =
...@@ -55,7 +55,7 @@ void MarkingVisitorBase::RegisterBackingStoreReference(void** slot) { ...@@ -55,7 +55,7 @@ void MarkingVisitorBase::RegisterBackingStoreReference(void** slot) {
} }
} }
void MarkingVisitorBase::RegisterBackingStoreCallback( void MarkingVisitorCommon::RegisterBackingStoreCallback(
void* backing, void* backing,
MovingObjectCallback callback) { MovingObjectCallback callback) {
if (marking_mode_ != kGlobalMarkingWithCompaction) if (marking_mode_ != kGlobalMarkingWithCompaction)
...@@ -65,15 +65,15 @@ void MarkingVisitorBase::RegisterBackingStoreCallback( ...@@ -65,15 +65,15 @@ void MarkingVisitorBase::RegisterBackingStoreCallback(
} }
} }
bool MarkingVisitorBase::RegisterWeakTable( bool MarkingVisitorCommon::RegisterWeakTable(
const void* closure, const void* closure,
EphemeronCallback iteration_callback) { EphemeronCallback iteration_callback) {
weak_table_worklist_.Push({const_cast<void*>(closure), iteration_callback}); weak_table_worklist_.Push({const_cast<void*>(closure), iteration_callback});
return true; return true;
} }
void MarkingVisitorBase::AdjustMarkedBytes(HeapObjectHeader* header, void MarkingVisitorCommon::AdjustMarkedBytes(HeapObjectHeader* header,
size_t old_size) { size_t old_size) {
DCHECK(header->IsMarked<HeapObjectHeader::AccessMode::kAtomic>()); DCHECK(header->IsMarked<HeapObjectHeader::AccessMode::kAtomic>());
// Currently, only expansion of an object is supported during marking. // Currently, only expansion of an object is supported during marking.
DCHECK_GE(header->size(), old_size); DCHECK_GE(header->size(), old_size);
......
...@@ -15,7 +15,7 @@ namespace blink { ...@@ -15,7 +15,7 @@ namespace blink {
class BasePage; class BasePage;
// Base visitor used to mark Oilpan objects on any thread. // Base visitor used to mark Oilpan objects on any thread.
class PLATFORM_EXPORT MarkingVisitorBase : public Visitor { class PLATFORM_EXPORT MarkingVisitorCommon : public Visitor {
public: public:
enum MarkingMode { enum MarkingMode {
// This is a default visitor. This is used for MarkingType=kAtomicMarking // This is a default visitor. This is used for MarkingType=kAtomicMarking
...@@ -34,18 +34,6 @@ class PLATFORM_EXPORT MarkingVisitorBase : public Visitor { ...@@ -34,18 +34,6 @@ class PLATFORM_EXPORT MarkingVisitorBase : public Visitor {
// Implementation of the visitor interface. // Implementation of the visitor interface.
// //
void Visit(void* object, TraceDescriptor desc) final {
DCHECK(object);
if (desc.base_object_payload == BlinkGC::kNotFullyConstructedObject) {
// This means that the objects are not-yet-fully-constructed. See comments
// on GarbageCollectedMixin for how those objects are handled.
not_fully_constructed_worklist_.Push(object);
return;
}
MarkHeader(HeapObjectHeader::FromPayload(desc.base_object_payload),
desc.callback);
}
void VisitWeak(void* object, void VisitWeak(void* object,
void* object_weak_ref, void* object_weak_ref,
TraceDescriptor desc, TraceDescriptor desc,
...@@ -102,9 +90,6 @@ class PLATFORM_EXPORT MarkingVisitorBase : public Visitor { ...@@ -102,9 +90,6 @@ class PLATFORM_EXPORT MarkingVisitorBase : public Visitor {
EphemeronCallback iteration_callback) final; EphemeronCallback iteration_callback) final;
void RegisterWeakCallback(void* closure, WeakCallback) final; void RegisterWeakCallback(void* closure, WeakCallback) final;
// Unused cross-component visit methods.
void Visit(const TraceWrapperV8Reference<v8::Value>&) override {}
// Flush private segments remaining in visitor's worklists to global pools. // Flush private segments remaining in visitor's worklists to global pools.
void FlushCompactionWorklists(); void FlushCompactionWorklists();
...@@ -115,11 +100,8 @@ class PLATFORM_EXPORT MarkingVisitorBase : public Visitor { ...@@ -115,11 +100,8 @@ class PLATFORM_EXPORT MarkingVisitorBase : public Visitor {
void AdjustMarkedBytes(HeapObjectHeader*, size_t); void AdjustMarkedBytes(HeapObjectHeader*, size_t);
protected: protected:
MarkingVisitorBase(ThreadState*, MarkingMode, int task_id); MarkingVisitorCommon(ThreadState*, MarkingMode, int task_id);
~MarkingVisitorBase() override = default; ~MarkingVisitorCommon() override = default;
// Marks an object and adds a tracing callback for processing of the object.
inline void MarkHeader(HeapObjectHeader*, TraceCallback);
// Try to mark an object without tracing. Returns true when the object was not // Try to mark an object without tracing. Returns true when the object was not
// marked upon calling. // marked upon calling.
...@@ -142,11 +124,12 @@ class PLATFORM_EXPORT MarkingVisitorBase : public Visitor { ...@@ -142,11 +124,12 @@ class PLATFORM_EXPORT MarkingVisitorBase : public Visitor {
int task_id_; int task_id_;
}; };
ALWAYS_INLINE void MarkingVisitorBase::AccountMarkedBytes(size_t size) { ALWAYS_INLINE void MarkingVisitorCommon::AccountMarkedBytes(size_t size) {
marked_bytes_ += size; marked_bytes_ += size;
} }
inline bool MarkingVisitorBase::MarkHeaderNoTracing(HeapObjectHeader* header) { inline bool MarkingVisitorCommon::MarkHeaderNoTracing(
HeapObjectHeader* header) {
DCHECK(header); DCHECK(header);
DCHECK(State()->InAtomicMarkingPause() || State()->IsIncrementalMarking()); DCHECK(State()->InAtomicMarkingPause() || State()->IsIncrementalMarking());
// A GC should only mark the objects that belong in its heap. // A GC should only mark the objects that belong in its heap.
...@@ -167,23 +150,49 @@ inline bool MarkingVisitorBase::MarkHeaderNoTracing(HeapObjectHeader* header) { ...@@ -167,23 +150,49 @@ inline bool MarkingVisitorBase::MarkHeaderNoTracing(HeapObjectHeader* header) {
return false; return false;
} }
inline void MarkingVisitorBase::MarkHeader(HeapObjectHeader* header, // Base visitor used to mark Oilpan objects on any thread.
TraceCallback callback) { template <class Specialized>
DCHECK(header); class PLATFORM_EXPORT MarkingVisitorBase : public MarkingVisitorCommon {
DCHECK(callback); public:
void Visit(void* object, TraceDescriptor desc) final {
DCHECK(object);
if (desc.base_object_payload == BlinkGC::kNotFullyConstructedObject) {
// This means that the objects are not-yet-fully-constructed. See comments
// on GarbageCollectedMixin for how those objects are handled.
not_fully_constructed_worklist_.Push(object);
return;
}
MarkHeader(HeapObjectHeader::FromPayload(desc.base_object_payload),
desc.callback);
}
// Unused cross-component visit methods.
void Visit(const TraceWrapperV8Reference<v8::Value>&) override {}
if (header->IsInConstruction<HeapObjectHeader::AccessMode::kAtomic>()) { protected:
not_fully_constructed_worklist_.Push(header->Payload()); MarkingVisitorBase(ThreadState* state, MarkingMode marking_mode, int task_id)
} else if (MarkHeaderNoTracing(header)) { : MarkingVisitorCommon(state, marking_mode, task_id) {}
marking_worklist_.Push( ~MarkingVisitorBase() override = default;
{reinterpret_cast<void*>(header->Payload()), callback});
// Marks an object and adds a tracing callback for processing of the object.
inline void MarkHeader(HeapObjectHeader* header, TraceCallback callback) {
DCHECK(header);
DCHECK(callback);
if (Specialized::IsInConstruction(header)) {
not_fully_constructed_worklist_.Push(header->Payload());
} else if (MarkHeaderNoTracing(header)) {
marking_worklist_.Push(
{reinterpret_cast<void*>(header->Payload()), callback});
}
} }
} };
// Visitor used to mark Oilpan objects on the main thread. Also implements // Visitor used to mark Oilpan objects on the main thread. Also implements
// various sorts of write barriers that should only be called from the main // various sorts of write barriers that should only be called from the main
// thread. // thread.
class PLATFORM_EXPORT MarkingVisitor : public MarkingVisitorBase { class PLATFORM_EXPORT MarkingVisitor
: public MarkingVisitorBase<MarkingVisitor> {
public: public:
// Write barrier that adds |value| to the set of marked objects. The barrier // Write barrier that adds |value| to the set of marked objects. The barrier
// bails out if marking is off or the object is not yet marked. Returns true // bails out if marking is off or the object is not yet marked. Returns true
...@@ -212,6 +221,12 @@ class PLATFORM_EXPORT MarkingVisitor : public MarkingVisitorBase { ...@@ -212,6 +221,12 @@ class PLATFORM_EXPORT MarkingVisitor : public MarkingVisitorBase {
void FlushMarkingWorklist(); void FlushMarkingWorklist();
static bool IsInConstruction(HeapObjectHeader* header) {
// No need for atomics when operating on the mutator thread where
// construction happens.
return header->IsInConstruction<HeapObjectHeader::AccessMode::kNonAtomic>();
}
private: private:
// Exact version of the marking write barriers. // Exact version of the marking write barriers.
static bool WriteBarrierSlow(void*); static bool WriteBarrierSlow(void*);
...@@ -239,12 +254,17 @@ ALWAYS_INLINE void MarkingVisitor::TraceMarkedBackingStore(void* value) { ...@@ -239,12 +254,17 @@ ALWAYS_INLINE void MarkingVisitor::TraceMarkedBackingStore(void* value) {
} }
// Visitor used to mark Oilpan objects on concurrent threads. // Visitor used to mark Oilpan objects on concurrent threads.
class PLATFORM_EXPORT ConcurrentMarkingVisitor : public MarkingVisitorBase { class PLATFORM_EXPORT ConcurrentMarkingVisitor
: public MarkingVisitorBase<ConcurrentMarkingVisitor> {
public: public:
ConcurrentMarkingVisitor(ThreadState*, MarkingMode, int); ConcurrentMarkingVisitor(ThreadState*, MarkingMode, int);
~ConcurrentMarkingVisitor() override = default; ~ConcurrentMarkingVisitor() override = default;
virtual void FlushWorklists(); virtual void FlushWorklists();
static bool IsInConstruction(HeapObjectHeader* header) {
return header->IsInConstruction<HeapObjectHeader::AccessMode::kAtomic>();
}
}; };
} // namespace blink } // namespace blink
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment