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