910e62b5创建于 1月15日历史提交
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_H_

#include "base/compiler_specific.h"
#include "base/functional/callback_forward.h"
#include "build/build_config.h"
#include "third_party/blink/renderer/platform/bindings/active_script_wrappable_manager.h"
#include "third_party/blink/renderer/platform/heap/forward.h"
#include "third_party/blink/renderer/platform/heap/thread_state_storage.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/threading.h"
#include "v8/include/cppgc/common.h"  // IWYU pragma: export (for ThreadState::StackState alias)
#include "v8/include/cppgc/heap-consistency.h"
#include "v8/include/v8-callbacks.h"
#include "v8/include/v8-cppgc.h"
#include "v8/include/v8-profiler.h"

namespace v8 {
class CppHeap;
class EmbedderRootsHandler;
}  // namespace v8

namespace blink {

class ActiveScriptWrappableManager;
class BlinkGCMemoryDumpProvider;

// ThreadState manages garbage collections together with V8. This includes the
// setup and teardown of the GC wiring as well as custom weakness and clearing
// logic. The state is aware of which Isolate it is attached to and the
// ownership of the underlying CppHeap.
class PLATFORM_EXPORT ThreadState final {
 public:
  class GCForbiddenScope;
  class NoAllocationScope;

  using StackState = cppgc::EmbedderStackState;

  using DevToolsCountersCallback = void (*)(v8::Isolate*);

  ALWAYS_INLINE static ThreadState* Current() {
    return &ThreadStateStorage::Current()->thread_state();
  }

  // Attaches a ThreadState to the main-thread.
  static ThreadState* AttachMainThread();
  // Attaches a ThreadState to the currently running thread. Must not be the
  // main thread and must be called after AttachMainThread().
  static ThreadState* AttachCurrentThread();
  static void DetachCurrentThread();

  // Attaches custom GC handling to an Isolate. CppHeap is already owned by the
  // Isolate at this point.
  void AttachToIsolate(v8::Isolate* isolate, DevToolsCountersCallback);
  // Detaches custom GC handling from an Isolate. CppHeap is still owned by the
  // Isolate afterwards.
  void DetachFromIsolate();
  // Releases ownership of the CppHeap which is transferred to the v8::Isolate.
  std::unique_ptr<v8::CppHeap> ReleaseCppHeap();

  ALWAYS_INLINE cppgc::HeapHandle& heap_handle() const { return heap_handle_; }
  ALWAYS_INLINE v8::CppHeap& cpp_heap() const { return *cpp_heap_; }

  bool IsMainThread() const {
    return this ==
           &ThreadStateStorage::MainThreadStateStorage()->thread_state();
  }
  bool IsCreationThread() const { return thread_id_ == CurrentThread(); }

  bool IsAllocationAllowed() const {
    return cppgc::subtle::DisallowGarbageCollectionScope::
        IsGarbageCollectionAllowed(cpp_heap().GetHeapHandle());
  }

  // Waits until sweeping is done and invokes the given callback with
  // the total sizes of live objects in Node and CSS arenas.
  void CollectNodeAndCssStatistics(
      base::OnceCallback<void(size_t allocated_node_bytes,
                              size_t allocated_css_bytes)>);

  // Returns true if incremental marking is currently running, and false
  // otherwise.
  bool IsIncrementalMarking() const;

  // Returns true if the current thread is currently sweeping, i.e., whether the
  // caller is invoked from a destructor, and false otherwise.
  bool IsSweepingOnOwningThread() const;

  // Returns true during heap snapshot generation, and false otherwise.
  bool IsTakingHeapSnapshot() const;

  // Copies a string into the V8 heap profiler, and returns a pointer to the
  // copy. Only valid while taking a heap snapshot.
  const char* CopyNameForHeapSnapshot(const char* name) const;

  ActiveScriptWrappableManager* GetActiveScriptWrappableManager() {
    return active_script_wrappable_manager_.Get();
  }

  static ThreadState* AttachMainThreadForTesting(v8::Platform*);
  static ThreadState* AttachCurrentThreadForTesting(v8::Platform*);

  // Forced garbage collection for testing.
  //
  // Collects garbage as long as live memory decreases (capped at 5).
  void CollectAllGarbageForTesting(
      StackState stack_state = StackState::kNoHeapPointers);

  // Perform stop-the-world garbage collection in young generation for testing.
  void CollectGarbageInYoungGenerationForTesting(
      StackState stack_state = StackState::kNoHeapPointers);

  void EnableDetachedGarbageCollectionsForTesting();

  // Transfers ownership of a CppHeap back to ThreadState on Isolate teardown.
  // Only used in test drivers.
  void RecoverCppHeapAfterIsolateTearDownForTesting();

  // Takes a heap snapshot that can be loaded into DevTools. Requires that
  // `ThreadState` is attached to a `v8::Isolate`.
  //
  // `filename` specifies the path on the system to store the snapshot. If no
  // filename is provided, the snapshot will be emitted to `stdout`.
  //
  // Writing to a file requires a disabled sandbox.
  void TakeHeapSnapshotForTesting(const char* filename) const;

 private:
  static void RecoverCppHeapTrampoline(std::unique_ptr<v8::CppHeap>);

  // Prologue and epilogue callbacks for unified heap garbage collections. Set
  // and released during `AttachToIsolate()` and `DetachFromIsolate()`,
  // respectively.
  static void GcPrologue(v8::Isolate*, v8::GCType, v8::GCCallbackFlags);
  static void GcEpilogue(v8::Isolate*, v8::GCType, v8::GCCallbackFlags);

  explicit ThreadState(v8::Platform*);
  ~ThreadState();

  void RecoverCppHeap(std::unique_ptr<v8::CppHeap>);

  // During setup of a page ThreadState owns CppHeap. The ownership is
  // transferred to the v8::Isolate on its creation.
  std::unique_ptr<v8::CppHeap> owning_cpp_heap_;
  // Even when not owning the CppHeap (as the heap is owned by a v8::Isolate),
  // this pointer will keep a reference to the current CppHeap.
  v8::CppHeap* cpp_heap_;
  std::unique_ptr<v8::EmbedderRootsHandler> embedder_roots_handler_;
  cppgc::HeapHandle& heap_handle_;
  v8::Isolate* isolate_ = nullptr;
  base::PlatformThreadId thread_id_;
  size_t gc_callback_depth_ = 0;
  Persistent<ActiveScriptWrappableManager> active_script_wrappable_manager_;

  // TODO(mlippautz): Refactor to proper base::CheckedObserver once there's more
  // users that want to listen to GC events.
  DevToolsCountersCallback dev_tools_counters_callback_;

  friend class BlinkGCMemoryDumpProvider;
};

}  // namespace blink

#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_THREAD_STATE_H_