Chromium Code Reviews| Index: test/mjsunit/wasm/exceptions.js |
| diff --git a/test/mjsunit/wasm/exceptions.js b/test/mjsunit/wasm/exceptions.js |
| index 07b0bf4e0e18c3f2690ac59b05ec0ef87d781682..7fff1088d1848a3da94c077ad3bb4ed868ceec56 100644 |
| --- a/test/mjsunit/wasm/exceptions.js |
| +++ b/test/mjsunit/wasm/exceptions.js |
| @@ -7,61 +7,412 @@ |
| load("test/mjsunit/wasm/wasm-constants.js"); |
| load("test/mjsunit/wasm/wasm-module-builder.js"); |
| -var module = (function () { |
| +// 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, |
| - 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(); |
| + function always() { |
| + throw 50; |
| + } |
| + |
| + var sig_index = builder.addType(kSig_v_v); |
| + builder.addImport("_0", sig_index); |
| + |
| + builder.addFunction("throw_param_if_not_zero", kSig_i_i) |
| + .addBody([ |
| + kExprGetLocal, 0, |
| + kExprI32Const, 0, |
| + kExprI32Ne, |
| + kExprIf, |
| + kExprGetLocal, 0, |
| + kExprThrow, |
| + kExprEnd, |
| + kExprI32Const, 1 |
| + ]) |
| + .exportFunc() |
| + |
| + builder.addFunction("throw_20", kSig_i_v) |
| + .addBody([ |
| + kExprI32Const, 20, |
| + kExprThrow, |
| + kExprI32Const, 0 |
| + ]) |
| + .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({_0: always}); |
| })(); |
| -// Check the module exists. |
| -assertFalse(module === undefined); |
| -assertFalse(module === null); |
| -assertFalse(module === 0); |
| -assertEquals("object", typeof module.exports); |
| -assertEquals("function", typeof module.exports.throw_param_if_not_zero); |
| - |
| -assertEquals(1, module.exports.throw_param_if_not_zero(0)); |
| -assertWasmThrows(10, function() { module.exports.throw_param_if_not_zero(10) }); |
| -assertWasmThrows(-1, function() { module.exports.throw_param_if_not_zero(-1) }); |
| -assertWasmThrows(20, module.exports.throw_20); |
| +// 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() { module.exports.throw_expr_with_params(1.5, 2.5, 4); }); |
| + -8, function() { test_throw.exports.throw_expr_with_params(1.5, 2.5, 4); }); |
| assertWasmThrows( |
| - 12, function() { module.exports.throw_expr_with_params(5.7, 2.5, 4); }); |
| + 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(); |
| + |
| + function LEB128(value, size) { |
| + let bytes = []; |
| + |
| + let more = 1; |
| + let negative = (value < 0); |
| + while(more) { |
| + b = value & 0x7f; // low order 7 bits of value; |
| + value >>= 7; |
| + |
| + /* sign bit of byte is second high order bit (0x40) */ |
| + if (((value == 0) && ((b & 0x40) == 0)) || |
| + ((value == -1) && ((b & 0x40) != 0))) |
| + more = 0; |
| + else |
| + b |= 0x80; |
| + bytes = bytes.concat([b]); |
| + } |
| + |
| + return bytes; |
| + } |
| + |
| + function varint32(value) { |
| + let kBitsInI32 = 32; |
| + return LEB128(value, kBitsInI32); |
| + } |
| + |
| + // Helper function for throwing from Wasm. |
| + var kWasmThrowFunction = |
| + builder.addFunction("throw", kSig_v_i) |
| + .addBody([ |
| + kExprGetLocal, 0, |
| + kExprThrow |
| + ]) |
| + .index; |
| + |
| + // 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); |
| + |
| + // 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, |
| + kExprGetLocal, 0, |
| + kExprI32Const, 0, |
| + kExprI32Ne, |
| + kExprIf, |
| + kExprGetLocal, 0, |
| + kExprThrow, |
| + kExprEnd, |
| + kExprI32Const, 63, |
| + kExprCatch, 1, |
| + kExprGetLocal, 1, |
| + kExprEnd |
| + ]) |
| + .addLocals({i32_count: 1}) |
| + .exportFunc() |
| + .index; |
| + |
| + builder.addFunction("same_scope_ignore", kSig_i_i) |
| + .addBody([ |
| + kExprTry, |
| + 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, |
|
bradnelson
2016/09/27 04:25:56
Shame how verbose these are.
We've been chatting a
John
2016/09/28 13:37:18
Acknowledged.
|
| + kExprTry, |
| + kExprTry, |
| + kExprGetLocal, 0, |
| + kExprI32Const, 1, |
| + kExprI32Eq, |
| + kExprIf, |
| + kExprI32Const, 1, |
| + kExprThrow, |
| + kExprUnreachable, |
| + kExprElse, |
| + kExprI32Const, 2, |
| + kExprEnd, |
| + kExprCatch, 1, |
| + kExprGetLocal, 1, |
| + kExprI32Const, 4, |
| + kExprI32Ior, |
| + kExprThrow, |
| + kExprUnreachable, |
| + kExprEnd, |
| + kExprSetLocal, 2, |
| + kExprGetLocal, 0, |
| + kExprI32Const, 2, |
| + kExprI32Eq, |
| + kExprIf, |
| + kExprGetLocal, 2, |
| + kExprI32Const, 8, |
| + kExprI32Ior, |
| + kExprThrow, |
| + kExprUnreachable, |
| + kExprElse, |
| + kExprI32Const, 16, |
| + kExprEnd, |
| + kExprI32Ior, |
| + kExprCatch, 1, |
| + kExprGetLocal, 1, |
| + kExprI32Const, 32, |
| + kExprI32Ior, |
| + kExprThrow, |
| + kExprUnreachable, |
| + kExprEnd, |
| + kExprSetLocal, 2, |
| + kExprGetLocal, 0, |
| + kExprI32Const, 3, |
| + kExprI32Eq, |
| + kExprIf, |
| + kExprGetLocal, 2, |
| + kExprI32Const].concat(varint32(64)).concat([ |
| + kExprI32Ior, |
| + kExprThrow, |
| + kExprUnreachable, |
| + kExprElse, |
| + kExprI32Const]).concat(varint32(128)).concat([ |
| + kExprEnd, |
| + kExprI32Ior, |
| + kExprCatch, 1, |
| + kExprGetLocal, 1, |
| + kExprI32Const]).concat(varint32(256)).concat([ |
| + 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, |
| + kExprGetLocal, 0, |
| + kExprCallFunction, kArity1, kWasmThrowFunction, |
| + kExprI32Const].concat(varint32(-1)).concat([ |
| + 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, |
| + kExprGetLocal, 0, |
| + kExprI32Const, 1, |
| + kExprI32Sub, |
| + kExprGetLocal, 1, |
| + kExprI32Const, 1, |
| + kExprI32Sub, |
| + kExprCallFunction, kArity2, kFromIndirectCalleeHelper, |
| + kExprEnd, |
| + kExprGetLocal, 1, |
| + kExprCallFunction, kArity1, kWasmThrowFunction |
| + ]); |
| + |
| + builder.addFunction("from_indirect_callee", kSig_i_i) |
| + .addBody([ |
| + kExprTry, |
| + kExprGetLocal, 0, |
| + kExprI32Const, 0, |
| + kExprCallFunction, kArity2, kFromIndirectCalleeHelper, |
| + kExprI32Const].concat(varint32(-1)).concat([ |
|
titzer
2016/09/28 12:53:31
The concats here are a little messy. Maybe just al
John
2016/09/28 13:37:18
Done.
|
| + 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, |
| + kExprGetLocal, 0, |
| + kExprCallImport, kArity1, kJSThrowI, |
| + kExprI32Const].concat(varint32(-1)).concat([ |
| + 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([ |
| + kExprCallImport, kArity0, kJSThrowString, |
| + ]) |
| + .exportFunc(); |
| + |
| + builder.addFunction("fp_from_js", kSig_v_v) |
| + .addBody([ |
| + kExprCallImport, kArity0, kJSThrowFP, |
| + ]) |
| + .exportFunc(); |
| + |
| + builder.addFunction("large_from_js", kSig_v_v) |
| + .addBody([ |
| + kExprCallImport, kArity0, kJSThrowLarge, |
| + ]) |
| + .exportFunc(); |
| + |
| + builder.addFunction("undefined_from_js", kSig_v_v) |
| + .addBody([ |
| + kExprCallImport, kArity0, 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(1024, test_catch.exports.same_scope_ignore(1024)); |
| +assertEquals(0x7FFFFFFF, test_catch.exports.same_scope_ignore(0x7FFFFFFF)); |
| +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); |