v8/test/inspector/wasm-inspector-test.js
Matthias Liedtke 40a156813e [testing][wasm] Inspector: Print 'null' for empty table entries
The wrapper obects for the debugger displayed e.g. in dev tools
contain a proper `null` value already.

Note: This only affects the printing of wasm tables in the test.
Change-Id: I3c2e9580b0a3983b66b9c3e2e16e5a2b322a9ff7
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4020261
Auto-Submit: Matthias Liedtke <mliedtke@chromium.org>
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Reviewed-by: Manos Koukoutos <manoskouk@chromium.org>
Cr-Commit-Position: refs/heads/main@{#84201}
2022-11-11 10:53:52 +00:00

177 lines
6.4 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 = async function(expression, url) {
const sourceURL = `v8://test/${url}`;
const {result: {scriptId}} = await Protocol.Runtime.compileScript({
expression, sourceURL, persistScript: true}).then(printIfFailure);
return await Protocol.Runtime
.runScript({scriptId})
.then(printIfFailure);
};
WasmInspectorTest.compileFromBuffer = (function(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;
}
return new WebAssembly.Module(buffer);
}).toString();
WasmInspectorTest.instantiateFromBuffer =
(function(bytes, imports) {
return new WebAssembly.Instance(compileFromBuffer(bytes), imports);
})
.toString()
.replace('compileFromBuffer', WasmInspectorTest.compileFromBuffer);
WasmInspectorTest.compile = async function(bytes, module_name = 'module') {
const compile_code = `var ${module_name} = (${
WasmInspectorTest.compileFromBuffer})(${JSON.stringify(bytes)});`;
await WasmInspectorTest.evalWithUrl(compile_code, 'compile_module');
};
WasmInspectorTest.instantiate =
async function(bytes, instance_name = 'instance', imports) {
const instantiate_code = `var ${instance_name} = (${
WasmInspectorTest.instantiateFromBuffer})(${JSON.stringify(bytes)},
${imports});`;
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 = async function(value) {
let msg = await Protocol.Runtime.getProperties({ objectId: value.objectId });
printIfFailure(msg);
const value_type = msg.result.result.find(({name}) => name === 'type');
const value_value = msg.result.result.find(({name}) => name === 'value');
return `${
value_value.value.unserializableValue ??
value_value.value.description ??
value_value.value.value} (${value_type.value.value})`;
};
function printIfFailure(message) {
if (!message.result || message.result.exceptionDetails) {
InspectorTest.logMessage(message);
}
return message;
}
async function getScopeValues(name, value) {
async function printValue(value) {
if (value.type === 'object' && value.subtype === 'wasmvalue') {
return await WasmInspectorTest.getWasmValue(value);
} else if ('className' in value) {
return `(${value.className})`;
}
return `${value.unserializableValue ?? value.value} (${
value.subtype ?? value.type})`;
}
if (value.type === 'object' && value.subtype !== 'wasmvalue') {
if (value.subtype === 'typedarray' || value.subtype == 'webassemblymemory')
return value.description;
if (name === 'instance') return dumpInstanceProperties(value);
if (name === 'module') return value.description;
if (name === 'tables') return dumpTables(value);
let msg = await Protocol.Runtime.getProperties({objectId: value.objectId});
printIfFailure(msg);
async function printProperty({name, value}) {
return `"${name}": ${await printValue(value)}`;
}
return (await Promise.all(msg.result.result.map(printProperty))).join(', ');
}
return await printValue(value);
}
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);
function printExports(value) {
return `"${value.name}" (${value.value.className})`;
}
const formattedExports = exports.result.result.map(printExports).join(', ');
return `${exportsName}: ${formattedExports}`
}
async function dumpTables(tablesObj) {
let msg =
await Protocol.Runtime.getProperties({objectId: tablesObj.objectId});
let tables_str = [];
for (let table of msg.result.result) {
let table_content =
await Protocol.Runtime.getProperties({objectId: table.value.objectId});
let entries_object = table_content.result.internalProperties.filter(
p => p.name === '[[Entries]]')[0];
entries = await Protocol.Runtime.getProperties(
{objectId: entries_object.value.objectId});
let functions = [];
for (let entry of entries.result.result) {
if (entry.name === 'length') continue;
let description = entry.value.description;
// For tables containing references, explore one level into the ref.
if (entry.value.objectId != null) {
let referencedObj = await Protocol.Runtime.getProperties(
{objectId: entry.value.objectId});
let value = referencedObj.result.result
.filter(prop => prop.name == "value")[0].value;
// If the value doesn't have a description, fall back to its value
// property. (For null this makes sure to print "null", as the null
// value doesn't have a description.)
value = value.description ?? value.value;
description = `${value} (${description})`;
}
functions.push(`${entry.name}: ${description}`);
}
const functions_str = functions.join(', ');
tables_str.push(` ${table.name}: ${functions_str}`);
}
return '\n' + tables_str.join('\n');
}