Fast path for symbol lookup in JSON.parse.
authoryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 24 Sep 2012 14:23:46 +0000 (14:23 +0000)
committeryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 24 Sep 2012 14:23:46 +0000 (14:23 +0000)
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

src/json-parser.h
src/objects-inl.h
src/objects.cc
src/objects.h

index a4db130..0c2cb2d 100644 (file)
@@ -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<String> JsonParser<seq_ascii>::ScanJsonString() {
     AdvanceSkipWhitespace();
     return Handle<String>(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<SeqAsciiString, char>(source_,
+                                                        position_,
+                                                        position);
+      }
+      running_hash = StringHasher::AddCharacterCore(running_hash, c0);
+      position++;
+      if (position > source_length_) return Handle<String>::null();
+      c0 = seq_source_->SeqAsciiStringGet(position);
+    } while (c0 != '"');
+    int length = position - position_;
+    uint32_t hash = (length <= String::kMaxHashCalcLength)
+        ? StringHasher::GetHashCore(running_hash) : length;
+    Vector<const char> 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>(String::cast(element));
+      }
+      index = SymbolTable::NextProbe(hash, count++, capacity);
+    }
+  }
+
   int beg_pos = position_;
   // Fast case for ASCII only without escape characters.
   do {
index 411aeec..fb3fe64 100644 (file)
@@ -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_);
 }
 
 
index d9059de..8ce2fa3 100644 (file)
@@ -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_);
index 5c607fe..14f81f8 100644 (file)
@@ -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<SymbolTableShape, HashTableKey*> {
  private:
   MUST_USE_RESULT MaybeObject* LookupKey(HashTableKey* key, Object** s);
 
+  template <bool seq_ascii> 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 <bool seq_ascii> 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_;
 };