Commit 2a5791ce authored by Toon Verwaest's avatar Toon Verwaest Committed by Commit Bot

[json] Always internalize json string values to avoid memory overhead

Bug: 
Change-Id: Ie8b269467c8b1c5e97d1da9879f41319a49d5407
Reviewed-on: https://chromium-review.googlesource.com/911793
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51310}
parent 313e33a7
...@@ -416,7 +416,7 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() { ...@@ -416,7 +416,7 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() {
if (!follow_expected) { if (!follow_expected) {
// If the expected transition failed, parse an internalized string and // If the expected transition failed, parse an internalized string and
// try to find a matching transition. // try to find a matching transition.
key = ParseJsonInternalizedString(); key = ParseJsonString();
if (key.is_null()) return ReportUnexpectedCharacter(); if (key.is_null()) return ReportUnexpectedCharacter();
target = TransitionsAccessor(map).FindTransitionToField(key); target = TransitionsAccessor(map).FindTransitionToField(key);
...@@ -491,7 +491,7 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() { ...@@ -491,7 +491,7 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() {
Handle<String> key; Handle<String> key;
Handle<Object> value; Handle<Object> value;
key = ParseJsonInternalizedString(); key = ParseJsonString();
if (key.is_null() || c0_ != ':') return ReportUnexpectedCharacter(); if (key.is_null() || c0_ != ':') return ReportUnexpectedCharacter();
AdvanceSkipWhitespace(); AdvanceSkipWhitespace();
...@@ -812,7 +812,6 @@ Handle<String> JsonParser<seq_one_byte>::SlowScanJsonString( ...@@ -812,7 +812,6 @@ Handle<String> JsonParser<seq_one_byte>::SlowScanJsonString(
} }
template <bool seq_one_byte> template <bool seq_one_byte>
template <bool is_internalized>
Handle<String> JsonParser<seq_one_byte>::ScanJsonString() { Handle<String> JsonParser<seq_one_byte>::ScanJsonString() {
DCHECK_EQ('"', c0_); DCHECK_EQ('"', c0_);
Advance(); Advance();
...@@ -821,7 +820,7 @@ Handle<String> JsonParser<seq_one_byte>::ScanJsonString() { ...@@ -821,7 +820,7 @@ Handle<String> JsonParser<seq_one_byte>::ScanJsonString() {
return factory()->empty_string(); return factory()->empty_string();
} }
if (seq_one_byte && is_internalized) { if (seq_one_byte) {
// Fast path for existing internalized strings. If the the string being // Fast path for existing internalized strings. If the the string being
// parsed is not a known internalized string, contains backslashes or // parsed is not a known internalized string, contains backslashes or
// unexpectedly reaches the end of string, return with an empty handle. // unexpectedly reaches the end of string, return with an empty handle.
...@@ -829,9 +828,13 @@ Handle<String> JsonParser<seq_one_byte>::ScanJsonString() { ...@@ -829,9 +828,13 @@ Handle<String> JsonParser<seq_one_byte>::ScanJsonString() {
// We intentionally use local variables instead of fields, compute hash // We intentionally use local variables instead of fields, compute hash
// while we are iterating a string and manually inline StringTable lookup // while we are iterating a string and manually inline StringTable lookup
// here. // here.
uint32_t running_hash = isolate()->heap()->HashSeed();
int position = position_; int position = position_;
uc32 c0 = c0_; uc32 c0 = c0_;
uint32_t running_hash = isolate()->heap()->HashSeed();
uint32_t index = 0;
bool is_array_index = true;
do { do {
if (c0 == '\\') { if (c0 == '\\') {
c0_ = c0; c0_ = c0;
...@@ -845,6 +848,16 @@ Handle<String> JsonParser<seq_one_byte>::ScanJsonString() { ...@@ -845,6 +848,16 @@ Handle<String> JsonParser<seq_one_byte>::ScanJsonString() {
position_ = position; position_ = position;
return Handle<String>::null(); return Handle<String>::null();
} }
if (is_array_index) {
// With leading zero, the string has to be "0" to be a valid index.
if (!IsDecimalDigit(c0) || (position > position_ && index == 0)) {
is_array_index = false;
} else {
int d = c0 - '0';
is_array_index = index <= 429496729U - ((d + 3) >> 3);
index = (index * 10) + d;
}
}
running_hash = StringHasher::AddCharacterCore(running_hash, running_hash = StringHasher::AddCharacterCore(running_hash,
static_cast<uint16_t>(c0)); static_cast<uint16_t>(c0));
position++; position++;
...@@ -856,9 +869,15 @@ Handle<String> JsonParser<seq_one_byte>::ScanJsonString() { ...@@ -856,9 +869,15 @@ Handle<String> JsonParser<seq_one_byte>::ScanJsonString() {
c0 = seq_source_->SeqOneByteStringGet(position); c0 = seq_source_->SeqOneByteStringGet(position);
} while (c0 != '"'); } while (c0 != '"');
int length = position - position_; int length = position - position_;
uint32_t hash = (length <= String::kMaxHashCalcLength) uint32_t hash;
? StringHasher::GetHashCore(running_hash) if (is_array_index) {
: static_cast<uint32_t>(length); hash =
StringHasher::MakeArrayIndexHash(index, length) >> String::kHashShift;
} else if (length <= String::kMaxHashCalcLength) {
hash = StringHasher::GetHashCore(running_hash);
} else {
hash = static_cast<uint32_t>(length);
}
Vector<const uint8_t> string_vector(seq_source_->GetChars() + position_, Vector<const uint8_t> string_vector(seq_source_->GetChars() + position_,
length); length);
StringTable* string_table = isolate()->heap()->string_table(); StringTable* string_table = isolate()->heap()->string_table();
...@@ -877,12 +896,8 @@ Handle<String> JsonParser<seq_one_byte>::ScanJsonString() { ...@@ -877,12 +896,8 @@ Handle<String> JsonParser<seq_one_byte>::ScanJsonString() {
if (!element->IsTheHole(isolate()) && if (!element->IsTheHole(isolate()) &&
String::cast(element)->IsOneByteEqualTo(string_vector)) { String::cast(element)->IsOneByteEqualTo(string_vector)) {
result = Handle<String>(String::cast(element), isolate()); result = Handle<String>(String::cast(element), isolate());
#ifdef DEBUG DCHECK_EQ(result->Hash(),
uint32_t hash_field = (hash << String::kHashShift) >> String::kHashShift);
(hash << String::kHashShift) | String::kIsNotArrayIndexMask;
DCHECK_EQ(static_cast<int>(result->Hash()),
static_cast<int>(hash_field >> String::kHashShift));
#endif
break; break;
} }
entry = StringTable::NextProbe(entry, count++, capacity); entry = StringTable::NextProbe(entry, count++, capacity);
......
...@@ -75,19 +75,14 @@ class JsonParser BASE_EMBEDDED { ...@@ -75,19 +75,14 @@ class JsonParser BASE_EMBEDDED {
// literals. The string must only be double-quoted (not single-quoted), and // literals. The string must only be double-quoted (not single-quoted), and
// the only allowed backslash-escapes are ", /, \, b, f, n, r, t and // the only allowed backslash-escapes are ", /, \, b, f, n, r, t and
// four-digit hex escapes (uXXXX). Any other use of backslashes is invalid. // four-digit hex escapes (uXXXX). Any other use of backslashes is invalid.
Handle<String> ParseJsonString() {
return ScanJsonString<false>();
}
bool ParseJsonString(Handle<String> expected); bool ParseJsonString(Handle<String> expected);
Handle<String> ParseJsonInternalizedString() { Handle<String> ParseJsonString() {
Handle<String> result = ScanJsonString<true>(); Handle<String> result = ScanJsonString();
if (result.is_null()) return result; if (result.is_null()) return result;
return factory()->InternalizeString(result); return factory()->InternalizeString(result);
} }
template <bool is_internalized>
Handle<String> ScanJsonString(); Handle<String> ScanJsonString();
// Creates a new string and copies prefix[start..end] into the beginning // Creates a new string and copies prefix[start..end] into the beginning
// of it. Then scans the rest of the string, adding characters after the // of it. Then scans the rest of the string, adding characters after the
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment