Commit 3c4d23b9 authored by yangguo@chromium.org's avatar yangguo@chromium.org

Implement trigonometric functions using a fdlibm port.

R=jochen@chromium.org, rtoy@chromium.org, svenpanne@chromium.org
BUG=v8:3006
LOG=N

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22918 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent f862ed53
......@@ -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
......
......@@ -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") {
......
......@@ -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:
......
......@@ -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();
......
......@@ -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();
......@@ -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,21 @@ 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);
array->set(0, Smi::FromInt(n));
array->set(1, *factory->NewHeapNumber(y[0]));
array->set(2, *factory->NewHeapNumber(y[1]));
return *factory->NewJSArrayWithElements(array);
}
static const double kPiDividedBy4 = 0.78539816339744830962;
......
......@@ -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) \
......
// 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_
......@@ -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
......
......@@ -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);
......
// 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);
......@@ -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)));
......@@ -68,14 +68,7 @@
##################### 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.
......
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.
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.
// 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 {
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
// 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_
This diff is collapsed.
......@@ -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.
......
#!/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()
......@@ -121,14 +121,12 @@
'dependencies': [
'mksnapshot#host',
'js2c#host',
'generate_trig_table#host',
],
}, {
'toolsets': ['target'],
'dependencies': [
'mksnapshot',
'js2c',
'generate_trig_table',
],
}],
['component=="shared_library"', {
......@@ -153,7 +151,6 @@
'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',
],
......@@ -197,17 +194,16 @@
'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': [
......@@ -226,14 +222,12 @@
'dependencies': [
'mksnapshot#host',
'js2c#host',
'generate_trig_table#host',
'natives_blob#host',
]}, {
'toolsets': ['target'],
'dependencies': [
'mksnapshot',
'js2c',
'generate_trig_table',
'natives_blob',
],
}],
......@@ -257,7 +251,6 @@
'../..',
],
'sources': [
'<(SHARED_INTERMEDIATE_DIR)/trig-table.cc',
'../../src/natives-external.cc',
'../../src/snapshot-external.cc',
],
......@@ -291,32 +284,6 @@
},
],
},
{ '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',
......@@ -768,6 +735,8 @@
'../../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', {
......@@ -1420,6 +1389,7 @@
'../../src/array.js',
'../../src/string.js',
'../../src/uri.js',
'../../third_party/fdlibm/fdlibm.js',
'../../src/math.js',
'../../src/messages.js',
'../../src/apinatives.js',
......
......@@ -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
])
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment