From: yangguo@chromium.org Date: Mon, 24 Sep 2012 14:23:46 +0000 (+0000) Subject: Fast path for symbol lookup in JSON.parse. X-Git-Tag: upstream/4.7.83~15946 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=681eda652d31757c4fc364ebbc3c06887fa54694;p=platform%2Fupstream%2Fv8.git Fast path for symbol lookup in JSON.parse. R=verwaest@chromium.org BUG= Review URL: https://chromiumcodereview.appspot.com/10969069 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12598 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/json-parser.h b/src/json-parser.h index a4db130..0c2cb2d 100644 --- a/src/json-parser.h +++ b/src/json-parser.h @@ -71,11 +71,11 @@ class JsonParser BASE_EMBEDDED { inline void AdvanceSkipWhitespace() { do { Advance(); - } while (c0_ == '\t' || c0_ == '\r' || c0_ == '\n' || c0_ == ' '); + } while (c0_ == ' ' || c0_ == '\t' || c0_ == '\n' || c0_ == '\r'); } inline void SkipWhitespace() { - while (c0_ == '\t' || c0_ == '\r' || c0_ == '\n' || c0_ == ' ') { + while (c0_ == ' ' || c0_ == '\t' || c0_ == '\n' || c0_ == '\r') { Advance(); } } @@ -563,6 +563,52 @@ Handle JsonParser::ScanJsonString() { AdvanceSkipWhitespace(); return Handle(isolate()->heap()->empty_string()); } + + if (seq_ascii && is_symbol) { + // Fast path for existing symbols. If the the string being parsed is not + // a known symbol, contains backslashes or unexpectedly reaches the end of + // string, return with an empty handle. + uint32_t running_hash = isolate()->heap()->HashSeed(); + int position = position_; + uc32 c0 = c0_; + do { + if (c0 == '\\') { + return SlowScanJsonString(source_, + position_, + position); + } + running_hash = StringHasher::AddCharacterCore(running_hash, c0); + position++; + if (position > source_length_) return Handle::null(); + c0 = seq_source_->SeqAsciiStringGet(position); + } while (c0 != '"'); + int length = position - position_; + uint32_t hash = (length <= String::kMaxHashCalcLength) + ? StringHasher::GetHashCore(running_hash) : length; + Vector string_vector( + seq_source_->GetChars() + position_, length); + SymbolTable* symbol_table = isolate()->heap()->symbol_table(); + uint32_t capacity = symbol_table->Capacity(); + uint32_t index = SymbolTable::FirstProbe(hash, capacity); + uint32_t count = 1; + while (true) { + Object* element = symbol_table->KeyAt(index); + if (element == isolate()->heap()->raw_unchecked_undefined_value()) { + // Lookup failure. + break; + } + if (element != isolate()->heap()->raw_unchecked_the_hole_value() && + String::cast(element)->IsAsciiEqualTo(string_vector)) { + // Lookup success, update the current position. + position_ = position; + // Advance past the last '"'. + AdvanceSkipWhitespace(); + return Handle(String::cast(element)); + } + index = SymbolTable::NextProbe(hash, count++, capacity); + } + } + int beg_pos = position_; // Fast case for ASCII only without escape characters. do { diff --git a/src/objects-inl.h b/src/objects-inl.h index 411aeec..fb3fe64 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -4949,8 +4949,7 @@ StringHasher::StringHasher(int length, uint32_t seed) raw_running_hash_(seed), array_index_(0), is_array_index_(0 < length_ && length_ <= String::kMaxArrayIndexSize), - is_first_char_(true), - is_valid_(true) { + is_first_char_(true) { ASSERT(FLAG_randomize_hashes || raw_running_hash_ == 0); } @@ -4960,6 +4959,25 @@ bool StringHasher::has_trivial_hash() { } +uint32_t StringHasher::AddCharacterCore(uint32_t running_hash, uint32_t c) { + running_hash += c; + running_hash += (running_hash << 10); + running_hash ^= (running_hash >> 6); + return running_hash; +} + + +uint32_t StringHasher::GetHashCore(uint32_t running_hash) { + running_hash += (running_hash << 3); + running_hash ^= (running_hash >> 11); + running_hash += (running_hash << 15); + if ((running_hash & String::kHashBitMask) == 0) { + return 27; + } + return running_hash; +} + + void StringHasher::AddCharacter(uint32_t c) { if (c > unibrow::Utf16::kMaxNonSurrogateCharCode) { AddSurrogatePair(c); // Not inlined. @@ -4967,9 +4985,7 @@ void StringHasher::AddCharacter(uint32_t c) { } // Use the Jenkins one-at-a-time hash function to update the hash // for the given character. - raw_running_hash_ += c; - raw_running_hash_ += (raw_running_hash_ << 10); - raw_running_hash_ ^= (raw_running_hash_ >> 6); + raw_running_hash_ = AddCharacterCore(raw_running_hash_, c); // Incremental array index computation. if (is_array_index_) { if (c < '0' || c > '9') { @@ -4999,23 +5015,14 @@ void StringHasher::AddCharacterNoIndex(uint32_t c) { AddSurrogatePairNoIndex(c); // Not inlined. return; } - raw_running_hash_ += c; - raw_running_hash_ += (raw_running_hash_ << 10); - raw_running_hash_ ^= (raw_running_hash_ >> 6); + raw_running_hash_ = AddCharacterCore(raw_running_hash_, c); } 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. - uint32_t result = raw_running_hash_; - result += (result << 3); - result ^= (result >> 11); - result += (result << 15); - if ((result & String::kHashBitMask) == 0) { - result = 27; - } - return result; + return GetHashCore(raw_running_hash_); } diff --git a/src/objects.cc b/src/objects.cc index d9059de..8ce2fa3 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -7385,7 +7385,6 @@ void StringHasher::AddSurrogatePairNoIndex(uc32 c) { uint32_t StringHasher::GetHashField() { - ASSERT(is_valid()); if (length_ <= String::kMaxHashCalcLength) { if (is_array_index()) { return MakeArrayIndexHash(array_index(), length_); diff --git a/src/objects.h b/src/objects.h index 5c607fe..14f81f8 100644 --- a/src/objects.h +++ b/src/objects.h @@ -2913,11 +2913,12 @@ class HashTable: public FixedArray { return (hash + GetProbeOffset(number)) & (size - 1); } - static uint32_t FirstProbe(uint32_t hash, uint32_t size) { + inline static uint32_t FirstProbe(uint32_t hash, uint32_t size) { return hash & (size - 1); } - static uint32_t NextProbe(uint32_t last, uint32_t number, uint32_t size) { + inline static uint32_t NextProbe( + uint32_t last, uint32_t number, uint32_t size) { return (last + number) & (size - 1); } @@ -3004,6 +3005,8 @@ class SymbolTable: public HashTable { private: MUST_USE_RESULT MaybeObject* LookupKey(HashTableKey* key, Object** s); + template friend class JsonParser; + DISALLOW_IMPLICIT_CONSTRUCTORS(SymbolTable); }; @@ -7054,10 +7057,6 @@ class StringHasher { // index. bool is_array_index() { return is_array_index_; } - bool is_valid() { return is_valid_; } - - void invalidate() { is_valid_ = false; } - // Calculated hash value for a string consisting of 1 to // String::kMaxArrayIndexSize digits with no leading zeros (except "0"). // value is represented decimal value. @@ -7076,13 +7075,33 @@ class StringHasher { inline uint32_t GetHash(); + // Reusable parts of the hashing algorithm. + INLINE(static uint32_t AddCharacterCore(uint32_t running_hash, uint32_t c)); + INLINE(static uint32_t GetHashCore(uint32_t running_hash)); + int length_; uint32_t raw_running_hash_; uint32_t array_index_; bool is_array_index_; bool is_first_char_; - bool is_valid_; friend class TwoCharHashTableKey; + + template friend class JsonParser; +}; + + +class IncrementalAsciiStringHasher { + public: + explicit inline IncrementalAsciiStringHasher(uint32_t seed, char first_char); + inline void AddCharacter(uc32 c); + inline uint32_t GetHash(); + + private: + int length_; + uint32_t raw_running_hash_; + uint32_t array_index_; + bool is_array_index_; + char first_char_; };