// Copyright 2015 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 var stdlib = this; let kMinHeapSize = 4096; function assertValidAsm(func) { assertTrue(%IsAsmWasmCode(func), "must be valid asm code"); } function assertWasm(expected, func, ffi) { print("Testing " + func.name + "..."); assertEquals( expected, func(stdlib, ffi, new ArrayBuffer(kMinHeapSize)).caller()); assertValidAsm(func); } function EmptyTest(a, b, c) { "use asm"; function caller() { empty(); return 11; } function empty() { } return {caller: caller}; } assertWasm(11, EmptyTest); function VoidReturnTest(a, b, c) { "use asm"; function caller() { empty(); return 19; } function empty() { var x = 0; if (x) return; } return {caller: caller}; } assertWasm(19, VoidReturnTest); function IntTest(a, b, c) { "use asm"; function sum(a, b) { a = a|0; b = b|0; var c = 0; var d = 3.0; var e = 0; e = ~~d; // double conversion c = (b + 1)|0 return (a + c + 1)|0; } function caller() { return sum(77,22) | 0; } return {caller: caller}; } assertWasm(101,IntTest); function Float64Test() { "use asm"; function sum(a, b) { a = +a; b = +b; return +(a + b); } function caller() { var a = 0.0; var ret = 0; a = +sum(70.1,10.2); if (a == 80.3) { ret = 1|0; } else { ret = 0|0; } return ret|0; } return {caller: caller}; } assertWasm(1, Float64Test); function BadModule() { "use asm"; function caller(a, b) { a = a|0; b = b+0; var c = 0; c = (b + 1)|0 return (a + c + 1)|0; } function caller() { return call(1, 2)|0; } return {caller: caller}; } assertFalse(%IsAsmWasmCode(BadModule)); function TestReturnInBlock() { "use asm"; function caller() { if(1) { { { return 1; } } } return 0; } return {caller: caller}; } assertWasm(1, TestReturnInBlock); function TestAddSimple() { "use asm"; function caller() { var x = 0; x = (x + 1)|0; return x|0; } return {caller: caller}; } assertWasm(1, TestAddSimple); function TestWhileSimple() { "use asm"; function caller() { var x = 0; while((x|0) < 5) { x = (x + 1)|0; } return x|0; } return {caller: caller}; } assertWasm(5, TestWhileSimple); function TestWhileWithoutBraces() { "use asm"; function caller() { var x = 0; while((x|0) <= 3) x = (x + 1)|0; return x|0; } return {caller: caller}; } assertWasm(4, TestWhileWithoutBraces); function TestReturnInWhile() { "use asm"; function caller() { var x = 0; while((x|0) < 10) { x = (x + 6)|0; return x|0; } return x|0; } return {caller: caller}; } assertWasm(6, TestReturnInWhile); function TestReturnInWhileWithoutBraces() { "use asm"; function caller() { var x = 0; while((x|0) < 5) return 7; return x|0; } return {caller: caller}; } assertWasm(7, TestReturnInWhileWithoutBraces); function TestBreakInIf() { "use asm"; function caller() { label: { if(1) break label; return 11; } return 12; } return {caller: caller}; } assertWasm(12, TestBreakInIf); function TestBreakInIfInDoWhileFalse() { "use asm"; function caller() { do { if(1) break; return 11; } while(0); return 12; } return {caller: caller}; } assertWasm(12, TestBreakInIfInDoWhileFalse); function TestBreakInElse() { "use asm"; function caller() { do { if(0) ; else break; return 14; } while(0); return 15; } return {caller: caller}; } assertWasm(15, TestBreakInElse); function TestBreakInWhile() { "use asm"; function caller() { while(1) { break; } return 8; } return {caller: caller}; } assertWasm(8, TestBreakInWhile); function TestBreakInIfInWhile() { "use asm"; function caller() { while(1) { if (1) break; else break; } return 8; } return {caller: caller}; } assertWasm(8, TestBreakInIfInWhile); function TestBreakInNestedWhile() { "use asm"; function caller() { var x = 1.0; var ret = 0; while(x < 1.5) { while(1) break; x = +(x + 0.25); } if (x == 1.5) { ret = 9; } return ret|0; } return {caller: caller}; } assertWasm(9, TestBreakInNestedWhile); function TestBreakInBlock() { "use asm"; function caller() { var x = 0; abc: { x = 10; if ((x|0) == 10) { break abc; } x = 20; } return x|0; } return {caller: caller}; } assertWasm(10, TestBreakInBlock); function TestBreakInNamedWhile() { "use asm"; function caller() { var x = 0; outer: while (1) { x = (x + 1)|0; while ((x|0) == 11) { break outer; } } return x|0; } return {caller: caller}; } assertWasm(11, TestBreakInNamedWhile); function TestContinue() { "use asm"; function caller() { var x = 5; var ret = 0; while ((x|0) >= 0) { x = (x - 1)|0; if ((x|0) == 2) { continue; } ret = (ret - 1)|0; } return ret|0; } return {caller: caller}; } assertWasm(-5, TestContinue); function TestContinueInNamedWhile() { "use asm"; function caller() { var x = 5; var y = 0; var ret = 0; outer: while ((x|0) > 0) { x = (x - 1)|0; y = 0; while ((y|0) < 5) { if ((x|0) == 3) { continue outer; } ret = (ret + 1)|0; y = (y + 1)|0; } } return ret|0; } return {caller: caller}; } assertWasm(20, TestContinueInNamedWhile); function TestContinueInDoWhileFalse() { "use asm"; function caller() { do { continue; } while (0); return 47; } return {caller: caller}; } assertWasm(47, TestContinueInDoWhileFalse); function TestContinueInForLoop() { "use asm"; function caller() { var i = 0; for (; (i|0) < 10; i = (i+1)|0) { continue; } return 4711; } return {caller: caller}; } assertWasm(4711, TestContinueInForLoop); function TestNot() { "use asm"; function caller() { var a = 0; a = !(2 > 3); return a | 0; } return {caller:caller}; } assertWasm(1, TestNot); function TestNotEquals() { "use asm"; function caller() { var a = 3; if ((a|0) != 2) { return 21; } return 0; } return {caller:caller}; } assertWasm(21, TestNotEquals); function TestUnsignedComparison() { "use asm"; function caller() { var a = 0xffffffff; if ((a>>>0) > (0>>>0)) { return 22; } return 0; } return {caller:caller}; } assertWasm(22, TestUnsignedComparison); function TestMixedAdd() { "use asm"; function caller() { var a = 0x80000000; var b = 0x7fffffff; var c = 0; c = ((a>>>0) + b)|0; if ((c >>> 0) > (0>>>0)) { if ((c|0) < 0) { return 23; } } return 0; } return {caller:caller}; } assertWasm(23, TestMixedAdd); function TestConvertI32() { "use asm"; function caller() { var a = 1.5; if ((~~(a + a)) == 3) { return 24; } return 0; } return {caller:caller}; } assertWasm(24, TestConvertI32); function TestConvertF64FromInt() { "use asm"; function caller() { var a = 1; if ((+((a + a)|0)) > 1.5) { return 25; } return 0; } return {caller:caller}; } assertWasm(25, TestConvertF64FromInt); function TestConvertF64FromUnsigned() { "use asm"; function caller() { var a = 0xffffffff; if ((+(a>>>0)) > 0.0) { if((+(a|0)) < 0.0) { return 26; } } return 0; } return {caller:caller}; } assertWasm(26, TestConvertF64FromUnsigned); function TestModInt() { "use asm"; function caller() { var a = -83; var b = 28; return ((a|0)%(b|0))|0; } return {caller:caller}; } assertWasm(-27,TestModInt); function TestModUnsignedInt() { "use asm"; function caller() { var a = 0x80000000; //2147483648 var b = 10; return ((a>>>0)%(b>>>0))|0; } return {caller:caller}; } assertWasm(8, TestModUnsignedInt); function TestModDouble() { "use asm"; function caller() { var a = 5.25; var b = 2.5; if (a%b == 0.25) { return 28; } return 0; } return {caller:caller}; } assertWasm(28, TestModDouble); function TestModDoubleNegative() { "use asm"; function caller() { var a = -34359738368.25; var b = 2.5; if (a%b == -0.75) { return 28; } return 0; } return {caller:caller}; } assertWasm(28, TestModDoubleNegative); (function () { function TestNamedFunctions() { "use asm"; var a = 0.0; var b = 0.0; function add() { return +(a + b); } function init() { a = 43.25; b = 34.25; } return {init:init, add:add}; } var module_decl = eval('(' + TestNamedFunctions.toString() + ')'); var module = module_decl(stdlib); assertValidAsm(module_decl); module.init(); assertEquals(77.5, module.add()); })(); (function () { function TestGlobalsWithInit() { "use asm"; var a = 43.25; var b = 34.25; function add() { return +(a + b); } return {add:add}; } var module_decl = eval('(' + TestGlobalsWithInit.toString() + ')'); var module = module_decl(stdlib); assertValidAsm(module_decl); assertEquals(77.5, module.add()); })(); function TestForLoop() { "use asm" function caller() { var ret = 0; var i = 0; for (i = 2; (i|0) <= 10; i = (i+1)|0) { ret = (ret + i) | 0; } return ret|0; } return {caller:caller}; } assertWasm(54, TestForLoop); function TestForLoopWithoutInit() { "use asm" function caller() { var ret = 0; var i = 0; for (; (i|0) < 10; i = (i+1)|0) { ret = (ret + 10) | 0; } return ret|0; } return {caller:caller}; } assertWasm(100,TestForLoopWithoutInit); function TestForLoopWithoutCondition() { "use asm" function caller() { var ret = 0; var i = 0; for (i=1;; i = (i+1)|0) { ret = (ret + i) | 0; if ((i|0) == 11) { break; } } return ret|0; } return {caller:caller}; } assertWasm(66, TestForLoopWithoutCondition); function TestForLoopWithoutNext() { "use asm" function caller() { var i = 0; for (i=1; (i|0) < 41;) { i = (i + 1) | 0; } return i|0; } return {caller:caller}; } assertWasm(41, TestForLoopWithoutNext); function TestForLoopWithoutBody() { "use asm" function caller() { var i = 0; for (i=1; (i|0) < 45 ; i = (i+1)|0) { } return i|0; } return {caller:caller}; } assertWasm(45, TestForLoopWithoutBody); function TestDoWhile() { "use asm" function caller() { var i = 0; var ret = 21; do { ret = (ret + ret)|0; i = (i + 1)|0; } while ((i|0) < 2); return ret|0; } return {caller:caller}; } assertWasm(84, TestDoWhile); function TestConditional() { "use asm" function caller() { var x = 1; return (((x|0) > 0) ? 41 : 71)|0; } return {caller:caller}; } assertWasm(41, TestConditional); function TestInitFunctionWithNoGlobals() { "use asm"; function caller() { return 51; } return {caller:caller}; } assertWasm(51, TestInitFunctionWithNoGlobals); (function () { function TestExportNameDifferentFromFunctionName() { "use asm"; function caller() { return 55; } return {alt_caller:caller}; } var module_decl = eval( '(' + TestExportNameDifferentFromFunctionName.toString() + ')'); var module = module_decl(stdlib); assertValidAsm(module_decl); assertEquals(55, module.alt_caller()); })(); function TestFunctionTableSingleFunction() { "use asm"; function dummy() { return 71; } function caller() { // TODO(jpp): the parser optimizes function_table[0&0] to function table[0]. var v = 0; return function_table[v&0]() | 0; } var function_table = [dummy] return {caller:caller}; } assertWasm(71, TestFunctionTableSingleFunction); function TestFunctionTableMultipleFunctions() { "use asm"; function inc1(x) { x = x|0; return (x+1)|0; } function inc2(x) { x = x|0; return (x+2)|0; } function caller() { var i = 0, j = 1; if ((function_table[i&1](50)|0) == 51) { if ((function_table[j&1](60)|0) == 62) { return 73; } } return 0; } var function_table = [inc1, inc2] return {caller:caller}; } assertWasm(73, TestFunctionTableMultipleFunctions); (function () { function TestFunctionTable(stdlib, foreign, buffer) { "use asm"; function add(a, b) { a = a|0; b = b|0; return (a+b)|0; } function sub(a, b) { a = a|0; b = b|0; return (a-b)|0; } function inc(a) { a = a|0; return (a+1)|0; } function caller(table_id, fun_id, arg1, arg2) { table_id = table_id|0; fun_id = fun_id|0; arg1 = arg1|0; arg2 = arg2|0; if ((table_id|0) == 0) { return funBin[fun_id&3](arg1, arg2)|0; } else if ((table_id|0) == 1) { return fun[fun_id&0](arg1)|0; } return 0; } var funBin = [add, sub, sub, add]; var fun = [inc]; return {caller:caller}; } print("TestFunctionTable..."); var module = TestFunctionTable(stdlib); assertEquals(55, module.caller(0, 0, 33, 22)); assertEquals(11, module.caller(0, 1, 33, 22)); assertEquals(9, module.caller(0, 2, 54, 45)); assertEquals(99, module.caller(0, 3, 54, 45)); assertEquals(23, module.caller(0, 4, 12, 11)); assertEquals(31, module.caller(1, 0, 30, 11)); })(); (function TestComma() { function CommaModule() { "use asm"; function ifunc(a, b) { a = +a; b = b | 0; return (a, b) | 0; } function dfunc(a, b) { a = a | 0; b = +b; return +(a, b); } return {ifunc: ifunc, dfunc: dfunc}; } var module_decl = eval('(' + CommaModule.toString() + ')'); var m = module_decl(stdlib); assertValidAsm(module_decl); assertEquals(123, m.ifunc(456.7, 123)); assertEquals(123.4, m.dfunc(456, 123.4)); })(); function TestFloatAsDouble(stdlib) { "use asm"; var fround = stdlib.Math.fround; function func() { var x = fround(1.0); return +fround(x); } return {caller: func}; } assertWasm(1, TestFloatAsDouble); function TestOr() { "use asm"; function func() { var x = 1; var y = 2; return (x | y) | 0; } return {caller: func}; } assertWasm(3, TestOr); function TestAnd() { "use asm"; function func() { var x = 3; var y = 2; return (x & y) | 0; } return {caller: func}; } assertWasm(2, TestAnd); function TestXor() { "use asm"; function func() { var x = 3; var y = 2; return (x ^ y) | 0; } return {caller: func}; } assertWasm(1, TestXor); function TestIntegerMultiplyBothWays(stdlib, foreign, heap) { "use asm"; function func() { var a = 1; return (((a * 3)|0) + ((4 * a)|0)) | 0; } return {caller: func}; } assertWasm(7, TestIntegerMultiplyBothWays); (function TestBadAssignDoubleFromIntish() { function Module(stdlib, foreign, heap) { "use asm"; function func() { var a = 1; var b = 3.0; b = a; } return {func: func}; } print("TestBadAssignDoubleFromIntish..."); Module(stdlib); assertFalse(%IsAsmWasmCode(Module)); })(); (function TestBadAssignIntFromDouble() { function Module(stdlib, foreign, heap) { "use asm"; function func() { var a = 1; var b = 3.0; a = b; } return {func: func}; } print("TestBadAssignIntFromDouble..."); Module(stdlib); assertFalse(%IsAsmWasmCode(Module)); })(); (function TestBadMultiplyIntish() { function Module(stdlib, foreign, heap) { "use asm"; function func() { var a = 1; return ((a + a) * 4) | 0; } return {func: func}; } print("TestBadMultiplyIntish..."); Module(stdlib); assertFalse(%IsAsmWasmCode(Module)); })(); (function TestBadCastFromInt() { function Module(stdlib, foreign, heap) { "use asm"; function func() { var a = 1; return +a; } return {func: func}; } print("TestBadCastFromInt..."); Module(stdlib); assertFalse(%IsAsmWasmCode(Module)); })(); function TestAndNegative() { "use asm"; function func() { var x = 1; var y = 2; var z = 0; z = x + y & -1; return z | 0; } return {caller: func}; } assertWasm(3, TestAndNegative); function TestNegativeDouble() { "use asm"; function func() { var x = -34359738368.25; var y = -2.5; return +(x + y); } return {caller: func}; } assertWasm(-34359738370.75, TestNegativeDouble); (function TestBadAndDouble() { function Module() { "use asm"; function func() { var x = 1.0; var y = 2.0; return (x & y) | 0; } return {func: func}; } Module(stdlib); assertFalse(%IsAsmWasmCode(Module)); })(); (function TestBadExportKey() { function Module() { "use asm"; function func() { } return {123: func}; } Module(stdlib); assertFalse(%IsAsmWasmCode(Module)); })(); /* // TODO(bradnelson): Technically invalid, but useful to cover unicode, revises // and re-enable. (function TestUnicodeExportKey() { function Module() { "use asm"; function func() { return 42; } return {"\u00d1\u00e6": func}; } var m = Module(stdlib); assertEquals(42, m.Ñæ()); assertValidAsm(Module); })(); */ function TestAndIntAndHeapValue(stdlib, foreign, buffer) { "use asm"; var HEAP32 = new stdlib.Int32Array(buffer); function func() { var x = 0; x = HEAP32[0] & -1; return x | 0; } return {caller: func}; } assertWasm(0, TestAndIntAndHeapValue); function TestOutOfBoundsConversion($a,$b,$c){'use asm'; function aaa() { var f = 0.0; var a = 0; f = 5616315000.000001; a = ~~f >>>0; return a | 0; } return { caller : aaa }; } assertWasm(1321347704, TestOutOfBoundsConversion); (function TestUnsignedLiterals() { function asmModule() { "use asm"; function u0xffffffff() { var f = 0xffffffff; return +(f >>> 0); } function u0x80000000() { var f = 0x80000000; return +(f >>> 0); } function u0x87654321() { var f = 0x87654321; return +(f >>> 0); } return { u0xffffffff: u0xffffffff, u0x80000000: u0x80000000, u0x87654321: u0x87654321, }; } var decl = eval('(' + asmModule.toString() + ')'); var wasm = decl(stdlib); assertValidAsm(decl); assertEquals(0xffffffff, wasm.u0xffffffff()); assertEquals(0x80000000, wasm.u0x80000000()); assertEquals(0x87654321, wasm.u0x87654321()); })(); function TestIfWithUnsigned() { "use asm"; function main() { if (2147483658) { // 2^31 + 10 return 231; } return 0; } return {caller:main}; } assertWasm(231, TestIfWithUnsigned); function TestLoopsWithUnsigned() { "use asm"; function main() { var val = 1; var count = 0; for (val = 2147483648; 2147483648;) { val = 2147483649; break; } while (val>>>0) { val = (val + 1) | 0; count = (count + 1)|0; if ((count|0) == 9) { break; } } count = 0; do { val = (val + 2) | 0; count = (count + 1)|0; if ((count|0) == 5) { break; } } while (0xffffffff); if ((val>>>0) == 2147483668) { return 323; } return 0; } return {caller:main}; } assertWasm(323, TestLoopsWithUnsigned); function TestSingleFunctionModule() { "use asm"; function add(a, b) { a = a | 0; b = b | 0; return (a + b) | 0; } return add; } assertEquals(7, TestSingleFunctionModule()(3, 4)); function TestNotZero() { "use asm"; function caller() { if (!0) { return 44; } else { return 55; } return 0; } return {caller: caller}; } assertWasm(44, TestNotZero); function TestNotOne() { "use asm"; function caller() { if (!1) { return 44; } else { return 55; } return 0; } return {caller: caller}; } assertWasm(55, TestNotOne); function TestDotfulFloat(stdlib) { "use asm"; var fround = stdlib.Math.fround; var foo = fround(55.0); function caller() { return +foo; } return {caller: caller}; } assertWasm(55, TestDotfulFloat); function TestDotfulLocalFloat(stdlib) { "use asm"; var fround = stdlib.Math.fround; function caller() { var foo = fround(55.0); return +foo; } return {caller: caller}; } assertWasm(55, TestDotfulLocalFloat); function TestDotlessFloat(stdlib) { "use asm"; var fround = stdlib.Math.fround; var foo = fround(55); function caller() { return +foo; } return {caller: caller}; } assertWasm(55, TestDotlessFloat); function TestDotlessLocalFloat(stdlib) { "use asm"; var fround = stdlib.Math.fround; function caller() { var foo = fround(55); return +foo; } return {caller: caller}; } assertWasm(55, TestDotlessLocalFloat); function TestFloatGlobals(stdlib) { "use asm"; var fround = stdlib.Math.fround; var foo = fround(1.25); function caller() { foo = fround(foo + fround(1.0)); foo = fround(foo + fround(1.0)); return +foo; } return {caller: caller}; } assertWasm(3.25, TestFloatGlobals); (function TestExportTwice() { function asmModule() { "use asm"; function foo() { return 42; } return {bar: foo, baz: foo}; } var m = asmModule(); assertEquals(42, m.bar()); assertEquals(42, m.baz()); })();