node/deps/v8/test/mjsunit/wasm/wasm-to-js.js
Michaël Zasso 17a74ddd3d
deps: update V8 to 11.8.172.13
PR-URL: https://github.com/nodejs/node/pull/49639
Reviewed-By: Jiawen Geng <technicalcute@gmail.com>
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
2023-10-10 08:25:41 +02:00

280 lines
7.2 KiB
JavaScript

// Copyright 2023 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: --wasm-to-js-generic-wrapper --expose-gc
d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
const debug = false;
// Use consecutive values as parameters for easier debugging.
const easyValues = false;
// This test tests the wasm-to-js wrapper with random signatures and random
// values. The test creates a WebAssembly function with the random signature.
// The WebAssembly function passes the incoming parameters directly to an
// imported JavaScript function. The JavaScript function checks that the
// incoming parameters match the original values passed to the WebAssembly
// function. The imported JavaScript function then returns random return values,
// which the WebAssembly function again forwards to the original caller. There
// the return values of the WebAssembly function are compared with the original
// random return values. `RunTest` is the core function, which runs the test
// case for a specific signature and value mapping. `RunTest` can be used well
// for debugging a specific signature. `GenerateAndRunTest` additionally
// generates the inputs for `RunTest`, which is good for fuzzing the js-to-wasm
// wrappers.
// Some documentation if the test fails in the CQ.
console.log("This test is a fuzzer, it tests the generic wasm-to-js wrapper");
console.log("with random signatures. If this test fails, then it may not fail");
console.log("for the CL that actually introduced the issue, but for a");
console.log("later CL in the CQ. You may want to use flako to identify that");
console.log("actual culprit.");
const kPossibleTypes = [kWasmI32, kWasmI64, kWasmF32, kWasmF64, kWasmExternRef];
function getRandomInt(max) {
return Math.floor(Math.random() * max);
}
function TypeString(type) {
switch (type) {
case kWasmI32:
return 'kWasmI32';
case kWasmI64:
return 'kWasmI64';
case kWasmF32:
return 'kWasmF32';
case kWasmF64:
return 'kWasmF64';
case kWasmExternRef:
return 'kWasmExternRef';
}
}
// A set of interesting values that will be used as parameters.
let interestingParams = {};
interestingParams[kWasmI32] = [
-1500000000, -0x4000_0000, -0x3fff_ffff, -1, 0, 1, 2, 0x3fff_ffff,
0x4000_0000, 1500000000, 0x7fff_ffff, {valueOf: () => 15}, {
toString: () => {
gc();
return '17';
}
}
];
interestingParams[kWasmI64] = [
-0x7fff_ffff_ffff_ffffn, -0xffff_ffffn, -0x8000_0000n, -1500000000n,
-0x4000_0000n, -0x3fff_ffffn, -1n, 0n, 1n, 2n, 0x3fff_ffffn, 0x4000_0000n,
1500000000n, 0x7fff_ffffn, 0x8000_0000n, 0xffff_ffffn, 0x7fff_ffff_ffff_ffffn,
{valueOf: () => 15n}, {
toString: () => {
gc();
return '17';
}
}
];
interestingParams[kWasmF32] = [
-Infinity,
-(2 ** 65),
-(2 ** 64),
-(2 ** 63),
-(2 ** 62),
-(2 ** 29),
-(2 ** 33),
-(2 ** 32),
-(2 ** 31),
-(2 ** 30),
-(2 ** 29),
-1.5,
-1,
0,
-0,
1,
1.5,
2,
2 ** 29,
2 ** 30,
2 ** 31,
2 ** 32,
2 ** 33,
2 ** 62,
2 ** 63,
2 ** 64,
2 ** 65,
{valueOf: () => 16},
{
toString: () => {
gc();
return '18';
}
},
Infinity,
NaN
];
interestingParams[kWasmF64] = [
-Infinity,
-(2 ** 65),
-(2 ** 64),
-(2 ** 63),
-(2 ** 62),
-(2 ** 29),
-(2 ** 33),
-(2 ** 32),
-(2 ** 31),
-(2 ** 30),
-(2 ** 29),
-1.5,
-1,
0,
-0,
1,
1.5,
2,
// 28 set bits, too many for float32.
0xfffffff,
2 ** 29,
2 ** 30,
2 ** 31,
2 ** 32,
2 ** 33,
2 ** 62,
2 ** 63,
2 ** 64,
2 ** 65,
{valueOf: () => 14},
{
toString: () => {
gc();
return '19';
}
},
Infinity,
NaN
];
interestingParams[kWasmExternRef] = [
17, 12.5, 17n, 0x7fff_ffff, {foo: 18}, [1, 2, 3], 'bar', () => 38, null,
undefined
];
function GenerateValueArray(params) {
let result = [];
let nextValue = 1;
for (let param of params) {
if (easyValues) {
switch (param) {
case kWasmI32:
case kWasmF32:
case kWasmF64:
result.push(nextValue++);
break;
case kWasmI64:
result.push(BigInt(nextValue++));
break;
case kWasmExternRef:
const val = nextValue++;
result.push({ val: val });
}
} else {
result.push(interestingParams[param][getRandomInt(
interestingParams[param].length)]);
}
}
return result;
}
function assertValueArray(original, transformed) {
assertEquals(transformed.length, original.length);
for (let i = 0; i < transformed.length; ++i) {
const arg = transformed[i];
if (typeof arg === 'bigint') {
// For values of type I64.
assertEquals(BigInt(original[i]), arg);
} else if (typeof arg === 'number') {
// For values of type I32, F32, and F64.
assertEquals(Number(original[i]), arg);
} else {
// For values of type externref.
assertEquals(original[i], arg);
}
}
}
function RunTest(params, returns) {
if (debug) {
let testcase = 'RunTest([';
for (let i = 0; i < params.length; ++i) {
testcase += (i == 0 ? '' : ', ') + TypeString(params[i]);
}
testcase += '], [';
if (returns.length > 0) {
testcase += TypeString(returns[0]);
for (let i = 1; i < returns.length; ++i) {
testcase += ', ' + TypeString(returns[i]);
}
}
testcase += ']);';
console.log(testcase);
}
const builder = new WasmModuleBuilder();
const impSig = makeSig(params, returns);
const impIndex = builder.addImport('m', 'f', impSig);
const paramValues = GenerateValueArray(params);
const returnValues = GenerateValueArray(returns);
let body = [];
for (let i = 0; i < params.length; ++i) {
body.push(kExprLocalGet, i);
}
body.push(kExprCallFunction, impIndex);
function impFunction() {
assertValueArray(paramValues, arguments);
if (returns.length === 0) return;
if (returns.length === 1) return returnValues[0];
return returnValues;
};
const sig = makeSig(params, returns);
builder.addFunction('main', sig).addBody(body).exportFunc();
const instance = builder.instantiate({ m: { f: impFunction } });
let result = instance.exports.main(...paramValues);
if (returns.length === 0) return;
if (returns.length === 1) result = [result];
assertValueArray(returnValues, result);
}
function GenerateAndRunTest() {
// Generate signature.
const kMaxParams = 20;
const kMaxReturns = 10;
const numParams = getRandomInt(kMaxParams) + 1;
const numReturns = getRandomInt(kMaxReturns + 1);
// The array of parameter types.
const params = [];
// The array of return types.
const returns = [];
for (let i = 0; i < numParams; ++i) {
params.push(kPossibleTypes[getRandomInt(kPossibleTypes.length)]);
}
for (let i = 0; i < numReturns; ++i) {
returns.push(kPossibleTypes[getRandomInt(kPossibleTypes.length)]);
}
RunTest(params, returns);
}
// Regression tests:
RunTest(
[
kWasmF32, kWasmF64, kWasmF64, kWasmF32, kWasmI32, kWasmI64, kWasmF32,
kWasmF64, kWasmF64, kWasmF64, kWasmF32, kWasmF32
],
[kWasmI64, kWasmI64, kWasmI32, kWasmF32]);
for (let i = 0; i < (debug ? 200 : 2); ++i) {
GenerateAndRunTest();
}