Commit 7b1f0c4f authored by Andrey Lushnikov's avatar Andrey Lushnikov Committed by Commit Bot

[heapprofiler] QueryObjects: do not return objects retained by feedback information

This was originally reported at https://github.com/GoogleChrome/puppeteer/issues/4545

R=ulan, alph

Change-Id: I5134506e56cd40e49b358cd47590913b81013b6d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1649473
Commit-Queue: Andrey Lushnikov <lushnikov@chromium.org>
Reviewed-by: 's avatarAlexei Filippov <alph@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62129}
parent 915aeab1
...@@ -374,6 +374,7 @@ void FeedbackVector::EvictOptimizedCodeMarkedForDeoptimization( ...@@ -374,6 +374,7 @@ void FeedbackVector::EvictOptimizedCodeMarkedForDeoptimization(
} }
bool FeedbackVector::ClearSlots(Isolate* isolate) { bool FeedbackVector::ClearSlots(Isolate* isolate) {
if (!shared_function_info().HasFeedbackMetadata()) return false;
MaybeObject uninitialized_sentinel = MaybeObject::FromObject( MaybeObject uninitialized_sentinel = MaybeObject::FromObject(
FeedbackVector::RawUninitializedSentinel(isolate)); FeedbackVector::RawUninitializedSentinel(isolate));
......
...@@ -202,10 +202,20 @@ Isolate* HeapProfiler::isolate() const { return heap()->isolate(); } ...@@ -202,10 +202,20 @@ Isolate* HeapProfiler::isolate() const { return heap()->isolate(); }
void HeapProfiler::QueryObjects(Handle<Context> context, void HeapProfiler::QueryObjects(Handle<Context> context,
debug::QueryObjectPredicate* predicate, debug::QueryObjectPredicate* predicate,
PersistentValueVector<v8::Object>* objects) { PersistentValueVector<v8::Object>* objects) {
{
CombinedHeapIterator function_heap_iterator(
heap(), HeapIterator::kFilterUnreachable);
for (HeapObject heap_obj = function_heap_iterator.Next();
!heap_obj.is_null(); heap_obj = function_heap_iterator.Next()) {
if (heap_obj.IsFeedbackVector()) {
FeedbackVector::cast(heap_obj).ClearSlots(isolate());
}
}
}
// We should return accurate information about live objects, so we need to // We should return accurate information about live objects, so we need to
// collect all garbage first. // collect all garbage first.
heap()->CollectAllAvailableGarbage(GarbageCollectionReason::kHeapProfiler); heap()->CollectAllAvailableGarbage(GarbageCollectionReason::kHeapProfiler);
CombinedHeapIterator heap_iterator(heap()); CombinedHeapIterator heap_iterator(heap(), HeapIterator::kFilterUnreachable);
for (HeapObject heap_obj = heap_iterator.Next(); !heap_obj.is_null(); for (HeapObject heap_obj = heap_iterator.Next(); !heap_obj.is_null();
heap_obj = heap_iterator.Next()) { heap_obj = heap_iterator.Next()) {
if (!heap_obj.IsJSObject() || heap_obj.IsExternal(isolate())) continue; if (!heap_obj.IsJSObject() || heap_obj.IsExternal(isolate())) continue;
......
...@@ -95,6 +95,9 @@ Dump each object constructor name. ...@@ -95,6 +95,9 @@ Dump each object constructor name.
[1] : Object,object [1] : Object,object
] ]
Running test: testQueryObjectsWithFeedbackVector
Before/After difference: 1
Running test: testWithObjectGroup Running test: testWithObjectGroup
Query for Array.prototype 3 times Query for Array.prototype 3 times
Results since initial: 0 Results since initial: 0
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --allow-natives-syntax
let {session, contextGroup, Protocol} = let {session, contextGroup, Protocol} =
InspectorTest.start('Checks Runtime.queryObjects'); InspectorTest.start('Checks Runtime.queryObjects');
...@@ -118,6 +120,33 @@ InspectorTest.runAsyncTestSuite([ ...@@ -118,6 +120,33 @@ InspectorTest.runAsyncTestSuite([
session.disconnect(); session.disconnect();
}, },
async function testQueryObjectsWithFeedbackVector() {
let contextGroup = new InspectorTest.ContextGroup();
let session = contextGroup.connect();
let Protocol = session.Protocol;
let {result:{result:{objectId}}} = await Protocol.Runtime.evaluate({
expression: 'Object.prototype',
});
let countBefore = await countObjects(session, objectId);
await Protocol.Runtime.evaluate({
returnByValue: true,
expression: `
global.dummyFunction = () => {
[42];
{foo: 'bar'};
[1,2,3];
}
%EnsureFeedbackVectorForFunction(dummyFunction);
dummyFunction();
`
});
let countAfter = await countObjects(session, objectId);
// Difference should be 1 since |dummyFunction| is retained.
InspectorTest.log('Before/After difference: ' + (countAfter - countBefore));
session.disconnect();
},
async function testWithObjectGroup() { async function testWithObjectGroup() {
let contextGroup = new InspectorTest.ContextGroup(); let contextGroup = new InspectorTest.ContextGroup();
let session = contextGroup.connect(); let session = contextGroup.connect();
...@@ -174,3 +203,18 @@ async function queryObjects(sesion, prototypeObjectId, name) { ...@@ -174,3 +203,18 @@ async function queryObjects(sesion, prototypeObjectId, name) {
InspectorTest.log('Dump each object constructor name.'); InspectorTest.log('Dump each object constructor name.');
InspectorTest.logMessage(value); InspectorTest.logMessage(value);
} }
async function countObjects(session, prototypeObjectId) {
let {result:{objects}} = await session.Protocol.Runtime.queryObjects({
prototypeObjectId
});
let {result:{result:{value}}} = await session.Protocol.Runtime.callFunctionOn({
objectId: objects.objectId,
functionDeclaration: `function() { return this.length; }`,
returnByValue: true
});
await session.Protocol.Runtime.releaseObject({
objectId: objects.objectId,
});
return value;
}
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