[inspector] Add Wasm test coverage for evaluateOnCallFrame().

Drive-by-fix: Handle duplicate globals names correctly in the
scope exposed module object.

Bug: chromium:1127914, chromium:1071432
Change-Id: I697256642c5ddbc13f86ff25ab012c53537b9c88
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2609416
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Commit-Queue: Yang Guo <yangguo@chromium.org>
Auto-Submit: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: Yang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#71910}
This commit is contained in:
Benedikt Meurer 2021-01-05 08:42:18 +01:00 committed by Commit Bot
parent adea008b75
commit d09b35f3b1
3 changed files with 402 additions and 1 deletions

View File

@ -241,7 +241,9 @@ Handle<JSObject> GetModuleScopeObject(Handle<WasmInstanceObject> instance) {
WasmValue value = WasmValue value =
WasmInstanceObject::GetGlobalValue(instance, globals[i]); WasmInstanceObject::GetGlobalValue(instance, globals[i]);
Handle<Object> value_obj = WasmValueToValueObject(isolate, value); Handle<Object> value_obj = WasmValueToValueObject(isolate, value);
JSObject::AddProperty(isolate, globals_obj, name, value_obj, NONE); LookupIterator it(isolate, globals_obj, name, globals_obj,
LookupIterator::OWN_SKIP_INTERCEPTOR);
JSObject::CreateDataProperty(&it, value_obj).Check();
} }
} }
return module_scope_object; return module_scope_object;

View File

@ -0,0 +1,109 @@
Test wasm debug evaluate
Running test: testInstanceAndModule
Compile module.
Set breakpoint in main.
Instantiate module.
Call main.
Debugger paused in main.
> instance = Instance
> module = Module
Running test: testGlobals
Compile module.
Set breakpoint in main.
Instantiate module.
Call main.
Debugger paused in main.
> typeof globals = "object"
> globals[0] = 0
> globals[1] = 1
> globals[2] = 2n
> globals[3] = 3n
> globals["$global0"] = 1
> $global0 = 1
> globals["$global3"] = 3n
> $global3 = 3n
Stepping twice in main.
Debugger paused in main.
> globals[0] = 0
> globals[1] = 1
> globals[2] = 2n
> globals[3] = 42n
> globals["$global0"] = 1
> $global0 = 1
> globals["$global3"] = 42n
> $global3 = 42n
Changing global from JavaScript.
> globals[0] = 0
> globals[1] = 21
> globals[2] = 2n
> globals[3] = 42n
> globals["$global0"] = 21
> $global0 = 21
> globals["$global3"] = 42n
> $global3 = 42n
Running test: testFunctions
Compile module.
Set breakpoint in main.
Instantiate module.
Call main.
Debugger paused in main.
> typeof functions = "object"
> functions[0] = function 0() { [native code] }
> functions[1] = function 1() { [native code] }
> functions[2] = function 2() { [native code] }
> functions[3] = function 3() { [native code] }
> functions["$main"] = function 0() { [native code] }
> $main = function 0() { [native code] }
> functions["$func1"] = function 2() { [native code] }
> $func1 = function 2() { [native code] }
> functions["$func3"] = function 3() { [native code] }
> $func3 = function 3() { [native code] }
Running test: testLocals
Compile module.
Set breakpoint in main.
Instantiate module.
Call main.
Debugger paused in main.
> typeof locals = "object"
> locals[0] = 3
> locals[1] = 6
> locals[2] = 0
> locals["$x"] = 6
> $x = 6
> locals["$var2"] = 0
> $var2 = 0
Stepping twice in main.
Debugger paused in main.
> locals[0] = 3
> locals[1] = 6
> locals[2] = 42
> locals["$x"] = 6
> $x = 6
> locals["$var2"] = 42
> $var2 = 42
Running test: testMemories
Compile module.
Set breakpoint in main.
Instantiate module.
Call main.
Debugger paused in main.
> typeof memories = "object"
> memories[0] = Memory(1)
> memories["$foo"] = Memory(1)
> $foo = Memory(1)
Running test: testTables
Compile module.
Set breakpoint in main.
Instantiate module.
Call main.
Debugger paused in main.
> typeof tables = "object"
> tables[0] = Table
> tables["$bar"] = Table
> $bar = Table

View File

@ -0,0 +1,290 @@
// 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}) {
const {result: {result}} = await Protocol.Runtime.callFunctionOn({
functionDeclaration: 'function() { return new WebAssembly.Instance(this); }',
objectId
});
return result;
}
async function dumpOnCallFrame(callFrameId, expression) {
const {result: {result}} = await Protocol.Debugger.evaluateOnCallFrame({
callFrameId, expression
});
if ('description' in result) {
InspectorTest.log(`> ${expression} = ${result.description}`);
} else {
InspectorTest.log(`> ${expression} = ${JSON.stringify(result.value)}`);
}
}
async function dumpKeysOnCallFrame(callFrameId, object, keys) {
for (const key of keys) {
await dumpOnCallFrame(callFrameId, `${object}[${JSON.stringify(key)}]`);
if (typeof key === 'string') {
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, `typeof 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();
const main = builder.addFunction('main', kSig_i_v)
.addBody([
kExprI32Const, 0,
]).exportFunc();
builder.addFunction('func1', kSig_i_v)
.addBody([
kExprI32Const, 1,
]);
builder.addFunction(undefined, kSig_i_v)
.addBody([
kExprI32Const, 2,
]).exportAs('func1');
builder.addFunction(undefined, kSig_i_v)
.addBody([
kExprI32Const, 3,
]);
const KEYS = [0, 1, 2, 3, '$main', '$func1', '$func3'];
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, `typeof 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, `typeof 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, `typeof 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, `typeof tables`);
await dumpKeysOnCallFrame(callFrameId, "tables", KEYS);
await Protocol.Debugger.resume();
await callMainPromise;
}
]);