// 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 testQueryObjectsWithArrayBuffer() { let contextGroup = new InspectorTest.ContextGroup(); let session = contextGroup.connect(); let Protocol = session.Protocol; await Protocol.Runtime.evaluate({ expression: 'new Int8Array(32)', }); let {result:{result:{objectId}}} = await Protocol.Runtime.evaluate({ expression: 'ArrayBuffer.prototype' }); let {result:{objects}} = await session.Protocol.Runtime.queryObjects({ prototypeObjectId: objectId }); let {result:{result: properties}} = await session.Protocol.Runtime.getProperties({ objectId: objects.objectId, ownProperties: true, generatePreview: true }); await session.Protocol.Runtime.getProperties({ objectId: properties[0].value.objectId, ownProperties: true, generatePreview: true }); InspectorTest.log('Test that queryObjects does not crash for on-heap TypedArrays'); 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; }