v8/test/mjsunit/asm/asm-validation.js
Michael Starzinger fe9c60c175 [asm.js] Maintain global order of exported functions.
This makes sure that the order of exports as they appear in asm.js
modules is maintained globally (not just per function) while being
translated to a WASM module.

R=clemensh@chromium.org
TEST=mjsunit/asm/asm-validation
BUG=chromium:720586

Change-Id: I8b26d717ae2f88467d41670bced901f196c7b3fc
Reviewed-on: https://chromium-review.googlesource.com/503708
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Reviewed-by: Clemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#45277}
2017-05-12 12:11:06 +00:00

500 lines
11 KiB
JavaScript

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