Skip to content

Commit dfa19a5

Browse files
Fast double-to-ascii conversion.
Review URL: http://codereview.chromium.org/866002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@4106 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
1 parent 61e9ff6 commit dfa19a5

18 files changed

+104250
-3
lines changed

src/SConscript

+1
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ SOURCES = {
6363
full-codegen.cc
6464
func-name-inferrer.cc
6565
global-handles.cc
66+
grisu3.cc
6667
handles.cc
6768
hashmap.cc
6869
heap-profiler.cc

src/cached_powers.h

+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// Copyright 2010 the V8 project authors. All rights reserved.
2+
// Redistribution and use in source and binary forms, with or without
3+
// modification, are permitted provided that the following conditions are
4+
// met:
5+
//
6+
// * Redistributions of source code must retain the above copyright
7+
// notice, this list of conditions and the following disclaimer.
8+
// * Redistributions in binary form must reproduce the above
9+
// copyright notice, this list of conditions and the following
10+
// disclaimer in the documentation and/or other materials provided
11+
// with the distribution.
12+
// * Neither the name of Google Inc. nor the names of its
13+
// contributors may be used to endorse or promote products derived
14+
// from this software without specific prior written permission.
15+
//
16+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17+
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18+
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19+
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20+
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21+
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22+
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23+
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24+
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25+
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26+
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27+
28+
#ifndef V8_CACHED_POWERS_H_
29+
#define V8_CACHED_POWERS_H_
30+
31+
#include "diy_fp.h"
32+
33+
namespace v8 {
34+
namespace internal {
35+
36+
struct CachedPower {
37+
uint64_t significand;
38+
int16_t binary_exponent;
39+
int16_t decimal_exponent;
40+
};
41+
42+
// The following defines implement the interface between this file and the
43+
// generated 'powers_ten.h'.
44+
// GRISU_CACHE_NAME(1) contains all possible cached powers.
45+
// GRISU_CACHE_NAME(i) contains GRISU_CACHE_NAME(1) where only every 'i'th
46+
// element is kept. More formally GRISU_CACHE_NAME(i) contains the elements j*i
47+
// with 0 <= j < k with k such that j*k < the size of GRISU_CACHE_NAME(1).
48+
// The higher 'i' is the fewer elements we use.
49+
// Given that there are less elements, the exponent-distance between two
50+
// elements in the cache grows. The variable GRISU_CACHE_MAX_DISTANCE(i) stores
51+
// the maximum distance between two elements.
52+
#define GRISU_CACHE_STRUCT CachedPower
53+
#define GRISU_CACHE_NAME(i) kCachedPowers##i
54+
#define GRISU_CACHE_MAX_DISTANCE(i) kCachedPowersMaxDistance##i
55+
#define GRISU_CACHE_OFFSET kCachedPowerOffset
56+
#define GRISU_UINT64_C V8_2PART_UINT64_C
57+
// The following include imports the precompiled cached powers.
58+
#include "powers_ten.h" // NOLINT
59+
60+
static const double kD_1_LOG2_10 = 0.30102999566398114; // 1 / lg(10)
61+
62+
// We can't use a function since we reference variables depending on the 'i'.
63+
// This way the compiler is able to see at compile time that only one
64+
// cache-array variable is used and thus can remove all the others.
65+
#define COMPUTE_FOR_CACHE(i) \
66+
if (!found && (gamma - alpha + 1 >= GRISU_CACHE_MAX_DISTANCE(i))) { \
67+
int kQ = DiyFp::kSignificandSize; \
68+
double k = ceiling((alpha - e + kQ - 1) * kD_1_LOG2_10); \
69+
int index = (GRISU_CACHE_OFFSET + static_cast<int>(k) - 1) / i + 1; \
70+
cached_power = GRISU_CACHE_NAME(i)[index]; \
71+
found = true; \
72+
} \
73+
74+
static void GetCachedPower(int e, int alpha, int gamma, int* mk, DiyFp* c_mk) {
75+
// The following if statement should be optimized by the compiler so that only
76+
// one array is referenced and the others are not included in the object file.
77+
bool found = false;
78+
CachedPower cached_power;
79+
COMPUTE_FOR_CACHE(20);
80+
COMPUTE_FOR_CACHE(19);
81+
COMPUTE_FOR_CACHE(18);
82+
COMPUTE_FOR_CACHE(17);
83+
COMPUTE_FOR_CACHE(16);
84+
COMPUTE_FOR_CACHE(15);
85+
COMPUTE_FOR_CACHE(14);
86+
COMPUTE_FOR_CACHE(13);
87+
COMPUTE_FOR_CACHE(12);
88+
COMPUTE_FOR_CACHE(11);
89+
COMPUTE_FOR_CACHE(10);
90+
COMPUTE_FOR_CACHE(9);
91+
COMPUTE_FOR_CACHE(8);
92+
COMPUTE_FOR_CACHE(7);
93+
COMPUTE_FOR_CACHE(6);
94+
COMPUTE_FOR_CACHE(5);
95+
COMPUTE_FOR_CACHE(4);
96+
COMPUTE_FOR_CACHE(3);
97+
COMPUTE_FOR_CACHE(2);
98+
COMPUTE_FOR_CACHE(1);
99+
if (!found) {
100+
UNIMPLEMENTED();
101+
// Silence compiler warnings.
102+
cached_power.significand = 0;
103+
cached_power.binary_exponent = 0;
104+
cached_power.decimal_exponent = 0;
105+
}
106+
*c_mk = DiyFp(cached_power.significand, cached_power.binary_exponent);
107+
*mk = cached_power.decimal_exponent;
108+
ASSERT((alpha <= c_mk->e() + e) && (c_mk->e() + e <= gamma));
109+
}
110+
#undef GRISU_REDUCTION
111+
#undef GRISU_CACHE_STRUCT
112+
#undef GRISU_CACHE_NAME
113+
#undef GRISU_CACHE_MAX_DISTANCE
114+
#undef GRISU_CACHE_OFFSET
115+
#undef GRISU_UINT64_C
116+
117+
} } // namespace v8::internal
118+
119+
#endif // V8_CACHED_POWERS_H_

src/checks.h

+22
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ static inline void CheckEqualsHelper(const char* file, int line,
8080
}
8181
}
8282

83+
8384
// Helper function used by the CHECK_EQ function when given int64_t
8485
// arguments. Should not be called directly.
8586
static inline void CheckEqualsHelper(const char* file, int line,
@@ -202,6 +203,27 @@ static inline void CheckEqualsHelper(const char* file,
202203
}
203204

204205

206+
static inline void CheckNonEqualsHelper(const char* file,
207+
int line,
208+
const char* expected_source,
209+
double expected,
210+
const char* value_source,
211+
double value) {
212+
// Force values to 64 bit memory to truncate 80 bit precision on IA32.
213+
volatile double* exp = new double[1];
214+
*exp = expected;
215+
volatile double* val = new double[1];
216+
*val = value;
217+
if (*exp == *val) {
218+
V8_Fatal(file, line,
219+
"CHECK_NE(%s, %s) failed\n# Value: %f",
220+
expected_source, value_source, *val);
221+
}
222+
delete[] exp;
223+
delete[] val;
224+
}
225+
226+
205227
namespace v8 {
206228
class Value;
207229
template <class T> class Handle;

src/conversions.cc

+13-3
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
#include "conversions-inl.h"
3333
#include "factory.h"
34+
#include "grisu3.h"
3435
#include "scanner.h"
3536

3637
namespace v8 {
@@ -382,8 +383,17 @@ const char* DoubleToCString(double v, Vector<char> buffer) {
382383
int decimal_point;
383384
int sign;
384385

385-
char* decimal_rep = dtoa(v, 0, 0, &decimal_point, &sign, NULL);
386-
int length = StrLength(decimal_rep);
386+
char* decimal_rep;
387+
bool used_dtoa = false;
388+
char grisu_buffer[kGrisu3MaximalLength + 1];
389+
int length;
390+
if (grisu3(v, grisu_buffer, &sign, &length, &decimal_point)) {
391+
decimal_rep = grisu_buffer;
392+
} else {
393+
decimal_rep = dtoa(v, 0, 0, &decimal_point, &sign, NULL);
394+
used_dtoa = true;
395+
length = StrLength(decimal_rep);
396+
}
387397

388398
if (sign) builder.AddCharacter('-');
389399

@@ -418,7 +428,7 @@ const char* DoubleToCString(double v, Vector<char> buffer) {
418428
builder.AddFormatted("%d", exponent);
419429
}
420430

421-
freedtoa(decimal_rep);
431+
if (used_dtoa) freedtoa(decimal_rep);
422432
}
423433
}
424434
return builder.Finalize();

src/diy_fp.h

+136
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
// Copyright 2010 the V8 project authors. All rights reserved.
2+
// Redistribution and use in source and binary forms, with or without
3+
// modification, are permitted provided that the following conditions are
4+
// met:
5+
//
6+
// * Redistributions of source code must retain the above copyright
7+
// notice, this list of conditions and the following disclaimer.
8+
// * Redistributions in binary form must reproduce the above
9+
// copyright notice, this list of conditions and the following
10+
// disclaimer in the documentation and/or other materials provided
11+
// with the distribution.
12+
// * Neither the name of Google Inc. nor the names of its
13+
// contributors may be used to endorse or promote products derived
14+
// from this software without specific prior written permission.
15+
//
16+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17+
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18+
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19+
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20+
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21+
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22+
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23+
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24+
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25+
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26+
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27+
28+
#ifndef V8_DIY_FP_H_
29+
#define V8_DIY_FP_H_
30+
31+
namespace v8 {
32+
namespace internal {
33+
34+
// This "Do It Yourself Floating Point" class implements a floating-point number
35+
// with a uint64 significand and an int exponent. Normalized DiyFp numbers will
36+
// have the most significant bit of the significand set.
37+
// Multiplication and Subtraction do not normalize their results.
38+
// DiyFp are not designed to contain special doubles (NaN and Infinity).
39+
class DiyFp {
40+
public:
41+
static const int kSignificandSize = 64;
42+
43+
DiyFp() : f_(0), e_(0) {}
44+
DiyFp(uint64_t f, int e) : f_(f), e_(e) {}
45+
46+
// this = this - other.
47+
// The exponents of both numbers must be the same and the significand of this
48+
// must be bigger than the significand of other.
49+
// The result will not be normalized.
50+
void Subtract(const DiyFp& other) {
51+
ASSERT(e_ == other.e_);
52+
ASSERT(f_ >= other.f_);
53+
f_ -= other.f_;
54+
}
55+
56+
// Returns a - b.
57+
// The exponents of both numbers must be the same and this must be bigger
58+
// than other. The result will not be normalized.
59+
static DiyFp Minus(const DiyFp& a, const DiyFp& b) {
60+
DiyFp result = a;
61+
result.Subtract(b);
62+
return result;
63+
}
64+
65+
66+
// this = this * other.
67+
void Multiply(const DiyFp& other) {
68+
// Simply "emulates" a 128 bit multiplication.
69+
// However: the resulting number only contains 64 bits. The least
70+
// significant 64 bits are only used for rounding the most significant 64
71+
// bits.
72+
const uint64_t kM32 = 0xFFFFFFFFu;
73+
uint64_t a = f_ >> 32;
74+
uint64_t b = f_ & kM32;
75+
uint64_t c = other.f_ >> 32;
76+
uint64_t d = other.f_ & kM32;
77+
uint64_t ac = a * c;
78+
uint64_t bc = b * c;
79+
uint64_t ad = a * d;
80+
uint64_t bd = b * d;
81+
uint64_t tmp = (bd >> 32) + (ad & kM32) + (bc & kM32);
82+
tmp += 1U << 31; // round
83+
uint64_t result_f = ac + (ad >> 32) + (bc >> 32) + (tmp >> 32);
84+
e_ += other.e_ + 64;
85+
f_ = result_f;
86+
}
87+
88+
// returns a * b;
89+
static DiyFp Times(const DiyFp& a, const DiyFp& b) {
90+
DiyFp result = a;
91+
result.Multiply(b);
92+
return result;
93+
}
94+
95+
void Normalize() {
96+
ASSERT(f_ != 0);
97+
uint64_t f = f_;
98+
int e = e_;
99+
100+
// This method is mainly called for normalizing boundaries. In general
101+
// boundaries need to be shifted by 10 bits. We thus optimize for this case.
102+
const uint64_t k10MSBits = V8_2PART_UINT64_C(0xFFC00000, 00000000);
103+
while ((f & k10MSBits) == 0) {
104+
f <<= 10;
105+
e -= 10;
106+
}
107+
while ((f & kUint64MSB) == 0) {
108+
f <<= 1;
109+
e--;
110+
}
111+
f_ = f;
112+
e_ = e;
113+
}
114+
115+
static DiyFp Normalize(const DiyFp& a) {
116+
DiyFp result = a;
117+
result.Normalize();
118+
return result;
119+
}
120+
121+
uint64_t f() const { return f_; }
122+
int e() const { return e_; }
123+
124+
void set_f(uint64_t new_value) { f_ = new_value; }
125+
void set_e(int new_value) { e_ = new_value; }
126+
127+
private:
128+
static const uint64_t kUint64MSB = V8_2PART_UINT64_C(0x80000000, 00000000);
129+
130+
uint64_t f_;
131+
int e_;
132+
};
133+
134+
} } // namespace v8::internal
135+
136+
#endif // V8_DIY_FP_H_

0 commit comments

Comments
 (0)