// 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 var stdlib = this; function assertValidAsm(func) { assertTrue(%IsAsmWasmCode(func)); } (function TestStdlibConstants() { function Module(stdlib) { "use asm"; var StdlibInfinity = stdlib.Infinity; var StdlibNaN = stdlib.NaN; var StdlibMathE = stdlib.Math.E; var StdlibMathLN10 = stdlib.Math.LN10; var StdlibMathLN2 = stdlib.Math.LN2; var StdlibMathLOG2E = stdlib.Math.LOG2E; var StdlibMathLOG10E = stdlib.Math.LOG10E; var StdlibMathPI = stdlib.Math.PI; var StdlibMathSQRT1_2 = stdlib.Math.SQRT1_2; var StdlibMathSQRT2 = stdlib.Math.SQRT2; function caller() { if (StdlibInfinity != 1.0 / 0.0) return 0; if (StdlibMathE != 2.718281828459045) return 0; if (StdlibMathLN10 != 2.302585092994046) return 0; if (StdlibMathLN2 != 0.6931471805599453) return 0; if (StdlibMathLOG2E != 1.4426950408889634) return 0; if (StdlibMathLOG10E != 0.4342944819032518) return 0; if (StdlibMathPI != 3.141592653589793) return 0; if (StdlibMathSQRT1_2 != 0.7071067811865476) return 0; if (StdlibMathSQRT2 != 1.4142135623730951) return 0; return 1; } function nanCheck() { return +StdlibNaN; } return {caller:caller, nanCheck:nanCheck}; } var m = Module(stdlib); assertValidAsm(Module); assertEquals(1, m.caller()); assertTrue(isNaN(m.nanCheck())); })(); var stdlib = this; var stdlib_root_members = [ 'Infinity', 'NaN', ]; var stdlib_math_members = [ 'E', 'LN10', 'LN2', 'LOG2E', 'LOG10E', 'PI', 'SQRT1_2', 'SQRT2', 'ceil', 'clz32', 'floor', 'sqrt', 'abs', 'min', 'max', 'acos', 'asin', 'atan', 'cos', 'sin', 'tan', 'exp', 'log', 'atan2', 'pow', 'imul', 'fround', ]; (function TestBadStdlib() { function Module(stdlib) { "use asm"; var foo = stdlib.NaN; return {}; } for (var i = 0; i < stdlib_root_members.length; ++i) { var member = stdlib_root_members[i]; var stdlib = {}; stdlib[member] = 0; print(member); var code = Module.toString().replace('NaN', member); var decl = eval('(' + code + ')'); decl(stdlib); assertTrue(%IsNotAsmWasmCode(decl)); } for (var i = 0; i < stdlib_math_members.length; ++i) { var member = stdlib_math_members[i]; var stdlib = {Math:{}}; stdlib['Math'][member] = 0; print(member); var code = Module.toString().replace('NaN', 'Math.' + member); var decl = eval('(' + code + ')'); decl(stdlib); assertTrue(%IsNotAsmWasmCode(decl)); } })(); (function TestMissingNaNStdlib() { function Module(stdlib) { "use asm"; var foo = stdlib.NaN; return {}; } for (var i = 0; i < stdlib_root_members.length; ++i) { var member = stdlib_root_members[i]; var code = Module.toString().replace('NaN', member); var decl = eval('(' + code + ')'); decl({}); assertTrue(%IsNotAsmWasmCode(decl)); } for (var i = 0; i < stdlib_math_members.length; ++i) { var member = stdlib_math_members[i]; var code = Module.toString().replace('NaN', 'Math.' + member); var decl = eval('(' + code + ')'); assertThrows(function() { decl({}); assertTrue(%IsNotAsmWasmCode(decl)); }); } })(); (function TestStdlibFunctionsInside() { function Module(stdlib) { "use asm"; var StdlibMathCeil = stdlib.Math.ceil; var StdlibMathClz32 = stdlib.Math.clz32; var StdlibMathFloor = stdlib.Math.floor; var StdlibMathSqrt = stdlib.Math.sqrt; var StdlibMathAbs = stdlib.Math.abs; var StdlibMathMin = stdlib.Math.min; var StdlibMathMax = stdlib.Math.max; var StdlibMathAcos = stdlib.Math.acos; var StdlibMathAsin = stdlib.Math.asin; var StdlibMathAtan = stdlib.Math.atan; var StdlibMathCos = stdlib.Math.cos; var StdlibMathSin = stdlib.Math.sin; var StdlibMathTan = stdlib.Math.tan; var StdlibMathExp = stdlib.Math.exp; var StdlibMathLog = stdlib.Math.log; var StdlibMathAtan2 = stdlib.Math.atan2; var StdlibMathPow = stdlib.Math.pow; var StdlibMathImul = stdlib.Math.imul; var fround = stdlib.Math.fround; function deltaEqual(x, y) { x = +x; y = +y; var t = 0.0; t = x - y; if (t < 0.0) { t = t * -1.0; } return (t < 1.0e-13) | 0; } function caller() { if (!(deltaEqual(+StdlibMathSqrt(123.0), 11.090536506409418)|0)) return 0; if (fround(StdlibMathSqrt(fround(256.0))) != fround(16.0)) return 0; if (+StdlibMathCeil(123.7) != 124.0) return 0; if (fround(StdlibMathCeil(fround(123.7))) != fround(124.0)) return 0; if (+StdlibMathFloor(123.7) != 123.0) return 0; if (fround(StdlibMathFloor(fround(123.7))) != fround(123.0)) return 0; if (+StdlibMathAbs(-123.0) != 123.0) return 0; if (fround(StdlibMathAbs(fround(-123.0))) != fround(123.0)) return 0; if (+StdlibMathMin(123.4, 1236.4) != 123.4) return 0; if (fround(StdlibMathMin(fround(123.4), fround(1236.4))) != fround(123.4)) return 0; if (+StdlibMathMax(123.4, 1236.4) != 1236.4) return 0; if (fround(StdlibMathMax(fround(123.4), fround(1236.4))) != fround(1236.4)) return 0; if (!(deltaEqual(+StdlibMathAcos(0.1), 1.4706289056333368)|0)) return 0; if (!(deltaEqual(+StdlibMathAsin(0.2), 0.2013579207903308)|0)) return 0; if (!(deltaEqual(+StdlibMathAtan(0.2), 0.19739555984988078)|0)) return 0; if (!(deltaEqual(+StdlibMathCos(0.2), 0.9800665778412416)|0)) return 0; if (!(deltaEqual(+StdlibMathSin(0.2), 0.19866933079506122)|0)) return 0; if (!(deltaEqual(+StdlibMathTan(0.2), 0.20271003550867250)|0)) return 0; if (!(deltaEqual(+StdlibMathExp(0.2), 1.2214027581601699)|0)) return 0; if (!(deltaEqual(+StdlibMathLog(0.2), -1.6094379124341003)|0)) return 0; if ((StdlibMathClz32(134217728)|0) != 4) return 0; if ((StdlibMathImul(6, 7)|0) != 42) return 0; if (!(deltaEqual(+StdlibMathAtan2(6.0, 7.0), 0.7086262721276703)|0)) return 0; if (+StdlibMathPow(6.0, 7.0) != 279936.0) return 0; return 1; } return {caller:caller}; } var m = Module(stdlib); assertValidAsm(Module); assertEquals(1, m.caller()); })(); (function TestStdlibFunctionOutside() { function looseEqual(x, y, delta) { if (delta === undefined) { delta = 1.0e-10; } if (isNaN(x) && isNaN(y)) { return true; } if (!isFinite(x) && !isFinite(y)) { return true; } x = +x; y = +y; var t = 0.0; t = x - y; if (t < 0.0) { t = t * -1.0; } return (t < delta) | 0; } function plainEqual(x, y) { if (isNaN(x) && isNaN(y)) { return true; } return x === y; } function Module(stdlib) { "use asm"; var ceil = stdlib.Math.ceil; var floor = stdlib.Math.floor; var sqrt = stdlib.Math.sqrt; var abs = stdlib.Math.abs; var fround = stdlib.Math.fround; var fround2 = stdlib.Math.fround; var acos = stdlib.Math.acos; var asin = stdlib.Math.asin; var atan = stdlib.Math.atan; var cos = stdlib.Math.cos; var sin = stdlib.Math.sin; var tan = stdlib.Math.tan; var exp = stdlib.Math.exp; var log = stdlib.Math.log; var atan2 = stdlib.Math.atan2; var pow = stdlib.Math.pow; var imul = stdlib.Math.imul; var min = stdlib.Math.min; var max = stdlib.Math.max; function ceil_f64(x) { x = +x; return +ceil(x); } function ceil_f32(x) { x = fround(x); return fround(ceil(x)); } function floor_f64(x) { x = +x; return +floor(x); } function floor_f32(x) { x = fround(x); return fround(floor(x)); } function sqrt_f64(x) { x = +x; return +sqrt(x); } function sqrt_f32(x) { x = fround(x); return fround(sqrt(x)); } function abs_f64(x) { x = +x; return +abs(x); } function abs_f32(x) { x = fround(x); return fround(abs(x)); } function abs_i32(x) { x = x | 0; return abs(x|0) | 0; } function acos_f64(x) { x = +x; return +acos(x); } function asin_f64(x) { x = +x; return +asin(x); } function atan_f64(x) { x = +x; return +atan(x); } function cos_f64(x) { x = +x; return +cos(x); } function sin_f64(x) { x = +x; return +sin(x); } function tan_f64(x) { x = +x; return +tan(x); } function exp_f64(x) { x = +x; return +exp(x); } function log_f64(x) { x = +x; return +log(x); } function atan2_f64(x, y) { x = +x; y = +y; return +atan2(x, y); } function pow_f64(x, y) { x = +x; y = +y; return +atan2(x, y); } function imul_i32(x, y) { x = x | 0; y = y | 0; return imul(x, y) | 0; } function imul_u32(x, y) { x = x | 0; y = y | 0; return imul(x>>>0, y>>>0) | 0; } // type -> f32 function fround_i32(x) { x = x | 0; return fround(x|0); } function fround_u32(x) { x = x | 0; return fround(x>>>0); } function fround_f32(x) { x = fround(x); return fround(x); } function fround_f64(x) { x = +x; return fround(x); } // type -> f32 -> type function fround2_i32(x) { x = x | 0; return ~~fround2(x|0) | 0; } function fround2_u32(x) { x = x | 0; return ~~fround2(x>>>0) | 0; } function fround2_f32(x) { x = fround2(x); return fround2(x); } function fround2_f64(x) { x = +x; return +fround2(x); } function min_i32(x, y) { x = x | 0; y = y | 0; return min(x|0, y|0) | 0; } function min_f32(x, y) { x = fround(x); y = fround(y); return fround(min(x, y)); } function min_f64(x, y) { x = +x; y = +y; return +min(x, y); } function max_i32(x, y) { x = x | 0; y = y | 0; return max(x|0, y|0) | 0; } function max_f32(x, y) { x = fround(x); y = fround(y); return fround(max(x, y)); } function max_f64(x, y) { x = +x; y = +y; return +max(x, y); } return { ceil_f64: ceil_f64, ceil_f32: ceil_f32, floor_f64: floor_f64, floor_f32: floor_f32, sqrt_f64: sqrt_f64, sqrt_f32: sqrt_f32, abs_f64: abs_f64, abs_f32: abs_f32, abs_i32: abs_i32, acos_f64: acos_f64, asin_f64: asin_f64, atan_f64: atan_f64, cos_f64: cos_f64, sin_f64: sin_f64, tan_f64: tan_f64, exp_f64: exp_f64, log_f64: log_f64, imul_i32: imul_i32, imul_u32: imul_u32, fround_i32: fround_i32, fround_u32: fround_u32, fround_f32: fround_f32, fround_f64: fround_f64, fround2_i32: fround2_i32, fround2_u32: fround2_u32, fround2_f32: fround2_f32, fround2_f64: fround2_f64, min_i32: min_i32, min_f32: min_f32, min_f64: min_f64, max_i32: max_i32, max_f32: max_f32, max_f64: max_f64, }; } var m = Module(stdlib); assertValidAsm(Module); var values = { i32: [ 0, 1, -1, 123, 456, -123, -456, 0x40000000, 0x7FFFFFFF, -0x80000000, ], u32: [ 0, 1, 123, 456, 0x40000000, 0x7FFFFFFF, 0xFFFFFFFF, 0x80000000, ], f32: [ 0, -0, 1, -1, 0.25, 0.125, 0.9, -0.9, 1.414, 0x7F, -0x80, -0x8000, -0x80000000, 0x7FFF, 0x7FFFFFFF, Infinity, -Infinity, NaN, ], f64: [ 0, -0, 1, -1, 0.25, 0.125, 0.9, -0.9, 1.414, 0x7F, -0x80, -0x8000, -0x80000000, 0x7FFF, 0x7FFFFFFF, Infinity, -Infinity, NaN, ], }; var converts = { i32: function(x) { return x | 0; }, u32: function(x) { return x >>> 0; }, f32: function(x) { return Math.fround(x); }, f64: function(x) { return x; }, }; var two_args = {atan2: true, pow: true, imul: true, min: true, max: true}; var funcs = { ceil: ['f32', 'f64'], floor: ['f32', 'f64'], sqrt: ['f32', 'f64'], abs: ['i32', 'f32', 'f64'], acos: ['f64'], asin: ['f64'], atan: ['f64'], cos: ['f64'], sin: ['f64'], tan: ['f64'], exp: ['f64'], log: ['f64'], imul: ['i32', 'u32'], fround: ['i32', 'u32', 'f32', 'f64'], min: ['i32', 'f32', 'f64'], max: ['i32', 'f32', 'f64'], }; var per_func_equals = { // JS uses fdlib for these, so they may not match. // ECMAscript does not required them to have a particular precision. exp_f64: function(x, y) { return looseEqual(x, y, 1e55); }, sqrt_f32: function(x, y) { return looseEqual(x, y, 1e-5); }, cos_f64: looseEqual, sin_f64: looseEqual, tan_f64: looseEqual, // TODO(bradnelson): // Figure out why some builds (avx2, rel_ng) return a uint. imul_u32: function(x, y) { return (x | 0) === (y | 0); }, }; for (var func in funcs) { var types = funcs[func]; for (var i = 0; i < types.length; i++) { var type = types[i]; var interesting = values[type]; for (var j = 0; j < interesting.length; j++) { for (var k = 0; k < interesting.length; k++) { var val0 = interesting[j]; var val1 = interesting[k]; var name = func + '_' + type; if (func === 'fround') { // fround returns f32 regardless of input. var expected = Math[func](val0); var actual = m[name](val0); } else if (two_args[func]) { var expected = converts[type](Math[func](val0, val1)); var actual = m[name](val0, val1); } else { var expected = converts[type](Math[func](val0, val1)); var actual = m[name](val0, val1); } var compare = per_func_equals[name]; if (compare === undefined) { compare = plainEqual; } assertTrue(typeof(compare) === 'function'); if (!compare(expected, actual)) { print(expected + ' !== ' + actual + ' for ' + name + ' with input ' + val0 + ' ' + val1); assertTrue(false); } } } } } })();