v8/test/inspector/debugger/wasm-get-breakable-locations-byte-offsets.js
Eric Leese a4e162f761 Remove fake wasm scripts from V8 backend
Inspector will no longer report per-function wasm scripts or
provide wasm disassembly. Locations in wasm are now consistently
reported through the inspector API as lineNumber=0
columnNumber=byte offset in module.

Bug: chromium:1013527, chromium:1003022
Change-Id: Ide85bbaa85ad75f29248ff82a3e7f3e40688d377
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1991481
Commit-Queue: Eric Leese <leese@chromium.org>
Reviewed-by: Clemens Backes <clemensb@chromium.org>
Reviewed-by: Simon Zünd <szuend@chromium.org>
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#65660}
2020-01-09 13:21:01 +00:00

246 lines
7.6 KiB
JavaScript

// Copyright 2016 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: --expose-wasm
let {session, contextGroup, Protocol} = InspectorTest.start('Tests breakable locations in wasm');
utils.load('test/mjsunit/wasm/wasm-module-builder.js');
var builder = new WasmModuleBuilder();
// clang-format off
var func_idx = builder.addFunction('helper', kSig_v_v)
.addLocals({ i32_count: 1 })
.addBody([
kExprNop,
kExprI32Const, 12,
kExprLocalSet, 0,
]).index;
builder.addFunction('main', kSig_v_i)
.addBody([
kExprLocalGet, 0,
kExprIf, kWasmStmt,
kExprBlock, kWasmStmt,
kExprCallFunction, func_idx,
kExprEnd,
kExprEnd
]).exportAs('main');
// clang-format on
var module_bytes = builder.toArray();
function testFunction(bytes) {
var buffer = new ArrayBuffer(bytes.length);
var view = new Uint8Array(buffer);
for (var i = 0; i < bytes.length; i++) {
view[i] = bytes[i] | 0;
}
var module = new WebAssembly.Module(buffer);
// Set global variable.
instance = new WebAssembly.Instance(module);
}
var evalWithUrl = (code, url) => Protocol.Runtime.evaluate(
{'expression': code + '\n//# sourceURL=v8://test/' + url});
var setupCode = testFunction.toString() + ';\nvar module_bytes = ' +
JSON.stringify(module_bytes) + ';\nvar instance;';
Protocol.Debugger.enable();
Protocol.Debugger.onScriptParsed(handleScriptParsed);
async function runTest() {
InspectorTest.log('Running testFunction...');
await evalWithUrl(setupCode, 'setup');
await evalWithUrl('testFunction(module_bytes)', 'runTestFunction');
await getBreakableLocationsForAllWasmScripts();
await setAllBreakableLocations();
InspectorTest.log('Running wasm code...');
// Begin executing code:
var promise = evalWithUrl('instance.exports.main(1)', 'runWasm');
await waitForAllPauses();
// Code should now complete
await promise;
InspectorTest.log('Finished!');
}
runTest()
.catch(reason => InspectorTest.log(`Failed: ${reason}`))
.then(InspectorTest.completeTest);
var allBreakableLocations = [];
var urls = {};
var numScripts = 0;
var wasmScripts = [];
function handleScriptParsed(messageObject) {
var scriptId = messageObject.params.scriptId;
var url = messageObject.params.url;
urls[scriptId] = url;
InspectorTest.log('Script nr ' + numScripts + ' parsed. URL: ' + url);
++numScripts;
if (url.startsWith('wasm://')) {
// Only want the full module script, not the function specific ones.
if (url.split('/').length == 4) {
InspectorTest.log('This is a wasm script (nr ' + wasmScripts.length + ').');
wasmScripts.push(scriptId);
}
}
}
function printFailure(message) {
if (!message.result) {
InspectorTest.logMessage(message);
}
}
function printBreakableLocations(message, expectedScriptId, bytecode) {
var locations = message.result.locations;
InspectorTest.log(locations.length + ' breakable location(s):');
for (var i = 0; i < locations.length; ++i) {
if (locations[i].scriptId != expectedScriptId) {
InspectorTest.log(
'SCRIPT ID MISMATCH!! ' + locations[i].scriptId + ' != ' +
expectedScriptId);
}
if (locations[i].lineNumber != 0) {
InspectorTest.log(`Unexpected line number: ${bytecode[locations[i].lineNumber]}`);
}
var line = `byte=${bytecode[locations[i].columnNumber]}`;
InspectorTest.log(
'[' + i + '] ' + locations[i].lineNumber + ':' +
locations[i].columnNumber + ' || ' + line);
}
}
function checkModuleBytes(encoded, bytecode) {
// Encode bytecode as base64.
var BASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
var PAD = '=';
var ret = '';
var leftchar = 0;
var leftbits = 0;
for (var i = 0; i < bytecode.length; i++) {
leftchar = (leftchar << 8) | bytecode[i];
leftbits += 8;
while (leftbits >= 6) {
var curr = (leftchar >> (leftbits-6)) & 0x3f;
leftbits -= 6;
ret += BASE[curr];
}
}
if (leftbits == 2) {
ret += BASE[(leftchar&3) << 4];
ret += PAD + PAD;
} else if (leftbits == 4) {
ret += BASE[(leftchar&0xf) << 2];
ret += PAD;
}
// Check the base64 strings match.
if(ret == encoded) {
InspectorTest.log('Bytecode matches!');
} else {
InspectorTest.log('Original: ' + ret);
InspectorTest.log('Returned by API: ' + encoded);
}
}
async function checkGetBreakableLocations(wasmScriptNr) {
InspectorTest.log(
'Requesting all breakable locations in wasm script ' + wasmScriptNr);
var scriptId = wasmScripts[wasmScriptNr];
var msg = await Protocol.Debugger.getScriptSource({scriptId: scriptId});
checkModuleBytes(msg.result.bytecode, module_bytes);
msg = await Protocol.Debugger.getPossibleBreakpoints(
{start: {lineNumber: 0, columnNumber: 0, scriptId: scriptId}});
printFailure(msg);
allBreakableLocations.push(...msg.result.locations);
printBreakableLocations(msg, scriptId, module_bytes);
InspectorTest.log('Requesting breakable locations in offsets [0,45)');
msg = await Protocol.Debugger.getPossibleBreakpoints({
start: {lineNumber: 0, columnNumber: 0, scriptId: scriptId},
end: {lineNumber: 0, columnNumber: 45, scriptId: scriptId}});
printFailure(msg);
printBreakableLocations(msg, scriptId, module_bytes);
InspectorTest.log('Requesting breakable locations in offsets [50,60)');
msg = await Protocol.Debugger.getPossibleBreakpoints({
start: {lineNumber: 0, columnNumber: 50, scriptId: scriptId},
end: {lineNumber: 0, columnNumber: 60, scriptId: scriptId}});
printFailure(msg);
printBreakableLocations(msg, scriptId, module_bytes);
}
async function getBreakableLocationsForAllWasmScripts() {
InspectorTest.log('Querying breakable locations for all wasm scripts now...');
for (var wasmScriptNr = 0; wasmScriptNr < wasmScripts.length;
++wasmScriptNr) {
await checkGetBreakableLocations(wasmScriptNr);
}
}
function locationMatches(loc1, loc2) {
return loc1.scriptId == loc2.scriptId && loc1.lineNumber == loc2.lineNumber &&
loc1.columnNumber == loc2.columnNumber;
}
function locationStr(loc) {
return urls[loc.scriptId] + ':' + loc.lineNumber + ':' + loc.columnNumber;
}
async function setBreakpoint(loc) {
InspectorTest.log('Setting at ' + locationStr(loc));
var msg = await Protocol.Debugger.setBreakpoint({ 'location': loc });
printFailure(msg);
if (locationMatches(loc, msg.result.actualLocation)) {
InspectorTest.log("Success!");
} else {
InspectorTest.log("Mismatch!");
InspectorTest.logMessage(msg);
}
}
async function setAllBreakableLocations() {
InspectorTest.log('Setting a breakpoint on each breakable location...');
for (var loc of allBreakableLocations) {
await setBreakpoint(loc);
}
}
function recordPausedLocation(msg) {
var topLocation = msg.params.callFrames[0].location;
InspectorTest.log('Stopped at ' + locationStr(topLocation));
for (var i = 0; i < allBreakableLocations.length; ++i) {
if (locationMatches(topLocation, allBreakableLocations[i])) {
allBreakableLocations.splice(i, 1);
break;
}
}
}
async function waitForAllPauses() {
var remaining = allBreakableLocations.length;
InspectorTest.log('Missing breakpoints: ' + remaining);
while (remaining > 0) {
recordPausedLocation(await Protocol.Debugger.oncePaused());
await Protocol.Debugger.resume();
remaining--;
InspectorTest.log('Missing breakpoints: ' + remaining);
}
if (allBreakableLocations.length != 0) {
InspectorTest.log('Did not hit all breakable locations: '
+ JSON.stringify(allBreakableLocations));
}
}