| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 72 return %Math_atan2(TO_NUMBER_INLINE(y), TO_NUMBER_INLINE(x)); | 72 return %Math_atan2(TO_NUMBER_INLINE(y), TO_NUMBER_INLINE(x)); |
| 73 } | 73 } |
| 74 | 74 |
| 75 // ECMA 262 - 15.8.2.6 | 75 // ECMA 262 - 15.8.2.6 |
| 76 function MathCeil(x) { | 76 function MathCeil(x) { |
| 77 return %Math_ceil(TO_NUMBER_INLINE(x)); | 77 return %Math_ceil(TO_NUMBER_INLINE(x)); |
| 78 } | 78 } |
| 79 | 79 |
| 80 // ECMA 262 - 15.8.2.7 | 80 // ECMA 262 - 15.8.2.7 |
| 81 function MathCos(x) { | 81 function MathCos(x) { |
| 82 return %_MathCos(TO_NUMBER_INLINE(x)); | 82 return MathCosImpl(x); |
| 83 } | 83 } |
| 84 | 84 |
| 85 // ECMA 262 - 15.8.2.8 | 85 // ECMA 262 - 15.8.2.8 |
| 86 function MathExp(x) { | 86 function MathExp(x) { |
| 87 return %Math_exp(TO_NUMBER_INLINE(x)); | 87 return %Math_exp(TO_NUMBER_INLINE(x)); |
| 88 } | 88 } |
| 89 | 89 |
| 90 // ECMA 262 - 15.8.2.9 | 90 // ECMA 262 - 15.8.2.9 |
| 91 function MathFloor(x) { | 91 function MathFloor(x) { |
| 92 x = TO_NUMBER_INLINE(x); | 92 x = TO_NUMBER_INLINE(x); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 110 | 110 |
| 111 // ECMA 262 - 15.8.2.11 | 111 // ECMA 262 - 15.8.2.11 |
| 112 function MathMax(arg1, arg2) { // length == 2 | 112 function MathMax(arg1, arg2) { // length == 2 |
| 113 var length = %_ArgumentsLength(); | 113 var length = %_ArgumentsLength(); |
| 114 if (length == 2) { | 114 if (length == 2) { |
| 115 arg1 = TO_NUMBER_INLINE(arg1); | 115 arg1 = TO_NUMBER_INLINE(arg1); |
| 116 arg2 = TO_NUMBER_INLINE(arg2); | 116 arg2 = TO_NUMBER_INLINE(arg2); |
| 117 if (arg2 > arg1) return arg2; | 117 if (arg2 > arg1) return arg2; |
| 118 if (arg1 > arg2) return arg1; | 118 if (arg1 > arg2) return arg1; |
| 119 if (arg1 == arg2) { | 119 if (arg1 == arg2) { |
| 120 // Make sure -0 is considered less than +0. -0 is never a Smi, +0 can be | 120 // Make sure -0 is considered less than +0. |
| 121 // a Smi or a heap number. | 121 return (arg1 === 0 && %_IsMinusZero(arg1)) ? arg2 : arg1; |
| 122 return (arg1 == 0 && !%_IsSmi(arg1) && 1 / arg1 < 0) ? arg2 : arg1; | |
| 123 } | 122 } |
| 124 // All comparisons failed, one of the arguments must be NaN. | 123 // All comparisons failed, one of the arguments must be NaN. |
| 125 return NAN; | 124 return NAN; |
| 126 } | 125 } |
| 127 var r = -INFINITY; | 126 var r = -INFINITY; |
| 128 for (var i = 0; i < length; i++) { | 127 for (var i = 0; i < length; i++) { |
| 129 var n = %_Arguments(i); | 128 var n = %_Arguments(i); |
| 130 if (!IS_NUMBER(n)) n = NonNumberToNumber(n); | 129 if (!IS_NUMBER(n)) n = NonNumberToNumber(n); |
| 131 // Make sure +0 is considered greater than -0. -0 is never a Smi, +0 can be | 130 // Make sure +0 is considered greater than -0. |
| 132 // a Smi or heap number. | 131 if (NUMBER_IS_NAN(n) || n > r || (r === 0 && n === 0 && %_IsMinusZero(r))) { |
| 133 if (NUMBER_IS_NAN(n) || n > r || | |
| 134 (r == 0 && n == 0 && !%_IsSmi(r) && 1 / r < 0)) { | |
| 135 r = n; | 132 r = n; |
| 136 } | 133 } |
| 137 } | 134 } |
| 138 return r; | 135 return r; |
| 139 } | 136 } |
| 140 | 137 |
| 141 // ECMA 262 - 15.8.2.12 | 138 // ECMA 262 - 15.8.2.12 |
| 142 function MathMin(arg1, arg2) { // length == 2 | 139 function MathMin(arg1, arg2) { // length == 2 |
| 143 var length = %_ArgumentsLength(); | 140 var length = %_ArgumentsLength(); |
| 144 if (length == 2) { | 141 if (length == 2) { |
| 145 arg1 = TO_NUMBER_INLINE(arg1); | 142 arg1 = TO_NUMBER_INLINE(arg1); |
| 146 arg2 = TO_NUMBER_INLINE(arg2); | 143 arg2 = TO_NUMBER_INLINE(arg2); |
| 147 if (arg2 > arg1) return arg1; | 144 if (arg2 > arg1) return arg1; |
| 148 if (arg1 > arg2) return arg2; | 145 if (arg1 > arg2) return arg2; |
| 149 if (arg1 == arg2) { | 146 if (arg1 == arg2) { |
| 150 // Make sure -0 is considered less than +0. -0 is never a Smi, +0 can be | 147 // Make sure -0 is considered less than +0. |
| 151 // a Smi or a heap number. | 148 return (arg1 === 0 && %_IsMinusZero(arg1)) ? arg1 : arg2; |
| 152 return (arg1 == 0 && !%_IsSmi(arg1) && 1 / arg1 < 0) ? arg1 : arg2; | |
| 153 } | 149 } |
| 154 // All comparisons failed, one of the arguments must be NaN. | 150 // All comparisons failed, one of the arguments must be NaN. |
| 155 return NAN; | 151 return NAN; |
| 156 } | 152 } |
| 157 var r = INFINITY; | 153 var r = INFINITY; |
| 158 for (var i = 0; i < length; i++) { | 154 for (var i = 0; i < length; i++) { |
| 159 var n = %_Arguments(i); | 155 var n = %_Arguments(i); |
| 160 if (!IS_NUMBER(n)) n = NonNumberToNumber(n); | 156 if (!IS_NUMBER(n)) n = NonNumberToNumber(n); |
| 161 // Make sure -0 is considered less than +0. -0 is never a Smi, +0 can be a | 157 // Make sure -0 is considered less than +0. |
| 162 // Smi or a heap number. | 158 if (NUMBER_IS_NAN(n) || n < r || (r === 0 && n === 0 && %_IsMinusZero(n))) { |
| 163 if (NUMBER_IS_NAN(n) || n < r || | |
| 164 (r == 0 && n == 0 && !%_IsSmi(n) && 1 / n < 0)) { | |
| 165 r = n; | 159 r = n; |
| 166 } | 160 } |
| 167 } | 161 } |
| 168 return r; | 162 return r; |
| 169 } | 163 } |
| 170 | 164 |
| 171 // ECMA 262 - 15.8.2.13 | 165 // ECMA 262 - 15.8.2.13 |
| 172 function MathPow(x, y) { | 166 function MathPow(x, y) { |
| 173 return %_MathPow(TO_NUMBER_INLINE(x), TO_NUMBER_INLINE(y)); | 167 return %_MathPow(TO_NUMBER_INLINE(x), TO_NUMBER_INLINE(y)); |
| 174 } | 168 } |
| 175 | 169 |
| 176 // ECMA 262 - 15.8.2.14 | 170 // ECMA 262 - 15.8.2.14 |
| 177 function MathRandom() { | 171 function MathRandom() { |
| 178 return %_RandomHeapNumber(); | 172 return %_RandomHeapNumber(); |
| 179 } | 173 } |
| 180 | 174 |
| 181 // ECMA 262 - 15.8.2.15 | 175 // ECMA 262 - 15.8.2.15 |
| 182 function MathRound(x) { | 176 function MathRound(x) { |
| 183 return %RoundNumber(TO_NUMBER_INLINE(x)); | 177 return %RoundNumber(TO_NUMBER_INLINE(x)); |
| 184 } | 178 } |
| 185 | 179 |
| 186 // ECMA 262 - 15.8.2.16 | 180 // ECMA 262 - 15.8.2.16 |
| 187 function MathSin(x) { | 181 function MathSin(x) { |
| 188 return %_MathSin(TO_NUMBER_INLINE(x)); | 182 return MathSinImpl(x); |
| 189 } | 183 } |
| 190 | 184 |
| 191 // ECMA 262 - 15.8.2.17 | 185 // ECMA 262 - 15.8.2.17 |
| 192 function MathSqrt(x) { | 186 function MathSqrt(x) { |
| 193 return %_MathSqrt(TO_NUMBER_INLINE(x)); | 187 return %_MathSqrt(TO_NUMBER_INLINE(x)); |
| 194 } | 188 } |
| 195 | 189 |
| 196 // ECMA 262 - 15.8.2.18 | 190 // ECMA 262 - 15.8.2.18 |
| 197 function MathTan(x) { | 191 function MathTan(x) { |
| 198 return %_MathTan(TO_NUMBER_INLINE(x)); | 192 return MathSinImpl(x) / MathCosImpl(x); |
| 199 } | 193 } |
| 200 | 194 |
| 201 // Non-standard extension. | 195 // Non-standard extension. |
| 202 function MathImul(x, y) { | 196 function MathImul(x, y) { |
| 203 return %NumberImul(TO_NUMBER_INLINE(x), TO_NUMBER_INLINE(y)); | 197 return %NumberImul(TO_NUMBER_INLINE(x), TO_NUMBER_INLINE(y)); |
| 204 } | 198 } |
| 205 | 199 |
| 206 | 200 |
| 201 var MathSinImpl = function(x) { |
| 202 InitTrigonometricFunctions(); |
| 203 return MathSinImpl(x); |
| 204 } |
| 205 |
| 206 |
| 207 var MathCosImpl = function(x) { |
| 208 InitTrigonometricFunctions(); |
| 209 return MathCosImpl(x); |
| 210 } |
| 211 |
| 212 |
| 213 var InitTrigonometricFunctions; |
| 214 |
| 215 |
| 216 // Define constants and interpolation functions. |
| 217 // Also define the initialization function that populates the lookup table |
| 218 // and then wires up the function definitions. |
| 219 function SetupTrigonometricFunctions() { |
| 220 var samples = 1800; // Table size. |
| 221 var pi = 3.1415926535897932; |
| 222 var pi_half = pi / 2; |
| 223 var inverse_pi_half = 1 / pi_half; |
| 224 var two_pi = pi * 2; |
| 225 var interval = pi_half / samples; |
| 226 var inverse_interval = samples / pi_half; |
| 227 var table_sin; |
| 228 var table_cos_interval; |
| 229 |
| 230 // This implements sine using the following algorithm. |
| 231 // 1) Multiplication takes care of to-number conversion. |
| 232 // 2) Reduce x to the first quadrant [0, pi/2]. |
| 233 // Conveniently enough, in case of +/-Infinity, we get NaN. |
| 234 // 3) Replace x by (pi/2-x) if x was in the 2nd or 4th quadrant. |
| 235 // 4) Do a table lookup for the closest samples to the left and right of x. |
| 236 // 5) Find the derivatives at those sampling points by table lookup: |
| 237 // dsin(x)/dx = cos(x) = sin(pi/2-x) for x in [0, pi/2]. |
| 238 // 6) Use cubic spline interpolation to approximate sin(x). |
| 239 // 7) Negate the result if x was in the 3rd or 4th quadrant. |
| 240 // 8) Get rid of -0 by adding 0. |
| 241 var Interpolation = function(x) { |
| 242 var double_index = x * inverse_interval; |
| 243 var index = double_index | 0; |
| 244 var t1 = double_index - index; |
| 245 var t2 = 1 - t1; |
| 246 var y1 = table_sin[index]; |
| 247 var y2 = table_sin[index + 1]; |
| 248 var dy = y2 - y1; |
| 249 return (t2 * y1 + t1 * y2 + |
| 250 t1 * t2 * ((table_cos_interval[index] - dy) * t2 + |
| 251 (dy - table_cos_interval[index + 1]) * t1)); |
| 252 } |
| 253 |
| 254 var MathSinInterpolation = function(x) { |
| 255 var multiple = MathFloor(x * inverse_pi_half); |
| 256 if (%_IsMinusZero(multiple)) return multiple; |
| 257 x = (multiple & 1) * pi_half + |
| 258 (1 - ((multiple & 1) << 1)) * (x - multiple * pi_half); |
| 259 return Interpolation(x) * (1 - (multiple & 2)) + 0; |
| 260 } |
| 261 |
| 262 // Cosine is sine with a phase offset of pi/2. |
| 263 var MathCosInterpolation = function(x) { |
| 264 var multiple = MathFloor(x * inverse_pi_half); |
| 265 var phase = multiple + 1; |
| 266 x = (phase & 1) * pi_half + |
| 267 (1 - ((phase & 1) << 1)) * (x - multiple * pi_half); |
| 268 return Interpolation(x) * (1 - (phase & 2)) + 0; |
| 269 }; |
| 270 |
| 271 %SetInlineBuiltinFlag(Interpolation); |
| 272 %SetInlineBuiltinFlag(MathSinInterpolation); |
| 273 %SetInlineBuiltinFlag(MathCosInterpolation); |
| 274 |
| 275 InitTrigonometricFunctions = function() { |
| 276 table_sin = new global.Float64Array(samples + 2); |
| 277 table_cos_interval = new global.Float64Array(samples + 2); |
| 278 %PopulateTrigonometricTable(table_sin, table_cos_interval, samples); |
| 279 MathSinImpl = MathSinInterpolation; |
| 280 MathCosImpl = MathCosInterpolation; |
| 281 } |
| 282 } |
| 283 |
| 284 SetupTrigonometricFunctions(); |
| 285 |
| 286 |
| 207 // ------------------------------------------------------------------- | 287 // ------------------------------------------------------------------- |
| 208 | 288 |
| 209 function SetUpMath() { | 289 function SetUpMath() { |
| 210 %CheckIsBootstrapping(); | 290 %CheckIsBootstrapping(); |
| 211 | 291 |
| 212 %SetPrototype($Math, $Object.prototype); | 292 %SetPrototype($Math, $Object.prototype); |
| 213 %SetProperty(global, "Math", $Math, DONT_ENUM); | 293 %SetProperty(global, "Math", $Math, DONT_ENUM); |
| 214 %FunctionSetInstanceClassName(MathConstructor, 'Math'); | 294 %FunctionSetInstanceClassName(MathConstructor, 'Math'); |
| 215 | 295 |
| 216 // Set up math constants. | 296 // Set up math constants. |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 269 "round", MathRound, | 349 "round", MathRound, |
| 270 "sin", MathSin, | 350 "sin", MathSin, |
| 271 "sqrt", MathSqrt, | 351 "sqrt", MathSqrt, |
| 272 "tan", MathTan, | 352 "tan", MathTan, |
| 273 "atan2", MathAtan2, | 353 "atan2", MathAtan2, |
| 274 "pow", MathPow, | 354 "pow", MathPow, |
| 275 "max", MathMax, | 355 "max", MathMax, |
| 276 "min", MathMin, | 356 "min", MathMin, |
| 277 "imul", MathImul | 357 "imul", MathImul |
| 278 )); | 358 )); |
| 359 |
| 360 %SetInlineBuiltinFlag(MathSin); |
| 361 %SetInlineBuiltinFlag(MathCos); |
| 362 %SetInlineBuiltinFlag(MathTan); |
| 279 } | 363 } |
| 280 | 364 |
| 281 SetUpMath(); | 365 SetUpMath(); |
| OLD | NEW |