Index: src/api.cc |
diff --git a/src/api.cc b/src/api.cc |
index 4cdd77ef05a6908c5cc5ebf0fa3398ab0c1f3e72..05b58b48b196f06899b0143c58a3974bbedaa813 100644 |
--- a/src/api.cc |
+++ b/src/api.cc |
@@ -4304,6 +4304,25 @@ bool String::IsOneByte() const { |
} |
+// Helpers for ContainsOnlyOneByteHelper |
+template<size_t size> struct OneByteMask; |
+template<> struct OneByteMask<4> { |
+ static const uint32_t value = 0xFF00FF00U; |
+}; |
+template<> struct OneByteMask<8> { |
+ static const uint64_t value = 0xFF00FF00FF00ULL; |
Yang
2013/06/07 09:19:06
Shouldn't this be 0xFF00FF00FF00FF00ULL (missing o
|
+}; |
+static const uintptr_t kOneByteMask = OneByteMask<sizeof(uintptr_t)>::value; |
Yang
2013/06/07 09:19:06
I guess you could also just static_cast<uintptr_t>
|
+static const uintptr_t kAlignmentMask = sizeof(uintptr_t) - 1; |
+static inline bool Unaligned(const uint16_t* chars) { |
+ return reinterpret_cast<const uintptr_t>(chars) & kAlignmentMask; |
+} |
+static inline const uint16_t* Align(const uint16_t* chars) { |
+ return reinterpret_cast<uint16_t*>( |
+ reinterpret_cast<uintptr_t>(chars) & ~kAlignmentMask); |
+} |
+ |
+ |
class ContainsOnlyOneByteHelper { |
public: |
ContainsOnlyOneByteHelper() : is_one_byte_(true) {} |
@@ -4315,14 +4334,36 @@ class ContainsOnlyOneByteHelper { |
void VisitOneByteString(const uint8_t* chars, int length) { |
// Nothing to do. |
} |
- // TODO(dcarney): do word aligned read. |
void VisitTwoByteString(const uint16_t* chars, int length) { |
- // Check whole string without breaking. |
- uint16_t total = 0; |
- for (int i = 0; i < length; i++) { |
- total |= chars[i] >> 8; |
+ // Accumulated bits. |
+ uintptr_t acc = 0; |
+ // Align to uintptr_t. |
+ const uint16_t* end = chars + length; |
+ while (Unaligned(chars) && chars != end) { |
+ acc |= *chars++; |
+ } |
+ // Read word aligned in blocks, |
+ // checking the return value at the end of each block. |
+ const uint16_t* aligned_end = Align(end); |
+ const int increment = sizeof(uintptr_t)/sizeof(uint16_t); |
+ const int inner_loops = 16; |
+ while (chars + inner_loops*increment < aligned_end) { |
+ for (int i = 0; i < inner_loops; i++) { |
+ acc |= *reinterpret_cast<const uintptr_t*>(chars); |
+ chars += increment; |
+ } |
+ // Check for early return. |
+ if ((acc & kOneByteMask) != 0) { |
+ is_one_byte_ = false; |
+ return; |
+ } |
+ } |
+ // Read the rest. |
+ while (chars != end) { |
+ acc |= *chars++; |
} |
- if (total != 0) is_one_byte_ = false; |
+ // Check result. |
+ if ((acc & kOneByteMask) != 0) is_one_byte_ = false; |
} |
private: |