Index: src/assembler.cc |
diff --git a/src/assembler.cc b/src/assembler.cc |
index 9cec04a087175c9932f1c69c1857b40740898c73..344e203b6da173027c4de1dc5750c4cab9c10dd6 100644 |
--- a/src/assembler.cc |
+++ b/src/assembler.cc |
@@ -103,6 +103,11 @@ static DoubleConstant double_constants; |
const char* const RelocInfo::kFillerCommentString = "DEOPTIMIZATION PADDING"; |
+static bool math_exp_data_initialized = false; |
+static Mutex* math_exp_data_mutex = NULL; |
+static double* math_exp_constants_array = NULL; |
+static double* math_exp_log_table_array = NULL; |
+ |
// ----------------------------------------------------------------------------- |
// Implementation of AssemblerBase |
@@ -836,6 +841,70 @@ void ExternalReference::SetUp() { |
double_constants.canonical_non_hole_nan = OS::nan_value(); |
double_constants.the_hole_nan = BitCast<double>(kHoleNanInt64); |
double_constants.negative_infinity = -V8_INFINITY; |
+ |
+ math_exp_data_mutex = OS::CreateMutex(); |
+} |
+ |
+ |
+void ExternalReference::InitializeMathExpData() { |
+ // Early return? |
+ if (math_exp_data_initialized) return; |
+ |
+ math_exp_data_mutex->Lock(); |
+ if (!math_exp_data_initialized) { |
+ // If this is changed, generated code must be adapted too. |
+ const int kTableSizeBits = 11; |
+ const int kTableSize = 1 << kTableSizeBits; |
+ const double kTableSizeDouble = static_cast<double>(kTableSize); |
+ |
+ math_exp_constants_array = new double[9]; |
+ // Input values smaller than this always return 0. |
+ math_exp_constants_array[0] = -708.39641853226408; |
+ // Input values larger than this always return +Infinity. |
+ math_exp_constants_array[1] = 709.78271289338397; |
+ math_exp_constants_array[2] = V8_INFINITY; |
+ // The rest is black magic. Do not attempt to understand it. It is |
+ // loosely based on the "expd" function published at: |
+ // http://herumi.blogspot.com/2011/08/fast-double-precision-exponential.html |
+ const double constant3 = (1 << kTableSizeBits) / log(2.0); |
+ math_exp_constants_array[3] = constant3; |
+ math_exp_constants_array[4] = |
+ static_cast<double>(static_cast<int64_t>(3) << 51); |
+ math_exp_constants_array[5] = 1 / constant3; |
+ math_exp_constants_array[6] = 3.0000000027955394; |
+ math_exp_constants_array[7] = 0.16666666685227835; |
+ math_exp_constants_array[8] = 1; |
+ |
+ math_exp_log_table_array = new double[kTableSize]; |
+ for (int i = 0; i < kTableSize; i++) { |
+ double value = pow(2, i / kTableSizeDouble); |
+ |
+ uint64_t bits = BitCast<uint64_t, double>(value); |
+ bits &= (static_cast<uint64_t>(1) << 52) - 1; |
+ double mantissa = BitCast<double, uint64_t>(bits); |
+ |
+ // <just testing> |
+ uint64_t doublebits; |
+ memcpy(&doublebits, &value, sizeof doublebits); |
+ doublebits &= (static_cast<uint64_t>(1) << 52) - 1; |
+ double mantissa2; |
+ memcpy(&mantissa2, &doublebits, sizeof mantissa2); |
+ CHECK_EQ(mantissa, mantissa2); |
+ // </just testing> |
+ |
+ math_exp_log_table_array[i] = mantissa; |
+ } |
+ |
+ math_exp_data_initialized = true; |
+ } |
+ math_exp_data_mutex->Unlock(); |
+} |
+ |
+ |
+void ExternalReference::TearDownMathExpData() { |
+ delete[] math_exp_constants_array; |
+ delete[] math_exp_log_table_array; |
+ delete math_exp_data_mutex; |
} |
@@ -1273,6 +1342,19 @@ ExternalReference ExternalReference::math_log_double_function( |
} |
+ExternalReference ExternalReference::math_exp_constants(int constant_index) { |
+ ASSERT(math_exp_data_initialized); |
+ return ExternalReference( |
+ reinterpret_cast<void*>(math_exp_constants_array + constant_index)); |
+} |
+ |
+ |
+ExternalReference ExternalReference::math_exp_log_table() { |
+ ASSERT(math_exp_data_initialized); |
+ return ExternalReference(reinterpret_cast<void*>(math_exp_log_table_array)); |
+} |
+ |
+ |
ExternalReference ExternalReference::page_flags(Page* page) { |
return ExternalReference(reinterpret_cast<Address>(page) + |
MemoryChunk::kFlagsOffset); |