11cb0ef41Sopenharmony_ci// Copyright 2020 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#include "src/heap/cppgc-js/cpp-snapshot.h" 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci#include <memory> 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ci#include "include/cppgc/internal/name-trait.h" 101cb0ef41Sopenharmony_ci#include "include/cppgc/trace-trait.h" 111cb0ef41Sopenharmony_ci#include "include/v8-cppgc.h" 121cb0ef41Sopenharmony_ci#include "include/v8-profiler.h" 131cb0ef41Sopenharmony_ci#include "src/api/api-inl.h" 141cb0ef41Sopenharmony_ci#include "src/base/logging.h" 151cb0ef41Sopenharmony_ci#include "src/execution/isolate.h" 161cb0ef41Sopenharmony_ci#include "src/heap/cppgc-js/cpp-heap.h" 171cb0ef41Sopenharmony_ci#include "src/heap/cppgc/heap-object-header.h" 181cb0ef41Sopenharmony_ci#include "src/heap/cppgc/heap-visitor.h" 191cb0ef41Sopenharmony_ci#include "src/heap/embedder-tracing.h" 201cb0ef41Sopenharmony_ci#include "src/heap/mark-compact.h" 211cb0ef41Sopenharmony_ci#include "src/objects/js-objects.h" 221cb0ef41Sopenharmony_ci#include "src/profiler/heap-profiler.h" 231cb0ef41Sopenharmony_ci 241cb0ef41Sopenharmony_cinamespace v8 { 251cb0ef41Sopenharmony_cinamespace internal { 261cb0ef41Sopenharmony_ci 271cb0ef41Sopenharmony_ciclass CppGraphBuilderImpl; 281cb0ef41Sopenharmony_ciclass StateStorage; 291cb0ef41Sopenharmony_ciclass State; 301cb0ef41Sopenharmony_ci 311cb0ef41Sopenharmony_ciusing cppgc::internal::GCInfo; 321cb0ef41Sopenharmony_ciusing cppgc::internal::GlobalGCInfoTable; 331cb0ef41Sopenharmony_ciusing cppgc::internal::HeapObjectHeader; 341cb0ef41Sopenharmony_ci 351cb0ef41Sopenharmony_ci// Node representing a C++ object on the heap. 361cb0ef41Sopenharmony_ciclass EmbedderNode : public v8::EmbedderGraph::Node { 371cb0ef41Sopenharmony_ci public: 381cb0ef41Sopenharmony_ci EmbedderNode(cppgc::internal::HeapObjectName name, size_t size) 391cb0ef41Sopenharmony_ci : name_(name), size_(size) { 401cb0ef41Sopenharmony_ci USE(size_); 411cb0ef41Sopenharmony_ci } 421cb0ef41Sopenharmony_ci ~EmbedderNode() override = default; 431cb0ef41Sopenharmony_ci 441cb0ef41Sopenharmony_ci const char* Name() final { return name_.value; } 451cb0ef41Sopenharmony_ci size_t SizeInBytes() final { return name_.name_was_hidden ? 0 : size_; } 461cb0ef41Sopenharmony_ci 471cb0ef41Sopenharmony_ci void SetWrapperNode(v8::EmbedderGraph::Node* wrapper_node) { 481cb0ef41Sopenharmony_ci // An embedder node may only be merged with a single wrapper node, as 491cb0ef41Sopenharmony_ci // consumers of the graph may merge a node and its wrapper node. 501cb0ef41Sopenharmony_ci // 511cb0ef41Sopenharmony_ci // TODO(chromium:1218404): Add a DCHECK() to avoid overriding an already 521cb0ef41Sopenharmony_ci // set `wrapper_node_`. This can currently happen with global proxies that 531cb0ef41Sopenharmony_ci // are rewired (and still kept alive) after reloading a page, see 541cb0ef41Sopenharmony_ci // `AddEdge`. We accept overriding the wrapper node in such cases, 551cb0ef41Sopenharmony_ci // leading to a random merged node and separated nodes for all other 561cb0ef41Sopenharmony_ci // proxies. 571cb0ef41Sopenharmony_ci wrapper_node_ = wrapper_node; 581cb0ef41Sopenharmony_ci } 591cb0ef41Sopenharmony_ci Node* WrapperNode() final { return wrapper_node_; } 601cb0ef41Sopenharmony_ci 611cb0ef41Sopenharmony_ci void SetDetachedness(Detachedness detachedness) { 621cb0ef41Sopenharmony_ci detachedness_ = detachedness; 631cb0ef41Sopenharmony_ci } 641cb0ef41Sopenharmony_ci Detachedness GetDetachedness() final { return detachedness_; } 651cb0ef41Sopenharmony_ci 661cb0ef41Sopenharmony_ci // Edge names are passed to V8 but are required to be held alive from the 671cb0ef41Sopenharmony_ci // embedder until the snapshot is compiled. 681cb0ef41Sopenharmony_ci const char* InternalizeEdgeName(std::string edge_name) { 691cb0ef41Sopenharmony_ci const size_t edge_name_len = edge_name.length(); 701cb0ef41Sopenharmony_ci named_edges_.emplace_back(std::make_unique<char[]>(edge_name_len + 1)); 711cb0ef41Sopenharmony_ci char* named_edge_str = named_edges_.back().get(); 721cb0ef41Sopenharmony_ci snprintf(named_edge_str, edge_name_len + 1, "%s", edge_name.c_str()); 731cb0ef41Sopenharmony_ci return named_edge_str; 741cb0ef41Sopenharmony_ci } 751cb0ef41Sopenharmony_ci 761cb0ef41Sopenharmony_ci private: 771cb0ef41Sopenharmony_ci cppgc::internal::HeapObjectName name_; 781cb0ef41Sopenharmony_ci size_t size_; 791cb0ef41Sopenharmony_ci Node* wrapper_node_ = nullptr; 801cb0ef41Sopenharmony_ci Detachedness detachedness_ = Detachedness::kUnknown; 811cb0ef41Sopenharmony_ci std::vector<std::unique_ptr<char[]>> named_edges_; 821cb0ef41Sopenharmony_ci}; 831cb0ef41Sopenharmony_ci 841cb0ef41Sopenharmony_ci// Node representing an artificial root group, e.g., set of Persistent handles. 851cb0ef41Sopenharmony_ciclass EmbedderRootNode final : public EmbedderNode { 861cb0ef41Sopenharmony_ci public: 871cb0ef41Sopenharmony_ci explicit EmbedderRootNode(const char* name) 881cb0ef41Sopenharmony_ci : EmbedderNode({name, false}, 0) {} 891cb0ef41Sopenharmony_ci ~EmbedderRootNode() final = default; 901cb0ef41Sopenharmony_ci 911cb0ef41Sopenharmony_ci bool IsRootNode() final { return true; } 921cb0ef41Sopenharmony_ci}; 931cb0ef41Sopenharmony_ci 941cb0ef41Sopenharmony_ci// Canonical state representing real and artificial (e.g. root) objects. 951cb0ef41Sopenharmony_ciclass StateBase { 961cb0ef41Sopenharmony_ci public: 971cb0ef41Sopenharmony_ci // Objects can either be hidden/visible, or depend on some other nodes while 981cb0ef41Sopenharmony_ci // traversing the same SCC. 991cb0ef41Sopenharmony_ci enum class Visibility { 1001cb0ef41Sopenharmony_ci kHidden, 1011cb0ef41Sopenharmony_ci kDependentVisibility, 1021cb0ef41Sopenharmony_ci kVisible, 1031cb0ef41Sopenharmony_ci }; 1041cb0ef41Sopenharmony_ci 1051cb0ef41Sopenharmony_ci StateBase(const void* key, size_t state_count, Visibility visibility, 1061cb0ef41Sopenharmony_ci EmbedderNode* node, bool visited) 1071cb0ef41Sopenharmony_ci : key_(key), 1081cb0ef41Sopenharmony_ci state_count_(state_count), 1091cb0ef41Sopenharmony_ci visibility_(visibility), 1101cb0ef41Sopenharmony_ci node_(node), 1111cb0ef41Sopenharmony_ci visited_(visited) { 1121cb0ef41Sopenharmony_ci DCHECK_NE(Visibility::kDependentVisibility, visibility); 1131cb0ef41Sopenharmony_ci } 1141cb0ef41Sopenharmony_ci virtual ~StateBase() = default; 1151cb0ef41Sopenharmony_ci 1161cb0ef41Sopenharmony_ci // Visited objects have already been processed or are currently being 1171cb0ef41Sopenharmony_ci // processed, see also IsPending() below. 1181cb0ef41Sopenharmony_ci bool IsVisited() const { return visited_; } 1191cb0ef41Sopenharmony_ci 1201cb0ef41Sopenharmony_ci // Pending objects are currently being processed as part of the same SCC. 1211cb0ef41Sopenharmony_ci bool IsPending() const { return pending_; } 1221cb0ef41Sopenharmony_ci 1231cb0ef41Sopenharmony_ci bool IsVisibleNotDependent() { 1241cb0ef41Sopenharmony_ci auto v = GetVisibility(); 1251cb0ef41Sopenharmony_ci CHECK_NE(Visibility::kDependentVisibility, v); 1261cb0ef41Sopenharmony_ci return v == Visibility::kVisible; 1271cb0ef41Sopenharmony_ci } 1281cb0ef41Sopenharmony_ci 1291cb0ef41Sopenharmony_ci void set_node(EmbedderNode* node) { 1301cb0ef41Sopenharmony_ci CHECK_EQ(Visibility::kVisible, GetVisibility()); 1311cb0ef41Sopenharmony_ci DCHECK_NULL(node_); 1321cb0ef41Sopenharmony_ci node_ = node; 1331cb0ef41Sopenharmony_ci } 1341cb0ef41Sopenharmony_ci 1351cb0ef41Sopenharmony_ci EmbedderNode* get_node() { 1361cb0ef41Sopenharmony_ci CHECK_EQ(Visibility::kVisible, GetVisibility()); 1371cb0ef41Sopenharmony_ci return node_; 1381cb0ef41Sopenharmony_ci } 1391cb0ef41Sopenharmony_ci 1401cb0ef41Sopenharmony_ci protected: 1411cb0ef41Sopenharmony_ci const void* key_; 1421cb0ef41Sopenharmony_ci // State count keeps track of node processing order. It is used to create only 1431cb0ef41Sopenharmony_ci // dependencies on ancestors in the sub graph which ensures that there will be 1441cb0ef41Sopenharmony_ci // no cycles in dependencies. 1451cb0ef41Sopenharmony_ci const size_t state_count_; 1461cb0ef41Sopenharmony_ci 1471cb0ef41Sopenharmony_ci Visibility visibility_; 1481cb0ef41Sopenharmony_ci StateBase* visibility_dependency_ = nullptr; 1491cb0ef41Sopenharmony_ci EmbedderNode* node_; 1501cb0ef41Sopenharmony_ci bool visited_; 1511cb0ef41Sopenharmony_ci bool pending_ = false; 1521cb0ef41Sopenharmony_ci 1531cb0ef41Sopenharmony_ci Visibility GetVisibility() { 1541cb0ef41Sopenharmony_ci FollowDependencies(); 1551cb0ef41Sopenharmony_ci return visibility_; 1561cb0ef41Sopenharmony_ci } 1571cb0ef41Sopenharmony_ci 1581cb0ef41Sopenharmony_ci StateBase* FollowDependencies() { 1591cb0ef41Sopenharmony_ci if (visibility_ != Visibility::kDependentVisibility) { 1601cb0ef41Sopenharmony_ci CHECK_NULL(visibility_dependency_); 1611cb0ef41Sopenharmony_ci return this; 1621cb0ef41Sopenharmony_ci } 1631cb0ef41Sopenharmony_ci StateBase* current = this; 1641cb0ef41Sopenharmony_ci std::vector<StateBase*> dependencies; 1651cb0ef41Sopenharmony_ci while (current->visibility_dependency_ && 1661cb0ef41Sopenharmony_ci current->visibility_dependency_ != current) { 1671cb0ef41Sopenharmony_ci DCHECK_EQ(Visibility::kDependentVisibility, current->visibility_); 1681cb0ef41Sopenharmony_ci dependencies.push_back(current); 1691cb0ef41Sopenharmony_ci current = current->visibility_dependency_; 1701cb0ef41Sopenharmony_ci } 1711cb0ef41Sopenharmony_ci auto new_visibility = Visibility::kDependentVisibility; 1721cb0ef41Sopenharmony_ci auto* new_visibility_dependency = current; 1731cb0ef41Sopenharmony_ci if (current->visibility_ == Visibility::kVisible) { 1741cb0ef41Sopenharmony_ci new_visibility = Visibility::kVisible; 1751cb0ef41Sopenharmony_ci new_visibility_dependency = nullptr; 1761cb0ef41Sopenharmony_ci } else if (!IsPending()) { 1771cb0ef41Sopenharmony_ci DCHECK(IsVisited()); 1781cb0ef41Sopenharmony_ci // The object was not visible (above case). Having a dependency on itself 1791cb0ef41Sopenharmony_ci // or null means no visible object was found. 1801cb0ef41Sopenharmony_ci new_visibility = Visibility::kHidden; 1811cb0ef41Sopenharmony_ci new_visibility_dependency = nullptr; 1821cb0ef41Sopenharmony_ci } 1831cb0ef41Sopenharmony_ci current->visibility_ = new_visibility; 1841cb0ef41Sopenharmony_ci current->visibility_dependency_ = new_visibility_dependency; 1851cb0ef41Sopenharmony_ci for (auto* state : dependencies) { 1861cb0ef41Sopenharmony_ci state->visibility_ = new_visibility; 1871cb0ef41Sopenharmony_ci state->visibility_dependency_ = new_visibility_dependency; 1881cb0ef41Sopenharmony_ci } 1891cb0ef41Sopenharmony_ci return current; 1901cb0ef41Sopenharmony_ci } 1911cb0ef41Sopenharmony_ci 1921cb0ef41Sopenharmony_ci friend class State; 1931cb0ef41Sopenharmony_ci}; 1941cb0ef41Sopenharmony_ci 1951cb0ef41Sopenharmony_ciclass State final : public StateBase { 1961cb0ef41Sopenharmony_ci public: 1971cb0ef41Sopenharmony_ci State(const HeapObjectHeader& header, size_t state_count) 1981cb0ef41Sopenharmony_ci : StateBase(&header, state_count, Visibility::kHidden, nullptr, false) {} 1991cb0ef41Sopenharmony_ci ~State() final = default; 2001cb0ef41Sopenharmony_ci 2011cb0ef41Sopenharmony_ci const HeapObjectHeader* header() const { 2021cb0ef41Sopenharmony_ci return static_cast<const HeapObjectHeader*>(key_); 2031cb0ef41Sopenharmony_ci } 2041cb0ef41Sopenharmony_ci 2051cb0ef41Sopenharmony_ci void MarkVisited() { visited_ = true; } 2061cb0ef41Sopenharmony_ci 2071cb0ef41Sopenharmony_ci void MarkPending() { pending_ = true; } 2081cb0ef41Sopenharmony_ci void UnmarkPending() { pending_ = false; } 2091cb0ef41Sopenharmony_ci 2101cb0ef41Sopenharmony_ci void MarkVisible() { 2111cb0ef41Sopenharmony_ci visibility_ = Visibility::kVisible; 2121cb0ef41Sopenharmony_ci visibility_dependency_ = nullptr; 2131cb0ef41Sopenharmony_ci } 2141cb0ef41Sopenharmony_ci 2151cb0ef41Sopenharmony_ci void MarkDependentVisibility(StateBase* dependency) { 2161cb0ef41Sopenharmony_ci // Follow and update dependencies as much as possible. 2171cb0ef41Sopenharmony_ci dependency = dependency->FollowDependencies(); 2181cb0ef41Sopenharmony_ci DCHECK(dependency->IsVisited()); 2191cb0ef41Sopenharmony_ci if (visibility_ == StateBase::Visibility::kVisible) { 2201cb0ef41Sopenharmony_ci // Already visible, no dependency needed. 2211cb0ef41Sopenharmony_ci DCHECK_NULL(visibility_dependency_); 2221cb0ef41Sopenharmony_ci return; 2231cb0ef41Sopenharmony_ci } 2241cb0ef41Sopenharmony_ci if (dependency->visibility_ == Visibility::kVisible) { 2251cb0ef41Sopenharmony_ci // Simple case: Dependency is visible. 2261cb0ef41Sopenharmony_ci visibility_ = Visibility::kVisible; 2271cb0ef41Sopenharmony_ci visibility_dependency_ = nullptr; 2281cb0ef41Sopenharmony_ci return; 2291cb0ef41Sopenharmony_ci } 2301cb0ef41Sopenharmony_ci if ((visibility_dependency_ && 2311cb0ef41Sopenharmony_ci (visibility_dependency_->state_count_ > dependency->state_count_)) || 2321cb0ef41Sopenharmony_ci (!visibility_dependency_ && 2331cb0ef41Sopenharmony_ci (state_count_ > dependency->state_count_))) { 2341cb0ef41Sopenharmony_ci // Only update when new state_count_ < original state_count_. This 2351cb0ef41Sopenharmony_ci // ensures that we pick an ancestor as dependency and not a child which 2361cb0ef41Sopenharmony_ci // is guaranteed to converge to an answer. 2371cb0ef41Sopenharmony_ci // 2381cb0ef41Sopenharmony_ci // Dependency is now 2391cb0ef41Sopenharmony_ci // a) either pending with unknown visibility (same call chain), or 2401cb0ef41Sopenharmony_ci // b) not pending and has defined visibility. 2411cb0ef41Sopenharmony_ci // 2421cb0ef41Sopenharmony_ci // It's not possible to point to a state that is not pending but has 2431cb0ef41Sopenharmony_ci // dependent visibility because dependencies are updated to the top-most 2441cb0ef41Sopenharmony_ci // dependency at the beginning of method. 2451cb0ef41Sopenharmony_ci if (dependency->IsPending()) { 2461cb0ef41Sopenharmony_ci visibility_ = Visibility::kDependentVisibility; 2471cb0ef41Sopenharmony_ci visibility_dependency_ = dependency; 2481cb0ef41Sopenharmony_ci } else { 2491cb0ef41Sopenharmony_ci CHECK_NE(Visibility::kDependentVisibility, dependency->visibility_); 2501cb0ef41Sopenharmony_ci if (dependency->visibility_ == Visibility::kVisible) { 2511cb0ef41Sopenharmony_ci visibility_ = Visibility::kVisible; 2521cb0ef41Sopenharmony_ci visibility_dependency_ = nullptr; 2531cb0ef41Sopenharmony_ci } 2541cb0ef41Sopenharmony_ci } 2551cb0ef41Sopenharmony_ci } 2561cb0ef41Sopenharmony_ci } 2571cb0ef41Sopenharmony_ci 2581cb0ef41Sopenharmony_ci void MarkAsWeakContainer() { is_weak_container_ = true; } 2591cb0ef41Sopenharmony_ci bool IsWeakContainer() const { return is_weak_container_; } 2601cb0ef41Sopenharmony_ci 2611cb0ef41Sopenharmony_ci void AddEphemeronEdge(const HeapObjectHeader& value) { 2621cb0ef41Sopenharmony_ci // This ignores duplicate entries (in different containers) for the same 2631cb0ef41Sopenharmony_ci // Key->Value pairs. Only one edge will be emitted in this case. 2641cb0ef41Sopenharmony_ci ephemeron_edges_.insert(&value); 2651cb0ef41Sopenharmony_ci } 2661cb0ef41Sopenharmony_ci 2671cb0ef41Sopenharmony_ci void AddEagerEphemeronEdge(const void* value, cppgc::TraceCallback callback) { 2681cb0ef41Sopenharmony_ci eager_ephemeron_edges_.insert({value, callback}); 2691cb0ef41Sopenharmony_ci } 2701cb0ef41Sopenharmony_ci 2711cb0ef41Sopenharmony_ci template <typename Callback> 2721cb0ef41Sopenharmony_ci void ForAllEphemeronEdges(Callback callback) { 2731cb0ef41Sopenharmony_ci for (const HeapObjectHeader* value : ephemeron_edges_) { 2741cb0ef41Sopenharmony_ci callback(*value); 2751cb0ef41Sopenharmony_ci } 2761cb0ef41Sopenharmony_ci } 2771cb0ef41Sopenharmony_ci 2781cb0ef41Sopenharmony_ci template <typename Callback> 2791cb0ef41Sopenharmony_ci void ForAllEagerEphemeronEdges(Callback callback) { 2801cb0ef41Sopenharmony_ci for (const auto& pair : eager_ephemeron_edges_) { 2811cb0ef41Sopenharmony_ci callback(pair.first, pair.second); 2821cb0ef41Sopenharmony_ci } 2831cb0ef41Sopenharmony_ci } 2841cb0ef41Sopenharmony_ci 2851cb0ef41Sopenharmony_ci private: 2861cb0ef41Sopenharmony_ci bool is_weak_container_ = false; 2871cb0ef41Sopenharmony_ci // Values that are held alive through ephemerons by this particular key. 2881cb0ef41Sopenharmony_ci std::unordered_set<const HeapObjectHeader*> ephemeron_edges_; 2891cb0ef41Sopenharmony_ci // Values that are eagerly traced and held alive through ephemerons by this 2901cb0ef41Sopenharmony_ci // particular key. 2911cb0ef41Sopenharmony_ci std::unordered_map<const void*, cppgc::TraceCallback> eager_ephemeron_edges_; 2921cb0ef41Sopenharmony_ci}; 2931cb0ef41Sopenharmony_ci 2941cb0ef41Sopenharmony_ci// Root states are similar to regular states with the difference that they are 2951cb0ef41Sopenharmony_ci// always visible. 2961cb0ef41Sopenharmony_ciclass RootState final : public StateBase { 2971cb0ef41Sopenharmony_ci public: 2981cb0ef41Sopenharmony_ci RootState(EmbedderRootNode* node, size_t state_count) 2991cb0ef41Sopenharmony_ci // Root states are always visited, visible, and have a node attached. 3001cb0ef41Sopenharmony_ci : StateBase(node, state_count, Visibility::kVisible, node, true) {} 3011cb0ef41Sopenharmony_ci ~RootState() final = default; 3021cb0ef41Sopenharmony_ci}; 3031cb0ef41Sopenharmony_ci 3041cb0ef41Sopenharmony_ci// Abstraction for storing states. Storage allows for creation and lookup of 3051cb0ef41Sopenharmony_ci// different state objects. 3061cb0ef41Sopenharmony_ciclass StateStorage final { 3071cb0ef41Sopenharmony_ci public: 3081cb0ef41Sopenharmony_ci bool StateExists(const void* key) const { 3091cb0ef41Sopenharmony_ci return states_.find(key) != states_.end(); 3101cb0ef41Sopenharmony_ci } 3111cb0ef41Sopenharmony_ci 3121cb0ef41Sopenharmony_ci StateBase& GetExistingState(const void* key) const { 3131cb0ef41Sopenharmony_ci CHECK(StateExists(key)); 3141cb0ef41Sopenharmony_ci return *states_.at(key).get(); 3151cb0ef41Sopenharmony_ci } 3161cb0ef41Sopenharmony_ci 3171cb0ef41Sopenharmony_ci State& GetExistingState(const HeapObjectHeader& header) const { 3181cb0ef41Sopenharmony_ci return static_cast<State&>(GetExistingState(&header)); 3191cb0ef41Sopenharmony_ci } 3201cb0ef41Sopenharmony_ci 3211cb0ef41Sopenharmony_ci State& GetOrCreateState(const HeapObjectHeader& header) { 3221cb0ef41Sopenharmony_ci if (!StateExists(&header)) { 3231cb0ef41Sopenharmony_ci auto it = states_.insert(std::make_pair( 3241cb0ef41Sopenharmony_ci &header, std::make_unique<State>(header, ++state_count_))); 3251cb0ef41Sopenharmony_ci DCHECK(it.second); 3261cb0ef41Sopenharmony_ci USE(it); 3271cb0ef41Sopenharmony_ci } 3281cb0ef41Sopenharmony_ci return GetExistingState(header); 3291cb0ef41Sopenharmony_ci } 3301cb0ef41Sopenharmony_ci 3311cb0ef41Sopenharmony_ci RootState& CreateRootState(EmbedderRootNode* root_node) { 3321cb0ef41Sopenharmony_ci CHECK(!StateExists(root_node)); 3331cb0ef41Sopenharmony_ci auto it = states_.insert(std::make_pair( 3341cb0ef41Sopenharmony_ci root_node, std::make_unique<RootState>(root_node, ++state_count_))); 3351cb0ef41Sopenharmony_ci DCHECK(it.second); 3361cb0ef41Sopenharmony_ci USE(it); 3371cb0ef41Sopenharmony_ci return static_cast<RootState&>(*it.first->second.get()); 3381cb0ef41Sopenharmony_ci } 3391cb0ef41Sopenharmony_ci 3401cb0ef41Sopenharmony_ci template <typename Callback> 3411cb0ef41Sopenharmony_ci void ForAllVisibleStates(Callback callback) { 3421cb0ef41Sopenharmony_ci for (auto& state : states_) { 3431cb0ef41Sopenharmony_ci if (state.second->IsVisibleNotDependent()) { 3441cb0ef41Sopenharmony_ci callback(state.second.get()); 3451cb0ef41Sopenharmony_ci } 3461cb0ef41Sopenharmony_ci } 3471cb0ef41Sopenharmony_ci } 3481cb0ef41Sopenharmony_ci 3491cb0ef41Sopenharmony_ci private: 3501cb0ef41Sopenharmony_ci std::unordered_map<const void*, std::unique_ptr<StateBase>> states_; 3511cb0ef41Sopenharmony_ci size_t state_count_ = 0; 3521cb0ef41Sopenharmony_ci}; 3531cb0ef41Sopenharmony_ci 3541cb0ef41Sopenharmony_civoid* ExtractEmbedderDataBackref(Isolate* isolate, 3551cb0ef41Sopenharmony_ci v8::Local<v8::Value> v8_value) { 3561cb0ef41Sopenharmony_ci // See LocalEmbedderHeapTracer::VerboseWrapperTypeInfo for details on how 3571cb0ef41Sopenharmony_ci // wrapper objects are set up. 3581cb0ef41Sopenharmony_ci if (!v8_value->IsObject()) return nullptr; 3591cb0ef41Sopenharmony_ci 3601cb0ef41Sopenharmony_ci Handle<Object> v8_object = Utils::OpenHandle(*v8_value); 3611cb0ef41Sopenharmony_ci if (!v8_object->IsJSObject() || 3621cb0ef41Sopenharmony_ci !JSObject::cast(*v8_object).MayHaveEmbedderFields()) 3631cb0ef41Sopenharmony_ci return nullptr; 3641cb0ef41Sopenharmony_ci 3651cb0ef41Sopenharmony_ci JSObject js_object = JSObject::cast(*v8_object); 3661cb0ef41Sopenharmony_ci return LocalEmbedderHeapTracer::VerboseWrapperInfo( 3671cb0ef41Sopenharmony_ci isolate->heap()->local_embedder_heap_tracer()->ExtractWrapperInfo( 3681cb0ef41Sopenharmony_ci isolate, js_object)) 3691cb0ef41Sopenharmony_ci .instance(); 3701cb0ef41Sopenharmony_ci} 3711cb0ef41Sopenharmony_ci 3721cb0ef41Sopenharmony_ci// The following implements a snapshotting algorithm for C++ objects that also 3731cb0ef41Sopenharmony_ci// filters strongly-connected components (SCCs) of only "hidden" objects that 3741cb0ef41Sopenharmony_ci// are not (transitively) referencing any non-hidden objects. 3751cb0ef41Sopenharmony_ci// 3761cb0ef41Sopenharmony_ci// C++ objects come in two versions. 3771cb0ef41Sopenharmony_ci// a. Named objects that have been assigned a name through NameProvider. 3781cb0ef41Sopenharmony_ci// b. Unnamed objects, that are potentially hidden if the build configuration 3791cb0ef41Sopenharmony_ci// requires Oilpan to hide such names. Hidden objects have their name 3801cb0ef41Sopenharmony_ci// set to NameProvider::kHiddenName. 3811cb0ef41Sopenharmony_ci// 3821cb0ef41Sopenharmony_ci// The main challenge for the algorithm is to avoid blowing up the final object 3831cb0ef41Sopenharmony_ci// graph with hidden nodes that do not carry information. For that reason, the 3841cb0ef41Sopenharmony_ci// algorithm filters SCCs of only hidden objects, e.g.: 3851cb0ef41Sopenharmony_ci// ... -> (object) -> (object) -> (hidden) -> (hidden) 3861cb0ef41Sopenharmony_ci// In this case the (hidden) objects are filtered from the graph. The trickiest 3871cb0ef41Sopenharmony_ci// part is maintaining visibility state for objects referencing other objects 3881cb0ef41Sopenharmony_ci// that are currently being processed. 3891cb0ef41Sopenharmony_ci// 3901cb0ef41Sopenharmony_ci// Main algorithm idea (two passes): 3911cb0ef41Sopenharmony_ci// 1. First pass marks all non-hidden objects and those that transitively reach 3921cb0ef41Sopenharmony_ci// non-hidden objects as visible. Details: 3931cb0ef41Sopenharmony_ci// - Iterate over all objects. 3941cb0ef41Sopenharmony_ci// - If object is non-hidden mark it as visible and also mark parent as 3951cb0ef41Sopenharmony_ci// visible if needed. 3961cb0ef41Sopenharmony_ci// - If object is hidden, traverse children as DFS to find non-hidden 3971cb0ef41Sopenharmony_ci// objects. Post-order process the objects and mark those objects as 3981cb0ef41Sopenharmony_ci// visible that have child nodes that are visible themselves. 3991cb0ef41Sopenharmony_ci// - Maintain an epoch counter (StateStorage::state_count_) to allow 4001cb0ef41Sopenharmony_ci// deferring the visibility decision to other objects in the same SCC. This 4011cb0ef41Sopenharmony_ci// is similar to the "lowlink" value in Tarjan's algorithm for SCC. 4021cb0ef41Sopenharmony_ci// - After the first pass it is guaranteed that all deferred visibility 4031cb0ef41Sopenharmony_ci// decisions can be resolved. 4041cb0ef41Sopenharmony_ci// 2. Second pass adds nodes and edges for all visible objects. 4051cb0ef41Sopenharmony_ci// - Upon first checking the visibility state of an object, all deferred 4061cb0ef41Sopenharmony_ci// visibility states are resolved. 4071cb0ef41Sopenharmony_ci// 4081cb0ef41Sopenharmony_ci// For practical reasons, the recursion is transformed into an iteration. We do 4091cb0ef41Sopenharmony_ci// do not use plain Tarjan's algorithm to avoid another pass over all nodes to 4101cb0ef41Sopenharmony_ci// create SCCs. 4111cb0ef41Sopenharmony_ciclass CppGraphBuilderImpl final { 4121cb0ef41Sopenharmony_ci public: 4131cb0ef41Sopenharmony_ci CppGraphBuilderImpl(CppHeap& cpp_heap, v8::EmbedderGraph& graph) 4141cb0ef41Sopenharmony_ci : cpp_heap_(cpp_heap), graph_(graph) {} 4151cb0ef41Sopenharmony_ci 4161cb0ef41Sopenharmony_ci void Run(); 4171cb0ef41Sopenharmony_ci 4181cb0ef41Sopenharmony_ci void VisitForVisibility(State* parent, const HeapObjectHeader&); 4191cb0ef41Sopenharmony_ci void VisitForVisibility(State& parent, const TracedReferenceBase&); 4201cb0ef41Sopenharmony_ci void VisitEphemeronForVisibility(const HeapObjectHeader& key, 4211cb0ef41Sopenharmony_ci const HeapObjectHeader& value); 4221cb0ef41Sopenharmony_ci void VisitEphemeronWithNonGarbageCollectedValueForVisibility( 4231cb0ef41Sopenharmony_ci const HeapObjectHeader& key, const void* value, 4241cb0ef41Sopenharmony_ci cppgc::TraceDescriptor value_desc); 4251cb0ef41Sopenharmony_ci void VisitWeakContainerForVisibility(const HeapObjectHeader&); 4261cb0ef41Sopenharmony_ci void VisitRootForGraphBuilding(RootState&, const HeapObjectHeader&, 4271cb0ef41Sopenharmony_ci const cppgc::SourceLocation&); 4281cb0ef41Sopenharmony_ci void ProcessPendingObjects(); 4291cb0ef41Sopenharmony_ci 4301cb0ef41Sopenharmony_ci EmbedderRootNode* AddRootNode(const char* name) { 4311cb0ef41Sopenharmony_ci return static_cast<EmbedderRootNode*>(graph_.AddNode( 4321cb0ef41Sopenharmony_ci std::unique_ptr<v8::EmbedderGraph::Node>{new EmbedderRootNode(name)})); 4331cb0ef41Sopenharmony_ci } 4341cb0ef41Sopenharmony_ci 4351cb0ef41Sopenharmony_ci EmbedderNode* AddNode(const HeapObjectHeader& header) { 4361cb0ef41Sopenharmony_ci return static_cast<EmbedderNode*>( 4371cb0ef41Sopenharmony_ci graph_.AddNode(std::unique_ptr<v8::EmbedderGraph::Node>{ 4381cb0ef41Sopenharmony_ci new EmbedderNode(header.GetName(), header.AllocatedSize())})); 4391cb0ef41Sopenharmony_ci } 4401cb0ef41Sopenharmony_ci 4411cb0ef41Sopenharmony_ci void AddEdge(State& parent, const HeapObjectHeader& header, 4421cb0ef41Sopenharmony_ci const std::string& edge_name) { 4431cb0ef41Sopenharmony_ci DCHECK(parent.IsVisibleNotDependent()); 4441cb0ef41Sopenharmony_ci auto& current = states_.GetExistingState(header); 4451cb0ef41Sopenharmony_ci if (!current.IsVisibleNotDependent()) return; 4461cb0ef41Sopenharmony_ci 4471cb0ef41Sopenharmony_ci // Both states are visible. Create nodes in case this is the first edge 4481cb0ef41Sopenharmony_ci // created for any of them. 4491cb0ef41Sopenharmony_ci if (!parent.get_node()) { 4501cb0ef41Sopenharmony_ci parent.set_node(AddNode(*parent.header())); 4511cb0ef41Sopenharmony_ci } 4521cb0ef41Sopenharmony_ci if (!current.get_node()) { 4531cb0ef41Sopenharmony_ci current.set_node(AddNode(header)); 4541cb0ef41Sopenharmony_ci } 4551cb0ef41Sopenharmony_ci 4561cb0ef41Sopenharmony_ci if (!edge_name.empty()) { 4571cb0ef41Sopenharmony_ci graph_.AddEdge(parent.get_node(), current.get_node(), 4581cb0ef41Sopenharmony_ci parent.get_node()->InternalizeEdgeName(edge_name)); 4591cb0ef41Sopenharmony_ci } else { 4601cb0ef41Sopenharmony_ci graph_.AddEdge(parent.get_node(), current.get_node()); 4611cb0ef41Sopenharmony_ci } 4621cb0ef41Sopenharmony_ci } 4631cb0ef41Sopenharmony_ci 4641cb0ef41Sopenharmony_ci void AddEdge(State& parent, const TracedReferenceBase& ref, 4651cb0ef41Sopenharmony_ci const std::string& edge_name) { 4661cb0ef41Sopenharmony_ci DCHECK(parent.IsVisibleNotDependent()); 4671cb0ef41Sopenharmony_ci v8::Local<v8::Value> v8_value = 4681cb0ef41Sopenharmony_ci ref.Get(reinterpret_cast<v8::Isolate*>(cpp_heap_.isolate())); 4691cb0ef41Sopenharmony_ci if (!v8_value.IsEmpty()) { 4701cb0ef41Sopenharmony_ci if (!parent.get_node()) { 4711cb0ef41Sopenharmony_ci parent.set_node(AddNode(*parent.header())); 4721cb0ef41Sopenharmony_ci } 4731cb0ef41Sopenharmony_ci auto* v8_node = graph_.V8Node(v8_value); 4741cb0ef41Sopenharmony_ci if (!edge_name.empty()) { 4751cb0ef41Sopenharmony_ci graph_.AddEdge(parent.get_node(), v8_node, 4761cb0ef41Sopenharmony_ci parent.get_node()->InternalizeEdgeName(edge_name)); 4771cb0ef41Sopenharmony_ci } else { 4781cb0ef41Sopenharmony_ci graph_.AddEdge(parent.get_node(), v8_node); 4791cb0ef41Sopenharmony_ci } 4801cb0ef41Sopenharmony_ci 4811cb0ef41Sopenharmony_ci // References that have a class id set may have their internal fields 4821cb0ef41Sopenharmony_ci // pointing back to the object. Set up a wrapper node for the graph so 4831cb0ef41Sopenharmony_ci // that the snapshot generator can merge the nodes appropriately. 4841cb0ef41Sopenharmony_ci // Even with a set class id, do not set up a wrapper node when the edge 4851cb0ef41Sopenharmony_ci // has a specific name. 4861cb0ef41Sopenharmony_ci if (!ref.WrapperClassId() || !edge_name.empty()) return; 4871cb0ef41Sopenharmony_ci 4881cb0ef41Sopenharmony_ci void* back_reference_object = ExtractEmbedderDataBackref( 4891cb0ef41Sopenharmony_ci reinterpret_cast<v8::internal::Isolate*>(cpp_heap_.isolate()), 4901cb0ef41Sopenharmony_ci v8_value); 4911cb0ef41Sopenharmony_ci if (back_reference_object) { 4921cb0ef41Sopenharmony_ci auto& back_header = HeapObjectHeader::FromObject(back_reference_object); 4931cb0ef41Sopenharmony_ci auto& back_state = states_.GetExistingState(back_header); 4941cb0ef41Sopenharmony_ci 4951cb0ef41Sopenharmony_ci // Generally the back reference will point to `parent.header()`. In the 4961cb0ef41Sopenharmony_ci // case of global proxy set up the backreference will point to a 4971cb0ef41Sopenharmony_ci // different object, which may not have a node at t his point. Merge the 4981cb0ef41Sopenharmony_ci // nodes nevertheless as Window objects need to be able to query their 4991cb0ef41Sopenharmony_ci // detachedness state. 5001cb0ef41Sopenharmony_ci // 5011cb0ef41Sopenharmony_ci // TODO(chromium:1218404): See bug description on how to fix this 5021cb0ef41Sopenharmony_ci // inconsistency and only merge states when the backref points back 5031cb0ef41Sopenharmony_ci // to the same object. 5041cb0ef41Sopenharmony_ci if (!back_state.get_node()) { 5051cb0ef41Sopenharmony_ci back_state.set_node(AddNode(back_header)); 5061cb0ef41Sopenharmony_ci } 5071cb0ef41Sopenharmony_ci back_state.get_node()->SetWrapperNode(v8_node); 5081cb0ef41Sopenharmony_ci 5091cb0ef41Sopenharmony_ci auto* profiler = 5101cb0ef41Sopenharmony_ci reinterpret_cast<Isolate*>(cpp_heap_.isolate())->heap_profiler(); 5111cb0ef41Sopenharmony_ci if (profiler->HasGetDetachednessCallback()) { 5121cb0ef41Sopenharmony_ci back_state.get_node()->SetDetachedness( 5131cb0ef41Sopenharmony_ci profiler->GetDetachedness(v8_value, ref.WrapperClassId())); 5141cb0ef41Sopenharmony_ci } 5151cb0ef41Sopenharmony_ci } 5161cb0ef41Sopenharmony_ci } 5171cb0ef41Sopenharmony_ci } 5181cb0ef41Sopenharmony_ci 5191cb0ef41Sopenharmony_ci void AddRootEdge(RootState& root, State& child, std::string edge_name) { 5201cb0ef41Sopenharmony_ci DCHECK(root.IsVisibleNotDependent()); 5211cb0ef41Sopenharmony_ci if (!child.IsVisibleNotDependent()) return; 5221cb0ef41Sopenharmony_ci 5231cb0ef41Sopenharmony_ci // Root states always have a node set. 5241cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(root.get_node()); 5251cb0ef41Sopenharmony_ci if (!child.get_node()) { 5261cb0ef41Sopenharmony_ci child.set_node(AddNode(*child.header())); 5271cb0ef41Sopenharmony_ci } 5281cb0ef41Sopenharmony_ci 5291cb0ef41Sopenharmony_ci if (!edge_name.empty()) { 5301cb0ef41Sopenharmony_ci graph_.AddEdge(root.get_node(), child.get_node(), 5311cb0ef41Sopenharmony_ci root.get_node()->InternalizeEdgeName(edge_name)); 5321cb0ef41Sopenharmony_ci return; 5331cb0ef41Sopenharmony_ci } 5341cb0ef41Sopenharmony_ci graph_.AddEdge(root.get_node(), child.get_node()); 5351cb0ef41Sopenharmony_ci } 5361cb0ef41Sopenharmony_ci 5371cb0ef41Sopenharmony_ci private: 5381cb0ef41Sopenharmony_ci class WorkstackItemBase; 5391cb0ef41Sopenharmony_ci class VisitationItem; 5401cb0ef41Sopenharmony_ci class VisitationDoneItem; 5411cb0ef41Sopenharmony_ci 5421cb0ef41Sopenharmony_ci struct MergedNodeItem { 5431cb0ef41Sopenharmony_ci EmbedderGraph::Node* node_; 5441cb0ef41Sopenharmony_ci v8::Local<v8::Value> value_; 5451cb0ef41Sopenharmony_ci uint16_t wrapper_class_id_; 5461cb0ef41Sopenharmony_ci }; 5471cb0ef41Sopenharmony_ci 5481cb0ef41Sopenharmony_ci CppHeap& cpp_heap_; 5491cb0ef41Sopenharmony_ci v8::EmbedderGraph& graph_; 5501cb0ef41Sopenharmony_ci StateStorage states_; 5511cb0ef41Sopenharmony_ci std::vector<std::unique_ptr<WorkstackItemBase>> workstack_; 5521cb0ef41Sopenharmony_ci}; 5531cb0ef41Sopenharmony_ci 5541cb0ef41Sopenharmony_ci// Iterating live objects to mark them as visible if needed. 5551cb0ef41Sopenharmony_ciclass LiveObjectsForVisibilityIterator final 5561cb0ef41Sopenharmony_ci : public cppgc::internal::HeapVisitor<LiveObjectsForVisibilityIterator> { 5571cb0ef41Sopenharmony_ci friend class cppgc::internal::HeapVisitor<LiveObjectsForVisibilityIterator>; 5581cb0ef41Sopenharmony_ci 5591cb0ef41Sopenharmony_ci public: 5601cb0ef41Sopenharmony_ci explicit LiveObjectsForVisibilityIterator(CppGraphBuilderImpl& graph_builder) 5611cb0ef41Sopenharmony_ci : graph_builder_(graph_builder) {} 5621cb0ef41Sopenharmony_ci 5631cb0ef41Sopenharmony_ci private: 5641cb0ef41Sopenharmony_ci bool VisitHeapObjectHeader(HeapObjectHeader& header) { 5651cb0ef41Sopenharmony_ci if (header.IsFree()) return true; 5661cb0ef41Sopenharmony_ci graph_builder_.VisitForVisibility(nullptr, header); 5671cb0ef41Sopenharmony_ci graph_builder_.ProcessPendingObjects(); 5681cb0ef41Sopenharmony_ci return true; 5691cb0ef41Sopenharmony_ci } 5701cb0ef41Sopenharmony_ci 5711cb0ef41Sopenharmony_ci CppGraphBuilderImpl& graph_builder_; 5721cb0ef41Sopenharmony_ci}; 5731cb0ef41Sopenharmony_ci 5741cb0ef41Sopenharmony_ciclass ParentScope final { 5751cb0ef41Sopenharmony_ci public: 5761cb0ef41Sopenharmony_ci explicit ParentScope(StateBase& parent) : parent_(parent) {} 5771cb0ef41Sopenharmony_ci 5781cb0ef41Sopenharmony_ci RootState& ParentAsRootState() const { 5791cb0ef41Sopenharmony_ci return static_cast<RootState&>(parent_); 5801cb0ef41Sopenharmony_ci } 5811cb0ef41Sopenharmony_ci State& ParentAsRegularState() const { return static_cast<State&>(parent_); } 5821cb0ef41Sopenharmony_ci 5831cb0ef41Sopenharmony_ci private: 5841cb0ef41Sopenharmony_ci StateBase& parent_; 5851cb0ef41Sopenharmony_ci}; 5861cb0ef41Sopenharmony_ci 5871cb0ef41Sopenharmony_ci// This visitor can be used stand-alone to handle fully weak and ephemeron 5881cb0ef41Sopenharmony_ci// containers or as part of the VisibilityVisitor that recursively traverses 5891cb0ef41Sopenharmony_ci// the object graph. 5901cb0ef41Sopenharmony_ciclass WeakVisitor : public JSVisitor { 5911cb0ef41Sopenharmony_ci public: 5921cb0ef41Sopenharmony_ci explicit WeakVisitor(CppGraphBuilderImpl& graph_builder) 5931cb0ef41Sopenharmony_ci : JSVisitor(cppgc::internal::VisitorFactory::CreateKey()), 5941cb0ef41Sopenharmony_ci graph_builder_(graph_builder) {} 5951cb0ef41Sopenharmony_ci 5961cb0ef41Sopenharmony_ci void VisitWeakContainer(const void* object, 5971cb0ef41Sopenharmony_ci cppgc::TraceDescriptor strong_desc, 5981cb0ef41Sopenharmony_ci cppgc::TraceDescriptor weak_desc, cppgc::WeakCallback, 5991cb0ef41Sopenharmony_ci const void*) final { 6001cb0ef41Sopenharmony_ci const auto& container_header = 6011cb0ef41Sopenharmony_ci HeapObjectHeader::FromObject(strong_desc.base_object_payload); 6021cb0ef41Sopenharmony_ci 6031cb0ef41Sopenharmony_ci graph_builder_.VisitWeakContainerForVisibility(container_header); 6041cb0ef41Sopenharmony_ci 6051cb0ef41Sopenharmony_ci if (!weak_desc.callback) { 6061cb0ef41Sopenharmony_ci // Weak container does not contribute to liveness. 6071cb0ef41Sopenharmony_ci return; 6081cb0ef41Sopenharmony_ci } 6091cb0ef41Sopenharmony_ci // Heap snapshot is always run after a GC so we know there are no dead 6101cb0ef41Sopenharmony_ci // entries in the container. 6111cb0ef41Sopenharmony_ci if (object) { 6121cb0ef41Sopenharmony_ci // The container will itself be traced strongly via the regular Visit() 6131cb0ef41Sopenharmony_ci // handling that iterates over all live objects. The visibility visitor 6141cb0ef41Sopenharmony_ci // will thus see (because of strongly treating the container): 6151cb0ef41Sopenharmony_ci // 1. the container itself; 6161cb0ef41Sopenharmony_ci // 2. for each {key} in container: container->key; 6171cb0ef41Sopenharmony_ci // 3. for each {key, value} in container: key->value; 6181cb0ef41Sopenharmony_ci // 6191cb0ef41Sopenharmony_ci // In case the visitor is used stand-alone, we trace through the container 6201cb0ef41Sopenharmony_ci // here to create the same state as we would when the container is traced 6211cb0ef41Sopenharmony_ci // separately. 6221cb0ef41Sopenharmony_ci container_header.Trace(this); 6231cb0ef41Sopenharmony_ci } 6241cb0ef41Sopenharmony_ci } 6251cb0ef41Sopenharmony_ci void VisitEphemeron(const void* key, const void* value, 6261cb0ef41Sopenharmony_ci cppgc::TraceDescriptor value_desc) final { 6271cb0ef41Sopenharmony_ci // For ephemerons, the key retains the value. 6281cb0ef41Sopenharmony_ci // Key always must be a GarbageCollected object. 6291cb0ef41Sopenharmony_ci auto& key_header = HeapObjectHeader::FromObject(key); 6301cb0ef41Sopenharmony_ci if (!value_desc.base_object_payload) { 6311cb0ef41Sopenharmony_ci // Value does not represent an actual GarbageCollected object but rather 6321cb0ef41Sopenharmony_ci // should be traced eagerly. 6331cb0ef41Sopenharmony_ci graph_builder_.VisitEphemeronWithNonGarbageCollectedValueForVisibility( 6341cb0ef41Sopenharmony_ci key_header, value, value_desc); 6351cb0ef41Sopenharmony_ci return; 6361cb0ef41Sopenharmony_ci } 6371cb0ef41Sopenharmony_ci // Regular path where both key and value are GarbageCollected objects. 6381cb0ef41Sopenharmony_ci graph_builder_.VisitEphemeronForVisibility( 6391cb0ef41Sopenharmony_ci key_header, HeapObjectHeader::FromObject(value)); 6401cb0ef41Sopenharmony_ci } 6411cb0ef41Sopenharmony_ci 6421cb0ef41Sopenharmony_ci protected: 6431cb0ef41Sopenharmony_ci CppGraphBuilderImpl& graph_builder_; 6441cb0ef41Sopenharmony_ci}; 6451cb0ef41Sopenharmony_ci 6461cb0ef41Sopenharmony_ciclass VisiblityVisitor final : public WeakVisitor { 6471cb0ef41Sopenharmony_ci public: 6481cb0ef41Sopenharmony_ci VisiblityVisitor(CppGraphBuilderImpl& graph_builder, 6491cb0ef41Sopenharmony_ci const ParentScope& parent_scope) 6501cb0ef41Sopenharmony_ci : WeakVisitor(graph_builder), parent_scope_(parent_scope) {} 6511cb0ef41Sopenharmony_ci 6521cb0ef41Sopenharmony_ci // C++ handling. 6531cb0ef41Sopenharmony_ci void Visit(const void*, cppgc::TraceDescriptor desc) final { 6541cb0ef41Sopenharmony_ci graph_builder_.VisitForVisibility( 6551cb0ef41Sopenharmony_ci &parent_scope_.ParentAsRegularState(), 6561cb0ef41Sopenharmony_ci HeapObjectHeader::FromObject(desc.base_object_payload)); 6571cb0ef41Sopenharmony_ci } 6581cb0ef41Sopenharmony_ci void VisitRoot(const void*, cppgc::TraceDescriptor, 6591cb0ef41Sopenharmony_ci const cppgc::SourceLocation&) final {} 6601cb0ef41Sopenharmony_ci void VisitWeakRoot(const void*, cppgc::TraceDescriptor, cppgc::WeakCallback, 6611cb0ef41Sopenharmony_ci const void*, const cppgc::SourceLocation&) final {} 6621cb0ef41Sopenharmony_ci 6631cb0ef41Sopenharmony_ci // JS handling. 6641cb0ef41Sopenharmony_ci void Visit(const TracedReferenceBase& ref) final { 6651cb0ef41Sopenharmony_ci graph_builder_.VisitForVisibility(parent_scope_.ParentAsRegularState(), 6661cb0ef41Sopenharmony_ci ref); 6671cb0ef41Sopenharmony_ci } 6681cb0ef41Sopenharmony_ci 6691cb0ef41Sopenharmony_ci private: 6701cb0ef41Sopenharmony_ci const ParentScope& parent_scope_; 6711cb0ef41Sopenharmony_ci}; 6721cb0ef41Sopenharmony_ci 6731cb0ef41Sopenharmony_ciclass GraphBuildingVisitor final : public JSVisitor { 6741cb0ef41Sopenharmony_ci public: 6751cb0ef41Sopenharmony_ci GraphBuildingVisitor(CppGraphBuilderImpl& graph_builder, 6761cb0ef41Sopenharmony_ci const ParentScope& parent_scope) 6771cb0ef41Sopenharmony_ci : JSVisitor(cppgc::internal::VisitorFactory::CreateKey()), 6781cb0ef41Sopenharmony_ci graph_builder_(graph_builder), 6791cb0ef41Sopenharmony_ci parent_scope_(parent_scope) {} 6801cb0ef41Sopenharmony_ci 6811cb0ef41Sopenharmony_ci // C++ handling. 6821cb0ef41Sopenharmony_ci void Visit(const void*, cppgc::TraceDescriptor desc) final { 6831cb0ef41Sopenharmony_ci graph_builder_.AddEdge( 6841cb0ef41Sopenharmony_ci parent_scope_.ParentAsRegularState(), 6851cb0ef41Sopenharmony_ci HeapObjectHeader::FromObject(desc.base_object_payload), edge_name_); 6861cb0ef41Sopenharmony_ci } 6871cb0ef41Sopenharmony_ci void VisitWeakContainer(const void* object, 6881cb0ef41Sopenharmony_ci cppgc::TraceDescriptor strong_desc, 6891cb0ef41Sopenharmony_ci cppgc::TraceDescriptor weak_desc, cppgc::WeakCallback, 6901cb0ef41Sopenharmony_ci const void*) final { 6911cb0ef41Sopenharmony_ci // Add an edge from the object holding the weak container to the weak 6921cb0ef41Sopenharmony_ci // container itself. 6931cb0ef41Sopenharmony_ci graph_builder_.AddEdge( 6941cb0ef41Sopenharmony_ci parent_scope_.ParentAsRegularState(), 6951cb0ef41Sopenharmony_ci HeapObjectHeader::FromObject(strong_desc.base_object_payload), 6961cb0ef41Sopenharmony_ci edge_name_); 6971cb0ef41Sopenharmony_ci } 6981cb0ef41Sopenharmony_ci void VisitRoot(const void*, cppgc::TraceDescriptor desc, 6991cb0ef41Sopenharmony_ci const cppgc::SourceLocation& loc) final { 7001cb0ef41Sopenharmony_ci graph_builder_.VisitRootForGraphBuilding( 7011cb0ef41Sopenharmony_ci parent_scope_.ParentAsRootState(), 7021cb0ef41Sopenharmony_ci HeapObjectHeader::FromObject(desc.base_object_payload), loc); 7031cb0ef41Sopenharmony_ci } 7041cb0ef41Sopenharmony_ci void VisitWeakRoot(const void*, cppgc::TraceDescriptor, cppgc::WeakCallback, 7051cb0ef41Sopenharmony_ci const void*, const cppgc::SourceLocation&) final {} 7061cb0ef41Sopenharmony_ci // JS handling. 7071cb0ef41Sopenharmony_ci void Visit(const TracedReferenceBase& ref) final { 7081cb0ef41Sopenharmony_ci graph_builder_.AddEdge(parent_scope_.ParentAsRegularState(), ref, 7091cb0ef41Sopenharmony_ci edge_name_); 7101cb0ef41Sopenharmony_ci } 7111cb0ef41Sopenharmony_ci 7121cb0ef41Sopenharmony_ci void set_edge_name(std::string edge_name) { 7131cb0ef41Sopenharmony_ci edge_name_ = std::move(edge_name); 7141cb0ef41Sopenharmony_ci } 7151cb0ef41Sopenharmony_ci 7161cb0ef41Sopenharmony_ci private: 7171cb0ef41Sopenharmony_ci CppGraphBuilderImpl& graph_builder_; 7181cb0ef41Sopenharmony_ci const ParentScope& parent_scope_; 7191cb0ef41Sopenharmony_ci std::string edge_name_; 7201cb0ef41Sopenharmony_ci}; 7211cb0ef41Sopenharmony_ci 7221cb0ef41Sopenharmony_ci// Base class for transforming recursion into iteration. Items are processed 7231cb0ef41Sopenharmony_ci// in stack fashion. 7241cb0ef41Sopenharmony_ciclass CppGraphBuilderImpl::WorkstackItemBase { 7251cb0ef41Sopenharmony_ci public: 7261cb0ef41Sopenharmony_ci WorkstackItemBase(State* parent, State& current) 7271cb0ef41Sopenharmony_ci : parent_(parent), current_(current) {} 7281cb0ef41Sopenharmony_ci 7291cb0ef41Sopenharmony_ci virtual ~WorkstackItemBase() = default; 7301cb0ef41Sopenharmony_ci virtual void Process(CppGraphBuilderImpl&) = 0; 7311cb0ef41Sopenharmony_ci 7321cb0ef41Sopenharmony_ci protected: 7331cb0ef41Sopenharmony_ci State* parent_; 7341cb0ef41Sopenharmony_ci State& current_; 7351cb0ef41Sopenharmony_ci}; 7361cb0ef41Sopenharmony_ci 7371cb0ef41Sopenharmony_civoid CppGraphBuilderImpl::ProcessPendingObjects() { 7381cb0ef41Sopenharmony_ci while (!workstack_.empty()) { 7391cb0ef41Sopenharmony_ci std::unique_ptr<WorkstackItemBase> item = std::move(workstack_.back()); 7401cb0ef41Sopenharmony_ci workstack_.pop_back(); 7411cb0ef41Sopenharmony_ci item->Process(*this); 7421cb0ef41Sopenharmony_ci } 7431cb0ef41Sopenharmony_ci} 7441cb0ef41Sopenharmony_ci 7451cb0ef41Sopenharmony_ci// Post-order processing of an object. It's guaranteed that all children have 7461cb0ef41Sopenharmony_ci// been processed first. 7471cb0ef41Sopenharmony_ciclass CppGraphBuilderImpl::VisitationDoneItem final : public WorkstackItemBase { 7481cb0ef41Sopenharmony_ci public: 7491cb0ef41Sopenharmony_ci VisitationDoneItem(State* parent, State& current) 7501cb0ef41Sopenharmony_ci : WorkstackItemBase(parent, current) {} 7511cb0ef41Sopenharmony_ci 7521cb0ef41Sopenharmony_ci void Process(CppGraphBuilderImpl& graph_builder) final { 7531cb0ef41Sopenharmony_ci CHECK(parent_); 7541cb0ef41Sopenharmony_ci parent_->MarkDependentVisibility(¤t_); 7551cb0ef41Sopenharmony_ci current_.UnmarkPending(); 7561cb0ef41Sopenharmony_ci } 7571cb0ef41Sopenharmony_ci}; 7581cb0ef41Sopenharmony_ci 7591cb0ef41Sopenharmony_ciclass CppGraphBuilderImpl::VisitationItem final : public WorkstackItemBase { 7601cb0ef41Sopenharmony_ci public: 7611cb0ef41Sopenharmony_ci VisitationItem(State* parent, State& current) 7621cb0ef41Sopenharmony_ci : WorkstackItemBase(parent, current) {} 7631cb0ef41Sopenharmony_ci 7641cb0ef41Sopenharmony_ci void Process(CppGraphBuilderImpl& graph_builder) final { 7651cb0ef41Sopenharmony_ci if (parent_) { 7661cb0ef41Sopenharmony_ci // Re-add the same object for post-order processing. This must happen 7671cb0ef41Sopenharmony_ci // lazily, as the parent's visibility depends on its children. 7681cb0ef41Sopenharmony_ci graph_builder.workstack_.push_back(std::unique_ptr<WorkstackItemBase>{ 7691cb0ef41Sopenharmony_ci new VisitationDoneItem(parent_, current_)}); 7701cb0ef41Sopenharmony_ci } 7711cb0ef41Sopenharmony_ci ParentScope parent_scope(current_); 7721cb0ef41Sopenharmony_ci VisiblityVisitor object_visitor(graph_builder, parent_scope); 7731cb0ef41Sopenharmony_ci current_.header()->Trace(&object_visitor); 7741cb0ef41Sopenharmony_ci if (!parent_) { 7751cb0ef41Sopenharmony_ci current_.UnmarkPending(); 7761cb0ef41Sopenharmony_ci } 7771cb0ef41Sopenharmony_ci } 7781cb0ef41Sopenharmony_ci}; 7791cb0ef41Sopenharmony_ci 7801cb0ef41Sopenharmony_civoid CppGraphBuilderImpl::VisitForVisibility(State* parent, 7811cb0ef41Sopenharmony_ci const HeapObjectHeader& header) { 7821cb0ef41Sopenharmony_ci auto& current = states_.GetOrCreateState(header); 7831cb0ef41Sopenharmony_ci 7841cb0ef41Sopenharmony_ci if (current.IsVisited()) { 7851cb0ef41Sopenharmony_ci // Avoid traversing into already visited subgraphs and just update the state 7861cb0ef41Sopenharmony_ci // based on a previous result. 7871cb0ef41Sopenharmony_ci if (parent) { 7881cb0ef41Sopenharmony_ci parent->MarkDependentVisibility(¤t); 7891cb0ef41Sopenharmony_ci } 7901cb0ef41Sopenharmony_ci return; 7911cb0ef41Sopenharmony_ci } 7921cb0ef41Sopenharmony_ci 7931cb0ef41Sopenharmony_ci current.MarkVisited(); 7941cb0ef41Sopenharmony_ci if (header.GetName().name_was_hidden) { 7951cb0ef41Sopenharmony_ci current.MarkPending(); 7961cb0ef41Sopenharmony_ci workstack_.push_back(std::unique_ptr<WorkstackItemBase>{ 7971cb0ef41Sopenharmony_ci new VisitationItem(parent, current)}); 7981cb0ef41Sopenharmony_ci } else { 7991cb0ef41Sopenharmony_ci // No need to mark/unmark pending as the node is immediately processed. 8001cb0ef41Sopenharmony_ci current.MarkVisible(); 8011cb0ef41Sopenharmony_ci // In case the names are visible, the graph is not traversed in this phase. 8021cb0ef41Sopenharmony_ci // Explicitly trace one level to handle weak containers. 8031cb0ef41Sopenharmony_ci WeakVisitor weak_visitor(*this); 8041cb0ef41Sopenharmony_ci header.Trace(&weak_visitor); 8051cb0ef41Sopenharmony_ci if (parent) { 8061cb0ef41Sopenharmony_ci // Eagerly update a parent object as its visibility state is now fixed. 8071cb0ef41Sopenharmony_ci parent->MarkVisible(); 8081cb0ef41Sopenharmony_ci } 8091cb0ef41Sopenharmony_ci } 8101cb0ef41Sopenharmony_ci} 8111cb0ef41Sopenharmony_ci 8121cb0ef41Sopenharmony_civoid CppGraphBuilderImpl:: 8131cb0ef41Sopenharmony_ci VisitEphemeronWithNonGarbageCollectedValueForVisibility( 8141cb0ef41Sopenharmony_ci const HeapObjectHeader& key, const void* value, 8151cb0ef41Sopenharmony_ci cppgc::TraceDescriptor value_desc) { 8161cb0ef41Sopenharmony_ci auto& key_state = states_.GetOrCreateState(key); 8171cb0ef41Sopenharmony_ci // Eagerly trace the value here, effectively marking key as visible and 8181cb0ef41Sopenharmony_ci // queuing processing for all reachable values. 8191cb0ef41Sopenharmony_ci ParentScope parent_scope(key_state); 8201cb0ef41Sopenharmony_ci VisiblityVisitor visitor(*this, parent_scope); 8211cb0ef41Sopenharmony_ci value_desc.callback(&visitor, value); 8221cb0ef41Sopenharmony_ci key_state.AddEagerEphemeronEdge(value, value_desc.callback); 8231cb0ef41Sopenharmony_ci} 8241cb0ef41Sopenharmony_ci 8251cb0ef41Sopenharmony_civoid CppGraphBuilderImpl::VisitEphemeronForVisibility( 8261cb0ef41Sopenharmony_ci const HeapObjectHeader& key, const HeapObjectHeader& value) { 8271cb0ef41Sopenharmony_ci auto& key_state = states_.GetOrCreateState(key); 8281cb0ef41Sopenharmony_ci VisitForVisibility(&key_state, value); 8291cb0ef41Sopenharmony_ci key_state.AddEphemeronEdge(value); 8301cb0ef41Sopenharmony_ci} 8311cb0ef41Sopenharmony_ci 8321cb0ef41Sopenharmony_civoid CppGraphBuilderImpl::VisitWeakContainerForVisibility( 8331cb0ef41Sopenharmony_ci const HeapObjectHeader& container_header) { 8341cb0ef41Sopenharmony_ci // Mark the container here as weak container to avoid creating any 8351cb0ef41Sopenharmony_ci // outgoing edges in the second phase. 8361cb0ef41Sopenharmony_ci states_.GetOrCreateState(container_header).MarkAsWeakContainer(); 8371cb0ef41Sopenharmony_ci} 8381cb0ef41Sopenharmony_ci 8391cb0ef41Sopenharmony_civoid CppGraphBuilderImpl::VisitForVisibility(State& parent, 8401cb0ef41Sopenharmony_ci const TracedReferenceBase& ref) { 8411cb0ef41Sopenharmony_ci v8::Local<v8::Value> v8_value = 8421cb0ef41Sopenharmony_ci ref.Get(reinterpret_cast<v8::Isolate*>(cpp_heap_.isolate())); 8431cb0ef41Sopenharmony_ci if (!v8_value.IsEmpty()) { 8441cb0ef41Sopenharmony_ci parent.MarkVisible(); 8451cb0ef41Sopenharmony_ci } 8461cb0ef41Sopenharmony_ci} 8471cb0ef41Sopenharmony_ci 8481cb0ef41Sopenharmony_civoid CppGraphBuilderImpl::VisitRootForGraphBuilding( 8491cb0ef41Sopenharmony_ci RootState& root, const HeapObjectHeader& header, 8501cb0ef41Sopenharmony_ci const cppgc::SourceLocation& loc) { 8511cb0ef41Sopenharmony_ci State& current = states_.GetExistingState(header); 8521cb0ef41Sopenharmony_ci if (!current.IsVisibleNotDependent()) return; 8531cb0ef41Sopenharmony_ci 8541cb0ef41Sopenharmony_ci AddRootEdge(root, current, loc.ToString()); 8551cb0ef41Sopenharmony_ci} 8561cb0ef41Sopenharmony_ci 8571cb0ef41Sopenharmony_civoid CppGraphBuilderImpl::Run() { 8581cb0ef41Sopenharmony_ci // Sweeping from a previous GC might still be running, in which case not all 8591cb0ef41Sopenharmony_ci // pages have been returned to spaces yet. 8601cb0ef41Sopenharmony_ci cpp_heap_.sweeper().FinishIfRunning(); 8611cb0ef41Sopenharmony_ci // First pass: Figure out which objects should be included in the graph -- see 8621cb0ef41Sopenharmony_ci // class-level comment on CppGraphBuilder. 8631cb0ef41Sopenharmony_ci LiveObjectsForVisibilityIterator visitor(*this); 8641cb0ef41Sopenharmony_ci visitor.Traverse(cpp_heap_.raw_heap()); 8651cb0ef41Sopenharmony_ci // Second pass: Add graph nodes for objects that must be shown. 8661cb0ef41Sopenharmony_ci states_.ForAllVisibleStates([this](StateBase* state_base) { 8671cb0ef41Sopenharmony_ci // No roots have been created so far, so all StateBase objects are State. 8681cb0ef41Sopenharmony_ci State& state = *static_cast<State*>(state_base); 8691cb0ef41Sopenharmony_ci 8701cb0ef41Sopenharmony_ci // Emit no edges for the contents of the weak containers. For both, fully 8711cb0ef41Sopenharmony_ci // weak and ephemeron containers, the contents should be retained from 8721cb0ef41Sopenharmony_ci // somewhere else. 8731cb0ef41Sopenharmony_ci if (state.IsWeakContainer()) return; 8741cb0ef41Sopenharmony_ci 8751cb0ef41Sopenharmony_ci ParentScope parent_scope(state); 8761cb0ef41Sopenharmony_ci GraphBuildingVisitor object_visitor(*this, parent_scope); 8771cb0ef41Sopenharmony_ci state.header()->Trace(&object_visitor); 8781cb0ef41Sopenharmony_ci state.ForAllEphemeronEdges([this, &state](const HeapObjectHeader& value) { 8791cb0ef41Sopenharmony_ci AddEdge(state, value, "part of key -> value pair in ephemeron table"); 8801cb0ef41Sopenharmony_ci }); 8811cb0ef41Sopenharmony_ci object_visitor.set_edge_name( 8821cb0ef41Sopenharmony_ci "part of key -> value pair in ephemeron table"); 8831cb0ef41Sopenharmony_ci state.ForAllEagerEphemeronEdges( 8841cb0ef41Sopenharmony_ci [&object_visitor](const void* value, cppgc::TraceCallback callback) { 8851cb0ef41Sopenharmony_ci callback(&object_visitor, value); 8861cb0ef41Sopenharmony_ci }); 8871cb0ef41Sopenharmony_ci }); 8881cb0ef41Sopenharmony_ci // Add roots. 8891cb0ef41Sopenharmony_ci { 8901cb0ef41Sopenharmony_ci ParentScope parent_scope(states_.CreateRootState(AddRootNode("C++ roots"))); 8911cb0ef41Sopenharmony_ci GraphBuildingVisitor object_visitor(*this, parent_scope); 8921cb0ef41Sopenharmony_ci cpp_heap_.GetStrongPersistentRegion().Trace(&object_visitor); 8931cb0ef41Sopenharmony_ci } 8941cb0ef41Sopenharmony_ci { 8951cb0ef41Sopenharmony_ci ParentScope parent_scope( 8961cb0ef41Sopenharmony_ci states_.CreateRootState(AddRootNode("C++ cross-thread roots"))); 8971cb0ef41Sopenharmony_ci GraphBuildingVisitor object_visitor(*this, parent_scope); 8981cb0ef41Sopenharmony_ci cppgc::internal::PersistentRegionLock guard; 8991cb0ef41Sopenharmony_ci cpp_heap_.GetStrongCrossThreadPersistentRegion().Trace(&object_visitor); 9001cb0ef41Sopenharmony_ci } 9011cb0ef41Sopenharmony_ci} 9021cb0ef41Sopenharmony_ci 9031cb0ef41Sopenharmony_ci// static 9041cb0ef41Sopenharmony_civoid CppGraphBuilder::Run(v8::Isolate* isolate, v8::EmbedderGraph* graph, 9051cb0ef41Sopenharmony_ci void* data) { 9061cb0ef41Sopenharmony_ci CppHeap* cpp_heap = static_cast<CppHeap*>(data); 9071cb0ef41Sopenharmony_ci CHECK_NOT_NULL(cpp_heap); 9081cb0ef41Sopenharmony_ci CHECK_NOT_NULL(graph); 9091cb0ef41Sopenharmony_ci CppGraphBuilderImpl graph_builder(*cpp_heap, *graph); 9101cb0ef41Sopenharmony_ci graph_builder.Run(); 9111cb0ef41Sopenharmony_ci} 9121cb0ef41Sopenharmony_ci 9131cb0ef41Sopenharmony_ci} // namespace internal 9141cb0ef41Sopenharmony_ci} // namespace v8 915