// 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); let buffer = b.addFunction('run', kSig_v_v) .addBody([kExprI64Const, 0, kExprCallFunction, 0]) .exportFunc() .end() .toBuffer(); assertConversionError( buffer, {foo: {bar: (l) => {}}}, kTrapMsgs[kTrapTypeError]); buffer = builder() .addFunction('run', kSig_l_v) .addBody([kExprI64Const, 0]) .exportFunc() .end() .toBuffer(); assertConversionError(buffer, {}, kTrapMsgs[kTrapTypeError]); })(); (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(); })();