1// Copyright 2012 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5(function(global, utils) { 6"use strict"; 7 8%CheckIsBootstrapping(); 9 10// ------------------------------------------------------------------- 11// Imports 12 13define kRandomBatchSize = 64; 14// The first two slots are reserved to persist PRNG state. 15define kRandomNumberStart = 2; 16 17var GlobalFloat64Array = global.Float64Array; 18var GlobalMath = global.Math; 19var GlobalObject = global.Object; 20var InternalArray = utils.InternalArray; 21var NaN = %GetRootNaN(); 22var nextRandomIndex = kRandomBatchSize; 23var randomNumbers = UNDEFINED; 24var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol"); 25 26//------------------------------------------------------------------- 27 28// ECMA 262 - 15.8.2.1 29function MathAbs(x) { 30 x = +x; 31 return (x > 0) ? x : 0 - x; 32} 33 34// ECMA 262 - 15.8.2.2 35function MathAcosJS(x) { 36 return %_MathAcos(+x); 37} 38 39// ECMA 262 - 15.8.2.3 40function MathAsinJS(x) { 41 return %_MathAsin(+x); 42} 43 44// ECMA 262 - 15.8.2.4 45function MathAtanJS(x) { 46 return %_MathAtan(+x); 47} 48 49// ECMA 262 - 15.8.2.5 50// The naming of y and x matches the spec, as does the order in which 51// ToNumber (valueOf) is called. 52function MathAtan2JS(y, x) { 53 y = +y; 54 x = +x; 55 return %_MathAtan2(y, x); 56} 57 58// ECMA 262 - 15.8.2.6 59function MathCeil(x) { 60 return -%_MathFloor(-x); 61} 62 63// ECMA 262 - 15.8.2.8 64function MathExp(x) { 65 return %MathExpRT(TO_NUMBER(x)); 66} 67 68// ECMA 262 - 15.8.2.9 69function MathFloorJS(x) { 70 return %_MathFloor(+x); 71} 72 73// ECMA 262 - 15.8.2.10 74function MathLog(x) { 75 return %_MathLogRT(TO_NUMBER(x)); 76} 77 78// ECMA 262 - 15.8.2.11 79function MathMax(arg1, arg2) { // length == 2 80 var length = %_ArgumentsLength(); 81 if (length == 2) { 82 arg1 = TO_NUMBER(arg1); 83 arg2 = TO_NUMBER(arg2); 84 if (arg2 > arg1) return arg2; 85 if (arg1 > arg2) return arg1; 86 if (arg1 == arg2) { 87 // Make sure -0 is considered less than +0. 88 return (arg1 === 0 && %_IsMinusZero(arg1)) ? arg2 : arg1; 89 } 90 // All comparisons failed, one of the arguments must be NaN. 91 return NaN; 92 } 93 var r = -INFINITY; 94 for (var i = 0; i < length; i++) { 95 var n = %_Arguments(i); 96 n = TO_NUMBER(n); 97 // Make sure +0 is considered greater than -0. 98 if (NUMBER_IS_NAN(n) || n > r || (r === 0 && n === 0 && %_IsMinusZero(r))) { 99 r = n; 100 } 101 } 102 return r; 103} 104 105// ECMA 262 - 15.8.2.12 106function MathMin(arg1, arg2) { // length == 2 107 var length = %_ArgumentsLength(); 108 if (length == 2) { 109 arg1 = TO_NUMBER(arg1); 110 arg2 = TO_NUMBER(arg2); 111 if (arg2 > arg1) return arg1; 112 if (arg1 > arg2) return arg2; 113 if (arg1 == arg2) { 114 // Make sure -0 is considered less than +0. 115 return (arg1 === 0 && %_IsMinusZero(arg1)) ? arg1 : arg2; 116 } 117 // All comparisons failed, one of the arguments must be NaN. 118 return NaN; 119 } 120 var r = INFINITY; 121 for (var i = 0; i < length; i++) { 122 var n = %_Arguments(i); 123 n = TO_NUMBER(n); 124 // Make sure -0 is considered less than +0. 125 if (NUMBER_IS_NAN(n) || n < r || (r === 0 && n === 0 && %_IsMinusZero(n))) { 126 r = n; 127 } 128 } 129 return r; 130} 131 132// ECMA 262 - 15.8.2.13 133function MathPowJS(x, y) { 134 return %_MathPow(TO_NUMBER(x), TO_NUMBER(y)); 135} 136 137// ECMA 262 - 15.8.2.14 138function MathRandom() { 139 if (nextRandomIndex >= kRandomBatchSize) { 140 randomNumbers = %GenerateRandomNumbers(randomNumbers); 141 nextRandomIndex = kRandomNumberStart; 142 } 143 return randomNumbers[nextRandomIndex++]; 144} 145 146function MathRandomRaw() { 147 if (nextRandomIndex >= kRandomBatchSize) { 148 randomNumbers = %GenerateRandomNumbers(randomNumbers); 149 nextRandomIndex = kRandomNumberStart; 150 } 151 return %_DoubleLo(randomNumbers[nextRandomIndex++]) & 0x3FFFFFFF; 152} 153 154// ECMA 262 - 15.8.2.15 155function MathRound(x) { 156 return %RoundNumber(TO_NUMBER(x)); 157} 158 159// ECMA 262 - 15.8.2.17 160function MathSqrtJS(x) { 161 return %_MathSqrt(+x); 162} 163 164// Non-standard extension. 165function MathImul(x, y) { 166 return %NumberImul(TO_NUMBER(x), TO_NUMBER(y)); 167} 168 169// ES6 draft 09-27-13, section 20.2.2.28. 170function MathSign(x) { 171 x = +x; 172 if (x > 0) return 1; 173 if (x < 0) return -1; 174 // -0, 0 or NaN. 175 return x; 176} 177 178// ES6 draft 09-27-13, section 20.2.2.34. 179function MathTrunc(x) { 180 x = +x; 181 if (x > 0) return %_MathFloor(x); 182 if (x < 0) return -%_MathFloor(-x); 183 // -0, 0 or NaN. 184 return x; 185} 186 187// ES6 draft 09-27-13, section 20.2.2.5. 188function MathAsinh(x) { 189 x = TO_NUMBER(x); 190 // Idempotent for NaN, +/-0 and +/-Infinity. 191 if (x === 0 || !NUMBER_IS_FINITE(x)) return x; 192 if (x > 0) return MathLog(x + %_MathSqrt(x * x + 1)); 193 // This is to prevent numerical errors caused by large negative x. 194 return -MathLog(-x + %_MathSqrt(x * x + 1)); 195} 196 197// ES6 draft 09-27-13, section 20.2.2.3. 198function MathAcosh(x) { 199 x = TO_NUMBER(x); 200 if (x < 1) return NaN; 201 // Idempotent for NaN and +Infinity. 202 if (!NUMBER_IS_FINITE(x)) return x; 203 return MathLog(x + %_MathSqrt(x + 1) * %_MathSqrt(x - 1)); 204} 205 206// ES6 draft 09-27-13, section 20.2.2.7. 207function MathAtanh(x) { 208 x = TO_NUMBER(x); 209 // Idempotent for +/-0. 210 if (x === 0) return x; 211 // Returns NaN for NaN and +/- Infinity. 212 if (!NUMBER_IS_FINITE(x)) return NaN; 213 return 0.5 * MathLog((1 + x) / (1 - x)); 214} 215 216// ES6 draft 09-27-13, section 20.2.2.17. 217function MathHypot(x, y) { // Function length is 2. 218 // We may want to introduce fast paths for two arguments and when 219 // normalization to avoid overflow is not necessary. For now, we 220 // simply assume the general case. 221 var length = %_ArgumentsLength(); 222 var args = new InternalArray(length); 223 var max = 0; 224 for (var i = 0; i < length; i++) { 225 var n = %_Arguments(i); 226 n = TO_NUMBER(n); 227 if (n === INFINITY || n === -INFINITY) return INFINITY; 228 n = MathAbs(n); 229 if (n > max) max = n; 230 args[i] = n; 231 } 232 233 // Kahan summation to avoid rounding errors. 234 // Normalize the numbers to the largest one to avoid overflow. 235 if (max === 0) max = 1; 236 var sum = 0; 237 var compensation = 0; 238 for (var i = 0; i < length; i++) { 239 var n = args[i] / max; 240 var summand = n * n - compensation; 241 var preliminary = sum + summand; 242 compensation = (preliminary - sum) - summand; 243 sum = preliminary; 244 } 245 return %_MathSqrt(sum) * max; 246} 247 248// ES6 draft 09-27-13, section 20.2.2.16. 249function MathFroundJS(x) { 250 return %MathFround(TO_NUMBER(x)); 251} 252 253// ES6 draft 07-18-14, section 20.2.2.11 254function MathClz32JS(x) { 255 return %_MathClz32(x >>> 0); 256} 257 258// ES6 draft 09-27-13, section 20.2.2.9. 259// Cube root approximation, refer to: http://metamerist.com/cbrt/cbrt.htm 260// Using initial approximation adapted from Kahan's cbrt and 4 iterations 261// of Newton's method. 262function MathCbrt(x) { 263 x = TO_NUMBER(x); 264 if (x == 0 || !NUMBER_IS_FINITE(x)) return x; 265 return x >= 0 ? CubeRoot(x) : -CubeRoot(-x); 266} 267 268macro NEWTON_ITERATION_CBRT(x, approx) 269 (1.0 / 3.0) * (x / (approx * approx) + 2 * approx); 270endmacro 271 272function CubeRoot(x) { 273 var approx_hi = MathFloorJS(%_DoubleHi(x) / 3) + 0x2A9F7893; 274 var approx = %_ConstructDouble(approx_hi | 0, 0); 275 approx = NEWTON_ITERATION_CBRT(x, approx); 276 approx = NEWTON_ITERATION_CBRT(x, approx); 277 approx = NEWTON_ITERATION_CBRT(x, approx); 278 return NEWTON_ITERATION_CBRT(x, approx); 279} 280 281// ------------------------------------------------------------------- 282 283%AddNamedProperty(GlobalMath, toStringTagSymbol, "Math", READ_ONLY | DONT_ENUM); 284 285// Set up math constants. 286utils.InstallConstants(GlobalMath, [ 287 // ECMA-262, section 15.8.1.1. 288 "E", 2.7182818284590452354, 289 // ECMA-262, section 15.8.1.2. 290 "LN10", 2.302585092994046, 291 // ECMA-262, section 15.8.1.3. 292 "LN2", 0.6931471805599453, 293 // ECMA-262, section 15.8.1.4. 294 "LOG2E", 1.4426950408889634, 295 "LOG10E", 0.4342944819032518, 296 "PI", 3.1415926535897932, 297 "SQRT1_2", 0.7071067811865476, 298 "SQRT2", 1.4142135623730951 299]); 300 301// Set up non-enumerable functions of the Math object and 302// set their names. 303utils.InstallFunctions(GlobalMath, DONT_ENUM, [ 304 "random", MathRandom, 305 "abs", MathAbs, 306 "acos", MathAcosJS, 307 "asin", MathAsinJS, 308 "atan", MathAtanJS, 309 "ceil", MathCeil, 310 "exp", MathExp, 311 "floor", MathFloorJS, 312 "log", MathLog, 313 "round", MathRound, 314 "sqrt", MathSqrtJS, 315 "atan2", MathAtan2JS, 316 "pow", MathPowJS, 317 "max", MathMax, 318 "min", MathMin, 319 "imul", MathImul, 320 "sign", MathSign, 321 "trunc", MathTrunc, 322 "asinh", MathAsinh, 323 "acosh", MathAcosh, 324 "atanh", MathAtanh, 325 "hypot", MathHypot, 326 "fround", MathFroundJS, 327 "clz32", MathClz32JS, 328 "cbrt", MathCbrt 329]); 330 331%SetForceInlineFlag(MathAbs); 332%SetForceInlineFlag(MathAcosJS); 333%SetForceInlineFlag(MathAsinJS); 334%SetForceInlineFlag(MathAtanJS); 335%SetForceInlineFlag(MathAtan2JS); 336%SetForceInlineFlag(MathCeil); 337%SetForceInlineFlag(MathClz32JS); 338%SetForceInlineFlag(MathFloorJS); 339%SetForceInlineFlag(MathRandom); 340%SetForceInlineFlag(MathSign); 341%SetForceInlineFlag(MathSqrtJS); 342%SetForceInlineFlag(MathTrunc); 343 344// ------------------------------------------------------------------- 345// Exports 346 347utils.Export(function(to) { 348 to.MathAbs = MathAbs; 349 to.MathExp = MathExp; 350 to.MathFloor = MathFloorJS; 351 to.IntRandom = MathRandomRaw; 352 to.MathMax = MathMax; 353 to.MathMin = MathMin; 354}); 355 356}) 357