4d43ab04a4
WasmValueObjects used to not have a constructor defined. That prevents custom devtoolsFormatters from being applied to such objects. Change-Id: Id775cdb710d0c4106f70858cc1fc92b1f8bd4590 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2991243 Reviewed-by: Benedikt Meurer <bmeurer@chromium.org> Commit-Queue: Philip Pfaffe <pfaffe@chromium.org> Cr-Commit-Position: refs/heads/master@{#75438}
398 lines
15 KiB
JavaScript
398 lines
15 KiB
JavaScript
// Copyright 2021 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.
|
|
|
|
utils.load('test/inspector/wasm-inspector-test.js');
|
|
|
|
let {session, contextGroup, Protocol} =
|
|
InspectorTest.start('Test wasm debug evaluate');
|
|
|
|
Protocol.Debugger.enable();
|
|
Protocol.Runtime.enable();
|
|
|
|
async function compileModule(builder) {
|
|
const moduleBytes = JSON.stringify(builder.toArray());
|
|
const expression = `new WebAssembly.Module(new Uint8Array(${moduleBytes}).buffer);`;
|
|
const {result: {scriptId}} = await Protocol.Runtime.compileScript({expression, sourceURL: 'v8://test/compileModule', persistScript: true});
|
|
const [{params}, {result}] = await Promise.all([
|
|
Protocol.Debugger.onceScriptParsed(),
|
|
Protocol.Runtime.runScript({scriptId})
|
|
]);
|
|
return [result.result, params.scriptId];
|
|
}
|
|
|
|
async function instantiateModule({objectId}, importObject) {
|
|
const {result: {result}} = await Protocol.Runtime.callFunctionOn({
|
|
arguments: importObject ? [importObject] : [],
|
|
functionDeclaration: 'function(importObject) { return new WebAssembly.Instance(this, importObject); }',
|
|
objectId
|
|
});
|
|
return result;
|
|
}
|
|
|
|
async function dumpOnCallFrame(callFrameId, expression) {
|
|
const {result: {result: object}} = await Protocol.Debugger.evaluateOnCallFrame({
|
|
callFrameId, expression
|
|
});
|
|
if ('customPreview' in object) {
|
|
InspectorTest.log(
|
|
`> ${expression} = ${JSON.stringify(object.customPreview)}`);
|
|
} else if (object.type === 'object' && object.subtype === 'wasmvalue') {
|
|
const {result: {result: properties}} = await Protocol.Runtime.getProperties({objectId: object.objectId, ownProperties: true})
|
|
const valueProperty = properties.find(p => p.name === 'value');
|
|
InspectorTest.log(`> ${expression} = ${object.description} {${valueProperty.value.description}}`);
|
|
} else if ('description' in object) {
|
|
InspectorTest.log(`> ${expression} = ${object.description}`);
|
|
} else {
|
|
InspectorTest.log(`> ${expression} = ${JSON.stringify(object.value)}`);
|
|
}
|
|
}
|
|
|
|
async function dumpKeysOnCallFrame(callFrameId, object, keys) {
|
|
for (const key of keys) {
|
|
await dumpOnCallFrame(callFrameId, `${object}[${JSON.stringify(key)}]`);
|
|
if (typeof key === 'string' && key.indexOf('.') < 0) {
|
|
await dumpOnCallFrame(callFrameId, `${key}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
async function waitForDebuggerPaused() {
|
|
const {params: {callFrames: [{callFrameId, functionName}]}} = await Protocol.Debugger.oncePaused();
|
|
InspectorTest.log(`Debugger paused in ${functionName}.`);
|
|
return callFrameId;
|
|
}
|
|
|
|
InspectorTest.runAsyncTestSuite([
|
|
async function testInstanceAndModule() {
|
|
const builder = new WasmModuleBuilder();
|
|
const main = builder.addFunction('main', kSig_v_v)
|
|
.addBody([]).exportFunc();
|
|
|
|
InspectorTest.log('Compile module.');
|
|
const [module, scriptId] = await compileModule(builder);
|
|
|
|
InspectorTest.log('Set breakpoint in main.');
|
|
await Protocol.Debugger.setBreakpoint({
|
|
location: {scriptId, lineNumber: 0, columnNumber: main.body_offset}
|
|
});
|
|
|
|
InspectorTest.log('Instantiate module.');
|
|
const instance = await instantiateModule(module);
|
|
|
|
InspectorTest.log('Call main.');
|
|
const callMainPromise = Protocol.Runtime.callFunctionOn({
|
|
functionDeclaration: `function() { return this.exports.main(); }`,
|
|
objectId: instance.objectId
|
|
});
|
|
const callFrameId = await waitForDebuggerPaused();
|
|
await dumpOnCallFrame(callFrameId, `instance`);
|
|
await dumpOnCallFrame(callFrameId, `module`);
|
|
await Protocol.Debugger.resume();
|
|
await callMainPromise;
|
|
},
|
|
|
|
async function testGlobals() {
|
|
const builder = new WasmModuleBuilder();
|
|
const global0 = builder.addGlobal(kWasmI32, true); // global0
|
|
const global1 = builder.addGlobal(kWasmI32, true).exportAs('global0');
|
|
const global2 = builder.addGlobal(kWasmI64, true).exportAs('global3');
|
|
const global3 = builder.addGlobal(kWasmI64, true); // global3
|
|
const main = builder.addFunction('main', kSig_v_v)
|
|
.addBody([
|
|
kExprI64Const, 42,
|
|
kExprGlobalSet, global3.index,
|
|
]).exportFunc();
|
|
const start = builder.addFunction('start', kSig_v_v)
|
|
.addBody([
|
|
kExprNop,
|
|
kExprI32Const, 0,
|
|
kExprGlobalSet, global0.index,
|
|
kExprI32Const, 1,
|
|
kExprGlobalSet, global1.index,
|
|
kExprI64Const, 2,
|
|
kExprGlobalSet, global2.index,
|
|
kExprI64Const, 3,
|
|
kExprGlobalSet, global3.index,
|
|
]);
|
|
builder.addStart(start.index);
|
|
const KEYS = [0, 1, 2, 3, '$global0', '$global3'];
|
|
|
|
InspectorTest.log('Compile module.');
|
|
const [module, scriptId] = await compileModule(builder);
|
|
|
|
InspectorTest.log('Set breakpoint in main.');
|
|
await Protocol.Debugger.setBreakpoint({
|
|
location: {scriptId, lineNumber: 0, columnNumber: main.body_offset}
|
|
});
|
|
|
|
InspectorTest.log('Instantiate module.');
|
|
const instance = await instantiateModule(module);
|
|
|
|
InspectorTest.log('Call main.');
|
|
const callMainPromise = Protocol.Runtime.callFunctionOn({
|
|
functionDeclaration: `function() { return this.exports.main(); }`,
|
|
objectId: instance.objectId
|
|
});
|
|
let callFrameId = await waitForDebuggerPaused();
|
|
await dumpOnCallFrame(callFrameId, `globals`);
|
|
await dumpOnCallFrame(callFrameId, `typeof globals`);
|
|
await dumpOnCallFrame(callFrameId, `Object.keys(globals)`);
|
|
await dumpKeysOnCallFrame(callFrameId, "globals", KEYS);
|
|
|
|
InspectorTest.log(`Stepping twice in main.`)
|
|
await Protocol.Debugger.stepOver(); // i32.const 42
|
|
await Protocol.Debugger.stepOver(); // global.set $global3
|
|
callFrameId = await waitForDebuggerPaused();
|
|
await dumpKeysOnCallFrame(callFrameId, "globals", KEYS);
|
|
|
|
InspectorTest.log('Changing global from JavaScript.')
|
|
await Protocol.Debugger.evaluateOnCallFrame({
|
|
callFrameId,
|
|
expression: `instance.exports.global0.value = 21`
|
|
});
|
|
await dumpKeysOnCallFrame(callFrameId, "globals", KEYS);
|
|
await Protocol.Debugger.resume();
|
|
await callMainPromise;
|
|
},
|
|
|
|
async function testFunctions() {
|
|
const builder = new WasmModuleBuilder();
|
|
builder.addImport('foo', 'bar', kSig_v_v);
|
|
const main = builder.addFunction('main', kSig_i_v)
|
|
.addBody([
|
|
kExprI32Const, 0,
|
|
]).exportFunc();
|
|
builder.addFunction('func2', kSig_i_v)
|
|
.addBody([
|
|
kExprI32Const, 1,
|
|
]);
|
|
builder.addFunction(undefined, kSig_i_v)
|
|
.addBody([
|
|
kExprI32Const, 2,
|
|
]).exportAs('func2');
|
|
builder.addFunction(undefined, kSig_i_v)
|
|
.addBody([
|
|
kExprI32Const, 3,
|
|
]);
|
|
const KEYS = [0, 1, 2, 3, 4, '$foo.bar', '$main', '$func2', '$func4'];
|
|
|
|
InspectorTest.log('Compile module.');
|
|
const [module, scriptId] = await compileModule(builder);
|
|
|
|
InspectorTest.log('Set breakpoint in main.');
|
|
await Protocol.Debugger.setBreakpoint({
|
|
location: {scriptId, lineNumber: 0, columnNumber: main.body_offset}
|
|
});
|
|
|
|
InspectorTest.log('Instantiate module.');
|
|
const {result: { result: importObject }} = await Protocol.Runtime.evaluate({
|
|
expression: `({foo: {bar() { }}})`
|
|
});
|
|
const instance = await instantiateModule(module, importObject);
|
|
|
|
InspectorTest.log('Call main.');
|
|
const callMainPromise = Protocol.Runtime.callFunctionOn({
|
|
functionDeclaration: `function() { return this.exports.main(); }`,
|
|
objectId: instance.objectId
|
|
});
|
|
let callFrameId = await waitForDebuggerPaused();
|
|
await dumpOnCallFrame(callFrameId, `functions`);
|
|
await dumpOnCallFrame(callFrameId, `typeof functions`);
|
|
await dumpOnCallFrame(callFrameId, `Object.keys(functions)`);
|
|
await dumpKeysOnCallFrame(callFrameId, "functions", KEYS);
|
|
await Protocol.Debugger.resume();
|
|
await callMainPromise;
|
|
},
|
|
|
|
async function testLocals() {
|
|
const builder = new WasmModuleBuilder();
|
|
const main = builder.addFunction('main', kSig_v_ii, ['x', 'x'])
|
|
.addLocals(kWasmI32, 1)
|
|
.addBody([
|
|
kExprI32Const, 42,
|
|
kExprLocalSet, 2
|
|
]).exportFunc();
|
|
const KEYS = [0, 1, 2, '$x', '$var2'];
|
|
|
|
InspectorTest.log('Compile module.');
|
|
const [module, scriptId] = await compileModule(builder);
|
|
|
|
InspectorTest.log('Set breakpoint in main.');
|
|
await Protocol.Debugger.setBreakpoint({
|
|
location: {scriptId, lineNumber: 0, columnNumber: main.body_offset}
|
|
});
|
|
|
|
InspectorTest.log('Instantiate module.');
|
|
const instance = await instantiateModule(module);
|
|
|
|
InspectorTest.log('Call main.');
|
|
const callMainPromise = Protocol.Runtime.callFunctionOn({
|
|
functionDeclaration: `function() { return this.exports.main(3, 6); }`,
|
|
objectId: instance.objectId
|
|
});
|
|
let callFrameId = await waitForDebuggerPaused();
|
|
await dumpOnCallFrame(callFrameId, `locals`);
|
|
await dumpOnCallFrame(callFrameId, `typeof locals`);
|
|
await dumpOnCallFrame(callFrameId, `Object.keys(locals)`);
|
|
await dumpKeysOnCallFrame(callFrameId, "locals", KEYS);
|
|
|
|
InspectorTest.log(`Stepping twice in main.`)
|
|
await Protocol.Debugger.stepOver(); // i32.const 42
|
|
await Protocol.Debugger.stepOver(); // local.set $var2
|
|
callFrameId = await waitForDebuggerPaused();
|
|
await dumpKeysOnCallFrame(callFrameId, "locals", KEYS);
|
|
await Protocol.Debugger.resume();
|
|
await callMainPromise;
|
|
},
|
|
|
|
async function testMemories() {
|
|
const builder = new WasmModuleBuilder();
|
|
builder.addMemory(1, 1).exportMemoryAs('foo');
|
|
const main = builder.addFunction('main', kSig_v_v)
|
|
.addBody([kExprNop]).exportFunc();
|
|
const KEYS = [0, '$foo'];
|
|
|
|
InspectorTest.log('Compile module.');
|
|
const [module, scriptId] = await compileModule(builder);
|
|
|
|
InspectorTest.log('Set breakpoint in main.');
|
|
await Protocol.Debugger.setBreakpoint({
|
|
location: {scriptId, lineNumber: 0, columnNumber: main.body_offset}
|
|
});
|
|
|
|
InspectorTest.log('Instantiate module.');
|
|
const instance = await instantiateModule(module);
|
|
|
|
InspectorTest.log('Call main.');
|
|
const callMainPromise = Protocol.Runtime.callFunctionOn({
|
|
functionDeclaration: `function() { return this.exports.main(); }`,
|
|
objectId: instance.objectId
|
|
});
|
|
let callFrameId = await waitForDebuggerPaused();
|
|
await dumpOnCallFrame(callFrameId, `memories`);
|
|
await dumpOnCallFrame(callFrameId, `typeof memories`);
|
|
await dumpOnCallFrame(callFrameId, `Object.keys(memories)`);
|
|
await dumpKeysOnCallFrame(callFrameId, "memories", KEYS);
|
|
await Protocol.Debugger.resume();
|
|
await callMainPromise;
|
|
},
|
|
|
|
async function testTables() {
|
|
const builder = new WasmModuleBuilder();
|
|
builder.addTable(kWasmFuncRef, 2).exportAs('bar');
|
|
const main = builder.addFunction('main', kSig_v_v)
|
|
.addBody([kExprNop]).exportFunc();
|
|
const KEYS = [0, '$bar'];
|
|
|
|
InspectorTest.log('Compile module.');
|
|
const [module, scriptId] = await compileModule(builder);
|
|
|
|
InspectorTest.log('Set breakpoint in main.');
|
|
await Protocol.Debugger.setBreakpoint({
|
|
location: {scriptId, lineNumber: 0, columnNumber: main.body_offset}
|
|
});
|
|
|
|
InspectorTest.log('Instantiate module.');
|
|
const instance = await instantiateModule(module);
|
|
|
|
InspectorTest.log('Call main.');
|
|
const callMainPromise = Protocol.Runtime.callFunctionOn({
|
|
functionDeclaration: `function() { return this.exports.main(); }`,
|
|
objectId: instance.objectId
|
|
});
|
|
let callFrameId = await waitForDebuggerPaused();
|
|
await dumpOnCallFrame(callFrameId, `tables`);
|
|
await dumpOnCallFrame(callFrameId, `typeof tables`);
|
|
await dumpOnCallFrame(callFrameId, `Object.keys(tables)`);
|
|
await dumpKeysOnCallFrame(callFrameId, "tables", KEYS);
|
|
await Protocol.Debugger.resume();
|
|
await callMainPromise;
|
|
},
|
|
|
|
async function testStack() {
|
|
const builder = new WasmModuleBuilder();
|
|
const main = builder.addFunction('main', kSig_i_i)
|
|
.addBody([
|
|
kExprLocalGet, 0,
|
|
kExprI32Const, 42,
|
|
kExprI32Add,
|
|
]).exportFunc();
|
|
|
|
InspectorTest.log('Compile module.');
|
|
const [module, scriptId] = await compileModule(builder);
|
|
|
|
InspectorTest.log('Set breakpoint in main.');
|
|
await Protocol.Debugger.setBreakpoint({
|
|
location: {scriptId, lineNumber: 0, columnNumber: main.body_offset}
|
|
});
|
|
|
|
InspectorTest.log('Instantiate module.');
|
|
const instance = await instantiateModule(module);
|
|
|
|
InspectorTest.log('Call main.');
|
|
const callMainPromise = Protocol.Runtime.callFunctionOn({
|
|
functionDeclaration: `function() { return this.exports.main(5); }`,
|
|
objectId: instance.objectId
|
|
});
|
|
let callFrameId = await waitForDebuggerPaused();
|
|
await dumpOnCallFrame(callFrameId, `stack`);
|
|
await dumpOnCallFrame(callFrameId, `typeof stack`);
|
|
await dumpOnCallFrame(callFrameId, `Object.keys(stack)`);
|
|
|
|
InspectorTest.log(`Stepping twice in main.`)
|
|
await Protocol.Debugger.stepOver(); // local.get $var0
|
|
await Protocol.Debugger.stepOver(); // i32.const 42
|
|
callFrameId = await waitForDebuggerPaused();
|
|
await dumpOnCallFrame(callFrameId, `stack`);
|
|
await dumpOnCallFrame(callFrameId, `Object.keys(stack)`);
|
|
await dumpKeysOnCallFrame(callFrameId, "stack", [0, 1]);
|
|
await Protocol.Debugger.resume();
|
|
await callMainPromise;
|
|
},
|
|
|
|
async function testCustomFormatters() {
|
|
const builder = new WasmModuleBuilder();
|
|
const main = builder.addFunction('main', kSig_i_i, ['x'])
|
|
.addBody([
|
|
kExprLocalGet,
|
|
0,
|
|
])
|
|
.exportFunc();
|
|
|
|
InspectorTest.log('Compile module.');
|
|
const [module, scriptId] = await compileModule(builder);
|
|
|
|
await Protocol.Runtime.enable();
|
|
InspectorTest.log('Set breakpoint in main.');
|
|
await Protocol.Debugger.setBreakpoint(
|
|
{location: {scriptId, lineNumber: 0, columnNumber: main.body_offset}});
|
|
|
|
InspectorTest.log('Install custom formatter.');
|
|
await Protocol.Runtime.onConsoleAPICalled(m => InspectorTest.logMessage(m));
|
|
await Protocol.Runtime.setCustomObjectFormatterEnabled({enabled: true});
|
|
await Protocol.Runtime.evaluate({
|
|
expression: `this.devtoolsFormatters = [{
|
|
header: function(obj) { return ["div", {}, JSON.stringify(obj)]; },
|
|
hasBody: function() { return false; }
|
|
}]`
|
|
});
|
|
|
|
InspectorTest.log('Instantiate module.');
|
|
const instance = await instantiateModule(module);
|
|
|
|
InspectorTest.log('Call main.');
|
|
const callMainPromise = Protocol.Runtime.callFunctionOn({
|
|
functionDeclaration: `function() { return this.exports.main(5); }`,
|
|
objectId: instance.objectId
|
|
});
|
|
let callFrameId = await waitForDebuggerPaused();
|
|
await dumpOnCallFrame(callFrameId, `locals`);
|
|
await dumpOnCallFrame(callFrameId, `Object.keys(locals)`);
|
|
await dumpKeysOnCallFrame(callFrameId, 'locals', [0, '$x']);
|
|
|
|
await Protocol.Debugger.resume();
|
|
await callMainPromise;
|
|
}
|
|
]);
|