| // 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: --validate-asm --allow-natives-syntax | |
| // Note that this test file contains tests that explicitly check modules are | |
| // valid asm.js and then break them with invalid instantiation arguments. If | |
| // this script is run more than once (e.g. --stress-opt) then modules remain | |
| // broken in the second run and assertions would fail. We prevent re-runs. | |
| // Flags: --nostress-opt | |
| function assertValidAsm(func) { | |
| assertTrue(%IsAsmWasmCode(func)); | |
| } | |
| (function TestConst() { | |
| function Module(s) { | |
| "use asm"; | |
| var fround = s.Math.fround; | |
| // Global constants. These are treated just like numeric literals. | |
| const fConst = fround(-3.0); | |
| const dConst = -3.0; | |
| const iConst = -3; | |
| // consts can be used to initialize other consts. | |
| const fPrime = fConst; | |
| // The following methods verify that return statements with global constants | |
| // do not need type annotations. | |
| function f() { | |
| return fPrime; | |
| } | |
| function d() { | |
| return dConst; | |
| } | |
| function i() { | |
| return iConst; | |
| } | |
| // The following methods verify that locals initialized with global | |
| // constants do not need type annotations. | |
| function fVar() { | |
| var v = fPrime; | |
| return fround(v); | |
| } | |
| function iVar() { | |
| var v = iConst; | |
| return v|0; | |
| } | |
| function dVar() { | |
| var v = dConst; | |
| return +v; | |
| } | |
| return { | |
| f: f, d: d, i: i, | |
| fVar: fVar, dVar: dVar, iVar: iVar, | |
| }; | |
| } | |
| function DisallowAssignToConstGlobal() { | |
| const constant = 0; | |
| function invalid(i) { | |
| i = i|0; | |
| constant = i; | |
| return constant; | |
| } | |
| return invalid; | |
| } | |
| var m = Module(this); | |
| assertValidAsm(Module); | |
| assertEquals(-3, m.i()); | |
| assertEquals(-3.0, m.d()); | |
| assertEquals(Math.fround(-3.0), m.f()); | |
| assertEquals(-3, m.iVar()); | |
| assertEquals(-3.0, m.dVar()); | |
| assertEquals(Math.fround(-3.0), m.fVar()); | |
| var m = DisallowAssignToConstGlobal(); | |
| assertFalse(%IsAsmWasmCode(DisallowAssignToConstGlobal)); | |
| })(); | |
| (function TestModuleArgs() { | |
| function Module1(stdlib) { | |
| "use asm"; | |
| function foo() { } | |
| return { foo: foo }; | |
| } | |
| function Module2(stdlib, ffi) { | |
| "use asm"; | |
| function foo() { } | |
| return { foo: foo }; | |
| } | |
| function Module3(stdlib, ffi, heap) { | |
| "use asm"; | |
| function foo() { } | |
| return { foo: foo }; | |
| } | |
| var modules = [Module1, Module2, Module3]; | |
| var heap = new ArrayBuffer(1024 * 1024); | |
| for (var i = 0; i < modules.length; ++i) { | |
| print('Module' + (i + 1)); | |
| var module = modules[i]; | |
| var m = module(); | |
| assertValidAsm(module); | |
| var m = module({}); | |
| assertValidAsm(module); | |
| var m = module({}, {}); | |
| assertValidAsm(module); | |
| var m = module({}, {}, heap); | |
| assertValidAsm(module); | |
| var m = module({}, {}, heap, {}); | |
| assertValidAsm(module); | |
| } | |
| })(); | |
| (function TestBadModule() { | |
| function Module(stdlib, ffi, heap) { | |
| "use asm"; | |
| function foo() { var y = 3; var x = 1 + y; return 123; } | |
| return { foo: foo }; | |
| } | |
| var m = Module({}); | |
| assertFalse(%IsAsmWasmCode(Module)); | |
| assertEquals(123, m.foo()); | |
| })(); | |
| (function TestBadArgTypes() { | |
| function Module(a, b, c) { | |
| "use asm"; | |
| var NaN = a.NaN; | |
| return {}; | |
| } | |
| var m = Module(1, 2, 3); | |
| assertFalse(%IsAsmWasmCode(Module)); | |
| assertEquals({}, m); | |
| })(); | |
| (function TestBadArgTypesMismatch() { | |
| function Module(a, b, c) { | |
| "use asm"; | |
| var NaN = a.NaN; | |
| return {}; | |
| } | |
| var m = Module(1, 2); | |
| assertFalse(%IsAsmWasmCode(Module)); | |
| assertEquals({}, m); | |
| })(); | |
| (function TestModuleNoStdlib() { | |
| function Module() { | |
| "use asm"; | |
| function foo() { return 123; } | |
| return { foo: foo }; | |
| } | |
| var m = Module({}); | |
| assertValidAsm(Module); | |
| assertEquals(123, m.foo()); | |
| })(); | |
| (function TestModuleWith5() { | |
| function Module(a, b, c, d, e) { | |
| "use asm"; | |
| function foo() { return 123; } | |
| return { foo: foo }; | |
| } | |
| var heap = new ArrayBuffer(1024 * 1024); | |
| var m = Module({}, {}, heap); | |
| assertFalse(%IsAsmWasmCode(Module)); | |
| assertEquals(123, m.foo()); | |
| })(); | |
| (function TestModuleNoStdlibCall() { | |
| function Module(stdlib, ffi, heap) { | |
| "use asm"; | |
| function foo() { return 123; } | |
| return { foo: foo }; | |
| } | |
| var m = Module(); | |
| assertValidAsm(Module); | |
| assertEquals(123, m.foo()); | |
| })(); | |
| (function TestModuleNew() { | |
| function Module(stdlib, ffi, heap) { | |
| "use asm"; | |
| function foo() { return 123; } | |
| return { foo: foo }; | |
| } | |
| var m = new Module({}, {}); | |
| assertValidAsm(Module); | |
| assertEquals(123, m.foo()); | |
| })(); | |
| (function TestMultipleFailures() { | |
| function Module(stdlib) { | |
| "use asm"; | |
| var NaN = stdlib.NaN; | |
| function foo() { return 123; } | |
| return { foo: foo }; | |
| } | |
| var m1 = Module(1, 2, 3); | |
| assertFalse(%IsAsmWasmCode(Module)); | |
| var m2 = Module(1, 2, 3); | |
| assertFalse(%IsAsmWasmCode(Module)); | |
| assertEquals(123, m1.foo()); | |
| assertEquals(123, m2.foo()); | |
| })(); | |
| (function TestFailureThenSuccess() { | |
| function MkModule() { | |
| function Module(stdlib, ffi, heap) { | |
| "use asm"; | |
| var NaN = stdlib.NaN; | |
| function foo() { return 123; } | |
| return { foo: foo }; | |
| } | |
| return Module; | |
| } | |
| var Module1 = MkModule(); | |
| var Module2 = MkModule(); | |
| var heap = new ArrayBuffer(1024 * 1024); | |
| var m1 = Module1(1, 2, 3); | |
| assertFalse(%IsAsmWasmCode(Module1)); | |
| var m2 = Module2({}, {}, heap); | |
| assertFalse(%IsAsmWasmCode(Module2)); | |
| assertEquals(123, m1.foo()); | |
| assertEquals(123, m2.foo()); | |
| })(); | |
| (function TestSuccessThenFailure() { | |
| function MkModule() { | |
| function Module(stdlib, ffi, heap) { | |
| "use asm"; | |
| var NaN = stdlib.NaN; | |
| function foo() { return 123; } | |
| return { foo: foo }; | |
| } | |
| return Module; | |
| } | |
| var Module1 = MkModule(); | |
| var Module2 = MkModule(); | |
| var heap = new ArrayBuffer(1024 * 1024); | |
| var m1 = Module1({NaN: NaN}, {}, heap); | |
| assertValidAsm(Module1); | |
| var m2 = Module2(1, 2, 3); | |
| assertFalse(%IsAsmWasmCode(Module2)); | |
| assertEquals(123, m1.foo()); | |
| assertEquals(123, m2.foo()); | |
| })(); | |
| (function TestSuccessThenFailureThenRetry() { | |
| function MkModule() { | |
| function Module(stdlib, ffi, heap) { | |
| "use asm"; | |
| var NaN = stdlib.NaN; | |
| function foo() { return 123; } | |
| return { foo: foo }; | |
| } | |
| return Module; | |
| } | |
| var Module1 = MkModule(); | |
| var Module2 = MkModule(); | |
| var heap = new ArrayBuffer(1024 * 1024); | |
| var m1a = Module1({NaN: NaN}, {}, heap); | |
| assertValidAsm(Module1); | |
| var m2 = Module2(1, 2, 3); | |
| assertFalse(%IsAsmWasmCode(Module2)); | |
| var m1b = Module1({NaN: NaN}, {}, heap); | |
| assertFalse(%IsAsmWasmCode(Module1)); | |
| assertEquals(123, m1a.foo()); | |
| assertEquals(123, m1b.foo()); | |
| assertEquals(123, m2.foo()); | |
| })(); | |
| (function TestBoundFunction() { | |
| function Module(stdlib, ffi, heap) { | |
| "use asm"; | |
| function foo() { return 123; } | |
| return { foo: foo }; | |
| } | |
| var heap = new ArrayBuffer(1024 * 1024); | |
| var ModuleBound = Module.bind(this, {}, {}, heap); | |
| var m = ModuleBound(); | |
| assertValidAsm(Module); | |
| assertEquals(123, m.foo()); | |
| })(); | |
| (function TestBadConstUnsignedReturn() { | |
| function Module() { | |
| "use asm"; | |
| const i = 0xffffffff; | |
| function foo() { return i; } | |
| return { foo: foo }; | |
| } | |
| var m = Module(); | |
| assertFalse(%IsAsmWasmCode(Module)); | |
| assertEquals(0xffffffff, m.foo()); | |
| })(); | |
| (function TestBadBooleanParamAnnotation() { | |
| function Module() { | |
| "use asm"; | |
| function foo(x) { | |
| x = x | true; | |
| return x; | |
| } | |
| return { foo: foo }; | |
| } | |
| var m = Module(); | |
| assertFalse(%IsAsmWasmCode(Module)); | |
| assertEquals(3, m.foo(3)); | |
| })(); | |
| (function TestBadExportTwice() { | |
| function Module() { | |
| "use asm"; | |
| function bar() { return 1; } | |
| function baz() { return 2; } | |
| return {foo: bar, foo: baz}; | |
| } | |
| var m = Module(); | |
| assertTrue(%IsAsmWasmCode(Module)); | |
| assertEquals(2, m.foo()); | |
| })(); | |
| (function TestBadImport() { | |
| function Module(stdlib) { | |
| "use asm"; | |
| var set = 0; | |
| var foo = stdlib[set]; | |
| return {}; | |
| } | |
| var m = Module(this); | |
| assertFalse(%IsAsmWasmCode(Module)); | |
| })(); | |
| (function TestBadFroundTrue() { | |
| function Module(stdlib) { | |
| "use asm"; | |
| var fround = stdlib.Math.fround; | |
| function foo() { | |
| var x = fround(true); | |
| return +x; | |
| } | |
| return { foo: foo }; | |
| } | |
| var m = Module(this); | |
| assertFalse(%IsAsmWasmCode(Module)); | |
| assertEquals(1, m.foo()); | |
| })(); | |
| (function TestBadCase() { | |
| function Module() { | |
| "use asm"; | |
| function foo(x) { | |
| x = x | 0; | |
| switch (x|0) { | |
| case true: | |
| return 42; | |
| default: | |
| return 43; | |
| } | |
| return 0; | |
| } | |
| return { foo: foo }; | |
| } | |
| var m = Module(); | |
| assertFalse(%IsAsmWasmCode(Module)); | |
| assertEquals(43, m.foo(3)); | |
| })(); | |
| (function TestVarHidesExport() { | |
| function Module() { | |
| "use asm"; | |
| var foo; | |
| function foo() {} | |
| return foo; | |
| } | |
| Module(); | |
| assertFalse(%IsAsmWasmCode(Module)); | |
| })(); | |
| (function TestUndefinedGlobalCall() { | |
| function Module() { | |
| "use asm"; | |
| function foo() { | |
| return bar() | 0; | |
| } | |
| return foo; | |
| } | |
| Module(); | |
| assertFalse(%IsAsmWasmCode(Module)); | |
| })(); | |
| (function TestConditionalReturn() { | |
| function Module() { | |
| 'use asm'; | |
| function foo(a, b) { | |
| a = +a; | |
| b = +b; | |
| // Allowed, despite not matching the spec, as emscripten emits this in | |
| // practice. | |
| return a == b ? +a : +b; | |
| } | |
| return foo; | |
| } | |
| var m = Module(); | |
| assertEquals(4, m(4, 4)); | |
| assertEquals(5, m(4, 5)); | |
| assertEquals(4, m(5, 4)); | |
| assertValidAsm(Module); | |
| })(); | |
| (function TestMismatchedConditionalReturn() { | |
| function Module() { | |
| 'use asm'; | |
| function foo(a, b) { | |
| a = +a; | |
| return a == 0.0 ? 0 : +a; | |
| } | |
| return foo; | |
| } | |
| Module(); | |
| assertFalse(%IsAsmWasmCode(Module)); | |
| })(); | |
| (function TestBadIntConditionalReturn() { | |
| function Module() { | |
| 'use asm'; | |
| function foo(a, b) { | |
| a = a | 0; | |
| b = b | 0; | |
| // Disallowed because signature must be signed, but these will be int. | |
| return 1 ? a : b; | |
| } | |
| return foo; | |
| } | |
| Module(); | |
| assertFalse(%IsAsmWasmCode(Module)); | |
| })(); | |
| (function TestBadSignedConditionalReturn() { | |
| function Module() { | |
| 'use asm'; | |
| function foo(a, b) { | |
| a = a | 0; | |
| b = b | 0; | |
| // Disallowed because conditional yields int, even when both sides | |
| // are signed. | |
| return 1 ? a | 0 : b | 0; | |
| } | |
| return foo; | |
| } | |
| Module(); | |
| assertFalse(%IsAsmWasmCode(Module)); | |
| })(); | |
| (function TestAsmIsRegular() { | |
| function Module() { | |
| 'use asm'; | |
| var g = 123; | |
| function foo() { | |
| return g | 0; | |
| } | |
| return {x: foo}; | |
| } | |
| var o = Module(); | |
| assertValidAsm(Module); | |
| assertFalse(o instanceof WebAssembly.Instance); | |
| assertTrue(o instanceof Object); | |
| assertTrue(o.__proto__ === Object.prototype); | |
| var p = Object.getOwnPropertyDescriptor(o, "x") | |
| assertTrue(p.writable); | |
| assertTrue(p.enumerable); | |
| assertTrue(p.configurable); | |
| assertTrue(typeof o.x === 'function'); | |
| o.x = 5; | |
| assertTrue(typeof o.x === 'number'); | |
| assertTrue(o.__single_function__ === undefined); | |
| assertTrue(o.__foreign_init__ === undefined); | |
| })(); | |
| (function TestAsmExportOrderPreserved() { | |
| function Module() { | |
| "use asm"; | |
| function f() {} | |
| function g() {} | |
| return { a:f, b:g, x:f, c:g, d:f }; | |
| } | |
| var m = Module(); | |
| assertValidAsm(Module); | |
| var props = Object.getOwnPropertyNames(m); | |
| assertEquals(["a","b","x","c","d"], props); | |
| })(); |