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();
}
}
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 {
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);
}
}
+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.
}
// 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') {
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_);
}
uint32_t StringHasher::GetHashField() {
- ASSERT(is_valid());
if (length_ <= String::kMaxHashCalcLength) {
if (is_array_index()) {
return MakeArrayIndexHash(array_index(), length_);
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);
}
private:
MUST_USE_RESULT MaybeObject* LookupKey(HashTableKey* key, Object** s);
+ template <bool seq_ascii> friend class JsonParser;
+
DISALLOW_IMPLICIT_CONSTRUCTORS(SymbolTable);
};
// 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.
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_;
};