v8/test/inspector/runtime/query-objects.js
Andrey Lushnikov 7b1f0c4f6c [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: Alexei Filippov <alph@chromium.org>
Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62129}
2019-06-12 18:33:49 +00:00

221 lines
7.5 KiB
JavaScript

// Copyright 2017 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.
// Flags: --allow-natives-syntax
let {session, contextGroup, Protocol} =
InspectorTest.start('Checks Runtime.queryObjects');
InspectorTest.runAsyncTestSuite([
async function testClass() {
let contextGroup = new InspectorTest.ContextGroup();
let session = contextGroup.connect();
let Protocol = session.Protocol;
InspectorTest.log('Declare class Foo & store its constructor.');
await Protocol.Runtime.evaluate({
expression: 'class Foo{constructor(){}};'
});
let {result:{result:{objectId}}} = await Protocol.Runtime.evaluate({
expression: 'Foo.prototype'
});
for (let i = 0; i < 2; ++i) {
InspectorTest.log('Create object with class Foo.');
Protocol.Runtime.evaluate({expression: 'new Foo()'});
await queryObjects(session, objectId, 'Foo');
}
session.disconnect();
},
async function testDerivedNewClass() {
let contextGroup = new InspectorTest.ContextGroup();
let session = contextGroup.connect();
let Protocol = session.Protocol;
InspectorTest.log('Declare class Foo & store its constructor.');
Protocol.Runtime.evaluate({expression: 'class Foo{};'});
let {result:{result:{objectId}}} = await Protocol.Runtime.evaluate({
expression: 'Foo.prototype'
});
let fooConstructorId = objectId;
InspectorTest.log('Declare class Boo extends Foo & store its constructor.');
Protocol.Runtime.evaluate({expression: 'class Boo extends Foo{};'});
({result:{result:{objectId}}} = await Protocol.Runtime.evaluate({
expression: 'Boo.prototype'
}));
let booConstructorId = objectId;
await queryObjects(session, fooConstructorId, 'Foo');
await queryObjects(session, booConstructorId, 'Boo');
InspectorTest.log('Create object with class Foo');
Protocol.Runtime.evaluate({expression: 'new Foo()'});
await queryObjects(session, fooConstructorId, 'Foo');
InspectorTest.log('Create object with class Boo');
Protocol.Runtime.evaluate({expression: 'new Boo()'});
await queryObjects(session, fooConstructorId, 'Foo');
await queryObjects(session, booConstructorId, 'Boo');
session.disconnect();
},
async function testNewFunction() {
let contextGroup = new InspectorTest.ContextGroup();
let session = contextGroup.connect();
let Protocol = session.Protocol;
InspectorTest.log('Declare Foo & store it.');
Protocol.Runtime.evaluate({expression: 'function Foo(){}'});
let {result:{result:{objectId}}} = await Protocol.Runtime.evaluate({
expression: 'Foo.prototype'
});
for (let i = 0; i < 2; ++i) {
InspectorTest.log('Create object using Foo.');
Protocol.Runtime.evaluate({expression: 'new Foo()'});
await queryObjects(session, objectId, 'Foo');
}
session.disconnect();
},
async function testNonInspectable() {
let contextGroup = new InspectorTest.ContextGroup();
let session = contextGroup.connect();
let Protocol = session.Protocol;
InspectorTest.log('Declare Foo & store it.');
Protocol.Runtime.evaluate({expression: 'function Foo(){}'});
let {result:{result:{objectId}}} = await Protocol.Runtime.evaluate({
expression: 'Foo.prototype'
});
InspectorTest.log('Create object using Foo.');
Protocol.Runtime.evaluate({expression: 'a = new Foo()'});
await queryObjects(session, objectId, 'Foo');
InspectorTest.log('Mark object as not inspectable.')
Protocol.Runtime.evaluate({expression: 'inspector.markObjectAsNotInspectable(a)'});
await queryObjects(session, objectId, 'Foo');
session.disconnect();
},
async function testObjectCreate() {
let contextGroup = new InspectorTest.ContextGroup();
let session = contextGroup.connect();
let Protocol = session.Protocol;
InspectorTest.log('Declare Object p & store it.');
let {result:{result:{objectId}}} = await Protocol.Runtime.evaluate({
expression: 'p = {a:1}'
});
for (let i = 0; i < 2; ++i) {
InspectorTest.log('Create object using Object.create(p).');
Protocol.Runtime.evaluate({expression: 'Object.create(p)'});
await queryObjects(session, objectId, 'p');
}
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() {
let contextGroup = new InspectorTest.ContextGroup();
let session = contextGroup.connect();
let Protocol = session.Protocol;
let {result:{result:{objectId}}} = await Protocol.Runtime.evaluate({
expression: 'Array.prototype'
});
let initialArrayCount;
const N = 3;
InspectorTest.log(`Query for Array.prototype ${N} times`);
for (let i = 0; i < N; ++i) {
const {result:{objects}} = await Protocol.Runtime.queryObjects({
prototypeObjectId: objectId,
objectGroup: 'console'
});
logCountSinceInitial(objects.description);
}
await Protocol.Runtime.releaseObjectGroup({objectGroup: 'console'});
InspectorTest.log('\nReleased object group.');
const {result:{objects}} = await Protocol.Runtime.queryObjects({
prototypeObjectId: objectId,
objectGroup: 'console'
});
logCountSinceInitial(objects.description);
session.disconnect();
function logCountSinceInitial(description) {
const count = parseInt(/Array\((\d+)\)/.exec(description)[1]);
if (typeof initialArrayCount === 'undefined')
initialArrayCount = count;
InspectorTest.logMessage(`Results since initial: ${count - initialArrayCount}`);
}
},
]);
const constructorsNameFunction = `
function() {
return this.map(o => o.constructor.name + ',' + typeof o).sort();
}`;
async function queryObjects(sesion, prototypeObjectId, name) {
let {result:{objects}} = await sesion.Protocol.Runtime.queryObjects({
prototypeObjectId
});
InspectorTest.log(`Query objects with ${name} prototype.`);
let {result:{result:{value}}} = await sesion.Protocol.Runtime.callFunctionOn({
objectId: objects.objectId,
functionDeclaration: constructorsNameFunction,
returnByValue: true
});
InspectorTest.log('Dump each object constructor name.');
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;
}