diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /js/src/jit-test/tests/wasm/function-references/nnl-test.js | |
parent | Initial commit. (diff) | |
download | firefox-esr-upstream.tar.xz firefox-esr-upstream.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/jit-test/tests/wasm/function-references/nnl-test.js')
-rw-r--r-- | js/src/jit-test/tests/wasm/function-references/nnl-test.js | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/wasm/function-references/nnl-test.js b/js/src/jit-test/tests/wasm/function-references/nnl-test.js new file mode 100644 index 0000000000..0036a7b30d --- /dev/null +++ b/js/src/jit-test/tests/wasm/function-references/nnl-test.js @@ -0,0 +1,172 @@ +// |jit-test| skip-if: !wasmFunctionReferencesEnabled() + +// Generates combinations of different block types and operations for +// non-defaultable locals (local.set / .tee / .get). +// See the function references specification on the updated algorithm +// for validating non-null references in locals. + +const KINDS = [ + "block", + "loop", + "try", + "catch", + "if", + "else", +] +const INITIALIZED = [ + "nowhere", + "outer", + "inner", + "outer-tee", + "inner-tee", +]; +const USED = [ + "outer", + "inner", + "after-inner", + "after-outer", +]; + +function generateBlock(kind, contents) { + switch (kind) { + case "block": { + return `block\n${contents}end\n` + } + case "loop": { + return `loop\n${contents}end\n` + } + case "try": { + return `try\n${contents}end\n` + } + case "catch": { + return `try\ncatch_all\n${contents}end\n` + } + case "if": { + return `i32.const 0\nif\n${contents}end\n` + } + case "else": { + return `i32.const 0\nif\nelse\n${contents}end\n` + } + } +} + +// Generate a variation of the module below: +// +// (func +// (block +// $outer +// (block +// $inner +// ) +// $after-inner +// ) +// $after-outer +// ) +// +// Where a local is used and initialized at different points depending on the +// parameters. The block kinds of the inner and outer block may also be +// customized. +function generateModule(outerBlockKind, innerBlockKind, initializedWhere, usedWhere) { + const INITIALIZE_STMT = '(local.set 0 ref.func 0)\n'; + const INITIALIZE_STMT2 = '(drop (local.tee 0 ref.func 0))\n'; + const USE_STMT = '(drop local.get 0)\n'; + + // inner block + let innerBlockContents = ''; + if (initializedWhere === 'inner') { + innerBlockContents += INITIALIZE_STMT; + } else if (initializedWhere === 'inner-tee') { + innerBlockContents += INITIALIZE_STMT2; + } + if (usedWhere === 'inner') { + innerBlockContents += USE_STMT; + } + let innerBlock = generateBlock(innerBlockKind, innerBlockContents); + + // outer block + let outerBlockContents = ''; + if (initializedWhere === 'outer') { + outerBlockContents += INITIALIZE_STMT; + } else if (initializedWhere === 'outer-tee') { + outerBlockContents += INITIALIZE_STMT2; + } + if (usedWhere === 'outer') { + outerBlockContents += USE_STMT; + } + outerBlockContents += innerBlock; + if (usedWhere === 'after-inner') { + outerBlockContents += USE_STMT; + } + let outerBlock = generateBlock(outerBlockKind, outerBlockContents); + + // after outer block + let afterOuterBlock = ''; + if (usedWhere === 'after-outer') { + afterOuterBlock += USE_STMT; + } + + return `(module + (type $t (func)) + (func (export "test") + (local (ref $t)) +${outerBlock}${afterOuterBlock} ) +)`; +} + +const LOGGING = false; + +for (let outer of KINDS) { + for (let inner of KINDS) { + for (let initialized of INITIALIZED) { + for (let used of USED) { + let text = generateModule(outer, inner, initialized, used); + + let expectPass; + switch (initialized) { + case "outer": + case "outer-tee": { + // Defining the local in the outer block makes it valid + // in the outer block, the inner block, and after the + // inner block + expectPass = used !== "after-outer"; + break; + } + case "inner": + case "inner-tee": { + // Defining the local in the inner block makes it valid + // in the inner block + // + // NOTE: an extension to typing could make this valid + // after the inner block in some cases + expectPass = used === "inner"; + break; + } + case "nowhere": { + // Not defining the local makes it always invalid to + // use + expectPass = false; + break; + } + } + + if (LOGGING) { + console.log(); + console.log(`TEST: outer=${outer}, inner=${inner}, initialized=${initialized}, used=${used}`); + console.log(expectPass ? "EXPECT PASS" : "EXPECT FAIL"); + console.log(text); + } + + let binary = wasmTextToBinary(text); + assertEq(WebAssembly.validate(binary), expectPass); + if (!expectPass) { + // Check if the error message is right. + try { + new WebAssembly.Module(binary); + } catch (ex) { + assertEq(true, /local\.get read from unset local/.test(ex.message)); + } + } + } + } + } +} |