// 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. utils.load('test/mjsunit/wasm/wasm-constants.js'); utils.load('test/mjsunit/wasm/wasm-module-builder.js'); var builder = new WasmModuleBuilder(); var func_a_idx = builder.addFunction('wasm_A', kSig_v_v).addBody([kExprNop, kExprNop]).index; // wasm_B calls wasm_A times. builder.addFunction('wasm_B', kSig_v_i) .addBody([ // clang-format off kExprLoop, kWasmStmt, // while kExprGetLocal, 0, // - kExprIf, kWasmStmt, // if != 0 kExprGetLocal, 0, // - kExprI32Const, 1, // - kExprI32Sub, // - kExprSetLocal, 0, // decrease kExprCallFunction, func_a_idx, // - kExprBr, 1, // continue kExprEnd, // - kExprEnd, // break // clang-format on ]) .exportAs('main'); var module_bytes = builder.toArray(); function instantiate(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}); Protocol.Debugger.onPaused(handlePaused); var wasm_B_scriptId; var step_actions = [ 'stepInto', // == stepOver, to call instruction 'stepInto', // into call to wasm_A 'stepOver', // over first nop 'stepOut', // out of wasm_A 'stepOut', // out of wasm_B, stop on breakpoint again 'stepOver', // to call 'stepOver', // over call 'resume', // to next breakpoint (third iteration) 'stepInto', // to call 'stepInto', // into wasm_A 'stepOut', // out to wasm_B // now step 9 times, until we are in wasm_A again. 'stepInto', 'stepInto', 'stepInto', 'stepInto', 'stepInto', 'stepInto', 'stepInto', 'stepInto', 'stepInto', // 3 more times, back to wasm_B. 'stepInto', 'stepInto', 'stepInto', // then just resume. 'resume' ]; var sources = {}; var urls = {}; var afterTwoSourcesCallback; Protocol.Debugger.enable() .then(() => InspectorTest.log('Installing code an global variable.')) .then( () => evalWithUrl('var instance;\n' + instantiate.toString(), 'setup')) .then(() => InspectorTest.log('Calling instantiate function.')) .then( () => (evalWithUrl( 'instantiate(' + JSON.stringify(module_bytes) + ')', 'callInstantiate'), 0)) .then(waitForTwoWasmScripts) .then( () => InspectorTest.log( 'Setting breakpoint on line 7 (on the setlocal before the call), url ' + urls[wasm_B_scriptId])) .then( () => Protocol.Debugger.setBreakpoint( {'location': {'scriptId': wasm_B_scriptId, 'lineNumber': 7}})) .then(printFailure) .then(msg => InspectorTest.logMessage(msg.result.actualLocation)) .then(() => evalWithUrl('instance.exports.main(4)', 'runWasm')) .then(() => InspectorTest.log('exports.main returned!')) .then(() => InspectorTest.log('Finished!')) .then(InspectorTest.completeTest); function printFailure(message) { if (!message.result) { InspectorTest.logMessage(message); } return message; } function waitForTwoWasmScripts() { var num = 0; InspectorTest.log('Waiting for two wasm scripts to be parsed.'); var promise = new Promise(fulfill => gotBothSources = fulfill); function waitForMore() { if (num == 2) return promise; Protocol.Debugger.onceScriptParsed() .then(handleNewScript) .then(waitForMore); } function handleNewScript(msg) { var url = msg.params.url; if (!url.startsWith('wasm://')) { InspectorTest.log('Ignoring script with url ' + url); return; } num += 1; var scriptId = msg.params.scriptId; urls[scriptId] = url; InspectorTest.log('Got wasm script: ' + url); if (url.substr(-2) == '-1') wasm_B_scriptId = scriptId; InspectorTest.log('Requesting source for ' + url + '...'); Protocol.Debugger.getScriptSource({scriptId: scriptId}) .then(printFailure) .then(msg => sources[scriptId] = msg.result.scriptSource) .then(InspectorTest.log) .then(() => Object.keys(sources).length == 2 ? gotBothSources() : 0); } waitForMore(); return promise; } function printPauseLocation(scriptId, lineNr, columnNr) { var lines = sources[scriptId].split('\n'); var line = ''; if (lineNr < lines.length) { line = lines[lineNr]; if (columnNr < line.length) { line = line.substr(0, columnNr) + '>' + line.substr(columnNr); } } InspectorTest.log( 'Paused at ' + urls[scriptId] + ':' + lineNr + ':' + columnNr + ': ' + line); } function handlePaused(msg) { var loc = msg.params.callFrames[0].location; printPauseLocation(loc.scriptId, loc.lineNumber, loc.columnNumber); var action = step_actions.shift(); InspectorTest.log('Step action: ' + action); Protocol.Debugger[action](); }