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(); |