49106e4858
This is a second attempt at landing CL 644866 which was reverted by CL 667019. Extends the current implementation of WASM exceptions to be able to throw exceptions with values (not just tags). A JS typed (uint_16) array is used to hold the thrown values. This allows all WASM types to be stored (i32, i64, f32, and f64) as well as be inspected in JS. The previous CL was reverted because the WASM compiler made calls to run time functions with tagged objects, which must not be done. To fix this, all run time calls use the thread-level isolate to hold the exception being processed. Bug: v8:6577 Change-Id: I4b1ef7e2847b71a2fab8e9934a0531057db9de63 Reviewed-on: https://chromium-review.googlesource.com/677056 Commit-Queue: Karl Schimpf <kschimpf@chromium.org> Reviewed-by: Clemens Hammacher <clemensh@chromium.org> Reviewed-by: Eric Holk <eholk@chromium.org> Cr-Commit-Position: refs/heads/master@{#48148}
730 lines
23 KiB
JavaScript
730 lines
23 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 method doesn't attempt to catch an raised exception.
|
|
var test_throw = (function () {
|
|
var builder = new WasmModuleBuilder();
|
|
|
|
builder.addException(kSig_v_v);
|
|
|
|
builder.addFunction("throw_if_param_not_zero", kSig_i_i)
|
|
.addBody([
|
|
kExprGetLocal, 0,
|
|
kExprI32Const, 0,
|
|
kExprI32Ne,
|
|
kExprIf, kWasmStmt,
|
|
kExprThrow, 0,
|
|
kExprEnd,
|
|
kExprI32Const, 1
|
|
]).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_if_param_not_zero);
|
|
|
|
// Test expected behavior of throws
|
|
assertEquals(1, test_throw.exports.throw_if_param_not_zero(0));
|
|
assertWasmThrows(0, [], function() { test_throw.exports.throw_if_param_not_zero(10) });
|
|
assertWasmThrows(0, [], function() { test_throw.exports.throw_if_param_not_zero(-1) });
|
|
|
|
// Now that we know throwing works, we test catching the exceptions we raise.
|
|
var test_catch = (function () {
|
|
var builder = new WasmModuleBuilder();
|
|
|
|
builder.addException(kSig_v_v);
|
|
builder.addFunction("simple_throw_catch_to_0_1", kSig_i_i)
|
|
.addBody([
|
|
kExprTry, kWasmI32,
|
|
kExprGetLocal, 0,
|
|
kExprI32Eqz,
|
|
kExprIf, kWasmStmt,
|
|
kExprThrow, 0,
|
|
kExprEnd,
|
|
kExprI32Const, 1,
|
|
kExprCatch, 0,
|
|
kExprI32Const, 0,
|
|
kExprEnd
|
|
]).exportFunc();
|
|
|
|
return builder.instantiate();
|
|
})();
|
|
|
|
// 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.simple_throw_catch_to_0_1);
|
|
|
|
// Test expected behavior of simple catch.
|
|
assertEquals(0, test_catch.exports.simple_throw_catch_to_0_1(0));
|
|
assertEquals(1, test_catch.exports.simple_throw_catch_to_0_1(1));
|
|
|
|
// Test that we can distinguish which exception was thrown.
|
|
var test_catch_2 = (function () {
|
|
var builder = new WasmModuleBuilder();
|
|
|
|
builder.addException(kSig_v_v);
|
|
builder.addException(kSig_v_v);
|
|
builder.addException(kSig_v_v);
|
|
builder.addFunction("catch_different_exceptions", kSig_i_i)
|
|
.addBody([
|
|
kExprTry, kWasmI32,
|
|
kExprTry, kWasmI32,
|
|
kExprGetLocal, 0,
|
|
kExprI32Eqz,
|
|
kExprIf, kWasmStmt,
|
|
kExprThrow, 0,
|
|
kExprElse,
|
|
kExprGetLocal, 0,
|
|
kExprI32Const, 1,
|
|
kExprI32Eq,
|
|
kExprIf, kWasmStmt,
|
|
kExprThrow, 1,
|
|
kExprElse,
|
|
kExprThrow, 2,
|
|
kExprEnd,
|
|
kExprEnd,
|
|
kExprI32Const, 2,
|
|
kExprCatch, 0,
|
|
kExprI32Const, 3,
|
|
kExprEnd,
|
|
kExprCatch, 1,
|
|
kExprI32Const, 4,
|
|
kExprEnd
|
|
]).exportFunc();
|
|
return builder.instantiate();
|
|
})();
|
|
|
|
assertFalse(test_catch_2 === undefined);
|
|
assertFalse(test_catch_2 === null);
|
|
assertFalse(test_catch_2 === 0);
|
|
assertEquals("object", typeof test_catch_2.exports);
|
|
assertEquals("function", typeof test_catch_2.exports.catch_different_exceptions);
|
|
|
|
assertEquals(3, test_catch_2.exports.catch_different_exceptions(0));
|
|
assertEquals(4, test_catch_2.exports.catch_different_exceptions(1));
|
|
assertWasmThrows(2, [], function() { test_catch_2.exports.catch_different_exceptions(2) });
|
|
|
|
// Test throwing an exception with multiple values.
|
|
var test_throw_1_2 = (function() {
|
|
var builder = new WasmModuleBuilder();
|
|
builder.addException(kSig_v_ii);
|
|
builder.addFunction("throw_1_2", kSig_v_v)
|
|
.addBody([
|
|
kExprI32Const, 1,
|
|
kExprI32Const, 2,
|
|
kExprThrow, 0,
|
|
]).exportFunc();
|
|
|
|
return builder.instantiate();
|
|
})();
|
|
|
|
assertFalse(test_throw_1_2 === undefined);
|
|
assertFalse(test_throw_1_2 === null);
|
|
assertFalse(test_throw_1_2 === 0);
|
|
assertEquals("object", typeof test_throw_1_2.exports);
|
|
assertEquals("function", typeof test_throw_1_2.exports.throw_1_2);
|
|
|
|
assertWasmThrows(0, [0, 1, 0, 2], function() { test_throw_1_2.exports.throw_1_2(); });
|
|
|
|
// Test throwing/catching the i32 parameter value.
|
|
var test_throw_catch_param_i = (function () {
|
|
var builder = new WasmModuleBuilder();
|
|
builder.addException(kSig_v_i);
|
|
builder.addFunction("throw_catch_param", kSig_i_i)
|
|
.addBody([
|
|
kExprTry, kWasmI32,
|
|
kExprGetLocal, 0,
|
|
kExprThrow, 0,
|
|
kExprI32Const, 2,
|
|
kExprCatch, 0,
|
|
kExprReturn,
|
|
kExprEnd,
|
|
]).exportFunc();
|
|
|
|
return builder.instantiate();
|
|
})();
|
|
|
|
assertFalse(test_throw_catch_param_i === undefined);
|
|
assertFalse(test_throw_catch_param_i === null);
|
|
assertFalse(test_throw_catch_param_i === 0);
|
|
assertEquals("object", typeof test_throw_catch_param_i.exports);
|
|
assertEquals("function",
|
|
typeof test_throw_catch_param_i.exports.throw_catch_param);
|
|
|
|
assertEquals(0, test_throw_catch_param_i.exports.throw_catch_param(0));
|
|
assertEquals(1, test_throw_catch_param_i.exports.throw_catch_param(1));
|
|
assertEquals(10, test_throw_catch_param_i.exports.throw_catch_param(10));
|
|
|
|
// Test the encoding of a thrown exception with an integer exception.
|
|
|
|
var test_throw_param_i = (function () {
|
|
var builder = new WasmModuleBuilder();
|
|
builder.addException(kSig_v_i);
|
|
builder.addFunction("throw_param", kSig_v_i)
|
|
.addBody([
|
|
kExprGetLocal, 0,
|
|
kExprThrow, 0,
|
|
]).exportFunc();
|
|
|
|
return builder.instantiate();
|
|
})();
|
|
|
|
assertFalse(test_throw_param_i === undefined);
|
|
assertFalse(test_throw_param_i === null);
|
|
assertFalse(test_throw_param_i === 0);
|
|
assertEquals("object", typeof test_throw_param_i.exports);
|
|
assertEquals("function",
|
|
typeof test_throw_param_i.exports.throw_param);
|
|
|
|
assertWasmThrows(0, [0, 5], function() { test_throw_param_i.exports.throw_param(5); });
|
|
assertWasmThrows(0, [6, 31026],
|
|
function() { test_throw_param_i.exports.throw_param(424242); });
|
|
|
|
// Test throwing/catching the f32 parameter value.
|
|
var test_throw_catch_param_f = (function () {
|
|
var builder = new WasmModuleBuilder();
|
|
builder.addException(kSig_v_f);
|
|
builder.addFunction("throw_catch_param", kSig_f_f)
|
|
.addBody([
|
|
kExprTry, kWasmF32,
|
|
kExprGetLocal, 0,
|
|
kExprThrow, 0,
|
|
kExprF32Const, 0, 0, 0, 0,
|
|
kExprCatch, 0,
|
|
kExprReturn,
|
|
kExprEnd,
|
|
]).exportFunc();
|
|
|
|
return builder.instantiate();
|
|
})();
|
|
|
|
assertFalse(test_throw_catch_param_f === undefined);
|
|
assertFalse(test_throw_catch_param_f === null);
|
|
assertFalse(test_throw_catch_param_f === 0);
|
|
assertEquals("object", typeof test_throw_catch_param_f.exports);
|
|
assertEquals("function",
|
|
typeof test_throw_catch_param_f.exports.throw_catch_param);
|
|
|
|
assertEquals(5.0, test_throw_catch_param_f.exports.throw_catch_param(5.0));
|
|
assertEquals(10.5, test_throw_catch_param_f.exports.throw_catch_param(10.5));
|
|
|
|
// Test the encoding of a thrown exception with a float value.
|
|
|
|
var test_throw_param_f = (function () {
|
|
var builder = new WasmModuleBuilder();
|
|
builder.addException(kSig_v_f);
|
|
builder.addFunction("throw_param", kSig_v_f)
|
|
.addBody([
|
|
kExprGetLocal, 0,
|
|
kExprThrow, 0,
|
|
]).exportFunc();
|
|
|
|
return builder.instantiate();
|
|
})();
|
|
|
|
assertFalse(test_throw_param_f === undefined);
|
|
assertFalse(test_throw_param_f === null);
|
|
assertFalse(test_throw_param_f === 0);
|
|
assertEquals("object", typeof test_throw_param_f.exports);
|
|
assertEquals("function",
|
|
typeof test_throw_param_f.exports.throw_param);
|
|
|
|
assertWasmThrows(0, [16544, 0],
|
|
function() { test_throw_param_f.exports.throw_param(5.0); });
|
|
assertWasmThrows(0, [16680, 0],
|
|
function() { test_throw_param_f.exports.throw_param(10.5); });
|
|
|
|
// Test throwing/catching an I64 value
|
|
var test_throw_catch_param_l = (function () {
|
|
var builder = new WasmModuleBuilder();
|
|
builder.addException(kSig_v_l);
|
|
builder.addFunction("throw_catch_param", kSig_i_i)
|
|
.addBody([
|
|
kExprGetLocal, 0,
|
|
kExprI64UConvertI32,
|
|
kExprSetLocal, 1,
|
|
kExprTry, kWasmI32,
|
|
kExprGetLocal, 1,
|
|
kExprThrow, 0,
|
|
kExprI32Const, 2,
|
|
kExprCatch, 0,
|
|
kExprGetLocal, 1,
|
|
kExprI64Eq,
|
|
kExprIf, kWasmI32,
|
|
kExprI32Const, 1,
|
|
kExprElse,
|
|
kExprI32Const, 0,
|
|
kExprEnd,
|
|
// TODO(kschimpf): Why is this return necessary?
|
|
kExprReturn,
|
|
kExprEnd,
|
|
]).addLocals({i64_count: 1}).exportFunc();
|
|
|
|
return builder.instantiate();
|
|
})();
|
|
|
|
assertFalse(test_throw_catch_param_l === undefined);
|
|
assertFalse(test_throw_catch_param_l === null);
|
|
assertFalse(test_throw_catch_param_l === 0);
|
|
assertEquals("object", typeof test_throw_catch_param_l.exports);
|
|
assertEquals("function",
|
|
typeof test_throw_catch_param_l.exports.throw_catch_param);
|
|
|
|
assertEquals(1, test_throw_catch_param_l.exports.throw_catch_param(5));
|
|
assertEquals(1, test_throw_catch_param_l.exports.throw_catch_param(0));
|
|
assertEquals(1, test_throw_catch_param_l.exports.throw_catch_param(-1));
|
|
|
|
// Test the encoding of a thrown exception with an I64 value.
|
|
|
|
var test_throw_param_l = (function () {
|
|
var builder = new WasmModuleBuilder();
|
|
builder.addException(kSig_v_l);
|
|
builder.addFunction("throw_param", kSig_v_ii)
|
|
.addBody([
|
|
kExprGetLocal, 0,
|
|
kExprI64UConvertI32,
|
|
kExprI64Const, 32,
|
|
kExprI64Shl,
|
|
kExprGetLocal, 1,
|
|
kExprI64UConvertI32,
|
|
kExprI64Ior,
|
|
kExprThrow, 0
|
|
]).exportFunc();
|
|
|
|
return builder.instantiate();
|
|
})();
|
|
|
|
assertFalse(test_throw_param_l === undefined);
|
|
assertFalse(test_throw_param_l === null);
|
|
assertFalse(test_throw_param_l === 0);
|
|
assertEquals("object", typeof test_throw_param_l.exports);
|
|
assertEquals("function",
|
|
typeof test_throw_param_l.exports.throw_param);
|
|
|
|
assertWasmThrows(0, [0, 10, 0, 5],
|
|
function() { test_throw_param_l.exports.throw_param(10, 5); });
|
|
assertWasmThrows(0, [65535, 65535, 0, 13],
|
|
function() { test_throw_param_l.exports.throw_param(-1, 13); });
|
|
|
|
// Test throwing/catching the F64 parameter value
|
|
var test_throw_catch_param_d = (function () {
|
|
var builder = new WasmModuleBuilder();
|
|
builder.addException(kSig_v_d);
|
|
builder.addFunction("throw_catch_param", kSig_d_d)
|
|
.addBody([
|
|
kExprTry, kWasmF64,
|
|
kExprGetLocal, 0,
|
|
kExprThrow, 0,
|
|
kExprF64Const, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
kExprCatch, 0,
|
|
kExprReturn,
|
|
kExprEnd,
|
|
]).exportFunc();
|
|
|
|
return builder.instantiate();
|
|
})();
|
|
|
|
assertFalse(test_throw_catch_param_d === undefined);
|
|
assertFalse(test_throw_catch_param_d === null);
|
|
assertFalse(test_throw_catch_param_d === 0);
|
|
assertEquals("object", typeof test_throw_catch_param_d.exports);
|
|
assertEquals("function",
|
|
typeof test_throw_catch_param_d.exports.throw_catch_param);
|
|
|
|
assertEquals(5.0, test_throw_catch_param_d.exports.throw_catch_param(5.0));
|
|
assertEquals(10.5, test_throw_catch_param_d.exports.throw_catch_param(10.5));
|
|
|
|
// Test the encoding of a thrown exception with an f64 value.
|
|
|
|
var test_throw_param_d = (function () {
|
|
var builder = new WasmModuleBuilder();
|
|
builder.addException(kSig_v_d);
|
|
builder.addFunction("throw_param", kSig_v_f)
|
|
.addBody([
|
|
kExprGetLocal, 0,
|
|
kExprF64ConvertF32,
|
|
kExprThrow, 0
|
|
]).exportFunc();
|
|
|
|
return builder.instantiate();
|
|
})();
|
|
|
|
assertFalse(test_throw_param_d === undefined);
|
|
assertFalse(test_throw_param_d === null);
|
|
assertFalse(test_throw_param_d === 0);
|
|
assertEquals("object", typeof test_throw_param_d.exports);
|
|
assertEquals("function",
|
|
typeof test_throw_param_d.exports.throw_param);
|
|
|
|
assertWasmThrows(0, [16404, 0, 0, 0],
|
|
function() { test_throw_param_d.exports.throw_param(5.0); });
|
|
assertWasmThrows(0, [16739, 4816, 0, 0],
|
|
function() { test_throw_param_d.exports.throw_param(10000000.5); });
|
|
|
|
/* TODO(kschimpf) Convert these tests to work for the proposed exceptions.
|
|
|
|
// The following methods do not attempt to catch the exception they raise.
|
|
var test_throw = (function () {
|
|
var builder = new WasmModuleBuilder();
|
|
|
|
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_expr_with_params);
|
|
|
|
assertEquals(1, test_throw.exports.throw_param_if_not_zero(0));
|
|
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);
|
|
*/
|