wasm-scope-info.js 4.53 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
// 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.

let {session, contextGroup, Protocol} = InspectorTest.start(
    'Test retrieving scope information when pausing in wasm functions');
session.setupScriptMap();
Protocol.Debugger.enable();

let evaluate = code => Protocol.Runtime.evaluate({expression: code});

(async function test() {
  let scriptId = await instantiateWasm();
  await setBreakpoint(scriptId);
  printPauseLocationsAndContinue();
  await evaluate('instance.exports.main(4)');
  InspectorTest.log('exports.main returned. Test finished.');
  InspectorTest.completeTest();
})();

async function printPauseLocationsAndContinue() {
  while (true) {
    let msg = await Protocol.Debugger.oncePaused();
    let loc = msg.params.callFrames[0].location;
    InspectorTest.log('Paused:');
    await session.logSourceLocation(loc);
    await dumpScopeChainsOnPause(msg);
    Protocol.Debugger.stepOver();
  }
}

async function instantiateWasm() {
  utils.load('test/mjsunit/wasm/wasm-constants.js');
  utils.load('test/mjsunit/wasm/wasm-module-builder.js');

  var builder = new WasmModuleBuilder();

  builder.addFunction('func', kSig_v_i)
      .addLocals(
          {i32_count: 1, f64_count: 1}, ['i32Arg', undefined, 'unicode☼f64'])
      .addBody([
        // Set param 0 to 11.
        kExprI32Const, 11, kExprSetLocal, 0,
        // Set local 1 to 47.
        kExprI32Const, 47, kExprSetLocal, 1,
        // Set local 2 to 1/7.
        kExprI32Const, 1, kExprF64UConvertI32, kExprI32Const, 7,
        kExprF64UConvertI32, kExprF64Div, kExprSetLocal, 2
      ])
      .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);
  }

  InspectorTest.log('Installing code and global variable.');
  await evaluate('var instance;\n' + instantiate.toString());
  InspectorTest.log('Calling instantiate function.');
  evaluate('instantiate(' + JSON.stringify(module_bytes) + ')');
  return waitForWasmScript();
}

async function setBreakpoint(scriptId) {
  InspectorTest.log('Setting breakpoint on line 2 (first instruction)');
  let breakpoint = await Protocol.Debugger.setBreakpoint(
      {'location': {'scriptId': scriptId, 'lineNumber': 2}});
  printFailure(breakpoint);
  InspectorTest.logMessage(breakpoint.result.actualLocation);
}

function printFailure(message) {
  if (!message.result) {
    InspectorTest.logMessage(message);
  }
  return message;
}

async function waitForWasmScript() {
  InspectorTest.log('Waiting for wasm script to be parsed.');
  while (true) {
    let script_msg = await Protocol.Debugger.onceScriptParsed();
    let url = script_msg.params.url;
    if (!url.startsWith('wasm://')) {
      continue;
    }
    InspectorTest.log('Got wasm script!');
    return script_msg.params.scriptId;
  }
}

async function getValueString(value) {
  if (value.type == 'object') {
    var msg = await Protocol.Runtime.getProperties({objectId: value.objectId});
    printFailure(msg);
    let printProperty = elem => '"' + elem.name + '"' +
106
        ': ' + elem.value.description + ' (' + elem.value.type + ')';
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
    return msg.result.result.map(printProperty).join(', ');
  }
  return JSON.stringify(value.value) + ' (' + value.type + ')';
}

async function dumpProperties(message) {
  printFailure(message);
  for (var value of message.result.result) {
    var value_str = await getValueString(value.value);
    InspectorTest.log('   ' + value.name + ': ' + value_str);
  }
}

async function dumpScopeChainsOnPause(message) {
  for (var frame of message.params.callFrames) {
    var functionName = frame.functionName || '(anonymous)';
    var lineNumber = frame.location ? frame.location.lineNumber : frame.lineNumber;
    var columnNumber = frame.location ? frame.location.columnNumber : frame.columnNumber;
    InspectorTest.log(`at ${functionName} (${lineNumber}:${columnNumber}):`);
    for (var scope of frame.scopeChain) {
      InspectorTest.logObject(' - scope (' + scope.type + '):');
      if (scope.type == 'global') {
        InspectorTest.logObject('   -- skipped');
      } else {
        var properties = await Protocol.Runtime.getProperties(
            {'objectId': scope.object.objectId});
        await dumpProperties(properties);
      }
    }
  }
}