| // 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; |
| |
| 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(1024)).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 TestInt32HeapAccess(stdlib, foreign, buffer) { |
| "use asm"; |
| |
| var m = new stdlib.Int32Array(buffer); |
| function caller() { |
| var i = 4; |
| |
| m[0] = (i + 1) | 0; |
| m[i >> 2] = ((m[0]|0) + 1) | 0; |
| m[2] = ((m[i >> 2]|0) + 1) | 0; |
| return m[2] | 0; |
| } |
| |
| return {caller: caller}; |
| } |
| |
| assertWasm(7, TestInt32HeapAccess); |
| |
| |
| function TestInt32HeapAccessExternal() { |
| var memory = new ArrayBuffer(1024); |
| var memory_int32 = new Int32Array(memory); |
| var module_decl = eval('(' + TestInt32HeapAccess.toString() + ')'); |
| var module = module_decl(stdlib, null, memory); |
| assertValidAsm(module_decl); |
| assertEquals(7, module.caller()); |
| assertEquals(7, memory_int32[2]); |
| } |
| |
| TestInt32HeapAccessExternal(); |
| |
| |
| function TestHeapAccessIntTypes() { |
| var types = [ |
| [Int8Array, 'Int8Array', '>> 0'], |
| [Uint8Array, 'Uint8Array', '>> 0'], |
| [Int16Array, 'Int16Array', '>> 1'], |
| [Uint16Array, 'Uint16Array', '>> 1'], |
| [Int32Array, 'Int32Array', '>> 2'], |
| [Uint32Array, 'Uint32Array', '>> 2'], |
| ]; |
| for (var i = 0; i < types.length; i++) { |
| var code = TestInt32HeapAccess.toString(); |
| code = code.replace('Int32Array', types[i][1]); |
| code = code.replace(/>> 2/g, types[i][2]); |
| var memory = new ArrayBuffer(1024); |
| var memory_view = new types[i][0](memory); |
| var module_decl = eval('(' + code + ')'); |
| var module = module_decl(stdlib, null, memory); |
| assertValidAsm(module_decl); |
| assertEquals(7, module.caller()); |
| assertEquals(7, memory_view[2]); |
| assertValidAsm(module_decl); |
| } |
| } |
| |
| TestHeapAccessIntTypes(); |
| |
| |
| function TestFloatHeapAccess(stdlib, foreign, buffer) { |
| "use asm"; |
| |
| var f32 = new stdlib.Float32Array(buffer); |
| var f64 = new stdlib.Float64Array(buffer); |
| var fround = stdlib.Math.fround; |
| function caller() { |
| var i = 8; |
| var j = 8; |
| var v = 6.0; |
| |
| f64[2] = v + 1.0; |
| f64[i >> 3] = +f64[2] + 1.0; |
| f64[j >> 3] = +f64[j >> 3] + 1.0; |
| i = +f64[i >> 3] == 9.0; |
| return i|0; |
| } |
| |
| return {caller: caller}; |
| } |
| |
| assertWasm(1, TestFloatHeapAccess); |
| |
| |
| function TestFloatHeapAccessExternal() { |
| var memory = new ArrayBuffer(1024); |
| var memory_float64 = new Float64Array(memory); |
| var module_decl = eval('(' + TestFloatHeapAccess.toString() + ')'); |
| var module = module_decl(stdlib, null, memory); |
| assertValidAsm(module_decl); |
| assertEquals(1, module.caller()); |
| assertEquals(9.0, memory_float64[1]); |
| } |
| |
| TestFloatHeapAccessExternal(); |
| |
| |
| 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 TestForeignFunctions() { |
| function AsmModule(stdlib, foreign, buffer) { |
| "use asm"; |
| |
| var setVal = foreign.setVal; |
| var getVal = foreign.getVal; |
| |
| function caller(initial_value, new_value) { |
| initial_value = initial_value|0; |
| new_value = new_value|0; |
| if ((getVal()|0) == (initial_value|0)) { |
| setVal(new_value|0); |
| return getVal()|0; |
| } |
| return 0; |
| } |
| |
| return {caller:caller}; |
| } |
| |
| function ffi(initial_val) { |
| var val = initial_val; |
| |
| function getVal() { |
| return val; |
| } |
| |
| function setVal(new_val) { |
| val = new_val; |
| } |
| |
| return {getVal:getVal, setVal:setVal}; |
| } |
| |
| var foreign = new ffi(23); |
| |
| var module = AsmModule({Math: Math}, foreign, null); |
| assertValidAsm(AsmModule); |
| |
| assertEquals(103, module.caller(23, 103)); |
| } |
| |
| print("TestForeignFunctions..."); |
| TestForeignFunctions(); |
| |
| |
| function TestForeignFunctionMultipleUse() { |
| function AsmModule(stdlib, foreign, buffer) { |
| "use asm"; |
| |
| var getVal = foreign.getVal; |
| |
| function caller(int_val, double_val) { |
| int_val = int_val|0; |
| double_val = +double_val; |
| if ((getVal()|0) == (int_val|0)) { |
| if ((+getVal()) == (+double_val)) { |
| return 89; |
| } |
| } |
| return 0; |
| } |
| |
| return {caller:caller}; |
| } |
| |
| function ffi() { |
| function getVal() { |
| return 83.25; |
| } |
| |
| return {getVal:getVal}; |
| } |
| |
| var foreign = new ffi(); |
| |
| var module_decl = eval('(' + AsmModule.toString() + ')'); |
| var module = module_decl(stdlib, foreign, null); |
| assertValidAsm(module_decl); |
| |
| assertEquals(89, module.caller(83, 83.25)); |
| } |
| |
| print("TestForeignFunctionMultipleUse..."); |
| TestForeignFunctionMultipleUse(); |
| |
| function TestForeignVariables() { |
| function AsmModule(stdlib, foreign, buffer) { |
| "use asm"; |
| |
| var i1 = foreign.foo | 0; |
| var f1 = +foreign.bar; |
| var i2 = foreign.baz | 0; |
| var f2 = +foreign.baz; |
| |
| function geti1() { |
| return i1|0; |
| } |
| |
| function getf1() { |
| return +f1; |
| } |
| |
| function geti2() { |
| return i2|0; |
| } |
| |
| function getf2() { |
| return +f2; |
| } |
| |
| return {geti1:geti1, getf1:getf1, geti2:geti2, getf2:getf2}; |
| } |
| |
| function TestCase(env, i1, f1, i2, f2) { |
| print("Testing foreign variables..."); |
| var module_decl = eval('(' + AsmModule.toString() + ')'); |
| var module = module_decl(stdlib, env); |
| assertValidAsm(module_decl); |
| assertEquals(i1, module.geti1()); |
| assertEquals(f1, module.getf1()); |
| assertEquals(i2, module.geti2()); |
| assertEquals(f2, module.getf2()); |
| } |
| |
| // Check normal operation. |
| TestCase({foo: 123, bar: 234.5, baz: 345.7}, 123, 234.5, 345, 345.7); |
| // Check partial operation. |
| TestCase({baz: 345.7}, 0, NaN, 345, 345.7); |
| // Check that undefined values are converted to proper defaults. |
| TestCase({qux: 999}, 0, NaN, 0, NaN); |
| // Check that true values are converted properly. |
| TestCase({foo: true, bar: true, baz: true}, 1, 1.0, 1, 1.0); |
| // Check that false values are converted properly. |
| TestCase({foo: false, bar: false, baz: false}, 0, 0, 0, 0); |
| // Check that null values are converted properly. |
| TestCase({foo: null, bar: null, baz: null}, 0, 0, 0, 0); |
| // Check that string values are converted properly. |
| TestCase({foo: 'hi', bar: 'there', baz: 'dude'}, 0, NaN, 0, NaN); |
| TestCase({foo: '0xff', bar: '234', baz: '456.1'}, 255, 234, 456, 456.1); |
| // Check that function values are converted properly. |
| TestCase({foo: TestCase, bar: TestCase, qux: TestCase}, 0, NaN, 0, NaN); |
| } |
| |
| print("TestForeignVariables..."); |
| TestForeignVariables(); |
| |
| |
| (function() { |
| function TestByteHeapAccessCompat(stdlib, foreign, buffer) { |
| "use asm"; |
| |
| var HEAP8 = new stdlib.Uint8Array(buffer); |
| var HEAP32 = new stdlib.Int32Array(buffer); |
| |
| function store(i, v) { |
| i = i | 0; |
| v = v | 0; |
| HEAP32[i >> 2] = v; |
| } |
| |
| function storeb(i, v) { |
| i = i | 0; |
| v = v | 0; |
| HEAP8[i | 0] = v; |
| } |
| |
| function load(i) { |
| i = i | 0; |
| return HEAP8[i] | 0; |
| } |
| |
| function iload(i) { |
| i = i | 0; |
| return HEAP8[HEAP32[i >> 2] | 0] | 0; |
| } |
| |
| return {load: load, iload: iload, store: store, storeb: storeb}; |
| } |
| |
| var memory = new ArrayBuffer(1024); |
| var module_decl = eval('(' + TestByteHeapAccessCompat.toString() + ')'); |
| var m = module_decl(stdlib, null, memory); |
| assertValidAsm(module_decl); |
| m.store(0, 20); |
| m.store(4, 21); |
| m.store(8, 22); |
| m.storeb(20, 123); |
| m.storeb(21, 42); |
| m.storeb(22, 77); |
| assertEquals(123, m.load(20)); |
| assertEquals(42, m.load(21)); |
| assertEquals(77, m.load(22)); |
| assertEquals(123, m.iload(0)); |
| assertEquals(42, m.iload(4)); |
| assertEquals(77, m.iload(8)); |
| })(); |
| |
| |
| function TestGlobalBlock(stdlib, foreign, buffer) { |
| "use asm"; |
| |
| var x = foreign.x | 0, y = foreign.y | 0; |
| |
| function test() { |
| return (x + y) | 0; |
| } |
| |
| return {caller: test}; |
| } |
| |
| assertWasm(15, TestGlobalBlock, { x: 4, y: 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 TestIntishAssignment(stdlib, foreign, heap) { |
| "use asm"; |
| var HEAP32 = new stdlib.Int32Array(heap); |
| function func() { |
| var a = 1; |
| var b = 2; |
| HEAP32[0] = a + b; |
| return HEAP32[0] | 0; |
| } |
| return {caller: func}; |
| } |
| |
| assertWasm(3, TestIntishAssignment); |
| |
| |
| function TestFloatishAssignment(stdlib, foreign, heap) { |
| "use asm"; |
| var HEAPF32 = new stdlib.Float32Array(heap); |
| var fround = stdlib.Math.fround; |
| function func() { |
| var a = fround(1.0); |
| var b = fround(2.0); |
| HEAPF32[0] = a + b; |
| return +HEAPF32[0]; |
| } |
| return {caller: func}; |
| } |
| |
| assertWasm(3, TestFloatishAssignment); |
| |
| |
| function TestDoubleToFloatAssignment(stdlib, foreign, heap) { |
| "use asm"; |
| var HEAPF32 = new stdlib.Float32Array(heap); |
| var fround = stdlib.Math.fround; |
| function func() { |
| var a = 1.23; |
| HEAPF32[0] = a; |
| return +HEAPF32[0]; |
| } |
| return {caller: func}; |
| } |
| |
| assertWasm(Math.fround(1.23), TestDoubleToFloatAssignment); |
| |
| |
| 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()); |
| })(); |