31class CppGraphBuilderImpl;
44 size_(name.name_was_hidden ? 0 : size) {}
72 const size_t edge_name_len = edge_name.length();
73 named_edges_.emplace_back(std::make_unique<
char[]>(edge_name_len + 1));
75 snprintf(named_edge_str, edge_name_len + 1,
"%s", edge_name.c_str());
76 return named_edge_str;
172 std::vector<StateBase*> dependencies;
173 while (current->visibility_dependency_ &&
174 current->visibility_dependency_ != current) {
176 dependencies.push_back(current);
177 current = current->visibility_dependency_;
180 auto* new_visibility_dependency =
current;
183 new_visibility_dependency =
nullptr;
189 new_visibility_dependency =
nullptr;
192 current->visibility_dependency_ = new_visibility_dependency;
193 for (
auto* state : dependencies) {
194 state->visibility_ = new_visibility;
195 state->visibility_dependency_ = new_visibility_dependency;
225 dependency = dependency->FollowDependencies();
226 DCHECK(dependency->IsVisited());
253 if (dependency->IsPending()) {
288 template <
typename Callback>
295 template <
typename Callback>
302 template <
typename Callback>
337 return states_.find(
key) != states_.end();
342 return *states_.at(
key).get();
346 return static_cast<State&
>(GetExistingState(&header));
350 if (!StateExists(&header)) {
351 auto it = states_.insert(std::make_pair(
352 &header, std::make_unique<State>(header, ++
state_count_)));
356 return GetExistingState(header);
360 CHECK(!StateExists(root_node));
361 auto it = states_.insert(std::make_pair(
362 root_node, std::make_unique<RootState>(root_node, ++
state_count_)));
365 return static_cast<RootState&
>(*it.first->second);
368 template <
typename Callback>
370 for (
auto& state : states_) {
376 std::unordered_map<const void*, std::unique_ptr<StateBase>>
states_;
386 if (!IsJSObject(*v8_object) ||
443 : cpp_heap_(cpp_heap),
graph_(graph) {}
451 void VisitEphemeronWithNonGarbageCollectedValueForVisibility(
457 void ProcessPendingObjects();
470 graph_.AddNode(std::unique_ptr<v8::EmbedderGraph::Node>{
473 if (size > node_size) {
474 graph_.AddNativeSize(size - node_size);
480 const std::string& edge_name) {
482 auto& current = states_.GetExistingState(header);
483 if (!current.IsVisibleNotDependent())
return;
490 if (!current.get_node()) {
491 current.set_node(AddNode(header));
494 if (!edge_name.empty()) {
503 const std::string& edge_name) {
512 auto* v8_node =
graph_.V8Node(v8_data);
513 if (!edge_name.empty()) {
521 if (!edge_name.empty())
return;
528 if (!back_reference_object)
return;
532 auto& back_header = HeapObjectHeader::FromObject(back_reference_object);
533 auto& back_state = states_.GetExistingState(back_header);
537 if (parent.
header() != back_state.header())
return;
541 if (!back_state.get_node()) {
542 back_state.set_node(AddNode(back_header));
544 back_state.get_node()->SetWrapperNode(v8_node);
546 auto* profiler =
reinterpret_cast<Isolate*
>(cpp_heap_.isolate())
549 if (profiler->HasGetDetachednessCallback()) {
550 back_state.get_node()->SetDetachedness(
551 profiler->GetDetachedness(v8_data.
As<
v8::Value>(), 0));
565 if (!edge_name.empty()) {
574 class WorkstackItemBase;
575 class VisitationItem;
576 class VisitationDoneItem;
600 if (header.
IsFree())
return true;
635 const auto& container_header =
636 HeapObjectHeader::FromObject(strong_desc.base_object_payload);
641 if (!weak_desc.callback) {
658 container_header.TraceImpl(
this);
665 auto& key_header = HeapObjectHeader::FromObject(
key);
666 if (current_weak_container_header_) {
667 graph_builder_.RecordEphemeronKey(*current_weak_container_header_,
670 if (!value_desc.base_object_payload) {
673 graph_builder_.VisitEphemeronWithNonGarbageCollectedValueForVisibility(
674 key_header, value, value_desc);
679 key_header, HeapObjectHeader::FromObject(value));
687 : weak_visitor_(weak_visitor),
688 prev_weak_container_header_(
689 weak_visitor_.current_weak_container_header_) {
690 weak_visitor_.current_weak_container_header_ = &weak_container_header;
693 weak_visitor_.current_weak_container_header_ =
694 prev_weak_container_header_;
710 :
WeakVisitor(graph_builder), parent_scope_(parent_scope) {}
715 &parent_scope_.ParentAsRegularState(),
716 HeapObjectHeader::FromObject(desc.base_object_payload));
721 graph_builder_.VisitForVisibility(parent_scope_.ParentAsRegularState(),
738 parent_scope_.ParentAsRootState(),
739 HeapObjectHeader::FromObject(desc.base_object_payload), loc);
753 parent_scope_(parent_scope) {}
758 parent_scope_.ParentAsRegularState(),
759 HeapObjectHeader::FromObject(desc.base_object_payload), edge_name_);
768 parent_scope_.ParentAsRegularState(),
769 HeapObjectHeader::FromObject(strong_desc.base_object_payload),
780 edge_name_ = std::move(edge_name);
805 while (!workstack_.empty()) {
806 std::unique_ptr<WorkstackItemBase> item = std::move(workstack_.back());
807 workstack_.pop_back();
808 item->Process(*
this);
835 graph_builder.workstack_.push_back(std::unique_ptr<WorkstackItemBase>{
840 if (!
current_.header()->IsInConstruction()) {
842 current_.header()->TraceImpl(&object_visitor);
852 auto& current = states_.GetOrCreateState(header);
854 if (current.IsVisited()) {
863 current.MarkVisited();
865 current.MarkPending();
866 workstack_.push_back(std::unique_ptr<WorkstackItemBase>{
870 current.MarkVisible();
886 auto& key_state = states_.GetOrCreateState(
key);
891 value_desc.
callback(&visitor, value);
892 key_state.AddEagerEphemeronEdge(value, value_desc.
callback);
897 auto& key_state = states_.GetOrCreateState(
key);
898 VisitForVisibility(&key_state, value);
899 key_state.AddEphemeronEdge(value);
906 states_.GetOrCreateState(container_header).MarkAsWeakContainer();
911 auto& container_state = states_.GetOrCreateState(container);
912 DCHECK(container_state.IsWeakContainer());
913 container_state.RecordEphemeronKey(
key);
918 auto& state = states_.GetExistingState(header);
919 if (state.WasVisitedFromStack()) {
922 state.MarkVisitedFromStack();
924 DCHECK(state.IsWeakContainer());
925 AddEdge(state,
key,
"");
941 State& current = states_.GetExistingState(header);
942 if (!current.IsVisibleNotDependent())
return;
944 AddRootEdge(root, current, loc.
ToString());
950class GraphBuildingStackVisitor
963 void VisitPointer(
const void* address)
final {
968 TraceConservativelyIfNeeded(address);
971 void VisitFullyConstructedConservatively(HeapObjectHeader& header)
final {
972 VisitConservatively(header);
975 void VisitInConstructionConservatively(HeapObjectHeader& header,
976 TraceConservativelyCallback)
final {
977 VisitConservatively(header);
981 void VisitConservatively(
const HeapObjectHeader& header) {
983 {header.ObjectStart(), nullptr},
997 cpp_heap_.sweeper().FinishIfRunning();
999 cpp_heap_.GetHeapHandle());
1003 visitor.
Traverse(cpp_heap_.raw_heap());
1005 states_.ForAllStates([
this](
StateBase* state_base) {
1007 State& state = *
static_cast<State*
>(state_base);
1009 if (!state.IsVisibleNotDependent()) {
1010 graph_.AddNativeSize(state.header()->AllocatedSize());
1017 if (state.IsWeakContainer())
return;
1021 if (!state.header()->IsInConstruction()) {
1023 state.header()->TraceImpl(&object_visitor);
1026 AddEdge(state, value,
"part of key -> value pair in ephemeron table");
1029 "part of key -> value pair in ephemeron table");
1030 state.ForAllEagerEphemeronEdges(
1038 states_.CreateRootState(AddRootNode(
"C++ Persistent roots")));
1040 cpp_heap_.GetStrongPersistentRegion().Iterate(root_object_visitor);
1044 AddRootNode(
"C++ CrossThreadPersistent roots")));
1047 cpp_heap_.GetStrongCrossThreadPersistentRegion().Iterate(
1048 root_object_visitor);
1053 if (cpp_heap_.isolate()->heap()->IsGCWithMainThreadStack()) {
1055 states_.CreateRootState(AddRootNode(
"C++ native stack roots")));
1057 GraphBuildingStackVisitor stack_visitor(*
this, cpp_heap_,
1058 root_object_visitor);
1059 cpp_heap_.stack()->IteratePointersUntilMarker(&stack_visitor);
1070 graph_builder.
Run();
union v8::internal::@341::BuiltinMetadata::KindSpecificData data
void Traverse(RawHeap &heap)
V8_INLINE Local< S > As() const
std::string ToString() const
V8_INLINE Local< Data > Get(Isolate *isolate) const
static v8::internal::DirectHandle< To > OpenDirectHandle(v8::Local< From > handle)
V8_INLINE bool IsEmpty() const
VisitationDoneItem(State *parent, State ¤t)
void Process(CppGraphBuilderImpl &graph_builder) final
VisitationItem(State *parent, State ¤t)
void Process(CppGraphBuilderImpl &graph_builder) final
virtual ~WorkstackItemBase()=default
virtual void Process(CppGraphBuilderImpl &)=0
WorkstackItemBase(State *parent, State ¤t)
void VisitWeakContainerForVisibility(const HeapObjectHeader &)
void VisitEphemeronWithNonGarbageCollectedValueForVisibility(const HeapObjectHeader &key, const void *value, cppgc::TraceDescriptor value_desc)
void ProcessPendingObjects()
void VisitRootForGraphBuilding(RootState &, const HeapObjectHeader &, const cppgc::SourceLocation &)
void AddEdge(State &parent, const TracedReferenceBase &ref, const std::string &edge_name)
EmbedderNode * AddNode(const HeapObjectHeader &header)
std::vector< std::unique_ptr< WorkstackItemBase > > workstack_
void VisitEphemeronForVisibility(const HeapObjectHeader &key, const HeapObjectHeader &value)
void AddConservativeEphemeronKeyEdgesIfNeeded(const HeapObjectHeader &)
CppGraphBuilderImpl(CppHeap &cpp_heap, v8::EmbedderGraph &graph)
EmbedderRootNode * AddRootNode(const char *name)
v8::EmbedderGraph & graph_
void VisitForVisibility(State *parent, const HeapObjectHeader &)
void AddEdge(State &parent, const HeapObjectHeader &header, const std::string &edge_name)
void RecordEphemeronKey(const HeapObjectHeader &, const HeapObjectHeader &)
void AddRootEdge(RootState &root, State &child, std::string edge_name)
static void Run(v8::Isolate *isolate, v8::EmbedderGraph *graph, void *data)
const char * Name() final
~EmbedderNode() override=default
const char * InternalizeEdgeName(std::string edge_name)
size_t SizeInBytes() final
void SetWrapperNode(v8::EmbedderGraph::Node *wrapper_node)
std::vector< std::unique_ptr< char[]> > named_edges_
Detachedness detachedness_
Detachedness GetDetachedness() final
EmbedderNode(const HeapObjectHeader *header_address, cppgc::internal::HeapObjectName name, size_t size)
Node * WrapperNode() final
const void * header_address_
void SetDetachedness(Detachedness detachedness)
const void * GetAddress() override
EmbedderRootNode(const char *name)
~EmbedderRootNode() final=default
const ParentScope & parent_scope_
GraphBuildingRootVisitor(CppGraphBuilderImpl &graph_builder, const ParentScope &parent_scope)
CppGraphBuilderImpl & graph_builder_
void VisitRoot(const void *, cppgc::TraceDescriptor desc, const cppgc::SourceLocation &loc) final
void set_edge_name(std::string edge_name)
CppGraphBuilderImpl & graph_builder_
void Visit(const TracedReferenceBase &ref) final
void Visit(const void *, cppgc::TraceDescriptor desc) final
const ParentScope & parent_scope_
GraphBuildingVisitor(CppGraphBuilderImpl &graph_builder, const ParentScope &parent_scope)
void VisitWeakContainer(const void *object, cppgc::TraceDescriptor strong_desc, cppgc::TraceDescriptor weak_desc, cppgc::WeakCallback, const void *) final
HeapProfiler * heap_profiler() const
V8_INLINE void * GetCppHeapWrappable(IsolateForPointerCompression isolate) const
CppGraphBuilderImpl & graph_builder_
bool VisitHeapObjectHeader(HeapObjectHeader &header)
LiveObjectsForVisibilityIterator(CppGraphBuilderImpl &graph_builder)
RootState & ParentAsRootState() const
ParentScope(StateBase &parent)
State & ParentAsRegularState() const
~RootState() final=default
RootState(EmbedderRootNode *node, size_t state_count)
const size_t state_count_
StateBase * FollowDependencies()
void set_node(EmbedderNode *node)
Visibility GetVisibility()
virtual ~StateBase()=default
EmbedderNode * get_node()
bool IsVisibleNotDependent()
StateBase * visibility_dependency_
StateBase(const void *key, size_t state_count, Visibility visibility, EmbedderNode *node, bool visited)
std::unordered_map< const void *, std::unique_ptr< StateBase > > states_
RootState & CreateRootState(EmbedderRootNode *root_node)
bool StateExists(const void *key) const
State & GetOrCreateState(const HeapObjectHeader &header)
void ForAllStates(Callback callback)
State & GetExistingState(const HeapObjectHeader &header) const
StateBase & GetExistingState(const void *key) const
void MarkVisitedFromStack()
void AddEagerEphemeronEdge(const void *value, cppgc::TraceCallback callback)
bool IsWeakContainer() const
void RecordEphemeronKey(const HeapObjectHeader &key)
std::unordered_set< const HeapObjectHeader * > ephemeron_edges_
bool WasVisitedFromStack() const
std::unordered_map< const void *, cppgc::TraceCallback > eager_ephemeron_edges_
void MarkAsWeakContainer()
void ForAllEagerEphemeronEdges(Callback callback)
bool was_visited_from_stack_
State(const HeapObjectHeader &header, size_t state_count)
const HeapObjectHeader * header() const
void ForAllEphemeronEdges(Callback callback)
void ForAllEphemeronKeys(Callback callback)
void MarkDependentVisibility(StateBase *dependency)
std::unordered_set< const HeapObjectHeader * > ephemeron_keys_
void AddEphemeronEdge(const HeapObjectHeader &value)
void Visit(const TracedReferenceBase &ref) final
void Visit(const void *, cppgc::TraceDescriptor desc) final
const ParentScope & parent_scope_
VisiblityVisitor(CppGraphBuilderImpl &graph_builder, const ParentScope &parent_scope)
WeakContainerScope(WeakVisitor &weak_visitor, const HeapObjectHeader &weak_container_header)
const HeapObjectHeader * prev_weak_container_header_
WeakVisitor & weak_visitor_
void VisitEphemeron(const void *key, const void *value, cppgc::TraceDescriptor value_desc) final
void VisitWeakContainer(const void *object, cppgc::TraceDescriptor strong_desc, cppgc::TraceDescriptor weak_desc, cppgc::WeakCallback, const void *) final
CppGraphBuilderImpl & graph_builder_
WeakVisitor(CppGraphBuilderImpl &graph_builder)
GraphBuildingRootVisitor & root_visitor_
CppGraphBuilderImpl & graph_builder_
void(*)(const LivenessBroker &, const void *) WeakCallback
void(*)(Visitor *visitor, const void *object) TraceCallback
void * ExtractEmbedderDataBackref(Isolate *isolate, CppHeap &cpp_heap, v8::Local< v8::Data > v8_value)
constexpr HeapObjectHeader * kNoNativeAddress
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in name
bool IsJSApiWrapperObject(Tagged< Map > map)
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
constexpr CppHeapPointerTagRange kAnyCppHeapPointer(CppHeapPointerTag::kFirstTag, CppHeapPointerTag::kLastTag)
BytecodeSequenceNode * parent_
#define DCHECK_NOT_NULL(val)
#define CHECK_NOT_NULL(val)
#define DCHECK_NE(v1, v2)
#define CHECK_NE(lhs, rhs)
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
#define DCHECK_EQ(v1, v2)
EmbedderGraph::Node * node_
std::unique_ptr< ValueMirror > key