// ----------------------------------------------------------------------------- // This file contains tests checking Wasm functions with throwing functions and // try-catch code involving more complex control flow, testing that multiple // values returned from calls in try code are not affected by multiple branching // towards the landing pad, as well as making sure exceptions carrying multiple // values of any Wasm numtype transport the exception values correctly across // calls. // // There are tests for local direct calls, for imported direct calls, for // indirect calls in a local table with local functions, for indirect calls in a // local table of imported functions, and for indirect calls in an imported // table of imported functions. // // - TODO: Add reftype values, when support for reftypes in exceptions is // implemented. // -----------------------------------------------------------------------------
load(libdir + "eqArrayHelper.js");
// All individual tests take a string 'localThrow' as argument, and will be run // with each element of the result of the following function.
function generateLocalThrows(types, baseThrow) { // Arguments: // - 'types': A string of space separated Wasm types. // - 'baseThrow': A string with a Wasm instruction sequence of Wasm functype // `[${types}]-> [t*], which takes `types` arguments and ends // up throwing the tag '$exn'. // Result: // - A JS array of strings, each representing a Wasm instruction sequence // which is like `baseThrow', i.e., a Wasm instruction sequence of Wasm // functype `[${types}]-> [t*], which takes `types` arguments and ends up // throwing the tag '$exn'. The result does not include 'baseThrow'. // // All strings in Wasm text format.
let blockThrow =
`(block (param ${types})
${baseThrow})`;
// This Wasm code requires that the function it appears in has an i32 local // with name "$ifPredicate".
let conditionalThrow =
`(if (param ${types})
(local.get $ifPredicate)
(then ${baseThrow})
(else ${baseThrow}))`;
// Including try-delegate.
let baseDelegate =
`try (param ${types})
${baseThrow}
delegate 0`;
// Delegate just outside the block.
let nestedDelegate1InBlock =
`(block $label1 (param ${types}) try (param ${types})
${baseThrow}
delegate $label1)`;
let basicThrows = [catchlessTryThrow, blockThrow, conditionalThrow,
baseDelegate, nestedDelegate1InBlock]; if (wasmExnRefEnabled()) {
basicThrows = basicThrows.concat(catchlessThrowExnref, catchAndThrowExnref);
}
// Secondary throws (will end up inside a catch block).
for (let basicThrow of basicThrows) {
result.push(basicThrow);
let isExnref = basicThrow == catchlessThrowExnref || basicThrow == catchAndThrowExnref; for (let secondaryThrow of secondaryThrows) {
let isRethrow = secondaryThrow == baseRethrow || secondaryThrow == nestedRethrow || secondaryThrow == catchAllRethrowOriginal; if (isExnref && isRethrow) { continue;
}
result.push(basicNesting(basicThrow, secondaryThrow));
}
}
return result;
};
{ // Some variables to be used in all tests.
let typesJS = ["i32", "i64", "f32", "f64", "externref"];
let types = typesJS.join(" ");
// The following depend on whether simd is enabled or not. We write it like // this so we can run this test also when SIMD is not enabled.
let exntype = "";
let wrongV128 = "";
let throwV128 = "";
let checkV128Value = "";
let exnTypeDef = `(type $exnType (func (param ${exntype})))`;
let throwValues =
`;; Values to throw.
(i32.const 2)
(i64.const 3)
(f32.const 4)
(f64.const 13.37)
(local.get $correctRef)
${throwV128}`;
// The last 1 is the result of the test that the v128 value is correct, done // in wasm code (if simd is enabled).
let correctResultsJS = [2, 3n, 4, 13.37, "foo", 1];
// The individual tests. -----------------------------------------------------
function testDirectCallsThrowing(localThrow) { // Test direct function calls throwing any numeric value.
let throwifTypeInline = // The result of the "throwif" function will be used as an argument the // second time "throwif" is called.
`(param $ifPredicate i32) (param $correctRef externref) (result i32)`;
function testDirectLocalCallsThrowing() {
let mod = moduleHeaderThrowif + testModuleRest; // console.log("DIRECT LOCAL MOD = " + mod); // Uncomment for debugging.
// The main test function happens to have the same Wasm functype as the // indirect calls.
let testFuncHeader = `(func (export "testFunc") ${testFunctypeInline}
(local $ifPredicate i32)
`;
// To test indirect calls to a local table of local functions function moduleIndirectLocalLocal(functionBody) { return moduleHeader + testFuncHeader + functionBody + `))`;
};
let exports = wasmEvalText(moduleHeader + ")").exports; // Uncomment for debugging. //console.log("INDIRECT EXPORTS = " + moduleHeader + ")");
// To test indirect calls to a local table of imported functions. function moduleIndirectLocalImport(functionBody) { return moduleHeaderImporting +
`(table funcref (elem $throwExn $throwEmptyExn $returnArgs))` +
testFuncHeader + functionBody + `))`;
};
// To test indirect calls to an imported table of imported functions. function moduleIndirectImportImport(functionBody) { return moduleHeaderImporting +
`(import"m""tab" (table 3 funcref))` +
testFuncHeader + functionBody + `))`;
};
function getModuleTextsForFunctionBody(functionBody) { return [moduleIndirectLocalLocal(functionBody),
moduleIndirectLocalImport(functionBody),
moduleIndirectImportImport(functionBody)];
};
// The function bodies for the tests.
// Three indirect calls, the middle of which throws and will be caught. The // results of the first and second indirect calls are used by the next // indirect call. This should be called from try code, to check that the // pad-branches don't interfere with the results of each call.
let indirectThrow = `${throwValues}
(call_indirect (type $indirectFunctype) (i32.const 2)) ;; returnArgs
(call_indirect (type $indirectFunctype) (i32.const 0)) ;; throwExn
drop drop ;; Drop v128 and externref to do trivial and irrelevant ops.
(f64.const 5)
(f64.add)
(local.get $wrongRef)
${wrongV128}
;; throwEmptyExn
(call_indirect (type $indirectFunctype) (i32.const 1))
unreachable`;
// Simple try indirect throw and catch.
let simpleTryIndirect = ` try (result ${exntype})
${indirectThrow} catch $emptyExn
${wrongValues} catch $exn
catch_all
${wrongValues}
end
${checkV128Value}`;
// Indirect throw/catch_all, with a simple try indirect throw nested in the // catch_all.
let nestedTryIndirect =
`try (result ${types} i32)
${wrongValues}
;; throwEmptyExn
(call_indirect (type $indirectFunctype) (i32.const 1))
drop ;; Drop the last v128 value.
(i32.const 0)
catch_all
${simpleTryIndirect}
end`;
let functionBodies = [simpleTryIndirect, nestedTryIndirect];
// Test throwing from indirect calls. for (let functionBody of functionBodies) { // console.log("functionBody = : " + functionBody); // Uncomment for debugging.
for (let mod of getModuleTextsForFunctionBody(functionBody)) { //console.log("mod = : " + mod); // Uncomment for debugging.
let testFunction = wasmEvalText(mod, { m : exports}).exports.testFunc;
assertEqArray(testFunction("foo", "bar"),
correctResultsJS);
}
}
};
// Run all tests. ------------------------------------------------------------
let localThrows =
["(throw $exn)"].concat(generateLocalThrows(exntype, "(throw $exn)"));
for (let localThrow of localThrows) { // Uncomment for debugging. // console.log("Testing with localThrow = " + localThrow);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.