Index: src/objects-inl.h |
diff --git a/src/objects-inl.h b/src/objects-inl.h |
index 9e6044aaa9561cb1eba74d0cb6e94388bbf722e7..27644a83d5199fc337b9e04fa3ad288735391d7d 100644 |
--- a/src/objects-inl.h |
+++ b/src/objects-inl.h |
@@ -2584,8 +2584,7 @@ void String::Visit( |
case kConsStringTag | kOneByteStringTag: |
case kConsStringTag | kTwoByteStringTag: |
- string = cons_op.Operate(ConsString::cast(string), &offset, &type, |
- &length); |
+ string = cons_op.Operate(string, &offset, &type, &length); |
if (string == NULL) return; |
slice_offset = offset; |
ASSERT(length == static_cast<unsigned>(string->length())); |
@@ -2777,6 +2776,11 @@ const uint16_t* ExternalTwoByteString::ExternalTwoByteStringGetData( |
} |
+String* ConsStringNullOp::Operate(String*, unsigned*, int32_t*, unsigned*) { |
+ return NULL; |
+} |
+ |
+ |
unsigned ConsStringIteratorOp::OffsetForDepth(unsigned depth) { |
return depth & kDepthMask; |
} |
@@ -2805,42 +2809,38 @@ void ConsStringIteratorOp::Pop() { |
} |
-void ConsStringIteratorOp::Reset() { |
- depth_ = 0; |
- maximum_depth_ = 0; |
+bool ConsStringIteratorOp::HasMore() { |
+ return depth_ != 0; |
} |
-bool ConsStringIteratorOp::HasMore() { |
- return depth_ != 0; |
+void ConsStringIteratorOp::Reset() { |
+ depth_ = 0; |
} |
-bool ConsStringIteratorOp::ContinueOperation(ContinueResponse* response) { |
+String* ConsStringIteratorOp::ContinueOperation(int32_t* type_out, |
+ unsigned* length_out) { |
bool blew_stack; |
- int32_t type; |
- unsigned length; |
- String* string = NextLeaf(&blew_stack, &type, &length); |
+ String* string = NextLeaf(&blew_stack, type_out, length_out); |
// String found. |
if (string != NULL) { |
- consumed_ += length; |
- response->string_ = string; |
- response->offset_ = 0; |
- response->length_ = length; |
- response->type_ = type; |
- return true; |
+ // Verify output. |
+ ASSERT(*length_out == static_cast<unsigned>(string->length())); |
+ ASSERT(*type_out == string->map()->instance_type()); |
+ return string; |
} |
// Traversal complete. |
- if (!blew_stack) return false; |
- // Restart search. |
- Reset(); |
- // TODO(dcarney) This is unnecessary. |
- // After a reset, we don't need a String::Visit |
- response->string_ = root_; |
- response->offset_ = consumed_; |
- response->length_ = root_length_; |
- response->type_ = root_type_; |
- return true; |
+ if (!blew_stack) return NULL; |
+ // Restart search from root. |
+ unsigned offset_out; |
+ string = Search(&offset_out, type_out, length_out); |
+ // Verify output. |
+ ASSERT(string == NULL || offset_out == 0); |
+ ASSERT(string == NULL || |
+ *length_out == static_cast<unsigned>(string->length())); |
+ ASSERT(string == NULL || *type_out == string->map()->instance_type()); |
+ return string; |
} |
@@ -2857,18 +2857,24 @@ StringCharacterStream::StringCharacterStream( |
end_(NULL), |
op_(op) { |
op->Reset(); |
- String::Visit(string, |
- offset, *this, *op, string->map()->instance_type(), string->length()); |
+ int32_t type = string->map()->instance_type(); |
+ unsigned length = string->length(); |
+ String::Visit(string, offset, *this, *op, type, length); |
} |
bool StringCharacterStream::HasMore() { |
if (buffer8_ != end_) return true; |
if (!op_->HasMore()) return false; |
- ConsStringIteratorOp::ContinueResponse response; |
- if (!op_->ContinueOperation(&response)) return false; |
- String::Visit(response.string_, |
- response.offset_, *this, *op_, response.type_, response.length_); |
+ unsigned length; |
+ int32_t type; |
+ String* string = op_->ContinueOperation(&type, &length); |
+ if (string == NULL) return false; |
+ ASSERT(!string->IsConsString()); |
+ ASSERT(string->length() != 0); |
+ ConsStringNullOp null_op; |
+ String::Visit(string, 0, *this, null_op, type, length); |
+ ASSERT(buffer8_ != end_); |
return true; |
} |
@@ -5123,7 +5129,7 @@ bool StringHasher::has_trivial_hash() { |
} |
-uint32_t StringHasher::AddCharacterCore(uint32_t running_hash, uint32_t c) { |
+uint32_t StringHasher::AddCharacterCore(uint32_t running_hash, uint16_t c) { |
running_hash += c; |
running_hash += (running_hash << 10); |
running_hash ^= (running_hash >> 6); |
@@ -5142,66 +5148,62 @@ uint32_t StringHasher::GetHashCore(uint32_t running_hash) { |
} |
-void StringHasher::AddCharacter(uint32_t c) { |
- if (c > unibrow::Utf16::kMaxNonSurrogateCharCode) { |
- AddSurrogatePair(c); // Not inlined. |
- return; |
- } |
+void StringHasher::AddCharacter(uint16_t c) { |
// Use the Jenkins one-at-a-time hash function to update the hash |
// for the given character. |
raw_running_hash_ = AddCharacterCore(raw_running_hash_, c); |
- // Incremental array index computation. |
- if (is_array_index_) { |
- if (c < '0' || c > '9') { |
- is_array_index_ = false; |
- } else { |
- int d = c - '0'; |
- if (is_first_char_) { |
- is_first_char_ = false; |
- if (c == '0' && length_ > 1) { |
- is_array_index_ = false; |
- return; |
- } |
- } |
- if (array_index_ > 429496729U - ((d + 2) >> 3)) { |
- is_array_index_ = false; |
- } else { |
- array_index_ = array_index_ * 10 + d; |
- } |
- } |
- } |
} |
-void StringHasher::AddCharacterNoIndex(uint32_t c) { |
- ASSERT(!is_array_index()); |
- if (c > unibrow::Utf16::kMaxNonSurrogateCharCode) { |
- AddSurrogatePairNoIndex(c); // Not inlined. |
- return; |
+bool StringHasher::UpdateIndex(uint16_t c) { |
+ ASSERT(is_array_index_); |
+ if (c < '0' || c > '9') { |
+ is_array_index_ = false; |
+ return false; |
} |
- raw_running_hash_ = AddCharacterCore(raw_running_hash_, c); |
+ int d = c - '0'; |
+ if (is_first_char_) { |
+ is_first_char_ = false; |
+ if (c == '0' && length_ > 1) { |
+ is_array_index_ = false; |
+ return false; |
+ } |
+ } |
+ if (array_index_ > 429496729U - ((d + 2) >> 3)) { |
+ is_array_index_ = false; |
+ return false; |
+ } |
+ array_index_ = array_index_ * 10 + d; |
+ return true; |
} |
-uint32_t StringHasher::GetHash() { |
- // Get the calculated raw hash value and do some more bit ops to distribute |
- // the hash further. Ensure that we never return zero as the hash value. |
- return GetHashCore(raw_running_hash_); |
+template<typename Char> |
+inline void StringHasher::AddCharacters(const Char* chars, int length) { |
+ ASSERT(sizeof(Char) == 1 || sizeof(Char) == 2); |
+ int i = 0; |
+ if (is_array_index_) { |
+ for (; i < length; i++) { |
+ AddCharacter(chars[i]); |
+ if (!UpdateIndex(chars[i])) { |
+ i++; |
+ break; |
+ } |
+ } |
+ } |
+ for (; i < length; i++) { |
+ ASSERT(!is_array_index_); |
+ AddCharacter(chars[i]); |
+ } |
} |
template <typename schar> |
-uint32_t HashSequentialString(const schar* chars, int length, uint32_t seed) { |
+uint32_t StringHasher::HashSequentialString(const schar* chars, |
+ int length, |
+ uint32_t seed) { |
StringHasher hasher(length, seed); |
- if (!hasher.has_trivial_hash()) { |
- int i; |
- for (i = 0; hasher.is_array_index() && (i < length); i++) { |
- hasher.AddCharacter(chars[i]); |
- } |
- for (; i < length; i++) { |
- hasher.AddCharacterNoIndex(chars[i]); |
- } |
- } |
+ if (!hasher.has_trivial_hash()) hasher.AddCharacters(chars, length); |
return hasher.GetHashField(); |
} |