Chromium Code Reviews| Index: src/conversions-inl.h |
| diff --git a/src/conversions-inl.h b/src/conversions-inl.h |
| index b71fcfcf69db1dcb206e6f954341ea5efb448451..424332e52d17622ab04872e588e3d92ee7af76f6 100644 |
| --- a/src/conversions-inl.h |
| +++ b/src/conversions-inl.h |
| @@ -57,7 +57,7 @@ inline unsigned int FastD2UI(double x) { |
| #ifndef V8_TARGET_BIG_ENDIAN |
| Address mantissa_ptr = reinterpret_cast<Address>(&x); |
| #else |
| - Address mantissa_ptr = reinterpret_cast<Address>(&x) + kIntSize; |
| + Address mantissa_ptr = reinterpret_cast<Address>(&x) + kInt32Size; |
| #endif |
| // Copy least significant 32 bits of mantissa. |
| memcpy(&result, mantissa_ptr, sizeof(result)); |
| @@ -123,14 +123,41 @@ bool IsUint32Double(double value) { |
| } |
| bool DoubleToUint32IfEqualToSelf(double value, uint32_t* uint32_value) { |
| - if (value < 0) return false; |
| - // TODO(leszeks): We maybe could be faster than FastD2UI here, since we only |
| - // care about the value being valid if the conversion is valid. |
| - uint32_t converted_value = FastD2UI(value); |
| - if (FastUI2D(converted_value) == value) { |
| - *uint32_value = converted_value; |
| - return true; |
| + const double k2Pow52 = 4503599627370496.0; |
| + const uint32_t kValidTopBits = 0x43300000; |
| + |
| + // Add 2^52 to the double, to place valid uint32 values in the low-significant |
| + // bits of the exponent, by effectively setting the (implicit) top bit of the |
| + // significand. Note that this addition also normalises 0.0 and -0.0. |
| + double shifted_value = value + k2Pow52; |
| + |
| + // At this point, a valid uint32 valued double will be represented as: |
| + // |
| + // sign = 0 |
| + // exponent = 52 |
| + // significand = 1. 00...00 <value> |
| + // implicit^ ^^^^^^^ 32 bits |
| + // ^^^^^^^^^^^^^^^ 52 bits |
| + // |
| + // Therefore, it is sufficient to check the top 32 bits to make sure that the |
| + // sign, exponent and remaining significand bits are valid, and extract the |
| + // bottom 32 bits to get the value. |
| + |
| + uint32_t check; |
| +#ifndef V8_TARGET_BIG_ENDIAN |
| + Address top_ptr = reinterpret_cast<Address>(&shifted_value) + kInt32Size; |
| + Address bottom_ptr = reinterpret_cast<Address>(&shifted_value); |
| +#else |
| + Address top_ptr = reinterpret_cast<Address>(&shifted_value); |
| + Address bottom_ptr = reinterpret_cast<Address>(&shifted_value) + kInt32Size; |
| +#endif |
| + memcpy(&check, top_ptr, sizeof(uint32_t)); |
|
rmcilroy
2017/01/16 14:12:11
Could you just do a reinterpreter_cast on the addr
Leszek Swirski
2017/01/16 14:26:54
Good question -- short version, no, because of str
rmcilroy
2017/01/16 15:59:51
Ahh I see, thanks for the explination.
Leszek Swirski
2017/01/17 12:36:19
Whoops, it turns out my microbenchmarks were super
|
| + if (check == kValidTopBits) { |
| + memcpy(uint32_value, bottom_ptr, sizeof(uint32_t)); |
|
rmcilroy
2017/01/16 14:12:11
ditto
Leszek Swirski
2017/01/16 14:26:54
As above.
|
| + // Make sure we convert back to the right value. |
| + return FastUI2D(*uint32_value) == value; |
| } |
| + DCHECK(DoubleToUint32(value) != value); |
| return false; |
| } |