v8/test/mjsunit/wasm/exceptions.js
Clemens Hammacher 45618a9ab5 [wasm] Make prototype flags experimental
Most prototype implementations are not fully supported in the
interpreter. This is the case at least for exception handling, simd, and
atomics. Any function can be redirected to the interpreter though,
either by passing --wasm-interpret-all, or by dynamically redirecting to
the interpreter for debugging.
Making the flags experimental keeps the fuzzer from playing around with
these flags.

Drive-by: Refactor tests which explicitly set the prototype flag to use
a new scope for that.

R=ahaas@chromium.org
BUG=chromium:727584

Change-Id: I67da79f579f1ac93c67189afef40c6524bdd4430
Reviewed-on: https://chromium-review.googlesource.com/519402
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#45639}
2017-05-31 14:18:08 +00:00

384 lines
12 KiB
JavaScript

// Copyright 2015 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: --expose-wasm --experimental-wasm-eh
load("test/mjsunit/wasm/wasm-constants.js");
load("test/mjsunit/wasm/wasm-module-builder.js");
// The following methods do not attempt to catch the exception they raise.
var test_throw = (function () {
var builder = new WasmModuleBuilder();
builder.addFunction("throw_param_if_not_zero", kSig_i_i)
.addBody([
kExprGetLocal, 0,
kExprI32Const, 0,
kExprI32Ne,
kExprIf, kWasmStmt,
kExprGetLocal, 0,
kExprThrow,
kExprEnd,
kExprI32Const, 1
])
.exportFunc()
builder.addFunction("throw_20", kSig_v_v)
.addBody([
kExprI32Const, 20,
kExprThrow,
])
.exportFunc()
builder.addFunction("throw_expr_with_params", kSig_v_ddi)
.addBody([
// p2 * (p0 + min(p0, p1))|0 - 20
kExprGetLocal, 2,
kExprGetLocal, 0,
kExprGetLocal, 0,
kExprGetLocal, 1,
kExprF64Min,
kExprF64Add,
kExprI32SConvertF64,
kExprI32Mul,
kExprI32Const, 20,
kExprI32Sub,
kExprThrow,
])
.exportFunc()
return builder.instantiate();
})();
// Check the test_throw exists.
assertFalse(test_throw === undefined);
assertFalse(test_throw === null);
assertFalse(test_throw === 0);
assertEquals("object", typeof test_throw.exports);
assertEquals("function", typeof test_throw.exports.throw_param_if_not_zero);
assertEquals("function", typeof test_throw.exports.throw_20);
assertEquals("function", typeof test_throw.exports.throw_expr_with_params);
assertEquals(1, test_throw.exports.throw_param_if_not_zero(0));
assertWasmThrows(10, function() { test_throw.exports.throw_param_if_not_zero(10) });
assertWasmThrows(-1, function() { test_throw.exports.throw_param_if_not_zero(-1) });
assertWasmThrows(20, test_throw.exports.throw_20);
assertWasmThrows(
-8, function() { test_throw.exports.throw_expr_with_params(1.5, 2.5, 4); });
assertWasmThrows(
12, function() { test_throw.exports.throw_expr_with_params(5.7, 2.5, 4); });
// Now that we know throwing works, we test catching the exceptions we raise.
var test_catch = (function () {
var builder = new WasmModuleBuilder();
// Helper function for throwing from js. It is imported by the Wasm module
// as throw_i.
function throw_value(value) {
throw value;
}
var sig_index = builder.addType(kSig_v_i);
var kJSThrowI = builder.addImport("", "throw_i", sig_index);
// Helper function that throws a string. Wasm should not catch it.
function throw_string() {
throw "use wasm;";
}
sig_index = builder.addType(kSig_v_v);
var kJSThrowString = builder.addImport("", "throw_string", sig_index);
// Helper function that throws undefined. Wasm should not catch it.
function throw_undefined() {
throw undefined;
}
var kJSThrowUndefined = builder.addImport("", "throw_undefined", sig_index);
// Helper function that throws an fp. Wasm should not catch it.
function throw_fp() {
throw 10.5;
}
var kJSThrowFP = builder.addImport("", "throw_fp", sig_index);
// Helper function that throws a large number. Wasm should not catch it.
function throw_large() {
throw 1e+28;
}
var kJSThrowLarge = builder.addImport("", "throw_large", sig_index);
// Helper function for throwing from WebAssembly.
var kWasmThrowFunction =
builder.addFunction("throw", kSig_v_i)
.addBody([
kExprGetLocal, 0,
kExprThrow
])
.index;
// Scenario 1: Throw and catch appear on the same function. This should
// happen in case of inlining, for example.
builder.addFunction("same_scope", kSig_i_i)
.addBody([
kExprTry, kWasmI32,
kExprGetLocal, 0,
kExprI32Const, 0,
kExprI32Ne,
kExprIf, kWasmStmt,
kExprGetLocal, 0,
kExprThrow,
kExprUnreachable,
kExprEnd,
kExprI32Const, 63,
kExprCatch, 1,
kExprGetLocal, 1,
kExprEnd
])
.addLocals({i32_count: 1})
.exportFunc()
.index;
builder.addFunction("same_scope_ignore", kSig_i_i)
.addBody([
kExprTry, kWasmI32,
kExprGetLocal, 0,
kExprThrow,
kExprUnreachable,
kExprCatch, 1,
kExprGetLocal, 0,
kExprEnd,
])
.addLocals({i32_count: 1})
.exportFunc();
builder.addFunction("same_scope_multiple", kSig_i_i)
// path = 0;
//
// try {
// try {
// try {
// if (p == 1)
// throw 1;
// path |= 2
// } catch (v) {
// path |= v | 4;
// throw path;
// }
// if (p == 2)
// throw path|8;
// path |= 16;
// } catch (v) {
// path |= v | 32;
// throw path;
// }
// if (p == 3)
// throw path|64;
// path |= 128
// } catch (v) {
// path |= v | 256;
// }
//
// return path;
//
// p == 1 -> path == 293
// p == 2 -> path == 298
// p == 3 -> path == 338
// else -> path == 146
.addBody([
kExprTry, kWasmI32,
kExprTry, kWasmI32,
kExprTry, kWasmI32,
kExprGetLocal, 0,
kExprI32Const, 1,
kExprI32Eq,
kExprIf, kWasmStmt,
kExprI32Const, 1,
kExprThrow,
kExprUnreachable,
kExprEnd,
kExprI32Const, 2,
kExprCatch, 1,
kExprGetLocal, 1,
kExprI32Const, 4,
kExprI32Ior,
kExprThrow,
kExprUnreachable,
kExprEnd,
kExprTeeLocal, 2,
kExprGetLocal, 0,
kExprI32Const, 2,
kExprI32Eq,
kExprIf, kWasmStmt,
kExprGetLocal, 2,
kExprI32Const, 8,
kExprI32Ior,
kExprThrow,
kExprUnreachable,
kExprEnd,
kExprI32Const, 16,
kExprI32Ior,
kExprCatch, 1,
kExprGetLocal, 1,
kExprI32Const, 32,
kExprI32Ior,
kExprThrow,
kExprUnreachable,
kExprEnd,
kExprTeeLocal, 2,
kExprGetLocal, 0,
kExprI32Const, 3,
kExprI32Eq,
kExprIf, kWasmStmt,
kExprGetLocal, 2,
kExprI32Const, /*64=*/ 192, 0,
kExprI32Ior,
kExprThrow,
kExprUnreachable,
kExprEnd,
kExprI32Const, /*128=*/ 128, 1,
kExprI32Ior,
kExprCatch, 1,
kExprGetLocal, 1,
kExprI32Const, /*256=*/ 128, 2,
kExprI32Ior,
kExprEnd,
])
.addLocals({i32_count: 2})
.exportFunc();
// Scenario 2: Catches an exception raised from the direct callee.
var kFromDirectCallee =
builder.addFunction("from_direct_callee", kSig_i_i)
.addBody([
kExprTry, kWasmI32,
kExprGetLocal, 0,
kExprCallFunction, kWasmThrowFunction,
kExprI32Const, /*-1=*/ 127,
kExprCatch, 1,
kExprGetLocal, 1,
kExprEnd
])
.addLocals({i32_count: 1})
.exportFunc()
.index;
// Scenario 3: Catches an exception raised from an indirect callee.
var kFromIndirectCalleeHelper = kFromDirectCallee + 1;
builder.addFunction("from_indirect_callee_helper", kSig_v_ii)
.addBody([
kExprGetLocal, 0,
kExprI32Const, 0,
kExprI32GtS,
kExprIf, kWasmStmt,
kExprGetLocal, 0,
kExprI32Const, 1,
kExprI32Sub,
kExprGetLocal, 1,
kExprI32Const, 1,
kExprI32Sub,
kExprCallFunction, kFromIndirectCalleeHelper,
kExprEnd,
kExprGetLocal, 1,
kExprCallFunction, kWasmThrowFunction,
]);
builder.addFunction("from_indirect_callee", kSig_i_i)
.addBody([
kExprTry, kWasmI32,
kExprGetLocal, 0,
kExprI32Const, 0,
kExprCallFunction, kFromIndirectCalleeHelper,
kExprI32Const, /*-1=*/ 127,
kExprCatch, 1,
kExprGetLocal, 1,
kExprEnd
])
.addLocals({i32_count: 1})
.exportFunc();
// Scenario 4: Catches an exception raised in JS.
builder.addFunction("from_js", kSig_i_i)
.addBody([
kExprTry, kWasmI32,
kExprGetLocal, 0,
kExprCallFunction, kJSThrowI,
kExprI32Const, /*-1=*/ 127,
kExprCatch, 1,
kExprGetLocal, 1,
kExprEnd,
])
.addLocals({i32_count: 1})
.exportFunc();
// Scenario 5: Does not catch an exception raised in JS if it is not a
// number.
builder.addFunction("string_from_js", kSig_v_v)
.addBody([
kExprCallFunction, kJSThrowString
])
.exportFunc();
builder.addFunction("fp_from_js", kSig_v_v)
.addBody([
kExprCallFunction, kJSThrowFP
])
.exportFunc();
builder.addFunction("large_from_js", kSig_v_v)
.addBody([
kExprCallFunction, kJSThrowLarge
])
.exportFunc();
builder.addFunction("undefined_from_js", kSig_v_v)
.addBody([
kExprCallFunction, kJSThrowUndefined
])
.exportFunc();
return builder.instantiate({"": {
throw_i: throw_value,
throw_string: throw_string,
throw_fp: throw_fp,
throw_large, throw_large,
throw_undefined: throw_undefined
}});
})();
// Check the test_catch exists.
assertFalse(test_catch === undefined);
assertFalse(test_catch === null);
assertFalse(test_catch === 0);
assertEquals("object", typeof test_catch.exports);
assertEquals("function", typeof test_catch.exports.same_scope);
assertEquals("function", typeof test_catch.exports.same_scope_ignore);
assertEquals("function", typeof test_catch.exports.same_scope_multiple);
assertEquals("function", typeof test_catch.exports.from_direct_callee);
assertEquals("function", typeof test_catch.exports.from_indirect_callee);
assertEquals("function", typeof test_catch.exports.from_js);
assertEquals("function", typeof test_catch.exports.string_from_js);
assertEquals(63, test_catch.exports.same_scope(0));
assertEquals(1024, test_catch.exports.same_scope(1024));
assertEquals(-3, test_catch.exports.same_scope(-3));
assertEquals(-1, test_catch.exports.same_scope_ignore(-1));
assertEquals(1, test_catch.exports.same_scope_ignore(1));
assertEquals(0x7FFFFFFF, test_catch.exports.same_scope_ignore(0x7FFFFFFF));
assertEquals(1024, test_catch.exports.same_scope_ignore(1024));
assertEquals(-1, test_catch.exports.same_scope_ignore(-1));
assertEquals(293, test_catch.exports.same_scope_multiple(1));
assertEquals(298, test_catch.exports.same_scope_multiple(2));
assertEquals(338, test_catch.exports.same_scope_multiple(3));
assertEquals(146, test_catch.exports.same_scope_multiple(0));
assertEquals(-10024, test_catch.exports.from_direct_callee(-10024));
assertEquals(3334333, test_catch.exports.from_direct_callee(3334333));
assertEquals(-1, test_catch.exports.from_direct_callee(0xFFFFFFFF));
assertEquals(0x7FFFFFFF, test_catch.exports.from_direct_callee(0x7FFFFFFF));
assertEquals(-10, test_catch.exports.from_indirect_callee(10));
assertEquals(-77, test_catch.exports.from_indirect_callee(77));
assertEquals(10, test_catch.exports.from_js(10));
assertEquals(-10, test_catch.exports.from_js(-10));
assertThrowsEquals(test_catch.exports.string_from_js, "use wasm;");
assertThrowsEquals(test_catch.exports.large_from_js, 1e+28);
assertThrowsEquals(test_catch.exports.undefined_from_js, undefined);