Commit 4a90e486 authored by Ulan Degenbaev's avatar Ulan Degenbaev Committed by Commit Bot

[heap-profiler] Annotate global handles retained by console and debugger.

Bug: chromium:811842
Cq-Include-Trybots: master.tryserver.blink:linux_trusty_blink_rel
Change-Id: I72163abf0b20b123fb541fe0a1b168e036ef044e
Reviewed-on: https://chromium-review.googlesource.com/919063
Commit-Queue: Ulan Degenbaev <ulan@chromium.org>
Reviewed-by: 's avatarAlexei Filippov <alph@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51360}
parent e77e4e2f
...@@ -49,6 +49,7 @@ namespace v8_inspector { ...@@ -49,6 +49,7 @@ namespace v8_inspector {
namespace { namespace {
static const char privateKeyName[] = "v8-inspector#injectedScript"; static const char privateKeyName[] = "v8-inspector#injectedScript";
static const char kGlobalHandleLabel[] = "DevTools console";
} // namespace } // namespace
using protocol::Array; using protocol::Array;
...@@ -511,6 +512,7 @@ v8::Local<v8::Value> InjectedScript::lastEvaluationResult() const { ...@@ -511,6 +512,7 @@ v8::Local<v8::Value> InjectedScript::lastEvaluationResult() const {
void InjectedScript::setLastEvaluationResult(v8::Local<v8::Value> result) { void InjectedScript::setLastEvaluationResult(v8::Local<v8::Value> result) {
m_lastEvaluationResult.Reset(m_context->isolate(), result); m_lastEvaluationResult.Reset(m_context->isolate(), result);
m_lastEvaluationResult.AnnotateStrongRetainer(kGlobalHandleLabel);
} }
Response InjectedScript::resolveCallArgument( Response InjectedScript::resolveCallArgument(
...@@ -601,8 +603,10 @@ Response InjectedScript::wrapEvaluateResult( ...@@ -601,8 +603,10 @@ Response InjectedScript::wrapEvaluateResult(
Response response = wrapObject(resultValue, objectGroup, returnByValue, Response response = wrapObject(resultValue, objectGroup, returnByValue,
generatePreview, result); generatePreview, result);
if (!response.isSuccess()) return response; if (!response.isSuccess()) return response;
if (objectGroup == "console") if (objectGroup == "console") {
m_lastEvaluationResult.Reset(m_context->isolate(), resultValue); m_lastEvaluationResult.Reset(m_context->isolate(), resultValue);
m_lastEvaluationResult.AnnotateStrongRetainer(kGlobalHandleLabel);
}
} else { } else {
v8::Local<v8::Value> exception = tryCatch.Exception(); v8::Local<v8::Value> exception = tryCatch.Exception();
Response response = Response response =
...@@ -624,6 +628,7 @@ v8::Local<v8::Object> InjectedScript::commandLineAPI() { ...@@ -624,6 +628,7 @@ v8::Local<v8::Object> InjectedScript::commandLineAPI() {
m_context->isolate(), m_context->isolate(),
m_context->inspector()->console()->createCommandLineAPI( m_context->inspector()->console()->createCommandLineAPI(
m_context->context(), m_sessionId)); m_context->context(), m_sessionId));
m_commandLineAPI.AnnotateStrongRetainer(kGlobalHandleLabel);
} }
return m_commandLineAPI.Get(m_context->isolate()); return m_commandLineAPI.Get(m_context->isolate());
} }
...@@ -769,6 +774,7 @@ int InjectedScript::bindObject(v8::Local<v8::Value> value, ...@@ -769,6 +774,7 @@ int InjectedScript::bindObject(v8::Local<v8::Value> value,
if (m_lastBoundObjectId <= 0) m_lastBoundObjectId = 1; if (m_lastBoundObjectId <= 0) m_lastBoundObjectId = 1;
int id = m_lastBoundObjectId++; int id = m_lastBoundObjectId++;
m_idToWrappedObject[id].Reset(m_context->isolate(), value); m_idToWrappedObject[id].Reset(m_context->isolate(), value);
m_idToWrappedObject[id].AnnotateStrongRetainer(kGlobalHandleLabel);
if (!groupName.isEmpty() && id > 0) { if (!groupName.isEmpty() && id > 0) {
m_idToObjectGroupName[id] = groupName; m_idToObjectGroupName[id] = groupName;
......
...@@ -58,6 +58,7 @@ String16 consoleAPITypeValue(ConsoleAPIType type) { ...@@ -58,6 +58,7 @@ String16 consoleAPITypeValue(ConsoleAPIType type) {
return protocol::Runtime::ConsoleAPICalled::TypeEnum::Log; return protocol::Runtime::ConsoleAPICalled::TypeEnum::Log;
} }
const char kGlobalHandleLabel[] = "DevTools console";
const unsigned maxConsoleMessageCount = 1000; const unsigned maxConsoleMessageCount = 1000;
const int maxConsoleMessageV8Size = 10 * 1024 * 1024; const int maxConsoleMessageV8Size = 10 * 1024 * 1024;
const unsigned maxArrayItemsLimit = 10000; const unsigned maxArrayItemsLimit = 10000;
...@@ -379,8 +380,10 @@ std::unique_ptr<V8ConsoleMessage> V8ConsoleMessage::createForConsoleAPI( ...@@ -379,8 +380,10 @@ std::unique_ptr<V8ConsoleMessage> V8ConsoleMessage::createForConsoleAPI(
message->m_type = type; message->m_type = type;
message->m_contextId = contextId; message->m_contextId = contextId;
for (size_t i = 0; i < arguments.size(); ++i) { for (size_t i = 0; i < arguments.size(); ++i) {
message->m_arguments.push_back(std::unique_ptr<v8::Global<v8::Value>>( std::unique_ptr<v8::Global<v8::Value>> argument(
new v8::Global<v8::Value>(isolate, arguments.at(i)))); new v8::Global<v8::Value>(isolate, arguments.at(i)));
argument->AnnotateStrongRetainer(kGlobalHandleLabel);
message->m_arguments.push_back(std::move(argument));
message->m_v8Size += message->m_v8Size +=
v8::debug::EstimatedValueSize(isolate, arguments.at(i)); v8::debug::EstimatedValueSize(isolate, arguments.at(i));
} }
......
...@@ -13,6 +13,7 @@ namespace v8_inspector { ...@@ -13,6 +13,7 @@ namespace v8_inspector {
namespace { namespace {
const char hexDigits[17] = "0123456789ABCDEF"; const char hexDigits[17] = "0123456789ABCDEF";
const char kGlobalHandleLabel[] = "DevTools debugger";
void appendUnsignedAsHex(uint64_t number, String16Builder* destination) { void appendUnsignedAsHex(uint64_t number, String16Builder* destination) {
for (size_t i = 0; i < 8; ++i) { for (size_t i = 0; i < 8; ++i) {
...@@ -147,6 +148,7 @@ class ActualScript : public V8DebuggerScript { ...@@ -147,6 +148,7 @@ class ActualScript : public V8DebuggerScript {
m_isModule = script->IsModule(); m_isModule = script->IsModule();
m_script.Reset(m_isolate, script); m_script.Reset(m_isolate, script);
m_script.AnnotateStrongRetainer(kGlobalHandleLabel);
} }
bool isLiveEdit() const override { return m_isLiveEdit; } bool isLiveEdit() const override { return m_isLiveEdit; }
...@@ -264,6 +266,7 @@ class WasmVirtualScript : public V8DebuggerScript { ...@@ -264,6 +266,7 @@ class WasmVirtualScript : public V8DebuggerScript {
: V8DebuggerScript(isolate, std::move(id), std::move(url)), : V8DebuggerScript(isolate, std::move(id), std::move(url)),
m_script(isolate, script), m_script(isolate, script),
m_wasmTranslation(wasmTranslation) { m_wasmTranslation(wasmTranslation) {
m_script.AnnotateStrongRetainer(kGlobalHandleLabel);
int num_lines = 0; int num_lines = 0;
int last_newline = -1; int last_newline = -1;
size_t next_newline = source.find('\n', last_newline + 1); size_t next_newline = source.find('\n', last_newline + 1);
......
Tests edge labels of objects retained by DevTools.
Running test: testConsoleRetainingPath
Edge from (Global handles) to MyClass1: DevTools console
Edge from (Global handles) to MyClass2: DevTools console
// Copyright 2018 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.
let {session, contextGroup, Protocol} = InspectorTest.start(
'Tests edge labels of objects retained by DevTools.');
const kNodeName = 1;
const kNodeEdgeCount = 4;
const kNodeSize = 6;
const kEdgeName = 1;
const kEdgeTarget = 2;
const kEdgeSize = 3;
function EdgeName(snapshot, edgeIndex) {
return snapshot['strings'][snapshot['edges'][edgeIndex + kEdgeName]];
}
function EdgeTarget(snapshot, edgeIndex) {
return snapshot['edges'][edgeIndex + kEdgeTarget];
}
function EdgeCount(snapshot, nodeIndex) {
return snapshot['nodes'][nodeIndex + kNodeEdgeCount];
}
function NodeName(snapshot, nodeIndex) {
return snapshot['strings'][snapshot['nodes'][nodeIndex + kNodeName]];
}
function NodeEdges(snapshot, nodeIndex) {
let startEdgeIndex = 0;
for (let i = 0; i < nodeIndex; i += kNodeSize) {
startEdgeIndex += EdgeCount(snapshot, i);
}
let endEdgeIndex = startEdgeIndex + EdgeCount(snapshot, nodeIndex);
let result = [];
for (let i = startEdgeIndex; i < endEdgeIndex; ++i) {
result.push(i * kEdgeSize);
}
return result;
}
function NodeByName(snapshot, name) {
let count = snapshot['nodes'].length / kNodeSize;
for (let i = 0; i < count; i++) {
if (NodeName(snapshot, i * kNodeSize) == name) return i * kNodeSize;
}
InspectorTest.log(`Cannot node ${name}`);
return 0;
}
function FindEdge(snapshot, sourceName, targetName) {
let sourceIndex = NodeByName(snapshot, sourceName);
let targetIndex = NodeByName(snapshot, targetName);
let edges = NodeEdges(snapshot, sourceIndex);
for (let edge of edges) {
if (EdgeTarget(snapshot, edge) == targetIndex) return edge;
}
InspectorTest.log(`Cannot find edge between ${sourceName} and ${targetName}`);
return 0;
}
function GlobalHandleEdgeName(snapshot, targetName) {
let edge = FindEdge(snapshot, '(Global handles)', targetName);
let edgeName = EdgeName(snapshot, edge);
// Make the test more robust by skipping the edge index prefix and
// a single space.
return edgeName.substring(edgeName.indexOf('/') + 2);
}
contextGroup.addScript(`
class MyClass1 {};
class MyClass2 {};
//# sourceURL=test.js`);
Protocol.Debugger.enable();
Protocol.HeapProfiler.enable();
InspectorTest.runAsyncTestSuite([
async function testConsoleRetainingPath() {
let snapshot_string = '';
function onChunk(message) {
snapshot_string += message['params']['chunk'];
}
Protocol.HeapProfiler.onAddHeapSnapshotChunk(onChunk)
await Protocol.Runtime.evaluate({ expression: 'new MyClass1();' });
await Protocol.Runtime.evaluate(
{ expression: 'console.log(new MyClass2());' });
await Protocol.HeapProfiler.takeHeapSnapshot({ reportProgress: false })
let snapshot = JSON.parse(snapshot_string);
let edge1 = GlobalHandleEdgeName(snapshot, 'MyClass1');
let edge2 = GlobalHandleEdgeName(snapshot, 'MyClass2');
InspectorTest.log(`Edge from (Global handles) to MyClass1: ${edge1}`);
InspectorTest.log(`Edge from (Global handles) to MyClass2: ${edge2}`);
}
]);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment