| Index: src/json-parser.h
|
| diff --git a/src/json-parser.h b/src/json-parser.h
|
| index ac34c59b23e096c52ac14e13977a55a492629ddf..74850cae253aab2cabcdc5a7138052e2cf0c84c5 100644
|
| --- a/src/json-parser.h
|
| +++ b/src/json-parser.h
|
| @@ -102,9 +102,37 @@ 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 == '\\') {
|
| + return false;
|
| + }
|
| + }
|
| + if (input_chars[length] == '"') {
|
| + position_ = position_ + length + 1;
|
| + AdvanceSkipWhitespace();
|
| + return true;
|
| + }
|
| + }
|
| + }
|
| + return false;
|
| + }
|
| +
|
| Handle<String> ParseJsonInternalizedString() {
|
| return ScanJsonString<true>();
|
| }
|
| +
|
| template <bool is_internalized>
|
| Handle<String> ScanJsonString();
|
| // Creates a new string and copies prefix[start..end] into the beginning
|
| @@ -294,8 +322,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());
|
| ASSERT_EQ(c0_, '{');
|
|
|
| + bool transitioning = true;
|
| +
|
| AdvanceSkipWhitespace();
|
| if (c0_ != '}') {
|
| do {
|
| @@ -339,24 +372,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 internalized string and
|
| + // try 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 +728,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 +776,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();
|
|
|