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