Commit a7577ede authored by yangguo's avatar yangguo Committed by Commit bot

[debug] do not report unnecessary coverage data.

Only include function ranges for with non-0 counts or if the immediate outer function has non-0 count.

R=caseq@chromium.org, jgruber@chromium.org
BUG=v8:5808

Review-Url: https://codereview.chromium.org/2764073004
Cr-Commit-Position: refs/heads/master@{#44079}
parent b123ee34
...@@ -121,7 +121,7 @@ Coverage* Coverage::Collect(Isolate* isolate, ...@@ -121,7 +121,7 @@ Coverage* Coverage::Collect(Isolate* isolate,
// Create and add new script data. // Create and add new script data.
Handle<Script> script_handle(script, isolate); Handle<Script> script_handle(script, isolate);
result->emplace_back(isolate, script_handle); result->emplace_back(script_handle);
std::vector<CoverageFunction>* functions = &result->back().functions; std::vector<CoverageFunction>* functions = &result->back().functions;
std::vector<SharedFunctionInfo*> sorted; std::vector<SharedFunctionInfo*> sorted;
...@@ -135,11 +135,18 @@ Coverage* Coverage::Collect(Isolate* isolate, ...@@ -135,11 +135,18 @@ Coverage* Coverage::Collect(Isolate* isolate,
std::sort(sorted.begin(), sorted.end(), CompareSharedFunctionInfo); std::sort(sorted.begin(), sorted.end(), CompareSharedFunctionInfo);
} }
// Stack to track nested functions, referring function by index.
std::vector<size_t> nesting;
// Use sorted list to reconstruct function nesting. // Use sorted list to reconstruct function nesting.
for (SharedFunctionInfo* info : sorted) { for (SharedFunctionInfo* info : sorted) {
int start = StartPosition(info); int start = StartPosition(info);
int end = info->end_position(); int end = info->end_position();
uint32_t count = counter_map.Get(info); uint32_t count = counter_map.Get(info);
// Find the correct outer function based on start position.
while (!nesting.empty() && functions->at(nesting.back()).end <= start) {
nesting.pop_back();
}
if (count != 0) { if (count != 0) {
switch (collectionMode) { switch (collectionMode) {
case v8::debug::Coverage::kPreciseCount: case v8::debug::Coverage::kPreciseCount:
...@@ -152,10 +159,18 @@ Coverage* Coverage::Collect(Isolate* isolate, ...@@ -152,10 +159,18 @@ Coverage* Coverage::Collect(Isolate* isolate,
count = 1; count = 1;
break; break;
} }
} else if (nesting.empty() || functions->at(nesting.back()).count == 0) {
// Only include a function range if it has a non-0 count, or
// if it is directly nested inside a function with non-0 count.
continue;
} }
Handle<String> name(info->DebugName(), isolate); Handle<String> name(info->DebugName(), isolate);
nesting.push_back(functions->size());
functions->emplace_back(start, end, count, name); functions->emplace_back(start, end, count, name);
} }
// Remove entries for scripts that have no coverage.
if (functions->empty()) result->pop_back();
} }
return result; return result;
} }
......
...@@ -27,7 +27,7 @@ struct CoverageFunction { ...@@ -27,7 +27,7 @@ struct CoverageFunction {
struct CoverageScript { struct CoverageScript {
// Initialize top-level function in case it has been garbage-collected. // Initialize top-level function in case it has been garbage-collected.
CoverageScript(Isolate* isolate, Handle<Script> s) : script(s) {} explicit CoverageScript(Handle<Script> s) : script(s) {}
Handle<Script> script; Handle<Script> script;
// Functions are sorted by start position, from outer to inner function. // Functions are sorted by start position, from outer to inner function.
std::vector<CoverageFunction> functions; std::vector<CoverageFunction> functions;
......
...@@ -34,6 +34,22 @@ function h() { ...@@ -34,6 +34,22 @@ function h() {
f(3); f(3);
`; `;
var nested =
`
var f = (function outer() {
function nested_0() {
return function nested_1() {
return function nested_2() {
return function nested_3() {}
}
}
}
function nested_4() {}
return nested_0();
})();
f()()();
`;
InspectorTest.log("Test collecting code coverage data with Profiler.collectCoverage."); InspectorTest.log("Test collecting code coverage data with Profiler.collectCoverage.");
function ClearAndGC() { function ClearAndGC() {
...@@ -78,8 +94,8 @@ InspectorTest.runTestSuite([ ...@@ -78,8 +94,8 @@ InspectorTest.runTestSuite([
.then(() => Protocol.Profiler.startPreciseCoverage({callCount: true})) .then(() => Protocol.Profiler.startPreciseCoverage({callCount: true}))
.then(() => Protocol.Runtime.compileScript({ expression: source, sourceURL: arguments.callee.name, persistScript: true })) .then(() => Protocol.Runtime.compileScript({ expression: source, sourceURL: arguments.callee.name, persistScript: true }))
.then((result) => Protocol.Runtime.runScript({ scriptId: result.result.scriptId })) .then((result) => Protocol.Runtime.runScript({ scriptId: result.result.scriptId }))
.then(ClearAndGC)
.then(InspectorTest.logMessage) .then(InspectorTest.logMessage)
.then(ClearAndGC)
.then(Protocol.Profiler.takePreciseCoverage) .then(Protocol.Profiler.takePreciseCoverage)
.then(LogSorted) .then(LogSorted)
.then(Protocol.Profiler.takePreciseCoverage) .then(Protocol.Profiler.takePreciseCoverage)
...@@ -208,4 +224,44 @@ InspectorTest.runTestSuite([ ...@@ -208,4 +224,44 @@ InspectorTest.runTestSuite([
.then(ClearAndGC) .then(ClearAndGC)
.then(next); .then(next);
}, },
function testPreciseEmptyScriptCoverageEntries(next)
{
// Enabling the debugger holds onto script objects even though its
// functions can be garbage collected. We would get empty ScriptCoverage
// entires unless we remove them.
Protocol.Debugger.enable()
.then(Protocol.Runtime.enable)
.then(() => Protocol.Runtime.compileScript({ expression: source, sourceURL: arguments.callee.name, persistScript: true }))
.then((result) => Protocol.Runtime.runScript({ scriptId: result.result.scriptId }))
.then(ClearAndGC)
.then(Protocol.Profiler.enable)
.then(Protocol.Profiler.startPreciseCoverage)
.then(Protocol.Profiler.takePreciseCoverage)
.then(LogSorted)
.then(Protocol.Profiler.stopPreciseCoverage)
.then(Protocol.Profiler.disable)
.then(Protocol.Runtime.disable)
.then(Protocol.Debugger.disable)
.then(ClearAndGC)
.then(next);
},
function testPreciseCountCoveragePartial(next)
{
Protocol.Runtime.enable()
.then(Protocol.Profiler.enable)
.then(() => Protocol.Profiler.startPreciseCoverage({callCount: true}))
.then(() => Protocol.Runtime.compileScript({ expression: nested, sourceURL: arguments.callee.name, persistScript: true }))
.then((result) => Protocol.Runtime.runScript({ scriptId: result.result.scriptId }))
.then(InspectorTest.logMessage)
.then(Protocol.Profiler.takePreciseCoverage)
.then(LogSorted)
.then(() => Protocol.Runtime.evaluate({ expression: "f()" }))
.then(Protocol.Profiler.takePreciseCoverage)
.then(LogSorted)
.then(Protocol.Profiler.stopPreciseCoverage)
.then(Protocol.Profiler.disable)
.then(Protocol.Runtime.disable)
.then(ClearAndGC)
.then(next);
},
]); ]);
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