// Copyright 2020 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/heap/cppgc-js/cpp-snapshot.h" #include <memory> #include "include/cppgc/internal/name-trait.h" #include "include/cppgc/trace-trait.h" #include "include/cppgc/visitor.h" #include "include/v8-cppgc.h" #include "include/v8-internal.h" #include "include/v8-profiler.h" #include "src/api/api-inl.h" #include "src/base/logging.h" #include "src/execution/isolate.h" #include "src/heap/cppgc-js/cpp-heap.h" #include "src/heap/cppgc/heap-object-header.h" #include "src/heap/cppgc/heap-visitor.h" #include "src/heap/cppgc/visitor.h" #include "src/heap/mark-compact.h" #include "src/objects/js-objects.h" #include "src/objects/objects-inl.h" #include "src/profiler/heap-profiler.h" namespace v8 { namespace internal { class CppGraphBuilderImpl; class StateStorage; class State; HeapObjectHeader; // Node representing a C++ object on the heap. class EmbedderNode : public v8::EmbedderGraph::Node { … }; constexpr HeapObjectHeader* kNoNativeAddress = …; // Node representing an artificial root group, e.g., set of Persistent handles. class EmbedderRootNode final : public EmbedderNode { … }; // Canonical state representing real and artificial (e.g. root) objects. class StateBase { … }; class State final : public StateBase { … }; // Root states are similar to regular states with the difference that they are // always visible. class RootState final : public StateBase { … }; // Abstraction for storing states. Storage allows for creation and lookup of // different state objects. class StateStorage final { … }; void* ExtractEmbedderDataBackref(Isolate* isolate, CppHeap& cpp_heap, v8::Local<v8::Data> v8_value) { … } // The following implements a snapshotting algorithm for C++ objects that also // filters strongly-connected components (SCCs) of only "hidden" objects that // are not (transitively) referencing any non-hidden objects. // // C++ objects come in two versions. // a. Named objects that have been assigned a name through NameProvider. // b. Unnamed objects, that are potentially hidden if the build configuration // requires Oilpan to hide such names. Hidden objects have their name // set to NameProvider::kHiddenName. // // The main challenge for the algorithm is to avoid blowing up the final object // graph with hidden nodes that do not carry information. For that reason, the // algorithm filters SCCs of only hidden objects, e.g.: // ... -> (object) -> (object) -> (hidden) -> (hidden) // In this case the (hidden) objects are filtered from the graph. The trickiest // part is maintaining visibility state for objects referencing other objects // that are currently being processed. // // Main algorithm idea (two passes): // 1. First pass marks all non-hidden objects and those that transitively reach // non-hidden objects as visible. Details: // - Iterate over all objects. // - If object is non-hidden mark it as visible and also mark parent as // visible if needed. // - If object is hidden, traverse children as DFS to find non-hidden // objects. Post-order process the objects and mark those objects as // visible that have child nodes that are visible themselves. // - Maintain an epoch counter (StateStorage::state_count_) to allow // deferring the visibility decision to other objects in the same SCC. This // is similar to the "lowlink" value in Tarjan's algorithm for SCC. // - After the first pass it is guaranteed that all deferred visibility // decisions can be resolved. // 2. Second pass adds nodes and edges for all visible objects. // - Upon first checking the visibility state of an object, all deferred // visibility states are resolved. // // For practical reasons, the recursion is transformed into an iteration. We do // do not use plain Tarjan's algorithm to avoid another pass over all nodes to // create SCCs. class CppGraphBuilderImpl final { … }; // Iterating live objects to mark them as visible if needed. class LiveObjectsForVisibilityIterator final : public cppgc::internal::HeapVisitor<LiveObjectsForVisibilityIterator> { … }; class ParentScope final { … }; // This visitor can be used stand-alone to handle fully weak and ephemeron // containers or as part of the VisibilityVisitor that recursively traverses // the object graph. class WeakVisitor : public JSVisitor { … }; class VisiblityVisitor final : public WeakVisitor { … }; class GraphBuildingRootVisitor final : public cppgc::internal::RootVisitorBase { … }; class GraphBuildingVisitor final : public JSVisitor { … }; // Base class for transforming recursion into iteration. Items are processed // in stack fashion. class CppGraphBuilderImpl::WorkstackItemBase { … }; void CppGraphBuilderImpl::ProcessPendingObjects() { … } // Post-order processing of an object. It's guaranteed that all children have // been processed first. class CppGraphBuilderImpl::VisitationDoneItem final : public WorkstackItemBase { … }; class CppGraphBuilderImpl::VisitationItem final : public WorkstackItemBase { … }; void CppGraphBuilderImpl::VisitForVisibility(State* parent, const HeapObjectHeader& header) { … } void CppGraphBuilderImpl:: VisitEphemeronWithNonGarbageCollectedValueForVisibility( const HeapObjectHeader& key, const void* value, cppgc::TraceDescriptor value_desc) { … } void CppGraphBuilderImpl::VisitEphemeronForVisibility( const HeapObjectHeader& key, const HeapObjectHeader& value) { … } void CppGraphBuilderImpl::VisitWeakContainerForVisibility( const HeapObjectHeader& container_header) { … } void CppGraphBuilderImpl::RecordEphemeronKey(const HeapObjectHeader& container, const HeapObjectHeader& key) { … } void CppGraphBuilderImpl::AddConservativeEphemeronKeyEdgesIfNeeded( const HeapObjectHeader& header) { … } void CppGraphBuilderImpl::VisitForVisibility(State& parent, const TracedReferenceBase& ref) { … } void CppGraphBuilderImpl::VisitRootForGraphBuilding( RootState& root, const HeapObjectHeader& header, const cppgc::SourceLocation& loc) { … } namespace { // Visitor adds edges from native stack roots to objects. class GraphBuildingStackVisitor : public cppgc::internal::ConservativeTracingVisitor, public ::heap::base::StackVisitor, public cppgc::Visitor { … }; } // namespace void CppGraphBuilderImpl::Run() { … } // static void CppGraphBuilder::Run(v8::Isolate* isolate, v8::EmbedderGraph* graph, void* data) { … } } // namespace internal } // namespace v8