Reland "Implement trigonometric functions using a fdlibm port."
authoryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 6 Aug 2014 11:39:39 +0000 (11:39 +0000)
committeryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 6 Aug 2014 11:39:39 +0000 (11:39 +0000)
R=svenpanne@chromium.org

Review URL: https://codereview.chromium.org/448643002

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22923 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

22 files changed:
.gitignore
BUILD.gn
DEPS
src/bootstrapper.cc
src/math.js
src/runtime.cc
src/runtime.h
src/trig-table.h [deleted file]
test/mjsunit/debug-script.js
test/mjsunit/mirror-script.js
test/mjsunit/runtime-gen/rempio2.js [new file with mode: 0644]
test/mjsunit/sin-cos.js
test/test262/test262.status
third_party/fdlibm/LICENSE [new file with mode: 0644]
third_party/fdlibm/README.v8 [new file with mode: 0644]
third_party/fdlibm/fdlibm.cc [new file with mode: 0644]
third_party/fdlibm/fdlibm.h [new file with mode: 0644]
third_party/fdlibm/fdlibm.js [new file with mode: 0644]
tools/generate-runtime-tests.py
tools/generate-trig-table.py [deleted file]
tools/gyp/v8.gyp
tools/js2c.py

index 158e493..707582c 100644 (file)
@@ -63,7 +63,7 @@ shell_g
 /test/test262/tc39-test262-*
 /testing/gmock
 /testing/gtest
-/third_party
+/third_party/icu
 /tools/jsfunfuzz
 /tools/jsfunfuzz.zip
 /tools/oom_dump/oom_dump
index 07772ab..b3813d2 100644 (file)
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -194,6 +194,7 @@ action("js2c") {
     "src/string.js",
     "src/symbol.js",
     "src/uri.js",
+    "third_party/fdlibm/fdlibm.js",
     "src/math.js",
     "src/messages.js",
     "src/apinatives.js",
@@ -865,6 +866,8 @@ source_set("v8_base") {
     "src/zone-inl.h",
     "src/zone.cc",
     "src/zone.h",
+    "third_party/fdlibm/fdlibm.cc',
+    "third_party/fdlibm/fdlibm.h',
   ]
 
   if (v8_target_arch == "x86") {
diff --git a/DEPS b/DEPS
index de9d013..d45080f 100644 (file)
--- a/DEPS
+++ b/DEPS
@@ -41,6 +41,7 @@ include_rules = [
   # Everybody can use some things.
   "+include",
   "+unicode",
+  "+third_party/fdlibm",
 ]
 
 # checkdeps.py shouldn't check for includes in these directories:
index a746c90..c297a37 100644 (file)
@@ -14,7 +14,7 @@
 #include "src/isolate-inl.h"
 #include "src/natives.h"
 #include "src/snapshot.h"
-#include "src/trig-table.h"
+#include "third_party/fdlibm/fdlibm.h"
 
 namespace v8 {
 namespace internal {
@@ -121,7 +121,7 @@ char* Bootstrapper::AllocateAutoDeletedArray(int bytes) {
 void Bootstrapper::TearDown() {
   if (delete_these_non_arrays_on_tear_down_ != NULL) {
     int len = delete_these_non_arrays_on_tear_down_->length();
-    DCHECK(len < 24);  // Don't use this mechanism for unbounded allocations.
+    DCHECK(len < 25);  // Don't use this mechanism for unbounded allocations.
     for (int i = 0; i < len; i++) {
       delete delete_these_non_arrays_on_tear_down_->at(i);
       delete_these_non_arrays_on_tear_down_->at(i) = NULL;
@@ -2651,43 +2651,19 @@ Genesis::Genesis(Isolate* isolate,
                                   NONE).Assert();
 
     // Initialize trigonometric lookup tables and constants.
-    const int table_num_bytes = TrigonometricLookupTable::table_num_bytes();
-    v8::Local<v8::ArrayBuffer> sin_buffer = v8::ArrayBuffer::New(
+    const int constants_size = ARRAY_SIZE(TrigonometricConstants::constants);
+    const int table_num_bytes = constants_size * kDoubleSize;
+    v8::Local<v8::ArrayBuffer> trig_buffer = v8::ArrayBuffer::New(
         reinterpret_cast<v8::Isolate*>(isolate),
-        TrigonometricLookupTable::sin_table(), table_num_bytes);
-    v8::Local<v8::ArrayBuffer> cos_buffer = v8::ArrayBuffer::New(
-        reinterpret_cast<v8::Isolate*>(isolate),
-        TrigonometricLookupTable::cos_x_interval_table(), table_num_bytes);
-    v8::Local<v8::Float64Array> sin_table = v8::Float64Array::New(
-        sin_buffer, 0, TrigonometricLookupTable::table_size());
-    v8::Local<v8::Float64Array> cos_table = v8::Float64Array::New(
-        cos_buffer, 0, TrigonometricLookupTable::table_size());
+        const_cast<double*>(TrigonometricConstants::constants),
+        table_num_bytes);
+    v8::Local<v8::Float64Array> trig_table =
+        v8::Float64Array::New(trig_buffer, 0, constants_size);
 
-    Runtime::DefineObjectProperty(builtins,
-                                  factory()->InternalizeOneByteString(
-                                      STATIC_ASCII_VECTOR("kSinTable")),
-                                  Utils::OpenHandle(*sin_table),
-                                  NONE).Assert();
-    Runtime::DefineObjectProperty(
-        builtins,
-        factory()->InternalizeOneByteString(
-            STATIC_ASCII_VECTOR("kCosXIntervalTable")),
-        Utils::OpenHandle(*cos_table),
-        NONE).Assert();
-    Runtime::DefineObjectProperty(
-        builtins,
-        factory()->InternalizeOneByteString(
-            STATIC_ASCII_VECTOR("kSamples")),
-        factory()->NewHeapNumber(
-            TrigonometricLookupTable::samples()),
-        NONE).Assert();
     Runtime::DefineObjectProperty(
         builtins,
-        factory()->InternalizeOneByteString(
-            STATIC_ASCII_VECTOR("kIndexConvert")),
-        factory()->NewHeapNumber(
-            TrigonometricLookupTable::samples_over_pi_half()),
-        NONE).Assert();
+        factory()->InternalizeOneByteString(STATIC_ASCII_VECTOR("kTrig")),
+        Utils::OpenHandle(*trig_table), NONE).Assert();
   }
 
   result_ = native_context();
index 9dc4b37..436a41f 100644 (file)
@@ -56,12 +56,6 @@ function MathCeil(x) {
   return -MathFloor(-x);
 }
 
-// ECMA 262 - 15.8.2.7
-function MathCos(x) {
-  x = MathAbs(x);  // Convert to number and get rid of -0.
-  return TrigonometricInterpolation(x, 1);
-}
-
 // ECMA 262 - 15.8.2.8
 function MathExp(x) {
   return %MathExpRT(TO_NUMBER_INLINE(x));
@@ -164,97 +158,16 @@ function MathRound(x) {
   return %RoundNumber(TO_NUMBER_INLINE(x));
 }
 
-// ECMA 262 - 15.8.2.16
-function MathSin(x) {
-  x = x * 1;  // Convert to number and deal with -0.
-  if (%_IsMinusZero(x)) return x;
-  return TrigonometricInterpolation(x, 0);
-}
-
 // ECMA 262 - 15.8.2.17
 function MathSqrt(x) {
   return %_MathSqrtRT(TO_NUMBER_INLINE(x));
 }
 
-// ECMA 262 - 15.8.2.18
-function MathTan(x) {
-  return MathSin(x) / MathCos(x);
-}
-
 // Non-standard extension.
 function MathImul(x, y) {
   return %NumberImul(TO_NUMBER_INLINE(x), TO_NUMBER_INLINE(y));
 }
 
-
-var kInversePiHalf      = 0.636619772367581343;      // 2 / pi
-var kInversePiHalfS26   = 9.48637384723993156e-9;    // 2 / pi / (2^26)
-var kS26                = 1 << 26;
-var kTwoStepThreshold   = 1 << 27;
-// pi / 2 rounded up
-var kPiHalf             = 1.570796326794896780;      // 0x192d4454fb21f93f
-// We use two parts for pi/2 to emulate a higher precision.
-// pi_half_1 only has 26 significant bits for mantissa.
-// Note that pi_half > pi_half_1 + pi_half_2
-var kPiHalf1            = 1.570796325802803040;      // 0x00000054fb21f93f
-var kPiHalf2            = 9.920935796805404252e-10;  // 0x3326a611460b113e
-
-var kSamples;            // Initialized to a number during genesis.
-var kIndexConvert;       // Initialized to kSamples / (pi/2) during genesis.
-var kSinTable;           // Initialized to a Float64Array during genesis.
-var kCosXIntervalTable;  // Initialized to a Float64Array during genesis.
-
-// This implements sine using the following algorithm.
-// 1) Multiplication takes care of to-number conversion.
-// 2) Reduce x to the first quadrant [0, pi/2].
-//    Conveniently enough, in case of +/-Infinity, we get NaN.
-//    Note that we try to use only 26 instead of 52 significant bits for
-//    mantissa to avoid rounding errors when multiplying.  For very large
-//    input we therefore have additional steps.
-// 3) Replace x by (pi/2-x) if x was in the 2nd or 4th quadrant.
-// 4) Do a table lookup for the closest samples to the left and right of x.
-// 5) Find the derivatives at those sampling points by table lookup:
-//    dsin(x)/dx = cos(x) = sin(pi/2-x) for x in [0, pi/2].
-// 6) Use cubic spline interpolation to approximate sin(x).
-// 7) Negate the result if x was in the 3rd or 4th quadrant.
-// 8) Get rid of -0 by adding 0.
-function TrigonometricInterpolation(x, phase) {
-  if (x < 0 || x > kPiHalf) {
-    var multiple;
-    while (x < -kTwoStepThreshold || x > kTwoStepThreshold) {
-      // Let's assume this loop does not terminate.
-      // All numbers x in each loop forms a set S.
-      // (1) abs(x) > 2^27 for all x in S.
-      // (2) abs(multiple) != 0 since (2^27 * inverse_pi_half_s26) > 1
-      // (3) multiple is rounded down in 2^26 steps, so the rounding error is
-      //     at most max(ulp, 2^26).
-      // (4) so for x > 2^27, we subtract at most (1+pi/4)x and at least
-      //     (1-pi/4)x
-      // (5) The subtraction results in x' so that abs(x') <= abs(x)*pi/4.
-      //     Note that this difference cannot be simply rounded off.
-      // Set S cannot exist since (5) violates (1).  Loop must terminate.
-      multiple = MathFloor(x * kInversePiHalfS26) * kS26;
-      x = x - multiple * kPiHalf1 - multiple * kPiHalf2;
-    }
-    multiple = MathFloor(x * kInversePiHalf);
-    x = x - multiple * kPiHalf1 - multiple * kPiHalf2;
-    phase += multiple;
-  }
-  var double_index = x * kIndexConvert;
-  if (phase & 1) double_index = kSamples - double_index;
-  var index = double_index | 0;
-  var t1 = double_index - index;
-  var t2 = 1 - t1;
-  var y1 = kSinTable[index];
-  var y2 = kSinTable[index + 1];
-  var dy = y2 - y1;
-  return (t2 * y1 + t1 * y2 +
-              t1 * t2 * ((kCosXIntervalTable[index] - dy) * t2 +
-                         (dy - kCosXIntervalTable[index + 1]) * t1))
-         * (1 - (phase & 2)) + 0;
-}
-
-
 // ES6 draft 09-27-13, section 20.2.2.28.
 function MathSign(x) {
   x = TO_NUMBER_INLINE(x);
@@ -264,7 +177,6 @@ function MathSign(x) {
   return NAN;
 }
 
-
 // ES6 draft 09-27-13, section 20.2.2.34.
 function MathTrunc(x) {
   x = TO_NUMBER_INLINE(x);
@@ -274,7 +186,6 @@ function MathTrunc(x) {
   return NAN;
 }
 
-
 // ES6 draft 09-27-13, section 20.2.2.30.
 function MathSinh(x) {
   if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
@@ -283,7 +194,6 @@ function MathSinh(x) {
   return (MathExp(x) - MathExp(-x)) / 2;
 }
 
-
 // ES6 draft 09-27-13, section 20.2.2.12.
 function MathCosh(x) {
   if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
@@ -291,7 +201,6 @@ function MathCosh(x) {
   return (MathExp(x) + MathExp(-x)) / 2;
 }
 
-
 // ES6 draft 09-27-13, section 20.2.2.33.
 function MathTanh(x) {
   if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
@@ -304,7 +213,6 @@ function MathTanh(x) {
   return (exp1 - exp2) / (exp1 + exp2);
 }
 
-
 // ES6 draft 09-27-13, section 20.2.2.5.
 function MathAsinh(x) {
   if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
@@ -315,7 +223,6 @@ function MathAsinh(x) {
   return -MathLog(-x + MathSqrt(x * x + 1));
 }
 
-
 // ES6 draft 09-27-13, section 20.2.2.3.
 function MathAcosh(x) {
   if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
@@ -325,7 +232,6 @@ function MathAcosh(x) {
   return MathLog(x + MathSqrt(x + 1) * MathSqrt(x - 1));
 }
 
-
 // ES6 draft 09-27-13, section 20.2.2.7.
 function MathAtanh(x) {
   if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
@@ -336,7 +242,6 @@ function MathAtanh(x) {
   return 0.5 * MathLog((1 + x) / (1 - x));
 }
 
-
 // ES6 draft 09-27-13, section 20.2.2.21.
 function MathLog10(x) {
   return MathLog(x) * 0.434294481903251828;  // log10(x) = log(x)/log(10).
@@ -348,7 +253,6 @@ function MathLog2(x) {
   return MathLog(x) * 1.442695040888963407;  // log2(x) = log(x)/log(2).
 }
 
-
 // ES6 draft 09-27-13, section 20.2.2.17.
 function MathHypot(x, y) {  // Function length is 2.
   // We may want to introduce fast paths for two arguments and when
@@ -381,13 +285,12 @@ function MathHypot(x, y) {  // Function length is 2.
   return MathSqrt(sum) * max;
 }
 
-
 // ES6 draft 09-27-13, section 20.2.2.16.
 function MathFroundJS(x) {
   return %MathFround(TO_NUMBER_INLINE(x));
 }
 
-
+// ES6 draft 07-18-14, section 20.2.2.11
 function MathClz32(x) {
   x = ToUint32(TO_NUMBER_INLINE(x));
   if (x == 0) return 32;
@@ -401,7 +304,6 @@ function MathClz32(x) {
   return result;
 }
 
-
 // ES6 draft 09-27-13, section 20.2.2.9.
 // Cube root approximation, refer to: http://metamerist.com/cbrt/cbrt.htm
 // Using initial approximation adapted from Kahan's cbrt and 4 iterations
@@ -425,8 +327,6 @@ function CubeRoot(x) {
   return NEWTON_ITERATION_CBRT(x, approx);
 }
 
-
-
 // ES6 draft 09-27-13, section 20.2.2.14.
 // Use Taylor series to approximate.
 // exp(x) - 1 at 0 == -1 + exp(0) + exp'(0)*x/1! + exp''(0)*x^2/2! + ...
@@ -447,7 +347,6 @@ function MathExpm1(x) {
   }
 }
 
-
 // ES6 draft 09-27-13, section 20.2.2.20.
 // Use Taylor series to approximate. With y = x + 1;
 // log(y) at 1 == log(1) + log'(1)(y-1)/1! + log''(1)(y-1)^2/2! + ...
@@ -502,14 +401,14 @@ function SetUpMath() {
     "asin", MathAsinJS,
     "atan", MathAtanJS,
     "ceil", MathCeil,
-    "cos", MathCos,
+    "cos", MathCos,       // implemented by third_party/fdlibm
     "exp", MathExp,
     "floor", MathFloor,
     "log", MathLog,
     "round", MathRound,
-    "sin", MathSin,
+    "sin", MathSin,       // implemented by third_party/fdlibm
     "sqrt", MathSqrt,
-    "tan", MathTan,
+    "tan", MathTan,       // implemented by third_party/fdlibm
     "atan2", MathAtan2JS,
     "pow", MathPow,
     "max", MathMax,
@@ -537,8 +436,6 @@ function SetUpMath() {
   %SetInlineBuiltinFlag(MathRandom);
   %SetInlineBuiltinFlag(MathSin);
   %SetInlineBuiltinFlag(MathCos);
-  %SetInlineBuiltinFlag(MathTan);
-  %SetInlineBuiltinFlag(TrigonometricInterpolation);
 }
 
 SetUpMath();
index 5e18c97..cc41117 100644 (file)
@@ -45,6 +45,7 @@
 #include "src/utils.h"
 #include "src/v8threads.h"
 #include "src/vm-state-inl.h"
+#include "third_party/fdlibm/fdlibm.h"
 
 #ifdef V8_I18N_SUPPORT
 #include "src/i18n.h"
@@ -7683,6 +7684,23 @@ RUNTIME_FUNCTION(Runtime_ConstructDouble) {
 }
 
 
+RUNTIME_FUNCTION(Runtime_RemPiO2) {
+  HandleScope handle_scope(isolate);
+  DCHECK(args.length() == 1);
+  CONVERT_DOUBLE_ARG_CHECKED(x, 0);
+  Factory* factory = isolate->factory();
+  double y[2];
+  int n = rempio2(x, y);
+  Handle<FixedArray> array = factory->NewFixedArray(3);
+  Handle<HeapNumber> y0 = factory->NewHeapNumber(y[0]);
+  Handle<HeapNumber> y1 = factory->NewHeapNumber(y[1]);
+  array->set(0, Smi::FromInt(n));
+  array->set(1, *y0);
+  array->set(2, *y1);
+  return *factory->NewJSArrayWithElements(array);
+}
+
+
 static const double kPiDividedBy4 = 0.78539816339744830962;
 
 
index e8b7892..d0100c5 100644 (file)
@@ -149,6 +149,7 @@ namespace internal {
   F(MathExpRT, 1, 1)                                        \
   F(RoundNumber, 1, 1)                                      \
   F(MathFround, 1, 1)                                       \
+  F(RemPiO2, 1, 1)                                          \
                                                             \
   /* Regular expressions */                                 \
   F(RegExpCompile, 3, 1)                                    \
diff --git a/src/trig-table.h b/src/trig-table.h
deleted file mode 100644 (file)
index 7332152..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2013 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.
-
-#ifndef V8_TRIG_TABLE_H_
-#define V8_TRIG_TABLE_H_
-
-
-namespace v8 {
-namespace internal {
-
-class TrigonometricLookupTable : public AllStatic {
- public:
-  // Casting away const-ness to use as argument for typed array constructor.
-  static void* sin_table() {
-    return const_cast<double*>(&kSinTable[0]);
-  }
-
-  static void* cos_x_interval_table() {
-    return const_cast<double*>(&kCosXIntervalTable[0]);
-  }
-
-  static double samples_over_pi_half() { return kSamplesOverPiHalf; }
-  static int samples() { return kSamples; }
-  static int table_num_bytes() { return kTableSize * sizeof(*kSinTable); }
-  static int table_size() { return kTableSize; }
-
- private:
-  static const double kSinTable[];
-  static const double kCosXIntervalTable[];
-  static const int kSamples;
-  static const int kTableSize;
-  static const double kSamplesOverPiHalf;
-};
-
-} }  // namespace v8::internal
-
-#endif  // V8_TRIG_TABLE_H_
index 3a4361a..54e80e0 100644 (file)
@@ -59,7 +59,7 @@ for (i = 0; i < scripts.length; i++) {
 }
 
 // This has to be updated if the number of native scripts change.
-assertTrue(named_native_count == 22 || named_native_count == 23);
+assertTrue(named_native_count == 23 || named_native_count == 24);
 // Only the 'gc' extension is loaded.
 assertEquals(1, extension_count);
 // This script and mjsunit.js has been loaded.  If using d8, d8 loads
index 1d64ac2..e545a61 100644 (file)
@@ -84,7 +84,7 @@ function testScriptMirror(f, file_name, file_lines, type, compilation_type,
 
 // Test the script mirror for different functions.
 testScriptMirror(function(){}, 'mirror-script.js', 98, 2, 0);
-testScriptMirror(Math.sin, 'native math.js', -1, 0, 0);
+testScriptMirror(Math.round, 'native math.js', -1, 0, 0);
 testScriptMirror(eval('(function(){})'), null, 1, 2, 1, '(function(){})', 87);
 testScriptMirror(eval('(function(){\n  })'), null, 2, 2, 1, '(function(){\n  })', 88);
 
diff --git a/test/mjsunit/runtime-gen/rempio2.js b/test/mjsunit/runtime-gen/rempio2.js
new file mode 100644 (file)
index 0000000..03a84b3
--- /dev/null
@@ -0,0 +1,5 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
+// Flags: --allow-natives-syntax --harmony
+var _x = 1.5;
+%RemPiO2(_x);
index 02ae57b..71fae20 100644 (file)
@@ -157,8 +157,8 @@ assertEquals(0, Math.sin("0x00000"));
 assertEquals(1, Math.cos("0x00000"));
 assertTrue(isNaN(Math.sin(Infinity)));
 assertTrue(isNaN(Math.cos("-Infinity")));
-assertEquals("Infinity", String(Math.tan(Math.PI/2)));
-assertEquals("-Infinity", String(Math.tan(-Math.PI/2)));
+assertTrue(Math.tan(Math.PI/2) > 1e16);
+assertTrue(Math.tan(-Math.PI/2) < -1e16);
 assertEquals("-Infinity", String(1/Math.sin("-0")));
 
 // Assert that the remainder after division by pi is reasonably precise.
@@ -185,3 +185,96 @@ for (var i = -1024; i < 1024; i++) {
 assertFalse(isNaN(Math.cos(1.57079632679489700)));
 assertFalse(isNaN(Math.cos(-1e-100)));
 assertFalse(isNaN(Math.cos(-1e-323)));
+
+// Tests for specific values expected from the fdlibm implementation.
+
+var two_32 = Math.pow(2, -32);
+var two_28 = Math.pow(2, -28);
+
+// Tests for Math.sin for |x| < pi/4
+assertEquals(Infinity, 1/Math.sin(+0.0));
+assertEquals(-Infinity, 1/Math.sin(-0.0));
+// sin(x) = x for x < 2^-27
+assertEquals(two_32, Math.sin(two_32));
+assertEquals(-two_32, Math.sin(-two_32));
+// sin(pi/8) = sqrt(sqrt(2)-1)/2^(3/4)
+assertEquals(0.3826834323650898, Math.sin(Math.PI/8));
+assertEquals(-0.3826834323650898, -Math.sin(Math.PI/8));
+
+// Tests for Math.cos for |x| < pi/4
+// cos(x) = 1 for |x| < 2^-27
+assertEquals(1, Math.cos(two_32));
+assertEquals(1, Math.cos(-two_32));
+// Test KERNELCOS for |x| < 0.3.
+// cos(pi/20) = sqrt(sqrt(2)*sqrt(sqrt(5)+5)+4)/2^(3/2)
+assertEquals(0.9876883405951378, Math.cos(Math.PI/20));
+// Test KERNELCOS for x ~= 0.78125
+assertEquals(0.7100335477927638, Math.cos(0.7812504768371582));
+assertEquals(0.7100338835660797, Math.cos(0.78125));
+// Test KERNELCOS for |x| > 0.3.
+// cos(pi/8) = sqrt(sqrt(2)+1)/2^(3/4)
+assertEquals(0.9238795325112867, Math.cos(Math.PI/8));
+// Test KERNELTAN for |x| < 0.67434.
+assertEquals(0.9238795325112867, Math.cos(-Math.PI/8));
+
+// Tests for Math.tan for |x| < pi/4
+assertEquals(Infinity, 1/Math.tan(0.0));
+assertEquals(-Infinity, 1/Math.tan(-0.0));
+// tan(x) = x for |x| < 2^-28
+assertEquals(two_32, Math.tan(two_32));
+assertEquals(-two_32, Math.tan(-two_32));
+// Test KERNELTAN for |x| > 0.67434.
+assertEquals(0.8211418015898941, Math.tan(11/16));
+assertEquals(-0.8211418015898941, Math.tan(-11/16));
+assertEquals(0.41421356237309503, Math.tan(Math.PI / 8));
+
+// Tests for Math.sin.
+assertEquals(0.479425538604203, Math.sin(0.5));
+assertEquals(-0.479425538604203, Math.sin(-0.5));
+assertEquals(1, Math.sin(Math.PI/2));
+assertEquals(-1, Math.sin(-Math.PI/2));
+// Test that Math.sin(Math.PI) != 0 since Math.PI is not exact.
+assertEquals(1.2246467991473532e-16, Math.sin(Math.PI));
+assertEquals(-7.047032979958965e-14, Math.sin(2200*Math.PI));
+// Test Math.sin for various phases.
+assertEquals(-0.7071067811865477, Math.sin(7/4 * Math.PI));
+assertEquals(0.7071067811865474, Math.sin(9/4 * Math.PI));
+assertEquals(0.7071067811865483, Math.sin(11/4 * Math.PI));
+assertEquals(-0.7071067811865479, Math.sin(13/4 * Math.PI));
+assertEquals(-3.2103381051568376e-11, Math.sin(1048576/4 * Math.PI));
+
+// Tests for Math.cos.
+assertEquals(1, Math.cos(two_28));
+// Cover different code paths in KERNELCOS.
+assertEquals(0.9689124217106447, Math.cos(0.25));
+assertEquals(0.8775825618903728, Math.cos(0.5));
+assertEquals(0.7073882691671998, Math.cos(0.785));
+// Test that Math.cos(Math.PI/2) != 0 since Math.PI is not exact.
+assertEquals(6.123233995736766e-17, Math.cos(Math.PI/2));
+// Test Math.cos for various phases.
+assertEquals(0.7071067811865474, Math.cos(7/4 * Math.PI));
+assertEquals(0.7071067811865477, Math.cos(9/4 * Math.PI));
+assertEquals(-0.7071067811865467, Math.cos(11/4 * Math.PI));
+assertEquals(-0.7071067811865471, Math.cos(13/4 * Math.PI));
+assertEquals(0.9367521275331447, Math.cos(1000000));
+assertEquals(-3.435757038074824e-12, Math.cos(1048575/2 * Math.PI));
+
+// Tests for Math.tan.
+assertEquals(two_28, Math.tan(two_28));
+// Test that  Math.tan(Math.PI/2) != Infinity since Math.PI is not exact.
+assertEquals(1.633123935319537e16, Math.tan(Math.PI/2));
+// Cover different code paths in KERNELTAN (tangent and cotangent)
+assertEquals(0.5463024898437905, Math.tan(0.5));
+assertEquals(2.0000000000000027, Math.tan(1.107148717794091));
+assertEquals(-1.0000000000000004, Math.tan(7/4*Math.PI));
+assertEquals(0.9999999999999994, Math.tan(9/4*Math.PI));
+assertEquals(-6.420676210313675e-11, Math.tan(1048576/2*Math.PI));
+assertEquals(2.910566692924059e11, Math.tan(1048575/2*Math.PI));
+
+// Test Hayne-Panek reduction.
+assertEquals(0.377820109360752e0, Math.sin(Math.pow(2, 120)));
+assertEquals(-0.9258790228548379e0, Math.cos(Math.pow(2, 120)));
+assertEquals(-0.40806638884180424e0, Math.tan(Math.pow(2, 120)));
+assertEquals(-0.377820109360752e0, Math.sin(-Math.pow(2, 120)));
+assertEquals(-0.9258790228548379e0, Math.cos(-Math.pow(2, 120)));
+assertEquals(0.40806638884180424e0, Math.tan(-Math.pow(2, 120)));
index 18d65c4..dd075d9 100644 (file)
 
   ##################### DELIBERATE INCOMPATIBILITIES #####################
 
-  # This tests precision of Math functions.  The implementation for those
-  # trigonometric functions are platform/compiler dependent.  Furthermore, the
-  # expectation values by far deviates from the actual result given by an
-  # arbitrary-precision calculator, making those tests partly bogus.
-  'S15.8.2.7_A7': [PASS, FAIL_OK],  # Math.cos
   'S15.8.2.8_A6': [PASS, FAIL_OK],  # Math.exp (less precise with --fast-math)
-  'S15.8.2.16_A7': [PASS, FAIL_OK],  # Math.sin
-  'S15.8.2.18_A7': [PASS, FAIL_OK],  # Math.tan
 
   # Linux for ia32 (and therefore simulators) default to extended 80 bit
   # floating point formats, so these tests checking 64-bit FP precision fail.
diff --git a/third_party/fdlibm/LICENSE b/third_party/fdlibm/LICENSE
new file mode 100644 (file)
index 0000000..b024795
--- /dev/null
@@ -0,0 +1,6 @@
+Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+
+Developed at SunSoft, a Sun Microsystems, Inc. business.
+Permission to use, copy, modify, and distribute this
+software is freely granted, provided that this notice
+is preserved.
diff --git a/third_party/fdlibm/README.v8 b/third_party/fdlibm/README.v8
new file mode 100644 (file)
index 0000000..ea8fdb6
--- /dev/null
@@ -0,0 +1,18 @@
+Name: Freely Distributable LIBM 
+Short Name: fdlibm
+URL: http://www.netlib.org/fdlibm/
+Version: 5.3 
+License: Freely Distributable.
+License File: LICENSE.
+Security Critical: yes.
+License Android Compatible: yes.
+
+Description:
+This is used to provide a accurate implementation for trigonometric functions
+used in V8.
+
+Local Modifications:
+For the use in V8, fdlibm has been reduced to include only sine, cosine and
+tangent.  To make inlining into generated code possible, a large portion of
+that has been translated to Javascript.  The rest remains in C, but has been
+refactored and reformatted to interoperate with the rest of V8.
diff --git a/third_party/fdlibm/fdlibm.cc b/third_party/fdlibm/fdlibm.cc
new file mode 100644 (file)
index 0000000..6b8084f
--- /dev/null
@@ -0,0 +1,262 @@
+// The following is adapted from fdlibm (http://www.netlib.org/fdlibm).
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunSoft, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+// The original source code covered by the above license above has been
+// modified significantly by Google Inc.
+// Copyright 2014 the V8 project authors. All rights reserved.
+
+#include "src/v8.h"
+
+#include "src/double.h"
+#include "third_party/fdlibm/fdlibm.h"
+
+
+namespace v8 {
+namespace internal {
+
+#ifdef _MSC_VER
+inline double scalbn(double x, int y) { return _scalb(x, y); }
+#endif  // _MSC_VER
+
+const double TrigonometricConstants::constants[] = {
+    6.36619772367581382433e-01,   // invpio2   0
+    1.57079632673412561417e+00,   // pio2_1    1
+    6.07710050650619224932e-11,   // pio2_1t   2
+    6.07710050630396597660e-11,   // pio2_2    3
+    2.02226624879595063154e-21,   // pio2_2t   4
+    2.02226624871116645580e-21,   // pio2_3    5
+    8.47842766036889956997e-32,   // pio2_3t   6
+    -1.66666666666666324348e-01,  // S1        7
+    8.33333333332248946124e-03,   //           8
+    -1.98412698298579493134e-04,  //           9
+    2.75573137070700676789e-06,   //          10
+    -2.50507602534068634195e-08,  //          11
+    1.58969099521155010221e-10,   // S6       12
+    4.16666666666666019037e-02,   // C1       13
+    -1.38888888888741095749e-03,  //          14
+    2.48015872894767294178e-05,   //          15
+    -2.75573143513906633035e-07,  //          16
+    2.08757232129817482790e-09,   //          17
+    -1.13596475577881948265e-11,  // C6       18
+    3.33333333333334091986e-01,   // T0       19
+    1.33333333333201242699e-01,   //          20
+    5.39682539762260521377e-02,   //          21
+    2.18694882948595424599e-02,   //          22
+    8.86323982359930005737e-03,   //          23
+    3.59207910759131235356e-03,   //          24
+    1.45620945432529025516e-03,   //          25
+    5.88041240820264096874e-04,   //          26
+    2.46463134818469906812e-04,   //          27
+    7.81794442939557092300e-05,   //          28
+    7.14072491382608190305e-05,   //          29
+    -1.85586374855275456654e-05,  //          30
+    2.59073051863633712884e-05,   // T12      31
+    7.85398163397448278999e-01,   // pio4     32
+    3.06161699786838301793e-17,   // pio4lo   33
+};
+
+
+// Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi
+static const int two_over_pi[] = {
+    0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 0x95993C,
+    0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, 0x424DD2, 0xE00649,
+    0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, 0xA73EE8, 0x8235F5, 0x2EBB44,
+    0x84E99C, 0x7026B4, 0x5F7E41, 0x3991D6, 0x398353, 0x39F49C, 0x845F8B,
+    0xBDF928, 0x3B1FF8, 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D,
+    0x367ECF, 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5,
+    0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, 0x560330,
+    0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, 0x91615E, 0xE61B08,
+    0x659985, 0x5F14A0, 0x68408D, 0xFFD880, 0x4D7327, 0x310606, 0x1556CA,
+    0x73A8C9, 0x60E27B, 0xC08C6B};
+
+static const double zero = 0.0;
+static const double two24 = 1.6777216e+07;
+static const double one = 1.0;
+static const double twon24 = 5.9604644775390625e-08;
+
+static const double PIo2[] = {
+    1.57079625129699707031e+00,  // 0x3FF921FB, 0x40000000
+    7.54978941586159635335e-08,  // 0x3E74442D, 0x00000000
+    5.39030252995776476554e-15,  // 0x3CF84698, 0x80000000
+    3.28200341580791294123e-22,  // 0x3B78CC51, 0x60000000
+    1.27065575308067607349e-29,  // 0x39F01B83, 0x80000000
+    1.22933308981111328932e-36,  // 0x387A2520, 0x40000000
+    2.73370053816464559624e-44,  // 0x36E38222, 0x80000000
+    2.16741683877804819444e-51   // 0x3569F31D, 0x00000000
+};
+
+
+int __kernel_rem_pio2(double* x, double* y, int e0, int nx) {
+  static const int32_t jk = 3;
+  double fw;
+  int32_t jx = nx - 1;
+  int32_t jv = (e0 - 3) / 24;
+  if (jv < 0) jv = 0;
+  int32_t q0 = e0 - 24 * (jv + 1);
+  int32_t m = jx + jk;
+
+  double f[10];
+  for (int i = 0, j = jv - jx; i <= m; i++, j++) {
+    f[i] = (j < 0) ? zero : static_cast<double>(two_over_pi[j]);
+  }
+
+  double q[10];
+  for (int i = 0; i <= jk; i++) {
+    fw = 0.0;
+    for (int j = 0; j <= jx; j++) fw += x[j] * f[jx + i - j];
+    q[i] = fw;
+  }
+
+  int32_t jz = jk;
+
+recompute:
+
+  int32_t iq[10];
+  double z = q[jz];
+  for (int i = 0, j = jz; j > 0; i++, j--) {
+    fw = static_cast<double>(static_cast<int32_t>(twon24 * z));
+    iq[i] = static_cast<int32_t>(z - two24 * fw);
+    z = q[j - 1] + fw;
+  }
+
+  z = scalbn(z, q0);
+  z -= 8.0 * std::floor(z * 0.125);
+  int32_t n = static_cast<int32_t>(z);
+  z -= static_cast<double>(n);
+  int32_t ih = 0;
+  if (q0 > 0) {
+    int32_t i = (iq[jz - 1] >> (24 - q0));
+    n += i;
+    iq[jz - 1] -= i << (24 - q0);
+    ih = iq[jz - 1] >> (23 - q0);
+  } else if (q0 == 0) {
+    ih = iq[jz - 1] >> 23;
+  } else if (z >= 0.5) {
+    ih = 2;
+  }
+
+  if (ih > 0) {
+    n += 1;
+    int32_t carry = 0;
+    for (int i = 0; i < jz; i++) {
+      int32_t j = iq[i];
+      if (carry == 0) {
+        if (j != 0) {
+          carry = 1;
+          iq[i] = 0x1000000 - j;
+        }
+      } else {
+        iq[i] = 0xffffff - j;
+      }
+    }
+    if (q0 == 1) {
+      iq[jz - 1] &= 0x7fffff;
+    } else if (q0 == 2) {
+      iq[jz - 1] &= 0x3fffff;
+    }
+    if (ih == 2) {
+      z = one - z;
+      if (carry != 0) z -= scalbn(one, q0);
+    }
+  }
+
+  if (z == zero) {
+    int32_t j = 0;
+    for (int i = jz - 1; i >= jk; i--) j |= iq[i];
+    if (j == 0) {
+      int32_t k = 1;
+      while (iq[jk - k] == 0) k++;
+      for (int i = jz + 1; i <= jz + k; i++) {
+        f[jx + i] = static_cast<double>(two_over_pi[jv + i]);
+        for (j = 0, fw = 0.0; j <= jx; j++) fw += x[j] * f[jx + i - j];
+        q[i] = fw;
+      }
+      jz += k;
+      goto recompute;
+    }
+  }
+
+  if (z == 0.0) {
+    jz -= 1;
+    q0 -= 24;
+    while (iq[jz] == 0) {
+      jz--;
+      q0 -= 24;
+    }
+  } else {
+    z = scalbn(z, -q0);
+    if (z >= two24) {
+      fw = static_cast<double>(static_cast<int32_t>(twon24 * z));
+      iq[jz] = static_cast<int32_t>(z - two24 * fw);
+      jz += 1;
+      q0 += 24;
+      iq[jz] = static_cast<int32_t>(fw);
+    } else {
+      iq[jz] = static_cast<int32_t>(z);
+    }
+  }
+
+  fw = scalbn(one, q0);
+  for (int i = jz; i >= 0; i--) {
+    q[i] = fw * static_cast<double>(iq[i]);
+    fw *= twon24;
+  }
+
+  double fq[10];
+  for (int i = jz; i >= 0; i--) {
+    fw = 0.0;
+    for (int k = 0; k <= jk && k <= jz - i; k++) fw += PIo2[k] * q[i + k];
+    fq[jz - i] = fw;
+  }
+
+  fw = 0.0;
+  for (int i = jz; i >= 0; i--) fw += fq[i];
+  y[0] = (ih == 0) ? fw : -fw;
+  fw = fq[0] - fw;
+  for (int i = 1; i <= jz; i++) fw += fq[i];
+  y[1] = (ih == 0) ? fw : -fw;
+  return n & 7;
+}
+
+
+int rempio2(double x, double* y) {
+  int32_t hx = static_cast<int32_t>(double_to_uint64(x) >> 32);
+  int32_t ix = hx & 0x7fffffff;
+
+  if (ix >= 0x7ff00000) {
+    *y = base::OS::nan_value();
+    return 0;
+  }
+
+  int32_t e0 = (ix >> 20) - 1046;
+  uint64_t zi = double_to_uint64(x) & 0xFFFFFFFFu;
+  zi |= static_cast<uint64_t>(ix - (e0 << 20)) << 32;
+  double z = uint64_to_double(zi);
+
+  double tx[3];
+  for (int i = 0; i < 2; i++) {
+    tx[i] = static_cast<double>(static_cast<int32_t>(z));
+    z = (z - tx[i]) * two24;
+  }
+  tx[2] = z;
+
+  int nx = 3;
+  while (tx[nx - 1] == zero) nx--;
+  int n = __kernel_rem_pio2(tx, y, e0, nx);
+  if (hx < 0) {
+    y[0] = -y[0];
+    y[1] = -y[1];
+    return -n;
+  }
+  return n;
+}
+}
+}  // namespace v8::internal
diff --git a/third_party/fdlibm/fdlibm.h b/third_party/fdlibm/fdlibm.h
new file mode 100644 (file)
index 0000000..4ce7794
--- /dev/null
@@ -0,0 +1,31 @@
+// The following is adapted from fdlibm (http://www.netlib.org/fdlibm).
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunSoft, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+// The original source code covered by the above license above has been
+// modified significantly by Google Inc.
+// Copyright 2014 the V8 project authors. All rights reserved.
+
+#ifndef V8_FDLIBM_H_
+#define V8_FDLIBM_H_
+
+namespace v8 {
+namespace internal {
+
+int rempio2(double x, double* y);
+
+// Constants to be exposed to builtins via Float64Array.
+struct TrigonometricConstants {
+  static const double constants[34];
+};
+}
+}  // namespace v8::internal
+
+#endif  // V8_FDLIBM_H_
diff --git a/third_party/fdlibm/fdlibm.js b/third_party/fdlibm/fdlibm.js
new file mode 100644 (file)
index 0000000..d5dbb72
--- /dev/null
@@ -0,0 +1,356 @@
+// The following is adapted from fdlibm (http://www.netlib.org/fdlibm),
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunSoft, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+// The original source code covered by the above license above has been
+// modified significantly by Google Inc.
+// Copyright 2014 the V8 project authors. All rights reserved.
+//
+// The following is a straightforward translation of fdlibm routines for
+// sin, cos, and tan, by Raymond Toy (rtoy@google.com).
+
+
+var kTrig;  // Initialized to a Float64Array during genesis and is not writable.
+
+const INVPIO2 = kTrig[0];
+const PIO2_1  = kTrig[1];
+const PIO2_1T = kTrig[2];
+const PIO2_2  = kTrig[3];
+const PIO2_2T = kTrig[4];
+const PIO2_3  = kTrig[5];
+const PIO2_3T = kTrig[6];
+const PIO4    = kTrig[32];
+const PIO4LO  = kTrig[33];
+
+// Compute k and r such that x - k*pi/2 = r where |r| < pi/4. For
+// precision, r is returned as two values y0 and y1 such that r = y0 + y1
+// to more than double precision.
+macro REMPIO2(X)
+  var n, y0, y1;
+  var hx = %_DoubleHi(X);
+  var ix = hx & 0x7fffffff;
+
+  if (ix < 0x4002d97c) {
+    // |X| ~< 3*pi/4, special case with n = +/- 1
+    if (hx > 0) {
+      var z = X - PIO2_1;
+      if (ix != 0x3ff921fb) {
+        // 33+53 bit pi is good enough
+        y0 = z - PIO2_1T;
+        y1 = (z - y0) - PIO2_1T;
+      } else {
+        // near pi/2, use 33+33+53 bit pi
+        z -= PIO2_2;
+        y0 = z - PIO2_2T;
+        y1 = (z - y0) - PIO2_2T;
+      }
+      n = 1;
+    } else {
+      // Negative X
+      var z = X + PIO2_1;
+      if (ix != 0x3ff921fb) {
+        // 33+53 bit pi is good enough
+        y0 = z + PIO2_1T;
+        y1 = (z - y0) + PIO2_1T;
+      } else {
+        // near pi/2, use 33+33+53 bit pi
+        z += PIO2_2;
+        y0 = z + PIO2_2T;
+        y1 = (z - y0) + PIO2_2T;
+      }
+      n = -1;
+    }
+  } else if (ix <= 0x413921fb) {
+    // |X| ~<= 2^19*(pi/2), medium size
+    var t = MathAbs(X);
+    n = (t * INVPIO2 + 0.5) | 0;
+    var r = t - n * PIO2_1;
+    var w = n * PIO2_1T;
+    // First round good to 85 bit
+    y0 = r - w;
+    if (ix - (%_DoubleHi(y0) & 0x7ff00000) > 0x1000000) {
+      // 2nd iteration needed, good to 118
+      t = r;
+      w = n * PIO2_2;
+      r = t - w;
+      w = n * PIO2_2T - ((t - r) - w);
+      y0 = r - w;
+      if (ix - (%_DoubleHi(y0) & 0x7ff00000) > 0x3100000) {
+        // 3rd iteration needed. 151 bits accuracy
+        t = r;
+        w = n * PIO2_3;
+        r = t - w;
+        w = n * PIO2_3T - ((t - r) - w);
+        y0 = r - w;
+      }
+    }
+    y1 = (r - y0) - w;
+    if (hx < 0) {
+      n = -n;
+      y0 = -y0;
+      y1 = -y1;
+    }
+  } else {
+    // Need to do full Payne-Hanek reduction here.
+    var r = %RemPiO2(X);
+    n = r[0];
+    y0 = r[1];
+    y1 = r[2];
+  }
+endmacro
+
+
+// __kernel_sin(X, Y, IY)
+// kernel sin function on [-pi/4, pi/4], pi/4 ~ 0.7854
+// Input X is assumed to be bounded by ~pi/4 in magnitude.
+// Input Y is the tail of X so that x = X + Y.
+//
+// Algorithm
+//  1. Since ieee_sin(-x) = -ieee_sin(x), we need only to consider positive x.
+//  2. ieee_sin(x) is approximated by a polynomial of degree 13 on
+//     [0,pi/4]
+//                           3            13
+//          sin(x) ~ x + S1*x + ... + S6*x
+//     where
+//
+//    |ieee_sin(x)    2     4     6     8     10     12  |     -58
+//    |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x  +S6*x   )| <= 2
+//    |  x                                               |
+//
+//  3. ieee_sin(X+Y) = ieee_sin(X) + sin'(X')*Y
+//              ~ ieee_sin(X) + (1-X*X/2)*Y
+//     For better accuracy, let
+//               3      2      2      2      2
+//          r = X *(S2+X *(S3+X *(S4+X *(S5+X *S6))))
+//     then                   3    2
+//          sin(x) = X + (S1*X + (X *(r-Y/2)+Y))
+//
+macro KSIN(x)
+kTrig[7+x]
+endmacro
+
+macro RETURN_KERNELSIN(X, Y, SIGN)
+  var z = X * X;
+  var v = z * X;
+  var r = KSIN(1) + z * (KSIN(2) + z * (KSIN(3) +
+                    z * (KSIN(4) + z * KSIN(5))));
+  return (X - ((z * (0.5 * Y - v * r) - Y) - v * KSIN(0))) SIGN;
+endmacro
+
+// __kernel_cos(X, Y)
+// kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164
+// Input X is assumed to be bounded by ~pi/4 in magnitude.
+// Input Y is the tail of X so that x = X + Y.
+//
+// Algorithm
+//  1. Since ieee_cos(-x) = ieee_cos(x), we need only to consider positive x.
+//  2. ieee_cos(x) is approximated by a polynomial of degree 14 on
+//     [0,pi/4]
+//                                   4            14
+//          cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x
+//     where the remez error is
+//
+//  |                   2     4     6     8     10    12     14 |     -58
+//  |ieee_cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x  +C6*x  )| <= 2
+//  |                                                           |
+//
+//                 4     6     8     10    12     14
+//  3. let r = C1*x +C2*x +C3*x +C4*x +C5*x  +C6*x  , then
+//         ieee_cos(x) = 1 - x*x/2 + r
+//     since ieee_cos(X+Y) ~ ieee_cos(X) - ieee_sin(X)*Y
+//                    ~ ieee_cos(X) - X*Y,
+//     a correction term is necessary in ieee_cos(x) and hence
+//         cos(X+Y) = 1 - (X*X/2 - (r - X*Y))
+//     For better accuracy when x > 0.3, let qx = |x|/4 with
+//     the last 32 bits mask off, and if x > 0.78125, let qx = 0.28125.
+//     Then
+//         cos(X+Y) = (1-qx) - ((X*X/2-qx) - (r-X*Y)).
+//     Note that 1-qx and (X*X/2-qx) is EXACT here, and the
+//     magnitude of the latter is at least a quarter of X*X/2,
+//     thus, reducing the rounding error in the subtraction.
+//
+macro KCOS(x)
+kTrig[13+x]
+endmacro
+
+macro RETURN_KERNELCOS(X, Y, SIGN)
+  var ix = %_DoubleHi(X) & 0x7fffffff;
+  var z = X * X;
+  var r = z * (KCOS(0) + z * (KCOS(1) + z * (KCOS(2)+
+          z * (KCOS(3) + z * (KCOS(4) + z * KCOS(5))))));
+  if (ix < 0x3fd33333) {  // |x| ~< 0.3
+    return (1 - (0.5 * z - (z * r - X * Y))) SIGN;
+  } else {
+    var qx;
+    if (ix > 0x3fe90000) {  // |x| > 0.78125
+      qx = 0.28125;
+    } else {
+      qx = %_ConstructDouble(%_DoubleHi(0.25 * X), 0);
+    }
+    var hz = 0.5 * z - qx;
+    return (1 - qx - (hz - (z * r - X * Y))) SIGN;
+  }
+endmacro
+
+// kernel tan function on [-pi/4, pi/4], pi/4 ~ 0.7854
+// Input x is assumed to be bounded by ~pi/4 in magnitude.
+// Input y is the tail of x.
+// Input k indicates whether ieee_tan (if k = 1) or -1/tan (if k = -1)
+// is returned.
+//
+// Algorithm
+//  1. Since ieee_tan(-x) = -ieee_tan(x), we need only to consider positive x.
+//  2. if x < 2^-28 (hx<0x3e300000 0), return x with inexact if x!=0.
+//  3. ieee_tan(x) is approximated by a odd polynomial of degree 27 on
+//     [0,0.67434]
+//                           3             27
+//          tan(x) ~ x + T1*x + ... + T13*x
+//     where
+//
+//     |ieee_tan(x)    2     4            26   |     -59.2
+//     |----- - (1+T1*x +T2*x +.... +T13*x    )| <= 2
+//     |  x                                    |
+//
+//     Note: ieee_tan(x+y) = ieee_tan(x) + tan'(x)*y
+//                    ~ ieee_tan(x) + (1+x*x)*y
+//     Therefore, for better accuracy in computing ieee_tan(x+y), let
+//               3      2      2       2       2
+//          r = x *(T2+x *(T3+x *(...+x *(T12+x *T13))))
+//     then
+//                              3    2
+//          tan(x+y) = x + (T1*x + (x *(r+y)+y))
+//
+//  4. For x in [0.67434,pi/4],  let y = pi/4 - x, then
+//          tan(x) = ieee_tan(pi/4-y) = (1-ieee_tan(y))/(1+ieee_tan(y))
+//                 = 1 - 2*(ieee_tan(y) - (ieee_tan(y)^2)/(1+ieee_tan(y)))
+//
+// Set returnTan to 1 for tan; -1 for cot.  Anything else is illegal
+// and will cause incorrect results.
+//
+macro KTAN(x)
+kTrig[19+x]
+endmacro
+
+function KernelTan(x, y, returnTan) {
+  var z;
+  var w;
+  var hx = %_DoubleHi(x);
+  var ix = hx & 0x7fffffff;
+
+  if (ix < 0x3e300000) {  // |x| < 2^-28
+    if (((ix | %_DoubleLo(x)) | (returnTan + 1)) == 0) {
+      // x == 0 && returnTan = -1
+      return 1 / MathAbs(x);
+    } else {
+      if (returnTan == 1) {
+        return x;
+      } else {
+        // Compute -1/(x + y) carefully
+        var w = x + y;
+        var z = %_ConstructDouble(%_DoubleHi(w), 0);
+        var v = y - (z - x);
+        var a = -1 / w;
+        var t = %_ConstructDouble(%_DoubleHi(a), 0);
+        var s = 1 + t * z;
+        return t + a * (s + t * v);
+      }
+    }
+  }
+  if (ix >= 0x3fe59429) {  // |x| > .6744
+    if (x < 0) {
+      x = -x;
+      y = -y;
+    }
+    z = PIO4 - x;
+    w = PIO4LO - y;
+    x = z + w;
+    y = 0;
+  }
+  z = x * x;
+  w = z * z;
+
+  // Break x^5 * (T1 + x^2*T2 + ...) into
+  // x^5 * (T1 + x^4*T3 + ... + x^20*T11) +
+  // x^5 * (x^2 * (T2 + x^4*T4 + ... + x^22*T12))
+  var r = KTAN(1) + w * (KTAN(3) + w * (KTAN(5) +
+                    w * (KTAN(7) + w * (KTAN(9) + w * KTAN(11)))));
+  var v = z * (KTAN(2) + w * (KTAN(4) + w * (KTAN(6) +
+                         w * (KTAN(8) + w * (KTAN(10) + w * KTAN(12))))));
+  var s = z * x;
+  r = y + z * (s * (r + v) + y);
+  r = r + KTAN(0) * s;
+  w = x + r;
+  if (ix >= 0x3fe59428) {
+    return (1 - ((hx >> 30) & 2)) *
+      (returnTan - 2.0 * (x - (w * w / (w + returnTan) - r)));
+  }
+  if (returnTan == 1) {
+    return w;
+  } else {
+    z = %_ConstructDouble(%_DoubleHi(w), 0);
+    v = r - (z - x);
+    var a = -1 / w;
+    var t = %_ConstructDouble(%_DoubleHi(a), 0);
+    s = 1 + t * z;
+    return t + a * (s + t * v);
+  }
+}
+
+function MathSinSlow(x) {
+  REMPIO2(x);
+  var sign = 1 - (n & 2);
+  if (n & 1) {
+    RETURN_KERNELCOS(y0, y1, * sign);
+  } else {
+    RETURN_KERNELSIN(y0, y1, * sign);
+  }
+}
+
+function MathCosSlow(x) {
+  REMPIO2(x);
+  if (n & 1) {
+    var sign = (n & 2) - 1;
+    RETURN_KERNELSIN(y0, y1, * sign);
+  } else {
+    var sign = 1 - (n & 2);
+    RETURN_KERNELCOS(y0, y1, * sign);
+  }
+}
+
+// ECMA 262 - 15.8.2.16
+function MathSin(x) {
+  x = x * 1;  // Convert to number.
+  if ((%_DoubleHi(x) & 0x7fffffff) <= 0x3fe921fb) {
+    // |x| < pi/4, approximately.  No reduction needed.
+    RETURN_KERNELSIN(x, 0, /* empty */);
+  }
+  return MathSinSlow(x);
+}
+
+// ECMA 262 - 15.8.2.7
+function MathCos(x) {
+  x = x * 1;  // Convert to number.
+  if ((%_DoubleHi(x) & 0x7fffffff) <= 0x3fe921fb) {
+    // |x| < pi/4, approximately.  No reduction needed.
+    RETURN_KERNELCOS(x, 0, /* empty */);
+  }
+  return MathCosSlow(x);
+}
+
+// ECMA 262 - 15.8.2.18
+function MathTan(x) {
+  x = x * 1;  // Convert to number.
+  if ((%_DoubleHi(x) & 0x7fffffff) <= 0x3fe921fb) {
+    // |x| < pi/4, approximately.  No reduction needed.
+    return KernelTan(x, 0, 1);
+  }
+  REMPIO2(x);
+  return KernelTan(y0, y1, (n & 1) ? -1 : 1);
+}
index c37ecca..7bf8736 100755 (executable)
@@ -47,11 +47,11 @@ EXPAND_MACROS = [
 # that the parser doesn't bit-rot. Change the values as needed when you add,
 # remove or change runtime functions, but make sure we don't lose our ability
 # to parse them!
-EXPECTED_FUNCTION_COUNT = 426
-EXPECTED_FUZZABLE_COUNT = 329
+EXPECTED_FUNCTION_COUNT = 427
+EXPECTED_FUZZABLE_COUNT = 330
 EXPECTED_CCTEST_COUNT = 7
 EXPECTED_UNKNOWN_COUNT = 16
-EXPECTED_BUILTINS_COUNT = 813
+EXPECTED_BUILTINS_COUNT = 809
 
 
 # Don't call these at all.
diff --git a/tools/generate-trig-table.py b/tools/generate-trig-table.py
deleted file mode 100644 (file)
index 0a4fe28..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright 2013 the V8 project authors. All rights reserved.
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-#       notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-#       copyright notice, this list of conditions and the following
-#       disclaimer in the documentation and/or other materials provided
-#       with the distribution.
-#     * Neither the name of Google Inc. nor the names of its
-#       contributors may be used to endorse or promote products derived
-#       from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-# This is a utility for populating the lookup table for the
-# approximation of trigonometric functions.
-
-import sys, math
-
-SAMPLES = 1800
-
-TEMPLATE = """\
-// Copyright 2013 Google Inc. All Rights Reserved.
-
-// This file was generated from a python script.
-
-#include "src/v8.h"
-#include "src/trig-table.h"
-
-namespace v8 {
-namespace internal {
-
-  const double TrigonometricLookupTable::kSinTable[] =
-      { %(sine_table)s };
-  const double TrigonometricLookupTable::kCosXIntervalTable[] =
-      { %(cosine_table)s };
-  const int TrigonometricLookupTable::kSamples = %(samples)i;
-  const int TrigonometricLookupTable::kTableSize = %(table_size)i;
-  const double TrigonometricLookupTable::kSamplesOverPiHalf =
-      %(samples_over_pi_half)s;
-
-} }  // v8::internal
-"""
-
-def main():
-  pi_half = math.pi / 2
-  interval = pi_half / SAMPLES
-  sin = []
-  cos_times_interval = []
-  table_size = SAMPLES + 2
-
-  for i in range(0, table_size):
-    sample = i * interval
-    sin.append(repr(math.sin(sample)))
-    cos_times_interval.append(repr(math.cos(sample) * interval))
-
-  output_file = sys.argv[1]
-  output = open(str(output_file), "w")
-  output.write(TEMPLATE % {
-    'sine_table': ','.join(sin),
-    'cosine_table': ','.join(cos_times_interval),
-    'samples': SAMPLES,
-    'table_size': table_size,
-    'samples_over_pi_half': repr(SAMPLES / pi_half)
-  })
-
-if __name__ == "__main__":
-  main()
index 097847e..967497b 100644 (file)
           'dependencies': [
             'mksnapshot#host',
             'js2c#host',
-            'generate_trig_table#host',
           ],
         }, {
           'toolsets': ['target'],
           'dependencies': [
             'mksnapshot',
             'js2c',
-            'generate_trig_table',
           ],
         }],
         ['component=="shared_library"', {
       'sources': [
         '<(SHARED_INTERMEDIATE_DIR)/libraries.cc',
         '<(SHARED_INTERMEDIATE_DIR)/experimental-libraries.cc',
-        '<(SHARED_INTERMEDIATE_DIR)/trig-table.cc',
         '<(INTERMEDIATE_DIR)/snapshot.cc',
         '../../src/snapshot-common.cc',
       ],
       'sources': [
         '<(SHARED_INTERMEDIATE_DIR)/libraries.cc',
         '<(SHARED_INTERMEDIATE_DIR)/experimental-libraries.cc',
-        '<(SHARED_INTERMEDIATE_DIR)/trig-table.cc',
         '../../src/snapshot-common.cc',
         '../../src/snapshot-empty.cc',
       ],
       'conditions': [
         ['want_separate_host_toolset==1', {
           'toolsets': ['host', 'target'],
-          'dependencies': ['js2c#host', 'generate_trig_table#host'],
+          'dependencies': ['js2c#host'],
         }, {
           'toolsets': ['target'],
-          'dependencies': ['js2c', 'generate_trig_table'],
+          'dependencies': ['js2c'],
         }],
         ['component=="shared_library"', {
           'defines': [
           'dependencies': [
             'mksnapshot#host',
             'js2c#host',
-            'generate_trig_table#host',
             'natives_blob#host',
         ]}, {
           'toolsets': ['target'],
           'dependencies': [
             'mksnapshot',
             'js2c',
-            'generate_trig_table',
             'natives_blob',
           ],
         }],
         '../..',
       ],
       'sources': [
-        '<(SHARED_INTERMEDIATE_DIR)/trig-table.cc',
         '../../src/natives-external.cc',
         '../../src/snapshot-external.cc',
       ],
         },
       ],
     },
-    { 'target_name': 'generate_trig_table',
-      'type': 'none',
-      'conditions': [
-        ['want_separate_host_toolset==1', {
-          'toolsets': ['host'],
-        }, {
-          'toolsets': ['target'],
-        }],
-      ],
-      'actions': [
-        {
-          'action_name': 'generate',
-          'inputs': [
-            '../../tools/generate-trig-table.py',
-          ],
-          'outputs': [
-            '<(SHARED_INTERMEDIATE_DIR)/trig-table.cc',
-          ],
-          'action': [
-            'python',
-            '../../tools/generate-trig-table.py',
-            '<@(_outputs)',
-          ],
-        },
-      ]
-    },
     {
       'target_name': 'v8_base',
       'type': 'static_library',
         '../../src/zone-inl.h',
         '../../src/zone.cc',
         '../../src/zone.h',
+        '../../third_party/fdlibm/fdlibm.cc',
+        '../../third_party/fdlibm/fdlibm.h',
       ],
       'conditions': [
         ['want_separate_host_toolset==1', {
           '../../src/array.js',
           '../../src/string.js',
           '../../src/uri.js',
+          '../../third_party/fdlibm/fdlibm.js',
           '../../src/math.js',
           '../../src/messages.js',
           '../../src/apinatives.js',
index 60f088b..77485f6 100755 (executable)
@@ -218,6 +218,27 @@ def ExpandInlineMacros(lines):
     lines = ExpandMacroDefinition(lines, pos, name_pattern, macro, non_expander)
 
 
+INLINE_CONSTANT_PATTERN = re.compile(r'const\s+([a-zA-Z0-9_]+)\s*=\s*([^;\n]+)[;\n]')
+
+def ExpandInlineConstants(lines):
+  pos = 0
+  while True:
+    const_match = INLINE_CONSTANT_PATTERN.search(lines, pos)
+    if const_match is None:
+      # no more constants
+      return lines
+    name = const_match.group(1)
+    replacement = const_match.group(2)
+    name_pattern = re.compile("\\b%s\\b" % name)
+
+    # remove constant definition and replace
+    lines = (lines[:const_match.start()] +
+             re.sub(name_pattern, replacement, lines[const_match.end():]))
+
+    # advance position to where the constant defintion was
+    pos = const_match.start()
+
+
 HEADER_TEMPLATE = """\
 // Copyright 2011 Google Inc. All Rights Reserved.
 
@@ -333,6 +354,7 @@ def BuildFilterChain(macro_filename):
   filter_chain.extend([
     RemoveCommentsAndTrailingWhitespace,
     ExpandInlineMacros,
+    ExpandInlineConstants,
     Validate,
     jsmin.JavaScriptMinifier().JSMinify
   ])