Chromium Code Reviews| Index: src/json-parser.h |
| diff --git a/src/json-parser.h b/src/json-parser.h |
| index ac34c59b23e096c52ac14e13977a55a492629ddf..46d24d8e76c57c6aafe3ad311c1afd63e952c69a 100644 |
| --- a/src/json-parser.h |
| +++ b/src/json-parser.h |
| @@ -102,6 +102,32 @@ class JsonParser BASE_EMBEDDED { |
| Handle<String> ParseJsonString() { |
| return ScanJsonString<false>(); |
| } |
| + |
| + bool ParseJsonString(Handle<String> expected) { |
| + int length = expected->length(); |
| + if (source_->length() - position_ - 1 > length) { |
| + AssertNoAllocation no_gc; |
| + String::FlatContent content = expected->GetFlatContent(); |
| + if (content.IsAscii()) { |
| + ASSERT_EQ('"', c0_); |
| + const uint8_t* input_chars = seq_source_->GetChars() + position_ + 1; |
| + const uint8_t* expected_chars = content.ToOneByteVector().start(); |
| + for (int i = 0; i < length; i++) { |
| + uint8_t c0 = input_chars[i]; |
| + if (c0 != expected_chars[i] || |
| + c0 == '"' || c0 < 0x20 || c0 == '\\') { |
|
Yang
2013/04/09 15:47:00
maybe you also need to check for 0x7f, which is al
Toon Verwaest
2013/04/09 16:47:59
Irrelevant, as discussed offline.
|
| + return false; |
| + } |
| + } |
| + if (input_chars[length] == '"') { |
| + position_ = position_ + length + 1; |
| + AdvanceSkipWhitespace(); |
| + return true; |
| + } |
| + } |
| + } |
| + return false; |
| + } |
|
Yang
2013/04/09 15:47:00
I guess an empty line here would make sense.
Toon Verwaest
2013/04/09 16:47:59
Done.
|
| Handle<String> ParseJsonInternalizedString() { |
| return ScanJsonString<true>(); |
| } |
|
Yang
2013/04/09 15:47:00
empty line here as well.
Toon Verwaest
2013/04/09 16:47:59
Done.
|
| @@ -294,8 +320,13 @@ Handle<Object> JsonParser<seq_ascii>::ParseJsonObject() { |
| HandleScope scope(isolate()); |
| Handle<JSObject> json_object = |
| factory()->NewJSObject(object_constructor(), pretenure_); |
| + Handle<Map> map(json_object->map()); |
| + ZoneScope zone_scope(zone(), DELETE_ON_EXIT); |
| + ZoneList<Handle<Object> > properties(8, zone()); |
|
Yang
2013/04/09 15:47:00
You could reuse one zone list through out the enti
Toon Verwaest
2013/04/09 16:47:59
That's unfortunately not possible since objects ar
|
| ASSERT_EQ(c0_, '{'); |
| + bool transitioning = true; |
| + |
| AdvanceSkipWhitespace(); |
| if (c0_ != '}') { |
| do { |
| @@ -339,24 +370,75 @@ Handle<Object> JsonParser<seq_ascii>::ParseJsonObject() { |
| c0_ = '"'; |
| #endif |
| - Handle<String> key = ParseJsonInternalizedString(); |
| - if (key.is_null() || c0_ != ':') return ReportUnexpectedCharacter(); |
| + Handle<String> key; |
| + Handle<Object> value; |
| + |
| + // Try to follow existing transitions as long as possible. Once we stop |
| + // transitioning, no transition can be found anymore. |
| + if (transitioning) { |
| + // First check whether there is a single expected transition. If so, try |
| + // to parse it first. |
| + bool follow_expected = false; |
| + if (seq_ascii) { |
| + key = JSObject::ExpectedTransitionKey(map); |
| + follow_expected = !key.is_null() && ParseJsonString(key); |
| + } |
| + // If the expected transition hits, follow it. |
| + if (follow_expected) { |
| + map = JSObject::ExpectedTransitionTarget(map); |
| + } else { |
| + // If the expected transition failed, parse an internal string and try |
|
Yang
2013/04/09 15:47:00
"internalized string"
Toon Verwaest
2013/04/09 16:47:59
Done.
|
| + // to find a matching transition. |
| + key = ParseJsonInternalizedString(); |
| + if (key.is_null()) return ReportUnexpectedCharacter(); |
| + |
| + Handle<Map> target = JSObject::FindTransitionToField(map, key); |
| + // If a transition was found, follow it and continue. |
| + if (!target.is_null()) { |
| + map = target; |
| + } else { |
| + // If no transition was found, commit the intermediate state to the |
| + // object and stop transitioning. |
| + JSObject::TransitionToMap(json_object, map); |
| + int length = properties.length(); |
| + for (int i = 0; i < length; i++) { |
| + json_object->FastPropertyAtPut(i, *properties[i]); |
| + } |
| + transitioning = false; |
| + } |
| + } |
| + if (c0_ != ':') return ReportUnexpectedCharacter(); |
| - AdvanceSkipWhitespace(); |
| - Handle<Object> value = ParseJsonValue(); |
| - if (value.is_null()) return ReportUnexpectedCharacter(); |
| + AdvanceSkipWhitespace(); |
| + value = ParseJsonValue(); |
| + if (value.is_null()) return ReportUnexpectedCharacter(); |
| - if (JSObject::TryTransitionToField(json_object, key)) { |
| - int index = json_object->LastAddedFieldIndex(); |
| - json_object->FastPropertyAtPut(index, *value); |
| + properties.Add(value, zone()); |
| + if (transitioning) continue; |
| } else { |
| - JSObject::SetLocalPropertyIgnoreAttributes( |
| - json_object, key, value, NONE); |
| + key = ParseJsonInternalizedString(); |
| + if (key.is_null() || c0_ != ':') return ReportUnexpectedCharacter(); |
| + |
| + AdvanceSkipWhitespace(); |
| + value = ParseJsonValue(); |
| + if (value.is_null()) return ReportUnexpectedCharacter(); |
| } |
| + |
| + JSObject::SetLocalPropertyIgnoreAttributes( |
| + json_object, key, value, NONE); |
| } while (MatchSkipWhiteSpace(',')); |
| if (c0_ != '}') { |
| return ReportUnexpectedCharacter(); |
| } |
| + |
| + // If we transitioned until the very end, transition the map now. |
| + if (transitioning) { |
| + JSObject::TransitionToMap(json_object, map); |
| + int length = properties.length(); |
| + for (int i = 0; i < length; i++) { |
| + json_object->FastPropertyAtPut(i, *properties[i]); |
| + } |
| + } |
| } |
| AdvanceSkipWhitespace(); |
| return scope.CloseAndEscape(json_object); |
| @@ -644,22 +726,32 @@ Handle<String> JsonParser<seq_ascii>::ScanJsonString() { |
| uint32_t capacity = string_table->Capacity(); |
| uint32_t entry = StringTable::FirstProbe(hash, capacity); |
| uint32_t count = 1; |
| + Handle<String> result; |
| while (true) { |
| Object* element = string_table->KeyAt(entry); |
| if (element == isolate()->heap()->undefined_value()) { |
| // Lookup failure. |
| + result = factory()->InternalizeOneByteString( |
| + seq_source_, position_, length); |
| break; |
| } |
| if (element != isolate()->heap()->the_hole_value() && |
| String::cast(element)->IsOneByteEqualTo(string_vector)) { |
| - // Lookup success, update the current position. |
| - position_ = position; |
| - // Advance past the last '"'. |
| - AdvanceSkipWhitespace(); |
| - return Handle<String>(String::cast(element), isolate()); |
| + result = Handle<String>(String::cast(element), isolate()); |
| +#ifdef DEBUG |
| + uint32_t hash_field = |
| + (hash << String::kHashShift) | String::kIsNotArrayIndexMask; |
| + ASSERT_EQ(static_cast<int>(result->Hash()), |
| + static_cast<int>(hash_field >> String::kHashShift)); |
| +#endif |
| + break; |
| } |
| entry = StringTable::NextProbe(entry, count++, capacity); |
| } |
| + position_ = position; |
| + // Advance past the last '"'. |
| + AdvanceSkipWhitespace(); |
| + return result; |
| } |
| int beg_pos = position_; |
| @@ -682,14 +774,10 @@ Handle<String> JsonParser<seq_ascii>::ScanJsonString() { |
| } |
| } while (c0_ != '"'); |
| int length = position_ - beg_pos; |
| - Handle<String> result; |
| - if (seq_ascii && is_internalized) { |
| - result = factory()->InternalizeOneByteString(seq_source_, beg_pos, length); |
| - } else { |
| - result = factory()->NewRawOneByteString(length, pretenure_); |
| - uint8_t* dest = SeqOneByteString::cast(*result)->GetChars(); |
| - String::WriteToFlat(*source_, dest, beg_pos, position_); |
| - } |
| + Handle<String> result = factory()->NewRawOneByteString(length, pretenure_); |
| + uint8_t* dest = SeqOneByteString::cast(*result)->GetChars(); |
| + String::WriteToFlat(*source_, dest, beg_pos, position_); |
| + |
| ASSERT_EQ('"', c0_); |
| // Advance past the last '"'. |
| AdvanceSkipWhitespace(); |