|  | // 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); | 
|  | })(); |