blob: cac61a6fe13b9a2642082d70c5704b9de70d51cd [file] [log] [blame]
/*
* Copyright (C) 2013 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_H_
#include <memory>
#include "base/atomicops.h"
#include "base/macros.h"
#include "third_party/blink/public/platform/scheduler/web_rail_mode_observer.h"
#include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
#include "third_party/blink/renderer/platform/heap/blink_gc.h"
#include "third_party/blink/renderer/platform/heap/threading_traits.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/address_sanitizer.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h"
#include "third_party/blink/renderer/platform/wtf/linked_hash_set.h"
#include "third_party/blink/renderer/platform/wtf/thread_specific.h"
#include "third_party/blink/renderer/platform/wtf/threading.h"
#include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
#include "third_party/blink/renderer/platform/wtf/time.h"
namespace v8 {
class Isolate;
};
namespace blink {
namespace incremental_marking_test {
class IncrementalMarkingScope;
class IncrementalMarkingTestDriver;
} // namespace incremental_marking_test
class GarbageCollectedMixinConstructorMarkerBase;
class MarkingVisitor;
class PersistentNode;
class PersistentRegion;
class ThreadHeap;
class ThreadState;
class Visitor;
template <ThreadAffinity affinity>
class ThreadStateFor;
// Declare that a class has a pre-finalizer. The pre-finalizer is called
// before any object gets swept, so it is safe to touch on-heap objects
// that may be collected in the same GC cycle. If you cannot avoid touching
// on-heap objects in a destructor (which is not allowed), you can consider
// using the pre-finalizer. The only restriction is that the pre-finalizer
// must not resurrect dead objects (e.g., store unmarked objects into
// Members etc). The pre-finalizer is called on the thread that registered
// the pre-finalizer.
//
// Since a pre-finalizer adds pressure on GC performance, you should use it
// only if necessary.
//
// A pre-finalizer is similar to the
// HeapHashMap<WeakMember<Foo>, std::unique_ptr<Disposer>> idiom. The
// difference between this and the idiom is that pre-finalizer function is
// called whenever an object is destructed with this feature. The
// HeapHashMap<WeakMember<Foo>, std::unique_ptr<Disposer>> idiom requires an
// assumption that the HeapHashMap outlives objects pointed by WeakMembers.
// FIXME: Replace all of the
// HeapHashMap<WeakMember<Foo>, std::unique_ptr<Disposer>> idiom usages with the
// pre-finalizer if the replacement won't cause performance regressions.
//
// Usage:
//
// class Foo : GarbageCollected<Foo> {
// USING_PRE_FINALIZER(Foo, dispose);
// private:
// void dispose()
// {
// bar_->...; // It is safe to touch other on-heap objects.
// }
// Member<Bar> bar_;
// };
#define USING_PRE_FINALIZER(Class, preFinalizer) \
public: \
static bool InvokePreFinalizer(void* object) { \
Class* self = reinterpret_cast<Class*>(object); \
if (ThreadHeap::IsHeapObjectAlive(self)) \
return false; \
self->Class::preFinalizer(); \
return true; \
} \
\
private: \
ThreadState::PrefinalizerRegistration<Class> prefinalizer_dummy_ = this; \
using UsingPreFinalizerMacroNeedsTrailingSemiColon = char
class PLATFORM_EXPORT BlinkGCObserver {
public:
// The constructor automatically register this object to ThreadState's
// observer lists. The argument must not be null.
explicit BlinkGCObserver(ThreadState*);
// The destructor automatically unregister this object from ThreadState's
// observer lists.
virtual ~BlinkGCObserver();
virtual void OnCompleteSweepDone() = 0;
private:
// As a ThreadState must live when a BlinkGCObserver lives, holding a raw
// pointer is safe.
ThreadState* thread_state_;
};
class PLATFORM_EXPORT ThreadState final
: private scheduler::WebRAILModeObserver {
USING_FAST_MALLOC(ThreadState);
public:
// See setGCState() for possible state transitions.
enum GCState {
kNoGCScheduled,
kIdleGCScheduled,
kIncrementalMarkingStepPaused,
kIncrementalMarkingStepScheduled,
kIncrementalMarkingFinalizeScheduled,
kPreciseGCScheduled,
kFullGCScheduled,
kPageNavigationGCScheduled,
kIncrementalGCScheduled,
};
// The phase that the GC is in. The GCPhase will not return kNone for mutators
// running during incremental marking and lazy sweeping. See SetGCPhase() for
// possible state transitions.
enum class GCPhase {
// GC is doing nothing.
kNone,
// GC is in marking phase.
kMarking,
// GC is in sweeping phase.
kSweeping,
};
// The NoAllocationScope class is used in debug mode to catch unwanted
// allocations. E.g. allocations during GC.
class NoAllocationScope final {
STACK_ALLOCATED();
public:
explicit NoAllocationScope(ThreadState* state) : state_(state) {
state_->EnterNoAllocationScope();
}
~NoAllocationScope() { state_->LeaveNoAllocationScope(); }
private:
ThreadState* state_;
};
class SweepForbiddenScope final {
STACK_ALLOCATED();
public:
explicit SweepForbiddenScope(ThreadState* state) : state_(state) {
DCHECK(!state_->sweep_forbidden_);
state_->sweep_forbidden_ = true;
}
~SweepForbiddenScope() {
DCHECK(state_->sweep_forbidden_);
state_->sweep_forbidden_ = false;
}
private:
ThreadState* state_;
};
// Used to denote when access to unmarked objects is allowed but we shouldn't
// ressurect it by making new references (e.g. during weak processing and pre
// finalizer).
class ObjectResurrectionForbiddenScope final {
STACK_ALLOCATED();
public:
explicit ObjectResurrectionForbiddenScope(ThreadState* state)
: state_(state) {
state_->EnterObjectResurrectionForbiddenScope();
}
~ObjectResurrectionForbiddenScope() {
state_->LeaveObjectResurrectionForbiddenScope();
}
private:
ThreadState* state_;
};
// Returns true if any thread is currently incremental marking its heap and
// false otherwise. For an exact check use
// ThreadState::IsIncrementalMarking().
ALWAYS_INLINE static bool IsAnyIncrementalMarking() {
// Stores use full barrier to allow using the simplest relaxed load here.
return base::subtle::NoBarrier_Load(&incremental_marking_counter_) > 0;
}
// Returns true if any thread is currently incremental marking its heap and
// false otherwise. For an exact check use ThreadState::IsWrapperTracing().
static bool IsAnyWrapperTracing() {
// Stores use full barrier to allow using the simplest relaxed load here.
return base::subtle::NoBarrier_Load(&wrapper_tracing_counter_) > 0;
}
static void AttachMainThread();
// Associate ThreadState object with the current thread. After this
// call thread can start using the garbage collected heap infrastructure.
// It also has to periodically check for safepoints.
static void AttachCurrentThread();
// Disassociate attached ThreadState from the current thread. The thread
// can no longer use the garbage collected heap after this call.
static void DetachCurrentThread();
static ThreadState* Current() { return **thread_specific_; }
static ThreadState* MainThreadState() {
return reinterpret_cast<ThreadState*>(main_thread_state_storage_);
}
static ThreadState* FromObject(const void*);
bool IsMainThread() const { return this == MainThreadState(); }
bool CheckThread() const { return thread_ == CurrentThread(); }
ThreadHeap& Heap() const { return *heap_; }
ThreadIdentifier ThreadId() const { return thread_; }
// When ThreadState is detaching from non-main thread its
// heap is expected to be empty (because it is going away).
// Perform registered cleanup tasks and garbage collection
// to sweep away any objects that are left on this heap.
// We assert that nothing must remain after this cleanup.
// If assertion does not hold we crash as we are potentially
// in the dangling pointer situation.
void RunTerminationGC();
void PerformIdleGC(TimeTicks deadline);
void PerformIdleLazySweep(TimeTicks deadline);
void ScheduleIdleGC();
void ScheduleIdleLazySweep();
void SchedulePreciseGC();
void ScheduleIncrementalGC(BlinkGC::GCReason);
void ScheduleV8FollowupGCIfNeeded(BlinkGC::V8GCType);
void SchedulePageNavigationGCIfNeeded(float estimated_removal_ratio);
void SchedulePageNavigationGC();
void ScheduleFullGC();
void ScheduleGCIfNeeded();
void PostIdleGCTask();
void WillStartV8GC(BlinkGC::V8GCType);
void SetGCState(GCState);
GCState GetGCState() const { return gc_state_; }
void SetGCPhase(GCPhase);
bool IsMarkingInProgress() const { return gc_phase_ == GCPhase::kMarking; }
bool IsSweepingInProgress() const { return gc_phase_ == GCPhase::kSweeping; }
bool IsUnifiedGCMarkingInProgress() const {
return IsMarkingInProgress() &&
current_gc_data_.reason == BlinkGC::GCReason::kUnifiedHeapGC;
}
void EnableWrapperTracingBarrier();
void DisableWrapperTracingBarrier();
// Incremental GC.
void ScheduleIncrementalMarkingStep();
void ScheduleIncrementalMarkingFinalize();
void IncrementalMarkingStart(BlinkGC::GCReason);
void IncrementalMarkingStep(BlinkGC::StackState);
void IncrementalMarkingFinalize();
bool FinishIncrementalMarkingIfRunning(BlinkGC::StackState,
BlinkGC::MarkingType,
BlinkGC::SweepingType,
BlinkGC::GCReason);
void EnableIncrementalMarkingBarrier();
void DisableIncrementalMarkingBarrier();
void CompleteSweep();
void FinishSnapshot();
void PostSweep();
// Support for disallowing allocation. Mainly used for sanity
// checks asserts.
bool IsAllocationAllowed() const {
// Allocation is not allowed during atomic marking pause, but it is allowed
// during atomic sweeping pause.
return !InAtomicMarkingPause() && !no_allocation_count_;
}
void EnterNoAllocationScope() { no_allocation_count_++; }
void LeaveNoAllocationScope() { no_allocation_count_--; }
bool IsWrapperTracingForbidden() { return IsMixinInConstruction(); }
bool IsGCForbidden() const {
return gc_forbidden_count_ || IsMixinInConstruction();
}
void EnterGCForbiddenScope() { gc_forbidden_count_++; }
void LeaveGCForbiddenScope() {
DCHECK_GT(gc_forbidden_count_, 0u);
gc_forbidden_count_--;
}
bool IsMixinInConstruction() const { return mixins_being_constructed_count_; }
void EnterMixinConstructionScope() { mixins_being_constructed_count_++; }
void LeaveMixinConstructionScope() {
DCHECK_GT(mixins_being_constructed_count_, 0u);
mixins_being_constructed_count_--;
}
bool SweepForbidden() const { return sweep_forbidden_; }
bool IsObjectResurrectionForbidden() const {
return object_resurrection_forbidden_;
}
void EnterObjectResurrectionForbiddenScope() {
DCHECK(!object_resurrection_forbidden_);
object_resurrection_forbidden_ = true;
}
void LeaveObjectResurrectionForbiddenScope() {
DCHECK(object_resurrection_forbidden_);
object_resurrection_forbidden_ = false;
}
bool in_atomic_pause() const { return in_atomic_pause_; }
void EnterAtomicPause() {
DCHECK(!in_atomic_pause_);
in_atomic_pause_ = true;
}
void LeaveAtomicPause() {
DCHECK(in_atomic_pause_);
in_atomic_pause_ = false;
}
bool InAtomicMarkingPause() const {
return in_atomic_pause() && IsMarkingInProgress();
}
bool InAtomicSweepingPause() const {
return in_atomic_pause() && IsSweepingInProgress();
}
bool IsWrapperTracing() const { return wrapper_tracing_; }
void SetWrapperTracing(bool value) { wrapper_tracing_ = value; }
bool IsIncrementalMarking() const { return incremental_marking_; }
void SetIncrementalMarking(bool value) { incremental_marking_ = value; }
class MainThreadGCForbiddenScope final {
STACK_ALLOCATED();
public:
MainThreadGCForbiddenScope()
: thread_state_(ThreadState::MainThreadState()) {
thread_state_->EnterGCForbiddenScope();
}
~MainThreadGCForbiddenScope() { thread_state_->LeaveGCForbiddenScope(); }
private:
ThreadState* const thread_state_;
};
class GCForbiddenScope final {
STACK_ALLOCATED();
public:
explicit GCForbiddenScope(ThreadState* thread_state)
: thread_state_(thread_state) {
thread_state_->EnterGCForbiddenScope();
}
~GCForbiddenScope() { thread_state_->LeaveGCForbiddenScope(); }
private:
ThreadState* const thread_state_;
};
// Used to mark when we are in an atomic pause for GC.
class AtomicPauseScope final {
public:
explicit AtomicPauseScope(ThreadState* thread_state)
: thread_state_(thread_state), gc_forbidden_scope(thread_state) {
thread_state_->EnterAtomicPause();
}
~AtomicPauseScope() { thread_state_->LeaveAtomicPause(); }
private:
ThreadState* const thread_state_;
ScriptForbiddenScope script_forbidden_scope;
GCForbiddenScope gc_forbidden_scope;
};
void FlushHeapDoesNotContainCacheIfNeeded();
void SafePoint(BlinkGC::StackState);
void RecordStackEnd(intptr_t* end_of_stack) { end_of_stack_ = end_of_stack; }
void PushRegistersAndVisitStack();
// A region of non-weak PersistentNodes allocated on the given thread.
PersistentRegion* GetPersistentRegion() const {
return persistent_region_.get();
}
// A region of PersistentNodes for WeakPersistents allocated on the given
// thread.
PersistentRegion* GetWeakPersistentRegion() const {
return weak_persistent_region_.get();
}
// Visit local thread stack and trace all pointers conservatively.
void VisitStack(MarkingVisitor*);
// Visit the asan fake stack frame corresponding to a slot on the
// real machine stack if there is one.
void VisitAsanFakeStackForPointer(MarkingVisitor*, Address);
// Visit all non-weak persistents allocated on this thread.
void VisitPersistents(Visitor*);
// Visit all weak persistents allocated on this thread.
void VisitWeakPersistents(Visitor*);
// Visit all DOM wrappers allocatd on this thread.
void VisitDOMWrappers(Visitor*);
struct GCSnapshotInfo {
STACK_ALLOCATED();
public:
GCSnapshotInfo(wtf_size_t num_object_types);
// Map from gcInfoIndex (vector-index) to count/size.
Vector<int> live_count;
Vector<int> dead_count;
Vector<size_t> live_size;
Vector<size_t> dead_size;
};
void RegisterTraceDOMWrappers(
v8::Isolate* isolate,
void (*trace_dom_wrappers)(v8::Isolate*, Visitor*),
void (*invalidate_dead_objects_in_wrappers_marking_deque)(v8::Isolate*),
void (*perform_cleanup)(v8::Isolate*)) {
isolate_ = isolate;
DCHECK(!isolate_ || trace_dom_wrappers);
trace_dom_wrappers_ = trace_dom_wrappers;
invalidate_dead_objects_in_wrappers_marking_deque_ =
invalidate_dead_objects_in_wrappers_marking_deque;
perform_cleanup_ = perform_cleanup;
}
// By entering a gc-forbidden scope, conservative GCs will not
// be allowed while handling an out-of-line allocation request.
// Intended used when constructing subclasses of GC mixins, where
// the object being constructed cannot be safely traced & marked
// fully should a GC be allowed while its subclasses are being
// constructed.
void EnterGCForbiddenScopeIfNeeded(
GarbageCollectedMixinConstructorMarkerBase* gc_mixin_marker) {
DCHECK(CheckThread());
if (!gc_mixin_marker_) {
EnterMixinConstructionScope();
gc_mixin_marker_ = gc_mixin_marker;
}
}
void LeaveGCForbiddenScopeIfNeeded(
GarbageCollectedMixinConstructorMarkerBase* gc_mixin_marker) {
DCHECK(CheckThread());
if (gc_mixin_marker_ == gc_mixin_marker) {
LeaveMixinConstructionScope();
gc_mixin_marker_ = nullptr;
}
}
void FreePersistentNode(PersistentRegion*, PersistentNode*);
using PersistentClearCallback = void (*)(void*);
void RegisterStaticPersistentNode(PersistentNode*, PersistentClearCallback);
void ReleaseStaticPersistentNodes();
#if defined(LEAK_SANITIZER)
void enterStaticReferenceRegistrationDisabledScope();
void leaveStaticReferenceRegistrationDisabledScope();
#endif
v8::Isolate* GetIsolate() const { return isolate_; }
void CollectGarbage(BlinkGC::StackState,
BlinkGC::MarkingType,
BlinkGC::SweepingType,
BlinkGC::GCReason);
void CollectAllGarbage();
// Register the pre-finalizer for the |self| object. The class T must have
// USING_PRE_FINALIZER().
template <typename T>
class PrefinalizerRegistration final {
public:
PrefinalizerRegistration(T* self) {
static_assert(sizeof(&T::InvokePreFinalizer) > 0,
"USING_PRE_FINALIZER(T) must be defined.");
ThreadState* state =
ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState();
#if DCHECK_IS_ON()
DCHECK(state->CheckThread());
#endif
DCHECK(!state->SweepForbidden());
DCHECK(!state->ordered_pre_finalizers_.Contains(
PreFinalizer(self, T::InvokePreFinalizer)));
state->ordered_pre_finalizers_.insert(
PreFinalizer(self, T::InvokePreFinalizer));
}
};
// Returns |true| if |object| resides on this thread's heap.
// It is well-defined to call this method on any heap allocated
// reference, provided its associated heap hasn't been detached
// and shut down. Its behavior is undefined for any other pointer
// value.
bool IsOnThreadHeap(const void* object) const {
return &FromObject(object)->Heap() == &Heap();
}
int GcAge() const { return gc_age_; }
MarkingVisitor* CurrentVisitor() { return current_gc_data_.visitor.get(); }
// Implementation for WebRAILModeObserver
void OnRAILModeChanged(v8::RAILMode new_mode) override {
should_optimize_for_load_time_ = new_mode == v8::RAILMode::PERFORMANCE_LOAD;
// When switching RAIL mode to load we try to avoid incremental marking as
// the write barrier cost is noticeable on throughput and garbage
// accumulated during loading is likely to be alive during that phase. The
// same argument holds for unified heap garbage collections with the
// difference that these collections are triggered by V8 and should thus be
// avoided on that end.
if (should_optimize_for_load_time_ && IsIncrementalMarking() &&
!IsUnifiedGCMarkingInProgress() &&
GetGCState() == GCState::kIncrementalMarkingStepScheduled)
ScheduleIncrementalMarkingFinalize();
}
private:
// Number of ThreadState's that are currently in incremental marking. The
// counter is incremented by one when some ThreadState enters incremental
// marking and decremented upon finishing.
static base::subtle::AtomicWord incremental_marking_counter_;
// Same semantic as |incremental_marking_counter_|.
static base::subtle::AtomicWord wrapper_tracing_counter_;
ThreadState();
~ThreadState() override;
// The following methods are used to compose RunAtomicPause. Public users
// should use the CollectGarbage entrypoint. Internal users should use these
// methods to compose a full garbage collection.
void AtomicPauseMarkPrologue(BlinkGC::StackState,
BlinkGC::MarkingType,
BlinkGC::GCReason);
void AtomicPauseMarkTransitiveClosure();
void AtomicPauseMarkEpilogue(BlinkGC::MarkingType);
void AtomicPauseSweepAndCompact(BlinkGC::MarkingType marking_type,
BlinkGC::SweepingType sweeping_type);
void RunAtomicPause(BlinkGC::StackState,
BlinkGC::MarkingType,
BlinkGC::SweepingType,
BlinkGC::GCReason);
void UpdateStatisticsAfterSweeping();
// The version is needed to be able to start incremental marking.
void MarkPhasePrologue(BlinkGC::StackState,
BlinkGC::MarkingType,
BlinkGC::GCReason);
void AtomicPausePrologue(BlinkGC::StackState,
BlinkGC::MarkingType,
BlinkGC::GCReason);
void AtomicPauseEpilogue(BlinkGC::MarkingType, BlinkGC::SweepingType);
void MarkPhaseEpilogue(BlinkGC::MarkingType);
void MarkPhaseVisitRoots();
void MarkPhaseVisitNotFullyConstructedObjects();
bool MarkPhaseAdvanceMarking(TimeTicks deadline);
void VerifyMarking(BlinkGC::MarkingType);
bool ShouldVerifyMarking() const;
// shouldScheduleIdleGC and shouldForceConservativeGC
// implement the heuristics that are used to determine when to collect
// garbage.
// If shouldForceConservativeGC returns true, we force the garbage
// collection immediately. Otherwise, if should*GC returns true, we
// record that we should garbage collect the next time we return
// to the event loop. If both return false, we don't need to
// collect garbage at this point.
bool ShouldScheduleIdleGC();
bool ShouldForceConservativeGC();
bool ShouldScheduleIncrementalMarking();
// V8 minor or major GC is likely to drop a lot of references to objects
// on Oilpan's heap. We give a chance to schedule a GC.
bool ShouldScheduleV8FollowupGC();
// Page navigation is likely to drop a lot of references to objects
// on Oilpan's heap. We give a chance to schedule a GC.
// estimatedRemovalRatio is the estimated ratio of objects that will be no
// longer necessary due to the navigation.
bool ShouldSchedulePageNavigationGC(float estimated_removal_ratio);
void RescheduleIdleGC();
// Internal helpers to handle memory pressure conditions.
// Returns true if memory use is in a near-OOM state
// (aka being under "memory pressure".)
bool ShouldForceMemoryPressureGC();
// Returns true if shouldForceMemoryPressureGC() held and a
// conservative GC was performed to handle the emergency.
bool ForceMemoryPressureGCIfNeeded();
size_t EstimatedLiveSize(size_t current_size, size_t size_at_last_gc);
size_t TotalMemorySize();
double HeapGrowingRate();
double PartitionAllocGrowingRate();
bool JudgeGCThreshold(size_t allocated_object_size_threshold,
size_t total_memory_size_threshold,
double heap_growing_rate_threshold);
void RunScheduledGC(BlinkGC::StackState);
void UpdateIncrementalMarkingStepDuration();
void EagerSweep();
void InvokePreFinalizers();
void ReportMemoryToV8();
friend class BlinkGCObserver;
// Adds the given observer to the ThreadState's observer list. This doesn't
// take ownership of the argument. The argument must not be null. The argument
// must not be registered before calling this.
void AddObserver(BlinkGCObserver*);
// Removes the given observer from the ThreadState's observer list. This
// doesn't take ownership of the argument. The argument must not be null.
// The argument must be registered before calling this.
void RemoveObserver(BlinkGCObserver*);
static WTF::ThreadSpecific<ThreadState*>* thread_specific_;
// We can't create a static member of type ThreadState here
// because it will introduce global constructor and destructor.
// We would like to manage lifetime of the ThreadState attached
// to the main thread explicitly instead and still use normal
// constructor and destructor for the ThreadState class.
// For this we reserve static storage for the main ThreadState
// and lazily construct ThreadState in it using placement new.
static uint8_t main_thread_state_storage_[];
std::unique_ptr<ThreadHeap> heap_;
ThreadIdentifier thread_;
std::unique_ptr<PersistentRegion> persistent_region_;
std::unique_ptr<PersistentRegion> weak_persistent_region_;
intptr_t* start_of_stack_;
intptr_t* end_of_stack_;
bool sweep_forbidden_;
size_t no_allocation_count_;
size_t gc_forbidden_count_;
size_t mixins_being_constructed_count_;
bool object_resurrection_forbidden_;
bool in_atomic_pause_;
TimeDelta next_incremental_marking_step_duration_;
TimeDelta previous_incremental_marking_time_left_;
GarbageCollectedMixinConstructorMarkerBase* gc_mixin_marker_;
GCState gc_state_;
GCPhase gc_phase_;
BlinkGC::GCReason reason_for_scheduled_gc_;
bool should_optimize_for_load_time_;
using PreFinalizerCallback = bool (*)(void*);
using PreFinalizer = std::pair<void*, PreFinalizerCallback>;
// Pre-finalizers are called in the reverse order in which they are
// registered by the constructors (including constructors of Mixin objects)
// for an object, by processing the ordered_pre_finalizers_ back-to-front.
LinkedHashSet<PreFinalizer> ordered_pre_finalizers_;
v8::Isolate* isolate_;
void (*trace_dom_wrappers_)(v8::Isolate*, Visitor*);
void (*invalidate_dead_objects_in_wrappers_marking_deque_)(v8::Isolate*);
void (*perform_cleanup_)(v8::Isolate*);
bool wrapper_tracing_;
bool incremental_marking_;
#if defined(ADDRESS_SANITIZER)
void* asan_fake_stack_;
#endif
HashSet<BlinkGCObserver*> observers_;
// PersistentNodes that are stored in static references;
// references that either have to be cleared upon the thread
// detaching from Oilpan and shutting down or references we
// have to clear before initiating LSan's leak detection.
HashMap<PersistentNode*, PersistentClearCallback> static_persistents_;
#if defined(LEAK_SANITIZER)
// Count that controls scoped disabling of persistent registration.
size_t disabled_static_persistent_registration_;
#endif
size_t reported_memory_to_v8_;
int gc_age_ = 0;
struct GCData {
BlinkGC::StackState stack_state;
BlinkGC::MarkingType marking_type;
BlinkGC::GCReason reason;
std::unique_ptr<MarkingVisitor> visitor;
};
GCData current_gc_data_;
// Needs to set up visitor for testing purposes.
friend class incremental_marking_test::IncrementalMarkingScope;
friend class incremental_marking_test::IncrementalMarkingTestDriver;
template <typename T>
friend class PrefinalizerRegistration;
friend class TestGCScope;
friend class ThreadStateSchedulingTest;
friend class UnifiedHeapController;
DISALLOW_COPY_AND_ASSIGN(ThreadState);
};
template <>
class ThreadStateFor<kMainThreadOnly> {
STATIC_ONLY(ThreadStateFor);
public:
static ThreadState* GetState() {
// This specialization must only be used from the main thread.
DCHECK(ThreadState::Current()->IsMainThread());
return ThreadState::MainThreadState();
}
};
template <>
class ThreadStateFor<kAnyThread> {
STATIC_ONLY(ThreadStateFor);
public:
static ThreadState* GetState() { return ThreadState::Current(); }
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_H_