Index: src/inspector/V8HeapProfilerAgentImpl.cpp |
diff --git a/src/inspector/V8HeapProfilerAgentImpl.cpp b/src/inspector/V8HeapProfilerAgentImpl.cpp |
deleted file mode 100644 |
index d55e1a37ea91d70ccd000d386b9b645064a2bcdc..0000000000000000000000000000000000000000 |
--- a/src/inspector/V8HeapProfilerAgentImpl.cpp |
+++ /dev/null |
@@ -1,402 +0,0 @@ |
-// Copyright 2016 the V8 project authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "src/inspector/V8HeapProfilerAgentImpl.h" |
- |
-#include "src/inspector/InjectedScript.h" |
-#include "src/inspector/StringUtil.h" |
-#include "src/inspector/V8Debugger.h" |
-#include "src/inspector/V8InspectorImpl.h" |
-#include "src/inspector/V8InspectorSessionImpl.h" |
-#include "src/inspector/protocol/Protocol.h" |
-#include "src/inspector/public/V8InspectorClient.h" |
- |
-#include <v8-profiler.h> |
-#include <v8-version.h> |
- |
-namespace v8_inspector { |
- |
-namespace { |
- |
-namespace HeapProfilerAgentState { |
-static const char heapProfilerEnabled[] = "heapProfilerEnabled"; |
-static const char heapObjectsTrackingEnabled[] = "heapObjectsTrackingEnabled"; |
-static const char allocationTrackingEnabled[] = "allocationTrackingEnabled"; |
-#if V8_MAJOR_VERSION >= 5 |
-static const char samplingHeapProfilerEnabled[] = "samplingHeapProfilerEnabled"; |
-static const char samplingHeapProfilerInterval[] = "samplingHeapProfilerInterval"; |
-#endif |
-} |
- |
-class HeapSnapshotProgress final : public v8::ActivityControl { |
-public: |
- HeapSnapshotProgress(protocol::HeapProfiler::Frontend* frontend) |
- : m_frontend(frontend) { } |
- ControlOption ReportProgressValue(int done, int total) override |
- { |
- m_frontend->reportHeapSnapshotProgress(done, total, protocol::Maybe<bool>()); |
- if (done >= total) { |
- m_frontend->reportHeapSnapshotProgress(total, total, true); |
- } |
- m_frontend->flush(); |
- return kContinue; |
- } |
-private: |
- protocol::HeapProfiler::Frontend* m_frontend; |
-}; |
- |
-class GlobalObjectNameResolver final : public v8::HeapProfiler::ObjectNameResolver { |
-public: |
- explicit GlobalObjectNameResolver(V8InspectorSessionImpl* session) |
- : m_offset(0), m_strings(10000), m_session(session) {} |
- |
- const char* GetName(v8::Local<v8::Object> object) override |
- { |
- InspectedContext* context = m_session->inspector()->getContext(m_session->contextGroupId(), V8Debugger::contextId(object->CreationContext())); |
- if (!context) |
- return ""; |
- String16 name = context->origin(); |
- size_t length = name.length(); |
- if (m_offset + length + 1 >= m_strings.size()) |
- return ""; |
- for (size_t i = 0; i < length; ++i) { |
- UChar ch = name[i]; |
- m_strings[m_offset + i] = ch > 0xff ? '?' : static_cast<char>(ch); |
- } |
- m_strings[m_offset + length] = '\0'; |
- char* result = &*m_strings.begin() + m_offset; |
- m_offset += length + 1; |
- return result; |
- } |
- |
-private: |
- size_t m_offset; |
- std::vector<char> m_strings; |
- V8InspectorSessionImpl* m_session; |
-}; |
- |
-class HeapSnapshotOutputStream final : public v8::OutputStream { |
-public: |
- HeapSnapshotOutputStream(protocol::HeapProfiler::Frontend* frontend) |
- : m_frontend(frontend) { } |
- void EndOfStream() override { } |
- int GetChunkSize() override { return 102400; } |
- WriteResult WriteAsciiChunk(char* data, int size) override |
- { |
- m_frontend->addHeapSnapshotChunk(String16(data, size)); |
- m_frontend->flush(); |
- return kContinue; |
- } |
-private: |
- protocol::HeapProfiler::Frontend* m_frontend; |
-}; |
- |
-v8::Local<v8::Object> objectByHeapObjectId(v8::Isolate* isolate, int id) |
-{ |
- v8::HeapProfiler* profiler = isolate->GetHeapProfiler(); |
- v8::Local<v8::Value> value = profiler->FindObjectById(id); |
- if (value.IsEmpty() || !value->IsObject()) |
- return v8::Local<v8::Object>(); |
- return value.As<v8::Object>(); |
-} |
- |
-class InspectableHeapObject final : public V8InspectorSession::Inspectable { |
-public: |
- explicit InspectableHeapObject(int heapObjectId) : m_heapObjectId(heapObjectId) { } |
- v8::Local<v8::Value> get(v8::Local<v8::Context> context) override |
- { |
- return objectByHeapObjectId(context->GetIsolate(), m_heapObjectId); |
- } |
-private: |
- int m_heapObjectId; |
-}; |
- |
-class HeapStatsStream final : public v8::OutputStream { |
-public: |
- HeapStatsStream(protocol::HeapProfiler::Frontend* frontend) |
- : m_frontend(frontend) |
- { |
- } |
- |
- void EndOfStream() override { } |
- |
- WriteResult WriteAsciiChunk(char* data, int size) override |
- { |
- DCHECK(false); |
- return kAbort; |
- } |
- |
- WriteResult WriteHeapStatsChunk(v8::HeapStatsUpdate* updateData, int count) override |
- { |
- DCHECK_GT(count, 0); |
- std::unique_ptr<protocol::Array<int>> statsDiff = protocol::Array<int>::create(); |
- for (int i = 0; i < count; ++i) { |
- statsDiff->addItem(updateData[i].index); |
- statsDiff->addItem(updateData[i].count); |
- statsDiff->addItem(updateData[i].size); |
- } |
- m_frontend->heapStatsUpdate(std::move(statsDiff)); |
- return kContinue; |
- } |
- |
-private: |
- protocol::HeapProfiler::Frontend* m_frontend; |
-}; |
- |
-} // namespace |
- |
-V8HeapProfilerAgentImpl::V8HeapProfilerAgentImpl(V8InspectorSessionImpl* session, protocol::FrontendChannel* frontendChannel, protocol::DictionaryValue* state) |
- : m_session(session) |
- , m_isolate(session->inspector()->isolate()) |
- , m_frontend(frontendChannel) |
- , m_state(state) |
- , m_hasTimer(false) |
-{ |
-} |
- |
-V8HeapProfilerAgentImpl::~V8HeapProfilerAgentImpl() |
-{ |
-} |
- |
-void V8HeapProfilerAgentImpl::restore() |
-{ |
- if (m_state->booleanProperty(HeapProfilerAgentState::heapProfilerEnabled, false)) |
- m_frontend.resetProfiles(); |
- if (m_state->booleanProperty(HeapProfilerAgentState::heapObjectsTrackingEnabled, false)) |
- startTrackingHeapObjectsInternal(m_state->booleanProperty(HeapProfilerAgentState::allocationTrackingEnabled, false)); |
-#if V8_MAJOR_VERSION >= 5 |
- if (m_state->booleanProperty(HeapProfilerAgentState::samplingHeapProfilerEnabled, false)) { |
- ErrorString error; |
- double samplingInterval = m_state->doubleProperty(HeapProfilerAgentState::samplingHeapProfilerInterval, -1); |
- DCHECK_GE(samplingInterval, 0); |
- startSampling(&error, Maybe<double>(samplingInterval)); |
- } |
-#endif |
-} |
- |
-void V8HeapProfilerAgentImpl::collectGarbage(ErrorString*) |
-{ |
- m_isolate->LowMemoryNotification(); |
-} |
- |
-void V8HeapProfilerAgentImpl::startTrackingHeapObjects(ErrorString*, const protocol::Maybe<bool>& trackAllocations) |
-{ |
- m_state->setBoolean(HeapProfilerAgentState::heapObjectsTrackingEnabled, true); |
- bool allocationTrackingEnabled = trackAllocations.fromMaybe(false); |
- m_state->setBoolean(HeapProfilerAgentState::allocationTrackingEnabled, allocationTrackingEnabled); |
- startTrackingHeapObjectsInternal(allocationTrackingEnabled); |
-} |
- |
-void V8HeapProfilerAgentImpl::stopTrackingHeapObjects(ErrorString* error, const protocol::Maybe<bool>& reportProgress) |
-{ |
- requestHeapStatsUpdate(); |
- takeHeapSnapshot(error, reportProgress); |
- stopTrackingHeapObjectsInternal(); |
-} |
- |
-void V8HeapProfilerAgentImpl::enable(ErrorString*) |
-{ |
- m_state->setBoolean(HeapProfilerAgentState::heapProfilerEnabled, true); |
-} |
- |
-void V8HeapProfilerAgentImpl::disable(ErrorString* error) |
-{ |
- stopTrackingHeapObjectsInternal(); |
-#if V8_MAJOR_VERSION >= 5 |
- if (m_state->booleanProperty(HeapProfilerAgentState::samplingHeapProfilerEnabled, false)) { |
- v8::HeapProfiler* profiler = m_isolate->GetHeapProfiler(); |
- if (profiler) |
- profiler->StopSamplingHeapProfiler(); |
- } |
-#endif |
- m_isolate->GetHeapProfiler()->ClearObjectIds(); |
- m_state->setBoolean(HeapProfilerAgentState::heapProfilerEnabled, false); |
-} |
- |
-void V8HeapProfilerAgentImpl::takeHeapSnapshot(ErrorString* errorString, const protocol::Maybe<bool>& reportProgress) |
-{ |
- v8::HeapProfiler* profiler = m_isolate->GetHeapProfiler(); |
- if (!profiler) { |
- *errorString = "Cannot access v8 heap profiler"; |
- return; |
- } |
- std::unique_ptr<HeapSnapshotProgress> progress; |
- if (reportProgress.fromMaybe(false)) |
- progress = wrapUnique(new HeapSnapshotProgress(&m_frontend)); |
- |
- GlobalObjectNameResolver resolver(m_session); |
- const v8::HeapSnapshot* snapshot = profiler->TakeHeapSnapshot(progress.get(), &resolver); |
- if (!snapshot) { |
- *errorString = "Failed to take heap snapshot"; |
- return; |
- } |
- HeapSnapshotOutputStream stream(&m_frontend); |
- snapshot->Serialize(&stream); |
- const_cast<v8::HeapSnapshot*>(snapshot)->Delete(); |
-} |
- |
-void V8HeapProfilerAgentImpl::getObjectByHeapObjectId(ErrorString* error, const String16& heapSnapshotObjectId, const protocol::Maybe<String16>& objectGroup, std::unique_ptr<protocol::Runtime::RemoteObject>* result) |
-{ |
- bool ok; |
- int id = heapSnapshotObjectId.toInteger(&ok); |
- if (!ok) { |
- *error = "Invalid heap snapshot object id"; |
- return; |
- } |
- |
- v8::HandleScope handles(m_isolate); |
- v8::Local<v8::Object> heapObject = objectByHeapObjectId(m_isolate, id); |
- if (heapObject.IsEmpty()) { |
- *error = "Object is not available"; |
- return; |
- } |
- |
- if (!m_session->inspector()->client()->isInspectableHeapObject(heapObject)) { |
- *error = "Object is not available"; |
- return; |
- } |
- |
- *result = m_session->wrapObject(heapObject->CreationContext(), heapObject, objectGroup.fromMaybe(""), false); |
- if (!result) |
- *error = "Object is not available"; |
-} |
- |
-void V8HeapProfilerAgentImpl::addInspectedHeapObject(ErrorString* errorString, const String16& inspectedHeapObjectId) |
-{ |
- bool ok; |
- int id = inspectedHeapObjectId.toInteger(&ok); |
- if (!ok) { |
- *errorString = "Invalid heap snapshot object id"; |
- return; |
- } |
- |
- v8::HandleScope handles(m_isolate); |
- v8::Local<v8::Object> heapObject = objectByHeapObjectId(m_isolate, id); |
- if (heapObject.IsEmpty()) { |
- *errorString = "Object is not available"; |
- return; |
- } |
- |
- if (!m_session->inspector()->client()->isInspectableHeapObject(heapObject)) { |
- *errorString = "Object is not available"; |
- return; |
- } |
- |
- m_session->addInspectedObject(wrapUnique(new InspectableHeapObject(id))); |
-} |
- |
-void V8HeapProfilerAgentImpl::getHeapObjectId(ErrorString* errorString, const String16& objectId, String16* heapSnapshotObjectId) |
-{ |
- v8::HandleScope handles(m_isolate); |
- v8::Local<v8::Value> value; |
- v8::Local<v8::Context> context; |
- if (!m_session->unwrapObject(errorString, objectId, &value, &context, nullptr) || value->IsUndefined()) |
- return; |
- |
- v8::SnapshotObjectId id = m_isolate->GetHeapProfiler()->GetObjectId(value); |
- *heapSnapshotObjectId = String16::fromInteger(id); |
-} |
- |
-void V8HeapProfilerAgentImpl::requestHeapStatsUpdate() |
-{ |
- HeapStatsStream stream(&m_frontend); |
- v8::SnapshotObjectId lastSeenObjectId = m_isolate->GetHeapProfiler()->GetHeapStats(&stream); |
- m_frontend.lastSeenObjectId(lastSeenObjectId, m_session->inspector()->client()->currentTimeMS()); |
-} |
- |
-// static |
-void V8HeapProfilerAgentImpl::onTimer(void* data) |
-{ |
- reinterpret_cast<V8HeapProfilerAgentImpl*>(data)->requestHeapStatsUpdate(); |
-} |
- |
-void V8HeapProfilerAgentImpl::startTrackingHeapObjectsInternal(bool trackAllocations) |
-{ |
- m_isolate->GetHeapProfiler()->StartTrackingHeapObjects(trackAllocations); |
- if (!m_hasTimer) { |
- m_hasTimer = true; |
- m_session->inspector()->client()->startRepeatingTimer(0.05, &V8HeapProfilerAgentImpl::onTimer, reinterpret_cast<void*>(this)); |
- } |
-} |
- |
-void V8HeapProfilerAgentImpl::stopTrackingHeapObjectsInternal() |
-{ |
- if (m_hasTimer) { |
- m_session->inspector()->client()->cancelTimer(reinterpret_cast<void*>(this)); |
- m_hasTimer = false; |
- } |
- m_isolate->GetHeapProfiler()->StopTrackingHeapObjects(); |
- m_state->setBoolean(HeapProfilerAgentState::heapObjectsTrackingEnabled, false); |
- m_state->setBoolean(HeapProfilerAgentState::allocationTrackingEnabled, false); |
-} |
- |
-void V8HeapProfilerAgentImpl::startSampling(ErrorString* errorString, const Maybe<double>& samplingInterval) |
-{ |
-#if V8_MAJOR_VERSION >= 5 |
- v8::HeapProfiler* profiler = m_isolate->GetHeapProfiler(); |
- if (!profiler) { |
- *errorString = "Cannot access v8 heap profiler"; |
- return; |
- } |
- const unsigned defaultSamplingInterval = 1 << 15; |
- double samplingIntervalValue = samplingInterval.fromMaybe(defaultSamplingInterval); |
- m_state->setDouble(HeapProfilerAgentState::samplingHeapProfilerInterval, samplingIntervalValue); |
- m_state->setBoolean(HeapProfilerAgentState::samplingHeapProfilerEnabled, true); |
-#if V8_MAJOR_VERSION * 1000 + V8_MINOR_VERSION >= 5002 |
- profiler->StartSamplingHeapProfiler(static_cast<uint64_t>(samplingIntervalValue), 128, v8::HeapProfiler::kSamplingForceGC); |
-#else |
- profiler->StartSamplingHeapProfiler(static_cast<uint64_t>(samplingIntervalValue), 128); |
-#endif |
-#endif |
-} |
- |
-#if V8_MAJOR_VERSION >= 5 |
-namespace { |
-std::unique_ptr<protocol::HeapProfiler::SamplingHeapProfileNode> buildSampingHeapProfileNode(const v8::AllocationProfile::Node* node) |
-{ |
- auto children = protocol::Array<protocol::HeapProfiler::SamplingHeapProfileNode>::create(); |
- for (const auto* child : node->children) |
- children->addItem(buildSampingHeapProfileNode(child)); |
- size_t selfSize = 0; |
- for (const auto& allocation : node->allocations) |
- selfSize += allocation.size * allocation.count; |
- std::unique_ptr<protocol::Runtime::CallFrame> callFrame = protocol::Runtime::CallFrame::create() |
- .setFunctionName(toProtocolString(node->name)) |
- .setScriptId(String16::fromInteger(node->script_id)) |
- .setUrl(toProtocolString(node->script_name)) |
- .setLineNumber(node->line_number - 1) |
- .setColumnNumber(node->column_number - 1) |
- .build(); |
- std::unique_ptr<protocol::HeapProfiler::SamplingHeapProfileNode> result = protocol::HeapProfiler::SamplingHeapProfileNode::create() |
- .setCallFrame(std::move(callFrame)) |
- .setSelfSize(selfSize) |
- .setChildren(std::move(children)).build(); |
- return result; |
-} |
-} // namespace |
-#endif |
- |
-void V8HeapProfilerAgentImpl::stopSampling(ErrorString* errorString, std::unique_ptr<protocol::HeapProfiler::SamplingHeapProfile>* profile) |
-{ |
-#if V8_MAJOR_VERSION >= 5 |
- v8::HeapProfiler* profiler = m_isolate->GetHeapProfiler(); |
- if (!profiler) { |
- *errorString = "Cannot access v8 heap profiler"; |
- return; |
- } |
- v8::HandleScope scope(m_isolate); // Allocation profile contains Local handles. |
- std::unique_ptr<v8::AllocationProfile> v8Profile(profiler->GetAllocationProfile()); |
- profiler->StopSamplingHeapProfiler(); |
- m_state->setBoolean(HeapProfilerAgentState::samplingHeapProfilerEnabled, false); |
- if (!v8Profile) { |
- *errorString = "Cannot access v8 sampled heap profile."; |
- return; |
- } |
- v8::AllocationProfile::Node* root = v8Profile->GetRootNode(); |
- *profile = protocol::HeapProfiler::SamplingHeapProfile::create() |
- .setHead(buildSampingHeapProfileNode(root)).build(); |
-#endif |
-} |
- |
-} // namespace v8_inspector |