11cb0ef41Sopenharmony_ci// Copyright 2016 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/inspector/v8-heap-profiler-agent-impl.h"
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci#include "include/v8-context.h"
81cb0ef41Sopenharmony_ci#include "include/v8-inspector.h"
91cb0ef41Sopenharmony_ci#include "include/v8-platform.h"
101cb0ef41Sopenharmony_ci#include "include/v8-profiler.h"
111cb0ef41Sopenharmony_ci#include "include/v8-version.h"
121cb0ef41Sopenharmony_ci#include "src/base/platform/mutex.h"
131cb0ef41Sopenharmony_ci#include "src/inspector/injected-script.h"
141cb0ef41Sopenharmony_ci#include "src/inspector/inspected-context.h"
151cb0ef41Sopenharmony_ci#include "src/inspector/protocol/Protocol.h"
161cb0ef41Sopenharmony_ci#include "src/inspector/string-util.h"
171cb0ef41Sopenharmony_ci#include "src/inspector/v8-debugger.h"
181cb0ef41Sopenharmony_ci#include "src/inspector/v8-inspector-impl.h"
191cb0ef41Sopenharmony_ci#include "src/inspector/v8-inspector-session-impl.h"
201cb0ef41Sopenharmony_ci
211cb0ef41Sopenharmony_cinamespace v8_inspector {
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_cinamespace {
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_cinamespace HeapProfilerAgentState {
261cb0ef41Sopenharmony_cistatic const char heapProfilerEnabled[] = "heapProfilerEnabled";
271cb0ef41Sopenharmony_cistatic const char heapObjectsTrackingEnabled[] = "heapObjectsTrackingEnabled";
281cb0ef41Sopenharmony_cistatic const char allocationTrackingEnabled[] = "allocationTrackingEnabled";
291cb0ef41Sopenharmony_cistatic const char samplingHeapProfilerEnabled[] = "samplingHeapProfilerEnabled";
301cb0ef41Sopenharmony_cistatic const char samplingHeapProfilerInterval[] =
311cb0ef41Sopenharmony_ci    "samplingHeapProfilerInterval";
321cb0ef41Sopenharmony_ci}  // namespace HeapProfilerAgentState
331cb0ef41Sopenharmony_ci
341cb0ef41Sopenharmony_ciclass HeapSnapshotProgress final : public v8::ActivityControl {
351cb0ef41Sopenharmony_ci public:
361cb0ef41Sopenharmony_ci  explicit HeapSnapshotProgress(protocol::HeapProfiler::Frontend* frontend)
371cb0ef41Sopenharmony_ci      : m_frontend(frontend) {}
381cb0ef41Sopenharmony_ci  ControlOption ReportProgressValue(uint32_t done, uint32_t total) override {
391cb0ef41Sopenharmony_ci    m_frontend->reportHeapSnapshotProgress(done, total,
401cb0ef41Sopenharmony_ci                                           protocol::Maybe<bool>());
411cb0ef41Sopenharmony_ci    if (done >= total) {
421cb0ef41Sopenharmony_ci      m_frontend->reportHeapSnapshotProgress(total, total, true);
431cb0ef41Sopenharmony_ci    }
441cb0ef41Sopenharmony_ci    m_frontend->flush();
451cb0ef41Sopenharmony_ci    return kContinue;
461cb0ef41Sopenharmony_ci  }
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_ci private:
491cb0ef41Sopenharmony_ci  protocol::HeapProfiler::Frontend* m_frontend;
501cb0ef41Sopenharmony_ci};
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ciclass GlobalObjectNameResolver final
531cb0ef41Sopenharmony_ci    : public v8::HeapProfiler::ObjectNameResolver {
541cb0ef41Sopenharmony_ci public:
551cb0ef41Sopenharmony_ci  explicit GlobalObjectNameResolver(V8InspectorSessionImpl* session)
561cb0ef41Sopenharmony_ci      : m_offset(0), m_strings(10000), m_session(session) {}
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ci  const char* GetName(v8::Local<v8::Object> object) override {
591cb0ef41Sopenharmony_ci    v8::Local<v8::Context> creationContext;
601cb0ef41Sopenharmony_ci    if (!object->GetCreationContext().ToLocal(&creationContext)) {
611cb0ef41Sopenharmony_ci      return "";
621cb0ef41Sopenharmony_ci    }
631cb0ef41Sopenharmony_ci    InspectedContext* context = m_session->inspector()->getContext(
641cb0ef41Sopenharmony_ci        m_session->contextGroupId(),
651cb0ef41Sopenharmony_ci        InspectedContext::contextId(creationContext));
661cb0ef41Sopenharmony_ci    if (!context) return "";
671cb0ef41Sopenharmony_ci    String16 name = context->origin();
681cb0ef41Sopenharmony_ci    size_t length = name.length();
691cb0ef41Sopenharmony_ci    if (m_offset + length + 1 >= m_strings.size()) return "";
701cb0ef41Sopenharmony_ci    for (size_t i = 0; i < length; ++i) {
711cb0ef41Sopenharmony_ci      UChar ch = name[i];
721cb0ef41Sopenharmony_ci      m_strings[m_offset + i] = ch > 0xFF ? '?' : static_cast<char>(ch);
731cb0ef41Sopenharmony_ci    }
741cb0ef41Sopenharmony_ci    m_strings[m_offset + length] = '\0';
751cb0ef41Sopenharmony_ci    char* result = &*m_strings.begin() + m_offset;
761cb0ef41Sopenharmony_ci    m_offset += length + 1;
771cb0ef41Sopenharmony_ci    return result;
781cb0ef41Sopenharmony_ci  }
791cb0ef41Sopenharmony_ci
801cb0ef41Sopenharmony_ci private:
811cb0ef41Sopenharmony_ci  size_t m_offset;
821cb0ef41Sopenharmony_ci  std::vector<char> m_strings;
831cb0ef41Sopenharmony_ci  V8InspectorSessionImpl* m_session;
841cb0ef41Sopenharmony_ci};
851cb0ef41Sopenharmony_ci
861cb0ef41Sopenharmony_ciclass HeapSnapshotOutputStream final : public v8::OutputStream {
871cb0ef41Sopenharmony_ci public:
881cb0ef41Sopenharmony_ci  explicit HeapSnapshotOutputStream(protocol::HeapProfiler::Frontend* frontend)
891cb0ef41Sopenharmony_ci      : m_frontend(frontend) {}
901cb0ef41Sopenharmony_ci  void EndOfStream() override {}
911cb0ef41Sopenharmony_ci  int GetChunkSize() override { return 102400; }
921cb0ef41Sopenharmony_ci  WriteResult WriteAsciiChunk(char* data, int size) override {
931cb0ef41Sopenharmony_ci    m_frontend->addHeapSnapshotChunk(String16(data, size));
941cb0ef41Sopenharmony_ci    m_frontend->flush();
951cb0ef41Sopenharmony_ci    return kContinue;
961cb0ef41Sopenharmony_ci  }
971cb0ef41Sopenharmony_ci
981cb0ef41Sopenharmony_ci private:
991cb0ef41Sopenharmony_ci  protocol::HeapProfiler::Frontend* m_frontend;
1001cb0ef41Sopenharmony_ci};
1011cb0ef41Sopenharmony_ci
1021cb0ef41Sopenharmony_civ8::Local<v8::Object> objectByHeapObjectId(v8::Isolate* isolate, int id) {
1031cb0ef41Sopenharmony_ci  v8::HeapProfiler* profiler = isolate->GetHeapProfiler();
1041cb0ef41Sopenharmony_ci  v8::Local<v8::Value> value = profiler->FindObjectById(id);
1051cb0ef41Sopenharmony_ci  if (value.IsEmpty() || !value->IsObject()) return v8::Local<v8::Object>();
1061cb0ef41Sopenharmony_ci  return value.As<v8::Object>();
1071cb0ef41Sopenharmony_ci}
1081cb0ef41Sopenharmony_ci
1091cb0ef41Sopenharmony_ciclass InspectableHeapObject final : public V8InspectorSession::Inspectable {
1101cb0ef41Sopenharmony_ci public:
1111cb0ef41Sopenharmony_ci  explicit InspectableHeapObject(int heapObjectId)
1121cb0ef41Sopenharmony_ci      : m_heapObjectId(heapObjectId) {}
1131cb0ef41Sopenharmony_ci  v8::Local<v8::Value> get(v8::Local<v8::Context> context) override {
1141cb0ef41Sopenharmony_ci    return objectByHeapObjectId(context->GetIsolate(), m_heapObjectId);
1151cb0ef41Sopenharmony_ci  }
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_ci private:
1181cb0ef41Sopenharmony_ci  int m_heapObjectId;
1191cb0ef41Sopenharmony_ci};
1201cb0ef41Sopenharmony_ci
1211cb0ef41Sopenharmony_ciclass HeapStatsStream final : public v8::OutputStream {
1221cb0ef41Sopenharmony_ci public:
1231cb0ef41Sopenharmony_ci  explicit HeapStatsStream(protocol::HeapProfiler::Frontend* frontend)
1241cb0ef41Sopenharmony_ci      : m_frontend(frontend) {}
1251cb0ef41Sopenharmony_ci
1261cb0ef41Sopenharmony_ci  void EndOfStream() override {}
1271cb0ef41Sopenharmony_ci
1281cb0ef41Sopenharmony_ci  WriteResult WriteAsciiChunk(char* data, int size) override {
1291cb0ef41Sopenharmony_ci    DCHECK(false);
1301cb0ef41Sopenharmony_ci    return kAbort;
1311cb0ef41Sopenharmony_ci  }
1321cb0ef41Sopenharmony_ci
1331cb0ef41Sopenharmony_ci  WriteResult WriteHeapStatsChunk(v8::HeapStatsUpdate* updateData,
1341cb0ef41Sopenharmony_ci                                  int count) override {
1351cb0ef41Sopenharmony_ci    DCHECK_GT(count, 0);
1361cb0ef41Sopenharmony_ci    auto statsDiff = std::make_unique<protocol::Array<int>>();
1371cb0ef41Sopenharmony_ci    for (int i = 0; i < count; ++i) {
1381cb0ef41Sopenharmony_ci      statsDiff->emplace_back(updateData[i].index);
1391cb0ef41Sopenharmony_ci      statsDiff->emplace_back(updateData[i].count);
1401cb0ef41Sopenharmony_ci      statsDiff->emplace_back(updateData[i].size);
1411cb0ef41Sopenharmony_ci    }
1421cb0ef41Sopenharmony_ci    m_frontend->heapStatsUpdate(std::move(statsDiff));
1431cb0ef41Sopenharmony_ci    return kContinue;
1441cb0ef41Sopenharmony_ci  }
1451cb0ef41Sopenharmony_ci
1461cb0ef41Sopenharmony_ci private:
1471cb0ef41Sopenharmony_ci  protocol::HeapProfiler::Frontend* m_frontend;
1481cb0ef41Sopenharmony_ci};
1491cb0ef41Sopenharmony_ci
1501cb0ef41Sopenharmony_ci}  // namespace
1511cb0ef41Sopenharmony_ci
1521cb0ef41Sopenharmony_cistruct V8HeapProfilerAgentImpl::AsyncGC {
1531cb0ef41Sopenharmony_ci  v8::base::Mutex m_mutex;
1541cb0ef41Sopenharmony_ci  bool m_canceled = false;
1551cb0ef41Sopenharmony_ci  bool m_pending = false;
1561cb0ef41Sopenharmony_ci  std::vector<std::unique_ptr<CollectGarbageCallback>> m_pending_callbacks;
1571cb0ef41Sopenharmony_ci};
1581cb0ef41Sopenharmony_ci
1591cb0ef41Sopenharmony_ciclass V8HeapProfilerAgentImpl::GCTask : public v8::Task {
1601cb0ef41Sopenharmony_ci public:
1611cb0ef41Sopenharmony_ci  GCTask(v8::Isolate* isolate, std::shared_ptr<AsyncGC> async_gc)
1621cb0ef41Sopenharmony_ci      : m_isolate(isolate), m_async_gc(async_gc) {}
1631cb0ef41Sopenharmony_ci
1641cb0ef41Sopenharmony_ci  void Run() override {
1651cb0ef41Sopenharmony_ci    std::shared_ptr<AsyncGC> async_gc = m_async_gc.lock();
1661cb0ef41Sopenharmony_ci    if (!async_gc) return;
1671cb0ef41Sopenharmony_ci    v8::base::MutexGuard lock(&async_gc->m_mutex);
1681cb0ef41Sopenharmony_ci    if (async_gc->m_canceled) return;
1691cb0ef41Sopenharmony_ci    v8::debug::ForceGarbageCollection(
1701cb0ef41Sopenharmony_ci        m_isolate, v8::EmbedderHeapTracer::EmbedderStackState::kNoHeapPointers);
1711cb0ef41Sopenharmony_ci    for (auto& callback : async_gc->m_pending_callbacks) {
1721cb0ef41Sopenharmony_ci      callback->sendSuccess();
1731cb0ef41Sopenharmony_ci    }
1741cb0ef41Sopenharmony_ci    async_gc->m_pending_callbacks.clear();
1751cb0ef41Sopenharmony_ci  }
1761cb0ef41Sopenharmony_ci
1771cb0ef41Sopenharmony_ci private:
1781cb0ef41Sopenharmony_ci  v8::Isolate* m_isolate;
1791cb0ef41Sopenharmony_ci  std::weak_ptr<AsyncGC> m_async_gc;
1801cb0ef41Sopenharmony_ci};
1811cb0ef41Sopenharmony_ci
1821cb0ef41Sopenharmony_ciV8HeapProfilerAgentImpl::V8HeapProfilerAgentImpl(
1831cb0ef41Sopenharmony_ci    V8InspectorSessionImpl* session, protocol::FrontendChannel* frontendChannel,
1841cb0ef41Sopenharmony_ci    protocol::DictionaryValue* state)
1851cb0ef41Sopenharmony_ci    : m_session(session),
1861cb0ef41Sopenharmony_ci      m_isolate(session->inspector()->isolate()),
1871cb0ef41Sopenharmony_ci      m_frontend(frontendChannel),
1881cb0ef41Sopenharmony_ci      m_state(state),
1891cb0ef41Sopenharmony_ci      m_hasTimer(false),
1901cb0ef41Sopenharmony_ci      m_async_gc(std::make_shared<AsyncGC>()) {}
1911cb0ef41Sopenharmony_ci
1921cb0ef41Sopenharmony_ciV8HeapProfilerAgentImpl::~V8HeapProfilerAgentImpl() {
1931cb0ef41Sopenharmony_ci  v8::base::MutexGuard lock(&m_async_gc->m_mutex);
1941cb0ef41Sopenharmony_ci  m_async_gc->m_canceled = true;
1951cb0ef41Sopenharmony_ci  m_async_gc->m_pending_callbacks.clear();
1961cb0ef41Sopenharmony_ci}
1971cb0ef41Sopenharmony_ci
1981cb0ef41Sopenharmony_civoid V8HeapProfilerAgentImpl::restore() {
1991cb0ef41Sopenharmony_ci  if (m_state->booleanProperty(HeapProfilerAgentState::heapProfilerEnabled,
2001cb0ef41Sopenharmony_ci                               false))
2011cb0ef41Sopenharmony_ci    m_frontend.resetProfiles();
2021cb0ef41Sopenharmony_ci  if (m_state->booleanProperty(
2031cb0ef41Sopenharmony_ci          HeapProfilerAgentState::heapObjectsTrackingEnabled, false))
2041cb0ef41Sopenharmony_ci    startTrackingHeapObjectsInternal(m_state->booleanProperty(
2051cb0ef41Sopenharmony_ci        HeapProfilerAgentState::allocationTrackingEnabled, false));
2061cb0ef41Sopenharmony_ci  if (m_state->booleanProperty(
2071cb0ef41Sopenharmony_ci          HeapProfilerAgentState::samplingHeapProfilerEnabled, false)) {
2081cb0ef41Sopenharmony_ci    double samplingInterval = m_state->doubleProperty(
2091cb0ef41Sopenharmony_ci        HeapProfilerAgentState::samplingHeapProfilerInterval, -1);
2101cb0ef41Sopenharmony_ci    DCHECK_GE(samplingInterval, 0);
2111cb0ef41Sopenharmony_ci    startSampling(Maybe<double>(samplingInterval));
2121cb0ef41Sopenharmony_ci  }
2131cb0ef41Sopenharmony_ci}
2141cb0ef41Sopenharmony_ci
2151cb0ef41Sopenharmony_civoid V8HeapProfilerAgentImpl::collectGarbage(
2161cb0ef41Sopenharmony_ci    std::unique_ptr<CollectGarbageCallback> callback) {
2171cb0ef41Sopenharmony_ci  v8::base::MutexGuard lock(&m_async_gc->m_mutex);
2181cb0ef41Sopenharmony_ci  m_async_gc->m_pending_callbacks.push_back(std::move(callback));
2191cb0ef41Sopenharmony_ci  if (!m_async_gc->m_pending) {
2201cb0ef41Sopenharmony_ci    v8::debug::GetCurrentPlatform()
2211cb0ef41Sopenharmony_ci        ->GetForegroundTaskRunner(m_isolate)
2221cb0ef41Sopenharmony_ci        ->PostNonNestableTask(std::make_unique<GCTask>(m_isolate, m_async_gc));
2231cb0ef41Sopenharmony_ci  }
2241cb0ef41Sopenharmony_ci}
2251cb0ef41Sopenharmony_ci
2261cb0ef41Sopenharmony_ciResponse V8HeapProfilerAgentImpl::startTrackingHeapObjects(
2271cb0ef41Sopenharmony_ci    Maybe<bool> trackAllocations) {
2281cb0ef41Sopenharmony_ci  m_state->setBoolean(HeapProfilerAgentState::heapObjectsTrackingEnabled, true);
2291cb0ef41Sopenharmony_ci  bool allocationTrackingEnabled = trackAllocations.fromMaybe(false);
2301cb0ef41Sopenharmony_ci  m_state->setBoolean(HeapProfilerAgentState::allocationTrackingEnabled,
2311cb0ef41Sopenharmony_ci                      allocationTrackingEnabled);
2321cb0ef41Sopenharmony_ci  startTrackingHeapObjectsInternal(allocationTrackingEnabled);
2331cb0ef41Sopenharmony_ci  return Response::Success();
2341cb0ef41Sopenharmony_ci}
2351cb0ef41Sopenharmony_ci
2361cb0ef41Sopenharmony_ciResponse V8HeapProfilerAgentImpl::stopTrackingHeapObjects(
2371cb0ef41Sopenharmony_ci    Maybe<bool> reportProgress, Maybe<bool> treatGlobalObjectsAsRoots,
2381cb0ef41Sopenharmony_ci    Maybe<bool> captureNumericValue) {
2391cb0ef41Sopenharmony_ci  requestHeapStatsUpdate();
2401cb0ef41Sopenharmony_ci  takeHeapSnapshot(std::move(reportProgress),
2411cb0ef41Sopenharmony_ci                   std::move(treatGlobalObjectsAsRoots),
2421cb0ef41Sopenharmony_ci                   std::move(captureNumericValue));
2431cb0ef41Sopenharmony_ci  stopTrackingHeapObjectsInternal();
2441cb0ef41Sopenharmony_ci  return Response::Success();
2451cb0ef41Sopenharmony_ci}
2461cb0ef41Sopenharmony_ci
2471cb0ef41Sopenharmony_ciResponse V8HeapProfilerAgentImpl::enable() {
2481cb0ef41Sopenharmony_ci  m_state->setBoolean(HeapProfilerAgentState::heapProfilerEnabled, true);
2491cb0ef41Sopenharmony_ci  return Response::Success();
2501cb0ef41Sopenharmony_ci}
2511cb0ef41Sopenharmony_ci
2521cb0ef41Sopenharmony_ciResponse V8HeapProfilerAgentImpl::disable() {
2531cb0ef41Sopenharmony_ci  stopTrackingHeapObjectsInternal();
2541cb0ef41Sopenharmony_ci  if (m_state->booleanProperty(
2551cb0ef41Sopenharmony_ci          HeapProfilerAgentState::samplingHeapProfilerEnabled, false)) {
2561cb0ef41Sopenharmony_ci    v8::HeapProfiler* profiler = m_isolate->GetHeapProfiler();
2571cb0ef41Sopenharmony_ci    if (profiler) profiler->StopSamplingHeapProfiler();
2581cb0ef41Sopenharmony_ci  }
2591cb0ef41Sopenharmony_ci  m_isolate->GetHeapProfiler()->ClearObjectIds();
2601cb0ef41Sopenharmony_ci  m_state->setBoolean(HeapProfilerAgentState::heapProfilerEnabled, false);
2611cb0ef41Sopenharmony_ci  return Response::Success();
2621cb0ef41Sopenharmony_ci}
2631cb0ef41Sopenharmony_ci
2641cb0ef41Sopenharmony_ciResponse V8HeapProfilerAgentImpl::takeHeapSnapshot(
2651cb0ef41Sopenharmony_ci    Maybe<bool> reportProgress, Maybe<bool> treatGlobalObjectsAsRoots,
2661cb0ef41Sopenharmony_ci    Maybe<bool> captureNumericValue) {
2671cb0ef41Sopenharmony_ci  v8::HeapProfiler* profiler = m_isolate->GetHeapProfiler();
2681cb0ef41Sopenharmony_ci  if (!profiler) return Response::ServerError("Cannot access v8 heap profiler");
2691cb0ef41Sopenharmony_ci  std::unique_ptr<HeapSnapshotProgress> progress;
2701cb0ef41Sopenharmony_ci  if (reportProgress.fromMaybe(false))
2711cb0ef41Sopenharmony_ci    progress.reset(new HeapSnapshotProgress(&m_frontend));
2721cb0ef41Sopenharmony_ci
2731cb0ef41Sopenharmony_ci  GlobalObjectNameResolver resolver(m_session);
2741cb0ef41Sopenharmony_ci  const v8::HeapSnapshot* snapshot = profiler->TakeHeapSnapshot(
2751cb0ef41Sopenharmony_ci      progress.get(), &resolver, treatGlobalObjectsAsRoots.fromMaybe(true),
2761cb0ef41Sopenharmony_ci      captureNumericValue.fromMaybe(false));
2771cb0ef41Sopenharmony_ci  if (!snapshot) return Response::ServerError("Failed to take heap snapshot");
2781cb0ef41Sopenharmony_ci  HeapSnapshotOutputStream stream(&m_frontend);
2791cb0ef41Sopenharmony_ci  snapshot->Serialize(&stream);
2801cb0ef41Sopenharmony_ci  const_cast<v8::HeapSnapshot*>(snapshot)->Delete();
2811cb0ef41Sopenharmony_ci  return Response::Success();
2821cb0ef41Sopenharmony_ci}
2831cb0ef41Sopenharmony_ci
2841cb0ef41Sopenharmony_ciResponse V8HeapProfilerAgentImpl::getObjectByHeapObjectId(
2851cb0ef41Sopenharmony_ci    const String16& heapSnapshotObjectId, Maybe<String16> objectGroup,
2861cb0ef41Sopenharmony_ci    std::unique_ptr<protocol::Runtime::RemoteObject>* result) {
2871cb0ef41Sopenharmony_ci  bool ok;
2881cb0ef41Sopenharmony_ci  int id = heapSnapshotObjectId.toInteger(&ok);
2891cb0ef41Sopenharmony_ci  if (!ok) return Response::ServerError("Invalid heap snapshot object id");
2901cb0ef41Sopenharmony_ci
2911cb0ef41Sopenharmony_ci  v8::HandleScope handles(m_isolate);
2921cb0ef41Sopenharmony_ci  v8::Local<v8::Object> heapObject = objectByHeapObjectId(m_isolate, id);
2931cb0ef41Sopenharmony_ci  if (heapObject.IsEmpty())
2941cb0ef41Sopenharmony_ci    return Response::ServerError("Object is not available");
2951cb0ef41Sopenharmony_ci
2961cb0ef41Sopenharmony_ci  if (!m_session->inspector()->client()->isInspectableHeapObject(heapObject))
2971cb0ef41Sopenharmony_ci    return Response::ServerError("Object is not available");
2981cb0ef41Sopenharmony_ci
2991cb0ef41Sopenharmony_ci  v8::Local<v8::Context> creationContext;
3001cb0ef41Sopenharmony_ci  if (!heapObject->GetCreationContext().ToLocal(&creationContext)) {
3011cb0ef41Sopenharmony_ci    return Response::ServerError("Object is not available");
3021cb0ef41Sopenharmony_ci  }
3031cb0ef41Sopenharmony_ci  *result = m_session->wrapObject(creationContext, heapObject,
3041cb0ef41Sopenharmony_ci                                  objectGroup.fromMaybe(""), false);
3051cb0ef41Sopenharmony_ci  if (!*result) return Response::ServerError("Object is not available");
3061cb0ef41Sopenharmony_ci  return Response::Success();
3071cb0ef41Sopenharmony_ci}
3081cb0ef41Sopenharmony_ci
3091cb0ef41Sopenharmony_ciResponse V8HeapProfilerAgentImpl::addInspectedHeapObject(
3101cb0ef41Sopenharmony_ci    const String16& inspectedHeapObjectId) {
3111cb0ef41Sopenharmony_ci  bool ok;
3121cb0ef41Sopenharmony_ci  int id = inspectedHeapObjectId.toInteger(&ok);
3131cb0ef41Sopenharmony_ci  if (!ok) return Response::ServerError("Invalid heap snapshot object id");
3141cb0ef41Sopenharmony_ci
3151cb0ef41Sopenharmony_ci  v8::HandleScope handles(m_isolate);
3161cb0ef41Sopenharmony_ci  v8::Local<v8::Object> heapObject = objectByHeapObjectId(m_isolate, id);
3171cb0ef41Sopenharmony_ci  if (heapObject.IsEmpty())
3181cb0ef41Sopenharmony_ci    return Response::ServerError("Object is not available");
3191cb0ef41Sopenharmony_ci
3201cb0ef41Sopenharmony_ci  if (!m_session->inspector()->client()->isInspectableHeapObject(heapObject))
3211cb0ef41Sopenharmony_ci    return Response::ServerError("Object is not available");
3221cb0ef41Sopenharmony_ci  m_session->addInspectedObject(
3231cb0ef41Sopenharmony_ci      std::unique_ptr<InspectableHeapObject>(new InspectableHeapObject(id)));
3241cb0ef41Sopenharmony_ci  return Response::Success();
3251cb0ef41Sopenharmony_ci}
3261cb0ef41Sopenharmony_ci
3271cb0ef41Sopenharmony_ciResponse V8HeapProfilerAgentImpl::getHeapObjectId(
3281cb0ef41Sopenharmony_ci    const String16& objectId, String16* heapSnapshotObjectId) {
3291cb0ef41Sopenharmony_ci  v8::HandleScope handles(m_isolate);
3301cb0ef41Sopenharmony_ci  v8::Local<v8::Value> value;
3311cb0ef41Sopenharmony_ci  v8::Local<v8::Context> context;
3321cb0ef41Sopenharmony_ci  Response response =
3331cb0ef41Sopenharmony_ci      m_session->unwrapObject(objectId, &value, &context, nullptr);
3341cb0ef41Sopenharmony_ci  if (!response.IsSuccess()) return response;
3351cb0ef41Sopenharmony_ci  if (value->IsUndefined()) return Response::InternalError();
3361cb0ef41Sopenharmony_ci
3371cb0ef41Sopenharmony_ci  v8::SnapshotObjectId id = m_isolate->GetHeapProfiler()->GetObjectId(value);
3381cb0ef41Sopenharmony_ci  *heapSnapshotObjectId = String16::fromInteger(static_cast<size_t>(id));
3391cb0ef41Sopenharmony_ci  return Response::Success();
3401cb0ef41Sopenharmony_ci}
3411cb0ef41Sopenharmony_ci
3421cb0ef41Sopenharmony_civoid V8HeapProfilerAgentImpl::requestHeapStatsUpdate() {
3431cb0ef41Sopenharmony_ci  HeapStatsStream stream(&m_frontend);
3441cb0ef41Sopenharmony_ci  v8::SnapshotObjectId lastSeenObjectId =
3451cb0ef41Sopenharmony_ci      m_isolate->GetHeapProfiler()->GetHeapStats(&stream);
3461cb0ef41Sopenharmony_ci  m_frontend.lastSeenObjectId(
3471cb0ef41Sopenharmony_ci      lastSeenObjectId, m_session->inspector()->client()->currentTimeMS());
3481cb0ef41Sopenharmony_ci}
3491cb0ef41Sopenharmony_ci
3501cb0ef41Sopenharmony_ci// static
3511cb0ef41Sopenharmony_civoid V8HeapProfilerAgentImpl::onTimer(void* data) {
3521cb0ef41Sopenharmony_ci  reinterpret_cast<V8HeapProfilerAgentImpl*>(data)->requestHeapStatsUpdate();
3531cb0ef41Sopenharmony_ci}
3541cb0ef41Sopenharmony_ci
3551cb0ef41Sopenharmony_civoid V8HeapProfilerAgentImpl::startTrackingHeapObjectsInternal(
3561cb0ef41Sopenharmony_ci    bool trackAllocations) {
3571cb0ef41Sopenharmony_ci  m_isolate->GetHeapProfiler()->StartTrackingHeapObjects(trackAllocations);
3581cb0ef41Sopenharmony_ci  if (!m_hasTimer) {
3591cb0ef41Sopenharmony_ci    m_hasTimer = true;
3601cb0ef41Sopenharmony_ci    m_session->inspector()->client()->startRepeatingTimer(
3611cb0ef41Sopenharmony_ci        0.05, &V8HeapProfilerAgentImpl::onTimer, reinterpret_cast<void*>(this));
3621cb0ef41Sopenharmony_ci  }
3631cb0ef41Sopenharmony_ci}
3641cb0ef41Sopenharmony_ci
3651cb0ef41Sopenharmony_civoid V8HeapProfilerAgentImpl::stopTrackingHeapObjectsInternal() {
3661cb0ef41Sopenharmony_ci  if (m_hasTimer) {
3671cb0ef41Sopenharmony_ci    m_session->inspector()->client()->cancelTimer(
3681cb0ef41Sopenharmony_ci        reinterpret_cast<void*>(this));
3691cb0ef41Sopenharmony_ci    m_hasTimer = false;
3701cb0ef41Sopenharmony_ci  }
3711cb0ef41Sopenharmony_ci  m_isolate->GetHeapProfiler()->StopTrackingHeapObjects();
3721cb0ef41Sopenharmony_ci  m_state->setBoolean(HeapProfilerAgentState::heapObjectsTrackingEnabled,
3731cb0ef41Sopenharmony_ci                      false);
3741cb0ef41Sopenharmony_ci  m_state->setBoolean(HeapProfilerAgentState::allocationTrackingEnabled, false);
3751cb0ef41Sopenharmony_ci}
3761cb0ef41Sopenharmony_ci
3771cb0ef41Sopenharmony_ciResponse V8HeapProfilerAgentImpl::startSampling(
3781cb0ef41Sopenharmony_ci    Maybe<double> samplingInterval) {
3791cb0ef41Sopenharmony_ci  v8::HeapProfiler* profiler = m_isolate->GetHeapProfiler();
3801cb0ef41Sopenharmony_ci  if (!profiler) return Response::ServerError("Cannot access v8 heap profiler");
3811cb0ef41Sopenharmony_ci  const unsigned defaultSamplingInterval = 1 << 15;
3821cb0ef41Sopenharmony_ci  double samplingIntervalValue =
3831cb0ef41Sopenharmony_ci      samplingInterval.fromMaybe(defaultSamplingInterval);
3841cb0ef41Sopenharmony_ci  if (samplingIntervalValue <= 0.0) {
3851cb0ef41Sopenharmony_ci    return Response::ServerError("Invalid sampling interval");
3861cb0ef41Sopenharmony_ci  }
3871cb0ef41Sopenharmony_ci  m_state->setDouble(HeapProfilerAgentState::samplingHeapProfilerInterval,
3881cb0ef41Sopenharmony_ci                     samplingIntervalValue);
3891cb0ef41Sopenharmony_ci  m_state->setBoolean(HeapProfilerAgentState::samplingHeapProfilerEnabled,
3901cb0ef41Sopenharmony_ci                      true);
3911cb0ef41Sopenharmony_ci  profiler->StartSamplingHeapProfiler(
3921cb0ef41Sopenharmony_ci      static_cast<uint64_t>(samplingIntervalValue), 128,
3931cb0ef41Sopenharmony_ci      v8::HeapProfiler::kSamplingForceGC);
3941cb0ef41Sopenharmony_ci  return Response::Success();
3951cb0ef41Sopenharmony_ci}
3961cb0ef41Sopenharmony_ci
3971cb0ef41Sopenharmony_cinamespace {
3981cb0ef41Sopenharmony_cistd::unique_ptr<protocol::HeapProfiler::SamplingHeapProfileNode>
3991cb0ef41Sopenharmony_cibuildSampingHeapProfileNode(v8::Isolate* isolate,
4001cb0ef41Sopenharmony_ci                            const v8::AllocationProfile::Node* node) {
4011cb0ef41Sopenharmony_ci  auto children = std::make_unique<
4021cb0ef41Sopenharmony_ci      protocol::Array<protocol::HeapProfiler::SamplingHeapProfileNode>>();
4031cb0ef41Sopenharmony_ci  for (const auto* child : node->children)
4041cb0ef41Sopenharmony_ci    children->emplace_back(buildSampingHeapProfileNode(isolate, child));
4051cb0ef41Sopenharmony_ci  size_t selfSize = 0;
4061cb0ef41Sopenharmony_ci  for (const auto& allocation : node->allocations)
4071cb0ef41Sopenharmony_ci    selfSize += allocation.size * allocation.count;
4081cb0ef41Sopenharmony_ci  std::unique_ptr<protocol::Runtime::CallFrame> callFrame =
4091cb0ef41Sopenharmony_ci      protocol::Runtime::CallFrame::create()
4101cb0ef41Sopenharmony_ci          .setFunctionName(toProtocolString(isolate, node->name))
4111cb0ef41Sopenharmony_ci          .setScriptId(String16::fromInteger(node->script_id))
4121cb0ef41Sopenharmony_ci          .setUrl(toProtocolString(isolate, node->script_name))
4131cb0ef41Sopenharmony_ci          .setLineNumber(node->line_number - 1)
4141cb0ef41Sopenharmony_ci          .setColumnNumber(node->column_number - 1)
4151cb0ef41Sopenharmony_ci          .build();
4161cb0ef41Sopenharmony_ci  std::unique_ptr<protocol::HeapProfiler::SamplingHeapProfileNode> result =
4171cb0ef41Sopenharmony_ci      protocol::HeapProfiler::SamplingHeapProfileNode::create()
4181cb0ef41Sopenharmony_ci          .setCallFrame(std::move(callFrame))
4191cb0ef41Sopenharmony_ci          .setSelfSize(selfSize)
4201cb0ef41Sopenharmony_ci          .setChildren(std::move(children))
4211cb0ef41Sopenharmony_ci          .setId(node->node_id)
4221cb0ef41Sopenharmony_ci          .build();
4231cb0ef41Sopenharmony_ci  return result;
4241cb0ef41Sopenharmony_ci}
4251cb0ef41Sopenharmony_ci}  // namespace
4261cb0ef41Sopenharmony_ci
4271cb0ef41Sopenharmony_ciResponse V8HeapProfilerAgentImpl::stopSampling(
4281cb0ef41Sopenharmony_ci    std::unique_ptr<protocol::HeapProfiler::SamplingHeapProfile>* profile) {
4291cb0ef41Sopenharmony_ci  Response result = getSamplingProfile(profile);
4301cb0ef41Sopenharmony_ci  if (result.IsSuccess()) {
4311cb0ef41Sopenharmony_ci    m_isolate->GetHeapProfiler()->StopSamplingHeapProfiler();
4321cb0ef41Sopenharmony_ci    m_state->setBoolean(HeapProfilerAgentState::samplingHeapProfilerEnabled,
4331cb0ef41Sopenharmony_ci                        false);
4341cb0ef41Sopenharmony_ci  }
4351cb0ef41Sopenharmony_ci  return result;
4361cb0ef41Sopenharmony_ci}
4371cb0ef41Sopenharmony_ci
4381cb0ef41Sopenharmony_ciResponse V8HeapProfilerAgentImpl::getSamplingProfile(
4391cb0ef41Sopenharmony_ci    std::unique_ptr<protocol::HeapProfiler::SamplingHeapProfile>* profile) {
4401cb0ef41Sopenharmony_ci  v8::HeapProfiler* profiler = m_isolate->GetHeapProfiler();
4411cb0ef41Sopenharmony_ci  // Need a scope as v8::AllocationProfile contains Local handles.
4421cb0ef41Sopenharmony_ci  v8::HandleScope scope(m_isolate);
4431cb0ef41Sopenharmony_ci  std::unique_ptr<v8::AllocationProfile> v8Profile(
4441cb0ef41Sopenharmony_ci      profiler->GetAllocationProfile());
4451cb0ef41Sopenharmony_ci  if (!v8Profile)
4461cb0ef41Sopenharmony_ci    return Response::ServerError("V8 sampling heap profiler was not started.");
4471cb0ef41Sopenharmony_ci  v8::AllocationProfile::Node* root = v8Profile->GetRootNode();
4481cb0ef41Sopenharmony_ci  auto samples = std::make_unique<
4491cb0ef41Sopenharmony_ci      protocol::Array<protocol::HeapProfiler::SamplingHeapProfileSample>>();
4501cb0ef41Sopenharmony_ci  for (const auto& sample : v8Profile->GetSamples()) {
4511cb0ef41Sopenharmony_ci    samples->emplace_back(
4521cb0ef41Sopenharmony_ci        protocol::HeapProfiler::SamplingHeapProfileSample::create()
4531cb0ef41Sopenharmony_ci            .setSize(sample.size * sample.count)
4541cb0ef41Sopenharmony_ci            .setNodeId(sample.node_id)
4551cb0ef41Sopenharmony_ci            .setOrdinal(static_cast<double>(sample.sample_id))
4561cb0ef41Sopenharmony_ci            .build());
4571cb0ef41Sopenharmony_ci  }
4581cb0ef41Sopenharmony_ci  *profile = protocol::HeapProfiler::SamplingHeapProfile::create()
4591cb0ef41Sopenharmony_ci                 .setHead(buildSampingHeapProfileNode(m_isolate, root))
4601cb0ef41Sopenharmony_ci                 .setSamples(std::move(samples))
4611cb0ef41Sopenharmony_ci                 .build();
4621cb0ef41Sopenharmony_ci  return Response::Success();
4631cb0ef41Sopenharmony_ci}
4641cb0ef41Sopenharmony_ci
4651cb0ef41Sopenharmony_ci}  // namespace v8_inspector
466