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; |
} |