#include "objects-visiting.h"
#include "platform.h"
#include "snapshot.h"
+#include "trig-table.h"
#include "extensions/externalize-string-extension.h"
#include "extensions/gc-extension.h"
#include "extensions/statistics-extension.h"
InitializeExperimentalGlobal();
if (!InstallExperimentalNatives()) return;
+ if (!Serializer::enabled()) {
+ Handle<JSBuiltinsObject> builtins(native_context()->builtins());
+ // Initialize trigonometric lookup tables and constants.
+ // The snapshot cannot contain typed arrays, and we don't need it to.
+ const int table_num_bytes = TrigonometricLookupTable::table_num_bytes();
+ v8::Local<v8::ArrayBuffer> sin_buffer = v8::ArrayBuffer::New(
+ TrigonometricLookupTable::sin_table(), table_num_bytes);
+ v8::Local<v8::ArrayBuffer> cos_buffer = v8::ArrayBuffer::New(
+ 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());
+
+ ForceSetProperty(builtins,
+ factory()->InternalizeOneByteString(
+ STATIC_ASCII_VECTOR("kSinTable")),
+ Utils::OpenHandle(*sin_table),
+ NONE);
+ ForceSetProperty(builtins,
+ factory()->InternalizeOneByteString(
+ STATIC_ASCII_VECTOR("kCosXIntervalTable")),
+ Utils::OpenHandle(*cos_table),
+ NONE);
+ ForceSetProperty(builtins,
+ factory()->InternalizeOneByteString(
+ STATIC_ASCII_VECTOR("kSamples")),
+ factory()->NewHeapNumber(
+ TrigonometricLookupTable::samples()),
+ NONE);
+ ForceSetProperty(builtins,
+ factory()->InternalizeOneByteString(
+ STATIC_ASCII_VECTOR("kIndexConvert")),
+ factory()->NewHeapNumber(
+ TrigonometricLookupTable::samples_over_pi_half()),
+ NONE);
+ }
+
// Initially seed the per-context random number generator
// using the per-isolate random number generator.
uint32_t* state = reinterpret_cast<uint32_t*>(
// ECMA 262 - 15.8.2.7
function MathCos(x) {
- return MathCosImpl(x);
+ x = MathAbs(x); // Convert to number and get rid of -0.
+ return TrigonometricInterpolation(x, 1);
}
// ECMA 262 - 15.8.2.8
// ECMA 262 - 15.8.2.16
function MathSin(x) {
- return MathSinImpl(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
// ECMA 262 - 15.8.2.18
function MathTan(x) {
- return MathSinImpl(x) / MathCosImpl(x);
+ return MathSin(x) / MathCos(x);
}
// Non-standard extension.
}
-var MathSinImpl = function(x) {
- InitTrigonometricFunctions();
- return MathSinImpl(x);
-}
-
-
-var MathCosImpl = function(x) {
- InitTrigonometricFunctions();
- return MathCosImpl(x);
-}
-
-
-var InitTrigonometricFunctions;
-
-
-// Define constants and interpolation functions.
-// Also define the initialization function that populates the lookup table
-// and then wires up the function definitions.
-function SetupTrigonometricFunctions() {
- var samples = 1800; // Table size. Do not change arbitrarily.
- var inverse_pi_half = 0.636619772367581343; // 2 / pi
- var inverse_pi_half_s_26 = 9.48637384723993156e-9; // 2 / pi / (2^26)
- var s_26 = 1 << 26;
- var two_step_threshold = 1 << 27;
- var index_convert = 1145.915590261646418; // samples / (pi / 2)
- // pi / 2 rounded up
- var pi_half = 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 pi_half_1 = 1.570796325802803040; // 0x00000054fb21f93f
- var pi_half_2 = 9.920935796805404252e-10; // 0x3326a611460b113e
- var table_sin;
- var table_cos_interval;
-
- // 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.
- var Interpolation = function(x, phase) {
- if (x < 0 || x > pi_half) {
- var multiple;
- while (x < -two_step_threshold || x > two_step_threshold) {
- // 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 * inverse_pi_half_s_26) * s_26;
- x = x - multiple * pi_half_1 - multiple * pi_half_2;
- }
- multiple = MathFloor(x * inverse_pi_half);
- x = x - multiple * pi_half_1 - multiple * pi_half_2;
- phase += multiple;
+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;
}
- var double_index = x * index_convert;
- if (phase & 1) double_index = samples - double_index;
- var index = double_index | 0;
- var t1 = double_index - index;
- var t2 = 1 - t1;
- var y1 = table_sin[index];
- var y2 = table_sin[index + 1];
- var dy = y2 - y1;
- return (t2 * y1 + t1 * y2 +
- t1 * t2 * ((table_cos_interval[index] - dy) * t2 +
- (dy - table_cos_interval[index + 1]) * t1))
- * (1 - (phase & 2)) + 0;
- }
-
- var MathSinInterpolation = function(x) {
- x = x * 1; // Convert to number and deal with -0.
- if (%_IsMinusZero(x)) return x;
- return Interpolation(x, 0);
- }
-
- // Cosine is sine with a phase offset.
- var MathCosInterpolation = function(x) {
- x = MathAbs(x); // Convert to number and get rid of -0.
- return Interpolation(x, 1);
- };
-
- %SetInlineBuiltinFlag(Interpolation);
- %SetInlineBuiltinFlag(MathSinInterpolation);
- %SetInlineBuiltinFlag(MathCosInterpolation);
-
- InitTrigonometricFunctions = function() {
- table_sin = new global.Float64Array(samples + 2);
- table_cos_interval = new global.Float64Array(samples + 2);
- %PopulateTrigonometricTable(table_sin, table_cos_interval, samples);
- MathSinImpl = MathSinInterpolation;
- MathCosImpl = MathCosInterpolation;
+ 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;
}
-SetupTrigonometricFunctions();
-
-
// -------------------------------------------------------------------
function SetUpMath() {
%SetInlineBuiltinFlag(MathSin);
%SetInlineBuiltinFlag(MathCos);
%SetInlineBuiltinFlag(MathTan);
+ %SetInlineBuiltinFlag(TrigonometricInterpolation);
}
SetUpMath();
}
-RUNTIME_FUNCTION(MaybeObject*, Runtime_PopulateTrigonometricTable) {
- HandleScope scope(isolate);
- ASSERT(args.length() == 3);
- CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sin_table, 0);
- CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, cos_table, 1);
- CONVERT_SMI_ARG_CHECKED(samples, 2);
- RUNTIME_ASSERT(sin_table->type() == kExternalDoubleArray);
- RUNTIME_ASSERT(cos_table->type() == kExternalDoubleArray);
- double* sin_buffer = reinterpret_cast<double*>(
- JSArrayBuffer::cast(sin_table->buffer())->backing_store());
- double* cos_buffer = reinterpret_cast<double*>(
- JSArrayBuffer::cast(cos_table->buffer())->backing_store());
-
- static const double pi_half = 3.1415926535897932 / 2;
- double interval = pi_half / samples;
- for (int i = 0; i < samples + 1; i++) {
- double sample = sin(i * interval);
- sin_buffer[i] = sample;
- cos_buffer[samples - i] = sample * interval;
- }
-
- // Fill this to catch out of bound accesses when calculating Math.sin(pi/2).
- sin_buffer[samples + 1] = sin(pi_half + interval);
- cos_buffer[samples + 1] = cos(pi_half + interval) * interval;
-
- return isolate->heap()->undefined_value();
-}
-
-
RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
SealHandleScope shs(isolate);
ASSERT(args.length() == 2);
F(Math_sin, 1, 1) \
F(Math_sqrt, 1, 1) \
F(Math_tan, 1, 1) \
- F(PopulateTrigonometricTable, 3, 1) \
\
/* Regular expressions */ \
F(RegExpCompile, 3, 1) \
--- /dev/null
+// 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.
+
+#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_
LocalContext context;
Isolate* isolate = GetIsolateFrom(&context);
- CHECK_EQ(0, CountArrayBuffersInWeakList(isolate->heap()));
+ int start = CountArrayBuffersInWeakList(isolate->heap());
{
v8::HandleScope s1(context->GetIsolate());
v8::Handle<v8::ArrayBuffer> ab1 = v8::ArrayBuffer::New(256);
Handle<JSArrayBuffer> iab1 = v8::Utils::OpenHandle(*ab1);
Handle<JSArrayBuffer> iab2 = v8::Utils::OpenHandle(*ab2);
- CHECK_EQ(2, CountArrayBuffersInWeakList(isolate->heap()));
+ CHECK_EQ(2, CountArrayBuffersInWeakList(isolate->heap()) - start);
CHECK(HasArrayBufferInWeakList(isolate->heap(), *iab1));
CHECK(HasArrayBufferInWeakList(isolate->heap(), *iab2));
}
isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
- CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()));
+ CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()) - start);
{
HandleScope scope2(isolate);
Handle<JSArrayBuffer> iab1 = v8::Utils::OpenHandle(*ab1);
}
isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
- CHECK_EQ(0, CountArrayBuffersInWeakList(isolate->heap()));
+ CHECK_EQ(start, CountArrayBuffersInWeakList(isolate->heap()));
}
--- /dev/null
+#!/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 "v8.h"
+#include "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()
+
'sources': [
'<(SHARED_INTERMEDIATE_DIR)/libraries.cc',
'<(SHARED_INTERMEDIATE_DIR)/experimental-libraries.cc',
+ '<(SHARED_INTERMEDIATE_DIR)/trig-table.cc',
'<(INTERMEDIATE_DIR)/snapshot.cc',
],
'actions': [
'sources': [
'<(SHARED_INTERMEDIATE_DIR)/libraries.cc',
'<(SHARED_INTERMEDIATE_DIR)/experimental-libraries.cc',
+ '<(SHARED_INTERMEDIATE_DIR)/trig-table.cc',
'../../src/snapshot-empty.cc',
],
'conditions': [
}],
]
},
+ { 'target_name': 'generate_trig_table',
+ 'type': 'none',
+ 'conditions': [
+ ['want_separate_host_toolset==1', {
+ 'toolsets': ['host', 'target'],
+ }, {
+ '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.<(v8_target_arch)',
'type': 'static_library',
+ 'dependencies': [
+ 'generate_trig_table',
+ ],
'variables': {
'optimize': 'max',
},