v8/test/inspector/wasm-inspector-test.js
Benedikt Meurer ad42f966a4 [wasm][debug] Expose instance and module instead of imports / exports.
The "imports" and "exports" that were exposed on WebAssembly frames via
Debug-Evaluate aren't useful for the DWARF C/C++ extension (and likely
not for any other language extension), since they only expose static
information that's easily available (upfront) by reading the Wasm wire
bytes.

In fact, there are already standardized functions in the WebAssembly
specification, namely `WebAssembly.Module.imports(module)` and
`WebAssembly.Module.exports(module)`, which yield static information
about the imports and exports of a Wasm module.

So instead of exposing special, non-standard "imports" and "exports", we
now instead expose both the "instance" and the "module" objects via both
the Debug Proxy and the Scope view, and also add internal [[Exports]]
and [[Imports]] properties to WasmModuleObject, which under the hood use
the standard methods mentioned above.

Fixed: chromium:1162069
Bug: chromium:1071432, chromium:1083146
Screenshot: https://imgur.com/lcaW2jL.png
Doc: https://docs.google.com/document/d/1rqbu0jKTl3q_xCxLnKzkjGXWEsHnJ9aERVhKV9RNDgE#bookmark=id.925bb2qgou38
Change-Id: Ie27e55bb08ea5f90493c57375bf2b48dfb11a4d2
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2606050
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Auto-Submit: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: Yang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#71893}
2020-12-29 12:48:23 +00:00

105 lines
3.6 KiB
JavaScript

// Copyright 2020 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-module-builder.js');
WasmInspectorTest = {}
InspectorTest.getWasmOpcodeName = getOpcodeName;
WasmInspectorTest.evalWithUrl = (code, url) =>
Protocol.Runtime
.evaluate({'expression': code + '\n//# sourceURL=v8://test/' + url})
.then(printIfFailure);
WasmInspectorTest.instantiateFromBuffer = function(bytes, imports) {
var buffer = new ArrayBuffer(bytes.length);
var view = new Uint8Array(buffer);
for (var i = 0; i < bytes.length; ++i) {
view[i] = bytes[i] | 0;
}
const module = new WebAssembly.Module(buffer);
return new WebAssembly.Instance(module, imports);
}
WasmInspectorTest.instantiate = async function(bytes, instance_name = 'instance') {
const instantiate_code = `var ${instance_name} = (${WasmInspectorTest.instantiateFromBuffer})(${JSON.stringify(bytes)});`;
await WasmInspectorTest.evalWithUrl(instantiate_code, 'instantiate');
}
WasmInspectorTest.dumpScopeProperties = async function(message) {
printIfFailure(message);
for (var value of message.result.result) {
var value_str = await getScopeValues(value.name, value.value);
InspectorTest.log(' ' + value.name + ': ' + value_str);
}
}
WasmInspectorTest.getWasmValue = function(wasmValue) {
return typeof (wasmValue.value) === 'undefined' ?
wasmValue.unserializableValue :
wasmValue.value;
}
function printIfFailure(message) {
if (!message.result) {
InspectorTest.logMessage(message);
}
return message;
}
async function getScopeValues(name, value) {
if (value.type == 'object') {
if (value.subtype === 'typedarray' || value.subtype == 'webassemblymemory') return value.description;
if (name === 'instance') return dumpInstanceProperties(value);
if (name === 'module') return value.description;
let msg = await Protocol.Runtime.getProperties({objectId: value.objectId});
printIfFailure(msg);
const printProperty = function(elem) {
const wasmValue = WasmInspectorTest.getWasmValue(elem.value);
return `"${elem.name}": ${wasmValue} (${elem.value.subtype})`;
}
return msg.result.result.map(printProperty).join(', ');
}
return WasmInspectorTest.getWasmValue(value) + ' (' + value.subtype + ')';
}
function recursiveGetPropertiesWrapper(value, depth) {
return recursiveGetProperties({result: {result: [value]}}, depth);
}
async function recursiveGetProperties(value, depth) {
if (depth > 0) {
const properties = await Promise.all(value.result.result.map(
x => {return Protocol.Runtime.getProperties({objectId: x.value.objectId});}));
const recursiveProperties = await Promise.all(properties.map(
x => {return recursiveGetProperties(x, depth - 1);}));
return recursiveProperties.flat();
}
return value;
}
async function dumpInstanceProperties(instanceObj) {
function invokeGetter(property) {
return this[JSON.parse(property)];
}
const exportsName = 'exports';
let exportsObj = await Protocol.Runtime.callFunctionOn(
{objectId: instanceObj.objectId,
functionDeclaration: invokeGetter.toString(),
arguments: [{value: JSON.stringify(exportsName)}]
});
printIfFailure(exportsObj);
let exports = await Protocol.Runtime.getProperties(
{objectId: exportsObj.result.result.objectId});
printIfFailure(exports);
const printExports = function(value) {
return `"${value.name}" (${value.value.className})`;
}
const formattedExports = exports.result.result.map(printExports).join(', ');
return `${exportsName}: ${formattedExports}`
}