| // Copyright 2016 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 --allow-natives-syntax |
| |
| 'use strict'; |
| |
| load("test/mjsunit/wasm/wasm-constants.js"); |
| load("test/mjsunit/wasm/wasm-module-builder.js"); |
| |
| function module(bytes) { |
| let buffer = bytes; |
| if (typeof buffer === 'string') { |
| buffer = new ArrayBuffer(bytes.length); |
| let view = new Uint8Array(buffer); |
| for (let i = 0; i < bytes.length; ++i) { |
| view[i] = bytes.charCodeAt(i); |
| } |
| } |
| return new WebAssembly.Module(buffer); |
| } |
| |
| function instance(bytes, imports = {}) { |
| return new WebAssembly.Instance(module(bytes), imports); |
| } |
| |
| // instantiate should succeed but run should fail. |
| function instantiateAndFailAtRuntime(bytes, imports = {}) { |
| var instance = |
| assertDoesNotThrow(new WebAssembly.Instance(module(bytes), imports)); |
| instance.exports.run(); |
| } |
| |
| function builder() { |
| return new WasmModuleBuilder; |
| } |
| |
| function assertCompileError(bytes, msg) { |
| assertThrows(() => module(bytes), WebAssembly.CompileError, msg); |
| } |
| |
| // default imports to {} so we get LinkError by default, thus allowing us to |
| // distinguish the TypeError we want to catch |
| function assertTypeError(bytes, imports = {}, msg) { |
| assertThrows(() => instance(bytes, imports), TypeError, msg); |
| } |
| |
| function assertLinkError(bytes, imports, msg) { |
| assertThrows(() => instance(bytes, imports), WebAssembly.LinkError, msg); |
| } |
| |
| function assertRuntimeError(bytes, imports, msg) { |
| assertThrows( |
| () => instantiateAndFailAtRuntime(bytes, imports), |
| WebAssembly.RuntimeError, msg); |
| } |
| |
| function assertConversionError(bytes, imports, msg) { |
| assertThrows( |
| () => instantiateAndFailAtRuntime(bytes, imports), TypeError, msg); |
| } |
| |
| (function TestDecodingError() { |
| assertCompileError("", /is empty/); |
| assertCompileError("X", /expected 4 bytes, fell off end @\+0/); |
| assertCompileError( |
| "\0x00asm", /expected magic word 00 61 73 6d, found 00 78 30 30 @\+0/); |
| })(); |
| |
| (function TestValidationError() { |
| assertCompileError( |
| builder().addFunction("f", kSig_i_v).end().toBuffer(), |
| /function body must end with "end" opcode @/); |
| assertCompileError(builder().addFunction("f", kSig_i_v).addBody([ |
| kExprReturn |
| ]).end().toBuffer(), /return found empty stack @/); |
| assertCompileError(builder().addFunction("f", kSig_v_v).addBody([ |
| kExprGetLocal, 0 |
| ]).end().toBuffer(), /invalid local index: 0 @/); |
| assertCompileError( |
| builder().addStart(0).toBuffer(), /function index 0 out of bounds/); |
| })(); |
| |
| (function TestTypeError() { |
| let b; |
| b = builder(); |
| b.addImport("foo", "bar", kSig_v_v); |
| assertTypeError(b.toBuffer(), {}, /module is not an object or function/); |
| |
| b = builder(); |
| b.addImportedGlobal("foo", "bar", kWasmI32); |
| assertTypeError(b.toBuffer(), {}, /module is not an object or function/); |
| |
| b = builder(); |
| b.addImportedMemory("foo", "bar"); |
| assertTypeError(b.toBuffer(), {}, /module is not an object or function/); |
| })(); |
| |
| (function TestLinkingError() { |
| let b; |
| |
| b = builder(); |
| b.addImport("foo", "bar", kSig_v_v); |
| assertLinkError( |
| b.toBuffer(), {foo: {}}, /function import requires a callable/); |
| b = builder(); |
| b.addImport("foo", "bar", kSig_v_v); |
| assertLinkError( |
| b.toBuffer(), {foo: {bar: 9}}, /function import requires a callable/); |
| |
| b = builder(); |
| b.addImportedGlobal("foo", "bar", kWasmI32); |
| assertLinkError(b.toBuffer(), {foo: {}}, /global import must be a number/); |
| b = builder(); |
| b.addImportedGlobal("foo", "bar", kWasmI32); |
| assertLinkError( |
| b.toBuffer(), {foo: {bar: ""}}, /global import must be a number/); |
| b = builder(); |
| b.addImportedGlobal("foo", "bar", kWasmI32); |
| assertLinkError( |
| b.toBuffer(), {foo: {bar: () => 9}}, /global import must be a number/); |
| |
| b = builder(); |
| b.addImportedMemory("foo", "bar"); |
| assertLinkError( |
| b.toBuffer(), {foo: {}}, |
| /memory import must be a WebAssembly\.Memory object/); |
| b = builder(); |
| b.addImportedMemory("foo", "bar", 1); |
| assertLinkError( |
| b.toBuffer(), {foo: {bar: () => new WebAssembly.Memory({initial: 0})}}, |
| /memory import must be a WebAssembly\.Memory object/); |
| |
| b = builder(); |
| b.addFunction("startup", kSig_v_v).addBody([ |
| kExprUnreachable, |
| ]).end().addStart(0); |
| assertRuntimeError(b.toBuffer(), {}, "unreachable"); |
| })(); |
| |
| (function TestTrapError() { |
| assertRuntimeError(builder().addFunction("run", kSig_v_v).addBody([ |
| kExprUnreachable |
| ]).exportFunc().end().toBuffer(), {}, "unreachable"); |
| |
| assertRuntimeError(builder().addFunction("run", kSig_v_v).addBody([ |
| kExprI32Const, 1, |
| kExprI32Const, 0, |
| kExprI32DivS, |
| kExprDrop |
| ]).exportFunc().end().toBuffer(), {}, "divide by zero"); |
| |
| assertRuntimeError(builder(). |
| addFunction("run", kSig_v_v).addBody([]).exportFunc().end(). |
| addFunction("start", kSig_v_v).addBody([kExprUnreachable]).end(). |
| addStart(1).toBuffer(), |
| {}, "unreachable"); |
| })(); |
| |
| (function TestConversionError() { |
| let b = builder(); |
| b.addImport("foo", "bar", kSig_v_l); |
| assertConversionError(b.addFunction("run", kSig_v_v).addBody([ |
| kExprI64Const, 0, kExprCallFunction, 0 |
| ]).exportFunc().end().toBuffer(), {foo:{bar: (l)=>{}}}, "invalid type"); |
| |
| b = builder() |
| assertConversionError(builder().addFunction("run", kSig_l_v).addBody([ |
| kExprI64Const, 0 |
| ]).exportFunc().end().toBuffer(), {}, "invalid type"); |
| })(); |
| |
| |
| (function InternalDebugTrace() { |
| var builder = new WasmModuleBuilder(); |
| var sig = builder.addType(kSig_i_dd); |
| builder.addImport("mod", "func", sig); |
| builder.addFunction("main", sig) |
| .addBody([kExprGetLocal, 0, kExprGetLocal, 1, kExprCallFunction, 0]) |
| .exportAs("main") |
| var main = builder.instantiate({ |
| mod: { |
| func: ()=>{%DebugTrace();} |
| } |
| }).exports.main; |
| main(); |
| })(); |