11cb0ef41Sopenharmony_ci#include "diagnosticfilename-inl.h" 21cb0ef41Sopenharmony_ci#include "env-inl.h" 31cb0ef41Sopenharmony_ci#include "memory_tracker-inl.h" 41cb0ef41Sopenharmony_ci#include "node_external_reference.h" 51cb0ef41Sopenharmony_ci#include "stream_base-inl.h" 61cb0ef41Sopenharmony_ci#include "util-inl.h" 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_ci// Copied from https://github.com/nodejs/node/blob/b07dc4d19fdbc15b4f76557dc45b3ce3a43ad0c3/src/util.cc#L36-L41. 91cb0ef41Sopenharmony_ci#ifdef _WIN32 101cb0ef41Sopenharmony_ci#include <io.h> // _S_IREAD _S_IWRITE 111cb0ef41Sopenharmony_ci#ifndef S_IRUSR 121cb0ef41Sopenharmony_ci#define S_IRUSR _S_IREAD 131cb0ef41Sopenharmony_ci#endif // S_IRUSR 141cb0ef41Sopenharmony_ci#ifndef S_IWUSR 151cb0ef41Sopenharmony_ci#define S_IWUSR _S_IWRITE 161cb0ef41Sopenharmony_ci#endif // S_IWUSR 171cb0ef41Sopenharmony_ci#endif 181cb0ef41Sopenharmony_ci 191cb0ef41Sopenharmony_ciusing v8::Array; 201cb0ef41Sopenharmony_ciusing v8::Boolean; 211cb0ef41Sopenharmony_ciusing v8::Context; 221cb0ef41Sopenharmony_ciusing v8::EmbedderGraph; 231cb0ef41Sopenharmony_ciusing v8::EscapableHandleScope; 241cb0ef41Sopenharmony_ciusing v8::FunctionCallbackInfo; 251cb0ef41Sopenharmony_ciusing v8::FunctionTemplate; 261cb0ef41Sopenharmony_ciusing v8::Global; 271cb0ef41Sopenharmony_ciusing v8::HandleScope; 281cb0ef41Sopenharmony_ciusing v8::HeapSnapshot; 291cb0ef41Sopenharmony_ciusing v8::Isolate; 301cb0ef41Sopenharmony_ciusing v8::JustVoid; 311cb0ef41Sopenharmony_ciusing v8::Local; 321cb0ef41Sopenharmony_ciusing v8::Maybe; 331cb0ef41Sopenharmony_ciusing v8::MaybeLocal; 341cb0ef41Sopenharmony_ciusing v8::Nothing; 351cb0ef41Sopenharmony_ciusing v8::Number; 361cb0ef41Sopenharmony_ciusing v8::Object; 371cb0ef41Sopenharmony_ciusing v8::ObjectTemplate; 381cb0ef41Sopenharmony_ciusing v8::String; 391cb0ef41Sopenharmony_ciusing v8::Value; 401cb0ef41Sopenharmony_ci 411cb0ef41Sopenharmony_cinamespace node { 421cb0ef41Sopenharmony_cinamespace heap { 431cb0ef41Sopenharmony_ci 441cb0ef41Sopenharmony_ciclass JSGraphJSNode : public EmbedderGraph::Node { 451cb0ef41Sopenharmony_ci public: 461cb0ef41Sopenharmony_ci const char* Name() override { return "<JS Node>"; } 471cb0ef41Sopenharmony_ci size_t SizeInBytes() override { return 0; } 481cb0ef41Sopenharmony_ci bool IsEmbedderNode() override { return false; } 491cb0ef41Sopenharmony_ci Local<Value> JSValue() { return PersistentToLocal::Strong(persistent_); } 501cb0ef41Sopenharmony_ci 511cb0ef41Sopenharmony_ci int IdentityHash() { 521cb0ef41Sopenharmony_ci Local<Value> v = JSValue(); 531cb0ef41Sopenharmony_ci if (v->IsObject()) return v.As<Object>()->GetIdentityHash(); 541cb0ef41Sopenharmony_ci if (v->IsName()) return v.As<v8::Name>()->GetIdentityHash(); 551cb0ef41Sopenharmony_ci if (v->IsInt32()) return v.As<v8::Int32>()->Value(); 561cb0ef41Sopenharmony_ci return 0; 571cb0ef41Sopenharmony_ci } 581cb0ef41Sopenharmony_ci 591cb0ef41Sopenharmony_ci JSGraphJSNode(Isolate* isolate, Local<Value> val) 601cb0ef41Sopenharmony_ci : persistent_(isolate, val) { 611cb0ef41Sopenharmony_ci CHECK(!val.IsEmpty()); 621cb0ef41Sopenharmony_ci } 631cb0ef41Sopenharmony_ci 641cb0ef41Sopenharmony_ci struct Hash { 651cb0ef41Sopenharmony_ci inline size_t operator()(JSGraphJSNode* n) const { 661cb0ef41Sopenharmony_ci return static_cast<size_t>(n->IdentityHash()); 671cb0ef41Sopenharmony_ci } 681cb0ef41Sopenharmony_ci }; 691cb0ef41Sopenharmony_ci 701cb0ef41Sopenharmony_ci struct Equal { 711cb0ef41Sopenharmony_ci inline bool operator()(JSGraphJSNode* a, JSGraphJSNode* b) const { 721cb0ef41Sopenharmony_ci return a->JSValue()->SameValue(b->JSValue()); 731cb0ef41Sopenharmony_ci } 741cb0ef41Sopenharmony_ci }; 751cb0ef41Sopenharmony_ci 761cb0ef41Sopenharmony_ci private: 771cb0ef41Sopenharmony_ci Global<Value> persistent_; 781cb0ef41Sopenharmony_ci}; 791cb0ef41Sopenharmony_ci 801cb0ef41Sopenharmony_ciclass JSGraph : public EmbedderGraph { 811cb0ef41Sopenharmony_ci public: 821cb0ef41Sopenharmony_ci explicit JSGraph(Isolate* isolate) : isolate_(isolate) {} 831cb0ef41Sopenharmony_ci 841cb0ef41Sopenharmony_ci Node* V8Node(const Local<Value>& value) override { 851cb0ef41Sopenharmony_ci std::unique_ptr<JSGraphJSNode> n { new JSGraphJSNode(isolate_, value) }; 861cb0ef41Sopenharmony_ci auto it = engine_nodes_.find(n.get()); 871cb0ef41Sopenharmony_ci if (it != engine_nodes_.end()) 881cb0ef41Sopenharmony_ci return *it; 891cb0ef41Sopenharmony_ci engine_nodes_.insert(n.get()); 901cb0ef41Sopenharmony_ci return AddNode(std::unique_ptr<Node>(n.release())); 911cb0ef41Sopenharmony_ci } 921cb0ef41Sopenharmony_ci 931cb0ef41Sopenharmony_ci Node* AddNode(std::unique_ptr<Node> node) override { 941cb0ef41Sopenharmony_ci Node* n = node.get(); 951cb0ef41Sopenharmony_ci nodes_.emplace(std::move(node)); 961cb0ef41Sopenharmony_ci return n; 971cb0ef41Sopenharmony_ci } 981cb0ef41Sopenharmony_ci 991cb0ef41Sopenharmony_ci void AddEdge(Node* from, Node* to, const char* name = nullptr) override { 1001cb0ef41Sopenharmony_ci edges_[from].insert(std::make_pair(name, to)); 1011cb0ef41Sopenharmony_ci } 1021cb0ef41Sopenharmony_ci 1031cb0ef41Sopenharmony_ci MaybeLocal<Array> CreateObject() const { 1041cb0ef41Sopenharmony_ci EscapableHandleScope handle_scope(isolate_); 1051cb0ef41Sopenharmony_ci Local<Context> context = isolate_->GetCurrentContext(); 1061cb0ef41Sopenharmony_ci Environment* env = Environment::GetCurrent(context); 1071cb0ef41Sopenharmony_ci 1081cb0ef41Sopenharmony_ci std::unordered_map<Node*, Local<Object>> info_objects; 1091cb0ef41Sopenharmony_ci Local<Array> nodes = Array::New(isolate_, nodes_.size()); 1101cb0ef41Sopenharmony_ci Local<String> edges_string = FIXED_ONE_BYTE_STRING(isolate_, "edges"); 1111cb0ef41Sopenharmony_ci Local<String> is_root_string = FIXED_ONE_BYTE_STRING(isolate_, "isRoot"); 1121cb0ef41Sopenharmony_ci Local<String> name_string = env->name_string(); 1131cb0ef41Sopenharmony_ci Local<String> size_string = env->size_string(); 1141cb0ef41Sopenharmony_ci Local<String> value_string = env->value_string(); 1151cb0ef41Sopenharmony_ci Local<String> wraps_string = FIXED_ONE_BYTE_STRING(isolate_, "wraps"); 1161cb0ef41Sopenharmony_ci Local<String> to_string = FIXED_ONE_BYTE_STRING(isolate_, "to"); 1171cb0ef41Sopenharmony_ci 1181cb0ef41Sopenharmony_ci for (const std::unique_ptr<Node>& n : nodes_) 1191cb0ef41Sopenharmony_ci info_objects[n.get()] = Object::New(isolate_); 1201cb0ef41Sopenharmony_ci 1211cb0ef41Sopenharmony_ci { 1221cb0ef41Sopenharmony_ci HandleScope handle_scope(isolate_); 1231cb0ef41Sopenharmony_ci size_t i = 0; 1241cb0ef41Sopenharmony_ci for (const std::unique_ptr<Node>& n : nodes_) { 1251cb0ef41Sopenharmony_ci Local<Object> obj = info_objects[n.get()]; 1261cb0ef41Sopenharmony_ci Local<Value> value; 1271cb0ef41Sopenharmony_ci std::string name_str; 1281cb0ef41Sopenharmony_ci const char* prefix = n->NamePrefix(); 1291cb0ef41Sopenharmony_ci if (prefix == nullptr) { 1301cb0ef41Sopenharmony_ci name_str = n->Name(); 1311cb0ef41Sopenharmony_ci } else { 1321cb0ef41Sopenharmony_ci name_str = n->NamePrefix(); 1331cb0ef41Sopenharmony_ci name_str += " "; 1341cb0ef41Sopenharmony_ci name_str += n->Name(); 1351cb0ef41Sopenharmony_ci } 1361cb0ef41Sopenharmony_ci if (!String::NewFromUtf8(isolate_, name_str.c_str()).ToLocal(&value) || 1371cb0ef41Sopenharmony_ci obj->Set(context, name_string, value).IsNothing() || 1381cb0ef41Sopenharmony_ci obj->Set(context, 1391cb0ef41Sopenharmony_ci is_root_string, 1401cb0ef41Sopenharmony_ci Boolean::New(isolate_, n->IsRootNode())) 1411cb0ef41Sopenharmony_ci .IsNothing() || 1421cb0ef41Sopenharmony_ci obj->Set( 1431cb0ef41Sopenharmony_ci context, 1441cb0ef41Sopenharmony_ci size_string, 1451cb0ef41Sopenharmony_ci Number::New(isolate_, static_cast<double>(n->SizeInBytes()))) 1461cb0ef41Sopenharmony_ci .IsNothing() || 1471cb0ef41Sopenharmony_ci obj->Set(context, edges_string, Array::New(isolate_)).IsNothing()) { 1481cb0ef41Sopenharmony_ci return MaybeLocal<Array>(); 1491cb0ef41Sopenharmony_ci } 1501cb0ef41Sopenharmony_ci if (nodes->Set(context, i++, obj).IsNothing()) 1511cb0ef41Sopenharmony_ci return MaybeLocal<Array>(); 1521cb0ef41Sopenharmony_ci if (!n->IsEmbedderNode()) { 1531cb0ef41Sopenharmony_ci value = static_cast<JSGraphJSNode*>(n.get())->JSValue(); 1541cb0ef41Sopenharmony_ci if (obj->Set(context, value_string, value).IsNothing()) 1551cb0ef41Sopenharmony_ci return MaybeLocal<Array>(); 1561cb0ef41Sopenharmony_ci } 1571cb0ef41Sopenharmony_ci } 1581cb0ef41Sopenharmony_ci } 1591cb0ef41Sopenharmony_ci 1601cb0ef41Sopenharmony_ci for (const std::unique_ptr<Node>& n : nodes_) { 1611cb0ef41Sopenharmony_ci Node* wraps = n->WrapperNode(); 1621cb0ef41Sopenharmony_ci if (wraps == nullptr) continue; 1631cb0ef41Sopenharmony_ci Local<Object> from = info_objects[n.get()]; 1641cb0ef41Sopenharmony_ci Local<Object> to = info_objects[wraps]; 1651cb0ef41Sopenharmony_ci if (from->Set(context, wraps_string, to).IsNothing()) 1661cb0ef41Sopenharmony_ci return MaybeLocal<Array>(); 1671cb0ef41Sopenharmony_ci } 1681cb0ef41Sopenharmony_ci 1691cb0ef41Sopenharmony_ci for (const auto& edge_info : edges_) { 1701cb0ef41Sopenharmony_ci Node* source = edge_info.first; 1711cb0ef41Sopenharmony_ci Local<Value> edges; 1721cb0ef41Sopenharmony_ci if (!info_objects[source]->Get(context, edges_string).ToLocal(&edges) || 1731cb0ef41Sopenharmony_ci !edges->IsArray()) { 1741cb0ef41Sopenharmony_ci return MaybeLocal<Array>(); 1751cb0ef41Sopenharmony_ci } 1761cb0ef41Sopenharmony_ci 1771cb0ef41Sopenharmony_ci size_t i = 0; 1781cb0ef41Sopenharmony_ci size_t j = 0; 1791cb0ef41Sopenharmony_ci for (const auto& edge : edge_info.second) { 1801cb0ef41Sopenharmony_ci Local<Object> to_object = info_objects[edge.second]; 1811cb0ef41Sopenharmony_ci Local<Object> edge_obj = Object::New(isolate_); 1821cb0ef41Sopenharmony_ci Local<Value> edge_name_value; 1831cb0ef41Sopenharmony_ci const char* edge_name = edge.first; 1841cb0ef41Sopenharmony_ci if (edge_name != nullptr) { 1851cb0ef41Sopenharmony_ci if (!String::NewFromUtf8(isolate_, edge_name) 1861cb0ef41Sopenharmony_ci .ToLocal(&edge_name_value)) { 1871cb0ef41Sopenharmony_ci return MaybeLocal<Array>(); 1881cb0ef41Sopenharmony_ci } 1891cb0ef41Sopenharmony_ci } else { 1901cb0ef41Sopenharmony_ci edge_name_value = Number::New(isolate_, static_cast<double>(j++)); 1911cb0ef41Sopenharmony_ci } 1921cb0ef41Sopenharmony_ci if (edge_obj->Set(context, name_string, edge_name_value).IsNothing() || 1931cb0ef41Sopenharmony_ci edge_obj->Set(context, to_string, to_object).IsNothing() || 1941cb0ef41Sopenharmony_ci edges.As<Array>()->Set(context, i++, edge_obj).IsNothing()) { 1951cb0ef41Sopenharmony_ci return MaybeLocal<Array>(); 1961cb0ef41Sopenharmony_ci } 1971cb0ef41Sopenharmony_ci } 1981cb0ef41Sopenharmony_ci } 1991cb0ef41Sopenharmony_ci 2001cb0ef41Sopenharmony_ci return handle_scope.Escape(nodes); 2011cb0ef41Sopenharmony_ci } 2021cb0ef41Sopenharmony_ci 2031cb0ef41Sopenharmony_ci private: 2041cb0ef41Sopenharmony_ci Isolate* isolate_; 2051cb0ef41Sopenharmony_ci std::unordered_set<std::unique_ptr<Node>> nodes_; 2061cb0ef41Sopenharmony_ci std::unordered_set<JSGraphJSNode*, JSGraphJSNode::Hash, JSGraphJSNode::Equal> 2071cb0ef41Sopenharmony_ci engine_nodes_; 2081cb0ef41Sopenharmony_ci std::unordered_map<Node*, std::set<std::pair<const char*, Node*>>> edges_; 2091cb0ef41Sopenharmony_ci}; 2101cb0ef41Sopenharmony_ci 2111cb0ef41Sopenharmony_civoid BuildEmbedderGraph(const FunctionCallbackInfo<Value>& args) { 2121cb0ef41Sopenharmony_ci Environment* env = Environment::GetCurrent(args); 2131cb0ef41Sopenharmony_ci JSGraph graph(env->isolate()); 2141cb0ef41Sopenharmony_ci Environment::BuildEmbedderGraph(env->isolate(), &graph, env); 2151cb0ef41Sopenharmony_ci Local<Array> ret; 2161cb0ef41Sopenharmony_ci if (graph.CreateObject().ToLocal(&ret)) 2171cb0ef41Sopenharmony_ci args.GetReturnValue().Set(ret); 2181cb0ef41Sopenharmony_ci} 2191cb0ef41Sopenharmony_ci 2201cb0ef41Sopenharmony_cinamespace { 2211cb0ef41Sopenharmony_ciclass FileOutputStream : public v8::OutputStream { 2221cb0ef41Sopenharmony_ci public: 2231cb0ef41Sopenharmony_ci FileOutputStream(const int fd, uv_fs_t* req) : fd_(fd), req_(req) {} 2241cb0ef41Sopenharmony_ci 2251cb0ef41Sopenharmony_ci int GetChunkSize() override { 2261cb0ef41Sopenharmony_ci return 65536; // big chunks == faster 2271cb0ef41Sopenharmony_ci } 2281cb0ef41Sopenharmony_ci 2291cb0ef41Sopenharmony_ci void EndOfStream() override {} 2301cb0ef41Sopenharmony_ci 2311cb0ef41Sopenharmony_ci WriteResult WriteAsciiChunk(char* data, const int size) override { 2321cb0ef41Sopenharmony_ci DCHECK_EQ(status_, 0); 2331cb0ef41Sopenharmony_ci int offset = 0; 2341cb0ef41Sopenharmony_ci while (offset < size) { 2351cb0ef41Sopenharmony_ci const uv_buf_t buf = uv_buf_init(data + offset, size - offset); 2361cb0ef41Sopenharmony_ci const int num_bytes_written = uv_fs_write(nullptr, 2371cb0ef41Sopenharmony_ci req_, 2381cb0ef41Sopenharmony_ci fd_, 2391cb0ef41Sopenharmony_ci &buf, 2401cb0ef41Sopenharmony_ci 1, 2411cb0ef41Sopenharmony_ci -1, 2421cb0ef41Sopenharmony_ci nullptr); 2431cb0ef41Sopenharmony_ci uv_fs_req_cleanup(req_); 2441cb0ef41Sopenharmony_ci if (num_bytes_written < 0) { 2451cb0ef41Sopenharmony_ci status_ = num_bytes_written; 2461cb0ef41Sopenharmony_ci return kAbort; 2471cb0ef41Sopenharmony_ci } 2481cb0ef41Sopenharmony_ci DCHECK_LE(static_cast<size_t>(num_bytes_written), buf.len); 2491cb0ef41Sopenharmony_ci offset += num_bytes_written; 2501cb0ef41Sopenharmony_ci } 2511cb0ef41Sopenharmony_ci DCHECK_EQ(offset, size); 2521cb0ef41Sopenharmony_ci return kContinue; 2531cb0ef41Sopenharmony_ci } 2541cb0ef41Sopenharmony_ci 2551cb0ef41Sopenharmony_ci int status() const { return status_; } 2561cb0ef41Sopenharmony_ci 2571cb0ef41Sopenharmony_ci private: 2581cb0ef41Sopenharmony_ci const int fd_; 2591cb0ef41Sopenharmony_ci uv_fs_t* req_; 2601cb0ef41Sopenharmony_ci int status_ = 0; 2611cb0ef41Sopenharmony_ci}; 2621cb0ef41Sopenharmony_ci 2631cb0ef41Sopenharmony_ciclass HeapSnapshotStream : public AsyncWrap, 2641cb0ef41Sopenharmony_ci public StreamBase, 2651cb0ef41Sopenharmony_ci public v8::OutputStream { 2661cb0ef41Sopenharmony_ci public: 2671cb0ef41Sopenharmony_ci HeapSnapshotStream( 2681cb0ef41Sopenharmony_ci Environment* env, 2691cb0ef41Sopenharmony_ci HeapSnapshotPointer&& snapshot, 2701cb0ef41Sopenharmony_ci Local<Object> obj) : 2711cb0ef41Sopenharmony_ci AsyncWrap(env, obj, AsyncWrap::PROVIDER_HEAPSNAPSHOT), 2721cb0ef41Sopenharmony_ci StreamBase(env), 2731cb0ef41Sopenharmony_ci snapshot_(std::move(snapshot)) { 2741cb0ef41Sopenharmony_ci MakeWeak(); 2751cb0ef41Sopenharmony_ci StreamBase::AttachToObject(GetObject()); 2761cb0ef41Sopenharmony_ci } 2771cb0ef41Sopenharmony_ci 2781cb0ef41Sopenharmony_ci ~HeapSnapshotStream() override {} 2791cb0ef41Sopenharmony_ci 2801cb0ef41Sopenharmony_ci int GetChunkSize() override { 2811cb0ef41Sopenharmony_ci return 65536; // big chunks == faster 2821cb0ef41Sopenharmony_ci } 2831cb0ef41Sopenharmony_ci 2841cb0ef41Sopenharmony_ci void EndOfStream() override { 2851cb0ef41Sopenharmony_ci EmitRead(UV_EOF); 2861cb0ef41Sopenharmony_ci snapshot_.reset(); 2871cb0ef41Sopenharmony_ci } 2881cb0ef41Sopenharmony_ci 2891cb0ef41Sopenharmony_ci WriteResult WriteAsciiChunk(char* data, int size) override { 2901cb0ef41Sopenharmony_ci int len = size; 2911cb0ef41Sopenharmony_ci while (len != 0) { 2921cb0ef41Sopenharmony_ci uv_buf_t buf = EmitAlloc(size); 2931cb0ef41Sopenharmony_ci ssize_t avail = len; 2941cb0ef41Sopenharmony_ci if (static_cast<ssize_t>(buf.len) < avail) 2951cb0ef41Sopenharmony_ci avail = buf.len; 2961cb0ef41Sopenharmony_ci memcpy(buf.base, data, avail); 2971cb0ef41Sopenharmony_ci data += avail; 2981cb0ef41Sopenharmony_ci len -= static_cast<int>(avail); 2991cb0ef41Sopenharmony_ci EmitRead(size, buf); 3001cb0ef41Sopenharmony_ci } 3011cb0ef41Sopenharmony_ci return kContinue; 3021cb0ef41Sopenharmony_ci } 3031cb0ef41Sopenharmony_ci 3041cb0ef41Sopenharmony_ci int ReadStart() override { 3051cb0ef41Sopenharmony_ci CHECK_NE(snapshot_, nullptr); 3061cb0ef41Sopenharmony_ci snapshot_->Serialize(this, HeapSnapshot::kJSON); 3071cb0ef41Sopenharmony_ci return 0; 3081cb0ef41Sopenharmony_ci } 3091cb0ef41Sopenharmony_ci 3101cb0ef41Sopenharmony_ci int ReadStop() override { 3111cb0ef41Sopenharmony_ci return 0; 3121cb0ef41Sopenharmony_ci } 3131cb0ef41Sopenharmony_ci 3141cb0ef41Sopenharmony_ci int DoShutdown(ShutdownWrap* req_wrap) override { 3151cb0ef41Sopenharmony_ci UNREACHABLE(); 3161cb0ef41Sopenharmony_ci } 3171cb0ef41Sopenharmony_ci 3181cb0ef41Sopenharmony_ci int DoWrite(WriteWrap* w, 3191cb0ef41Sopenharmony_ci uv_buf_t* bufs, 3201cb0ef41Sopenharmony_ci size_t count, 3211cb0ef41Sopenharmony_ci uv_stream_t* send_handle) override { 3221cb0ef41Sopenharmony_ci UNREACHABLE(); 3231cb0ef41Sopenharmony_ci } 3241cb0ef41Sopenharmony_ci 3251cb0ef41Sopenharmony_ci bool IsAlive() override { return snapshot_ != nullptr; } 3261cb0ef41Sopenharmony_ci bool IsClosing() override { return snapshot_ == nullptr; } 3271cb0ef41Sopenharmony_ci AsyncWrap* GetAsyncWrap() override { return this; } 3281cb0ef41Sopenharmony_ci 3291cb0ef41Sopenharmony_ci void MemoryInfo(MemoryTracker* tracker) const override { 3301cb0ef41Sopenharmony_ci if (snapshot_ != nullptr) { 3311cb0ef41Sopenharmony_ci tracker->TrackFieldWithSize( 3321cb0ef41Sopenharmony_ci "snapshot", sizeof(*snapshot_), "HeapSnapshot"); 3331cb0ef41Sopenharmony_ci } 3341cb0ef41Sopenharmony_ci } 3351cb0ef41Sopenharmony_ci 3361cb0ef41Sopenharmony_ci SET_MEMORY_INFO_NAME(HeapSnapshotStream) 3371cb0ef41Sopenharmony_ci SET_SELF_SIZE(HeapSnapshotStream) 3381cb0ef41Sopenharmony_ci 3391cb0ef41Sopenharmony_ci private: 3401cb0ef41Sopenharmony_ci HeapSnapshotPointer snapshot_; 3411cb0ef41Sopenharmony_ci}; 3421cb0ef41Sopenharmony_ci 3431cb0ef41Sopenharmony_ciinline void TakeSnapshot(Environment* env, v8::OutputStream* out) { 3441cb0ef41Sopenharmony_ci HeapSnapshotPointer snapshot { 3451cb0ef41Sopenharmony_ci env->isolate()->GetHeapProfiler()->TakeHeapSnapshot() }; 3461cb0ef41Sopenharmony_ci snapshot->Serialize(out, HeapSnapshot::kJSON); 3471cb0ef41Sopenharmony_ci} 3481cb0ef41Sopenharmony_ci 3491cb0ef41Sopenharmony_ci} // namespace 3501cb0ef41Sopenharmony_ci 3511cb0ef41Sopenharmony_ciMaybe<void> WriteSnapshot(Environment* env, const char* filename) { 3521cb0ef41Sopenharmony_ci uv_fs_t req; 3531cb0ef41Sopenharmony_ci int err; 3541cb0ef41Sopenharmony_ci 3551cb0ef41Sopenharmony_ci const int fd = uv_fs_open(nullptr, 3561cb0ef41Sopenharmony_ci &req, 3571cb0ef41Sopenharmony_ci filename, 3581cb0ef41Sopenharmony_ci O_WRONLY | O_CREAT | O_TRUNC, 3591cb0ef41Sopenharmony_ci S_IWUSR | S_IRUSR, 3601cb0ef41Sopenharmony_ci nullptr); 3611cb0ef41Sopenharmony_ci uv_fs_req_cleanup(&req); 3621cb0ef41Sopenharmony_ci if ((err = fd) < 0) { 3631cb0ef41Sopenharmony_ci env->ThrowUVException(err, "open", nullptr, filename); 3641cb0ef41Sopenharmony_ci return Nothing<void>(); 3651cb0ef41Sopenharmony_ci } 3661cb0ef41Sopenharmony_ci 3671cb0ef41Sopenharmony_ci FileOutputStream stream(fd, &req); 3681cb0ef41Sopenharmony_ci TakeSnapshot(env, &stream); 3691cb0ef41Sopenharmony_ci if ((err = stream.status()) < 0) { 3701cb0ef41Sopenharmony_ci env->ThrowUVException(err, "write", nullptr, filename); 3711cb0ef41Sopenharmony_ci return Nothing<void>(); 3721cb0ef41Sopenharmony_ci } 3731cb0ef41Sopenharmony_ci 3741cb0ef41Sopenharmony_ci err = uv_fs_close(nullptr, &req, fd, nullptr); 3751cb0ef41Sopenharmony_ci uv_fs_req_cleanup(&req); 3761cb0ef41Sopenharmony_ci if (err < 0) { 3771cb0ef41Sopenharmony_ci env->ThrowUVException(err, "close", nullptr, filename); 3781cb0ef41Sopenharmony_ci return Nothing<void>(); 3791cb0ef41Sopenharmony_ci } 3801cb0ef41Sopenharmony_ci 3811cb0ef41Sopenharmony_ci return JustVoid(); 3821cb0ef41Sopenharmony_ci} 3831cb0ef41Sopenharmony_ci 3841cb0ef41Sopenharmony_civoid DeleteHeapSnapshot(const HeapSnapshot* snapshot) { 3851cb0ef41Sopenharmony_ci const_cast<HeapSnapshot*>(snapshot)->Delete(); 3861cb0ef41Sopenharmony_ci} 3871cb0ef41Sopenharmony_ci 3881cb0ef41Sopenharmony_ciBaseObjectPtr<AsyncWrap> CreateHeapSnapshotStream( 3891cb0ef41Sopenharmony_ci Environment* env, HeapSnapshotPointer&& snapshot) { 3901cb0ef41Sopenharmony_ci HandleScope scope(env->isolate()); 3911cb0ef41Sopenharmony_ci 3921cb0ef41Sopenharmony_ci if (env->streambaseoutputstream_constructor_template().IsEmpty()) { 3931cb0ef41Sopenharmony_ci // Create FunctionTemplate for HeapSnapshotStream 3941cb0ef41Sopenharmony_ci Local<FunctionTemplate> os = FunctionTemplate::New(env->isolate()); 3951cb0ef41Sopenharmony_ci os->Inherit(AsyncWrap::GetConstructorTemplate(env)); 3961cb0ef41Sopenharmony_ci Local<ObjectTemplate> ost = os->InstanceTemplate(); 3971cb0ef41Sopenharmony_ci ost->SetInternalFieldCount(StreamBase::kInternalFieldCount); 3981cb0ef41Sopenharmony_ci os->SetClassName( 3991cb0ef41Sopenharmony_ci FIXED_ONE_BYTE_STRING(env->isolate(), "HeapSnapshotStream")); 4001cb0ef41Sopenharmony_ci StreamBase::AddMethods(env, os); 4011cb0ef41Sopenharmony_ci env->set_streambaseoutputstream_constructor_template(ost); 4021cb0ef41Sopenharmony_ci } 4031cb0ef41Sopenharmony_ci 4041cb0ef41Sopenharmony_ci Local<Object> obj; 4051cb0ef41Sopenharmony_ci if (!env->streambaseoutputstream_constructor_template() 4061cb0ef41Sopenharmony_ci ->NewInstance(env->context()) 4071cb0ef41Sopenharmony_ci .ToLocal(&obj)) { 4081cb0ef41Sopenharmony_ci return {}; 4091cb0ef41Sopenharmony_ci } 4101cb0ef41Sopenharmony_ci return MakeBaseObject<HeapSnapshotStream>(env, std::move(snapshot), obj); 4111cb0ef41Sopenharmony_ci} 4121cb0ef41Sopenharmony_ci 4131cb0ef41Sopenharmony_civoid CreateHeapSnapshotStream(const FunctionCallbackInfo<Value>& args) { 4141cb0ef41Sopenharmony_ci Environment* env = Environment::GetCurrent(args); 4151cb0ef41Sopenharmony_ci HeapSnapshotPointer snapshot { 4161cb0ef41Sopenharmony_ci env->isolate()->GetHeapProfiler()->TakeHeapSnapshot() }; 4171cb0ef41Sopenharmony_ci CHECK(snapshot); 4181cb0ef41Sopenharmony_ci BaseObjectPtr<AsyncWrap> stream = 4191cb0ef41Sopenharmony_ci CreateHeapSnapshotStream(env, std::move(snapshot)); 4201cb0ef41Sopenharmony_ci if (stream) 4211cb0ef41Sopenharmony_ci args.GetReturnValue().Set(stream->object()); 4221cb0ef41Sopenharmony_ci} 4231cb0ef41Sopenharmony_ci 4241cb0ef41Sopenharmony_civoid TriggerHeapSnapshot(const FunctionCallbackInfo<Value>& args) { 4251cb0ef41Sopenharmony_ci Environment* env = Environment::GetCurrent(args); 4261cb0ef41Sopenharmony_ci Isolate* isolate = args.GetIsolate(); 4271cb0ef41Sopenharmony_ci 4281cb0ef41Sopenharmony_ci Local<Value> filename_v = args[0]; 4291cb0ef41Sopenharmony_ci 4301cb0ef41Sopenharmony_ci if (filename_v->IsUndefined()) { 4311cb0ef41Sopenharmony_ci DiagnosticFilename name(env, "Heap", "heapsnapshot"); 4321cb0ef41Sopenharmony_ci if (WriteSnapshot(env, *name).IsNothing()) 4331cb0ef41Sopenharmony_ci return; 4341cb0ef41Sopenharmony_ci if (String::NewFromUtf8(isolate, *name).ToLocal(&filename_v)) { 4351cb0ef41Sopenharmony_ci args.GetReturnValue().Set(filename_v); 4361cb0ef41Sopenharmony_ci } 4371cb0ef41Sopenharmony_ci return; 4381cb0ef41Sopenharmony_ci } 4391cb0ef41Sopenharmony_ci 4401cb0ef41Sopenharmony_ci BufferValue path(isolate, filename_v); 4411cb0ef41Sopenharmony_ci CHECK_NOT_NULL(*path); 4421cb0ef41Sopenharmony_ci if (WriteSnapshot(env, *path).IsNothing()) 4431cb0ef41Sopenharmony_ci return; 4441cb0ef41Sopenharmony_ci return args.GetReturnValue().Set(filename_v); 4451cb0ef41Sopenharmony_ci} 4461cb0ef41Sopenharmony_ci 4471cb0ef41Sopenharmony_civoid Initialize(Local<Object> target, 4481cb0ef41Sopenharmony_ci Local<Value> unused, 4491cb0ef41Sopenharmony_ci Local<Context> context, 4501cb0ef41Sopenharmony_ci void* priv) { 4511cb0ef41Sopenharmony_ci SetMethod(context, target, "buildEmbedderGraph", BuildEmbedderGraph); 4521cb0ef41Sopenharmony_ci SetMethod(context, target, "triggerHeapSnapshot", TriggerHeapSnapshot); 4531cb0ef41Sopenharmony_ci SetMethod( 4541cb0ef41Sopenharmony_ci context, target, "createHeapSnapshotStream", CreateHeapSnapshotStream); 4551cb0ef41Sopenharmony_ci} 4561cb0ef41Sopenharmony_ci 4571cb0ef41Sopenharmony_civoid RegisterExternalReferences(ExternalReferenceRegistry* registry) { 4581cb0ef41Sopenharmony_ci registry->Register(BuildEmbedderGraph); 4591cb0ef41Sopenharmony_ci registry->Register(TriggerHeapSnapshot); 4601cb0ef41Sopenharmony_ci registry->Register(CreateHeapSnapshotStream); 4611cb0ef41Sopenharmony_ci} 4621cb0ef41Sopenharmony_ci 4631cb0ef41Sopenharmony_ci} // namespace heap 4641cb0ef41Sopenharmony_ci} // namespace node 4651cb0ef41Sopenharmony_ci 4661cb0ef41Sopenharmony_ciNODE_BINDING_CONTEXT_AWARE_INTERNAL(heap_utils, node::heap::Initialize) 4671cb0ef41Sopenharmony_ciNODE_BINDING_EXTERNAL_REFERENCE(heap_utils, 4681cb0ef41Sopenharmony_ci node::heap::RegisterExternalReferences) 469