| Index: src/json-parser.h | 
| diff --git a/src/json-parser.h b/src/json-parser.h | 
| index 1a9a36f283513bab2f3b72d2d6e5a78c6d0d2de8..39d9c38b44c7e8a7775b21fd1da581409c912ed0 100644 | 
| --- a/src/json-parser.h | 
| +++ b/src/json-parser.h | 
| @@ -16,6 +16,9 @@ | 
| namespace v8 { | 
| namespace internal { | 
|  | 
| +enum ParseElementResult { kElementFound, kElementNotFound, kNullHandle }; | 
| + | 
| + | 
| // A simple json parser. | 
| template <bool seq_one_byte> | 
| class JsonParser BASE_EMBEDDED { | 
| @@ -155,6 +158,10 @@ class JsonParser BASE_EMBEDDED { | 
| // JavaScript array. | 
| Handle<Object> ParseJsonObject(); | 
|  | 
| +  // Helper for ParseJsonObject. Parses the form "123": obj, which is recorded | 
| +  // as an element, not a property. | 
| +  ParseElementResult ParseElement(Handle<JSObject> json_object); | 
| + | 
| // Parses a JSON array literal (grammar production JSONArray). An array | 
| // literal is a square-bracketed and comma separated sequence (possibly empty) | 
| // of JSON values. | 
| @@ -299,6 +306,41 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonValue() { | 
| } | 
|  | 
|  | 
| +template <bool seq_one_byte> | 
| +ParseElementResult JsonParser<seq_one_byte>::ParseElement( | 
| +    Handle<JSObject> json_object) { | 
| +  uint32_t index = 0; | 
| +  // Maybe an array index, try to parse it. | 
| +  if (c0_ == '0') { | 
| +    // With a leading zero, the string has to be "0" only to be an index. | 
| +    Advance(); | 
| +  } else { | 
| +    do { | 
| +      int d = c0_ - '0'; | 
| +      if (index > 429496729U - ((d > 5) ? 1 : 0)) break; | 
| +      index = (index * 10) + d; | 
| +      Advance(); | 
| +    } while (IsDecimalDigit(c0_)); | 
| +  } | 
| + | 
| +  if (c0_ == '"') { | 
| +    // Successfully parsed index, parse and store element. | 
| +    AdvanceSkipWhitespace(); | 
| + | 
| +    if (c0_ == ':') { | 
| +      AdvanceSkipWhitespace(); | 
| +      Handle<Object> value = ParseJsonValue(); | 
| +      if (!value.is_null()) { | 
| +        JSObject::SetOwnElement(json_object, index, value, SLOPPY).Assert(); | 
| +        return kElementFound; | 
| +      } else { | 
| +        return kNullHandle; | 
| +      } | 
| +    } | 
| +  } | 
| +  return kElementNotFound; | 
| +} | 
| + | 
| // Parse a JSON object. Position must be right at '{'. | 
| template <bool seq_one_byte> | 
| Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() { | 
| @@ -320,35 +362,12 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() { | 
| int start_position = position_; | 
| Advance(); | 
|  | 
| -      uint32_t index = 0; | 
| if (IsDecimalDigit(c0_)) { | 
| -        // Maybe an array index, try to parse it. | 
| -        if (c0_ == '0') { | 
| -          // With a leading zero, the string has to be "0" only to be an index. | 
| -          Advance(); | 
| -        } else { | 
| -          do { | 
| -            int d = c0_ - '0'; | 
| -            if (index > 429496729U - ((d > 5) ? 1 : 0)) break; | 
| -            index = (index * 10) + d; | 
| -            Advance(); | 
| -          } while (IsDecimalDigit(c0_)); | 
| -        } | 
| - | 
| -        if (c0_ == '"') { | 
| -          // Successfully parsed index, parse and store element. | 
| -          AdvanceSkipWhitespace(); | 
| - | 
| -          if (c0_ != ':') return ReportUnexpectedCharacter(); | 
| -          AdvanceSkipWhitespace(); | 
| -          Handle<Object> value = ParseJsonValue(); | 
| -          if (value.is_null()) return ReportUnexpectedCharacter(); | 
| - | 
| -          JSObject::SetOwnElement(json_object, index, value, SLOPPY).Assert(); | 
| -          continue; | 
| -        } | 
| -        // Not an index, fallback to the slow path. | 
| +        ParseElementResult element_result = ParseElement(json_object); | 
| +        if (element_result == kNullHandle) return Handle<Object>::null(); | 
| +        if (element_result == kElementFound) continue; | 
| } | 
| +      // Not an index, fallback to the slow path. | 
|  | 
| position_ = start_position; | 
| #ifdef DEBUG | 
| @@ -360,81 +379,109 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() { | 
|  | 
| // Try to follow existing transitions as long as possible. Once we stop | 
| // transitioning, no transition can be found anymore. | 
| +      DCHECK(transitioning); | 
| +      // First check whether there is a single expected transition. If so, try | 
| +      // to parse it first. | 
| +      bool follow_expected = false; | 
| +      Handle<Map> target; | 
| +      if (seq_one_byte) { | 
| +        key = TransitionArray::ExpectedTransitionKey(map); | 
| +        follow_expected = !key.is_null() && ParseJsonString(key); | 
| +      } | 
| +      // If the expected transition hits, follow it. | 
| +      if (follow_expected) { | 
| +        target = TransitionArray::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(); | 
| + | 
| +        target = TransitionArray::FindTransitionToField(map, key); | 
| +        // If a transition was found, follow it and continue. | 
| +        transitioning = !target.is_null(); | 
| +      } | 
| +      if (c0_ != ':') return ReportUnexpectedCharacter(); | 
| + | 
| +      AdvanceSkipWhitespace(); | 
| +      value = ParseJsonValue(); | 
| +      if (value.is_null()) return ReportUnexpectedCharacter(); | 
| + | 
| if (transitioning) { | 
| -        // First check whether there is a single expected transition. If so, try | 
| -        // to parse it first. | 
| -        bool follow_expected = false; | 
| -        Handle<Map> target; | 
| -        if (seq_one_byte) { | 
| -          key = TransitionArray::ExpectedTransitionKey(map); | 
| -          follow_expected = !key.is_null() && ParseJsonString(key); | 
| -        } | 
| -        // If the expected transition hits, follow it. | 
| -        if (follow_expected) { | 
| -          target = TransitionArray::ExpectedTransitionTarget(map); | 
| +        PropertyDetails details = | 
| +            target->instance_descriptors()->GetDetails(descriptor); | 
| +        Representation expected_representation = details.representation(); | 
| + | 
| +        if (value->FitsRepresentation(expected_representation)) { | 
| +          if (expected_representation.IsHeapObject() && | 
| +              !target->instance_descriptors() | 
| +                   ->GetFieldType(descriptor) | 
| +                   ->NowContains(value)) { | 
| +            Handle<HeapType> value_type( | 
| +                value->OptimalType(isolate(), expected_representation)); | 
| +            Map::GeneralizeFieldType(target, descriptor, | 
| +                                     expected_representation, value_type); | 
| +          } | 
| +          DCHECK(target->instance_descriptors() | 
| +                     ->GetFieldType(descriptor) | 
| +                     ->NowContains(value)); | 
| +          properties.Add(value, zone()); | 
| +          map = target; | 
| +          descriptor++; | 
| +          continue; | 
| } 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(); | 
| - | 
| -          target = TransitionArray::FindTransitionToField(map, key); | 
| -          // If a transition was found, follow it and continue. | 
| -          transitioning = !target.is_null(); | 
| +          transitioning = false; | 
| } | 
| -        if (c0_ != ':') return ReportUnexpectedCharacter(); | 
| +      } | 
|  | 
| -        AdvanceSkipWhitespace(); | 
| -        value = ParseJsonValue(); | 
| -        if (value.is_null()) return ReportUnexpectedCharacter(); | 
| +      DCHECK(!transitioning); | 
|  | 
| -        if (transitioning) { | 
| -          PropertyDetails details = | 
| -              target->instance_descriptors()->GetDetails(descriptor); | 
| -          Representation expected_representation = details.representation(); | 
| +      // Commit the intermediate state to the object and stop transitioning. | 
| +      CommitStateToJsonObject(json_object, map, &properties); | 
|  | 
| -          if (value->FitsRepresentation(expected_representation)) { | 
| -            if (expected_representation.IsHeapObject() && | 
| -                !target->instance_descriptors() | 
| -                     ->GetFieldType(descriptor) | 
| -                     ->NowContains(value)) { | 
| -              Handle<HeapType> value_type(value->OptimalType( | 
| -                      isolate(), expected_representation)); | 
| -              Map::GeneralizeFieldType(target, descriptor, | 
| -                                       expected_representation, value_type); | 
| -            } | 
| -            DCHECK(target->instance_descriptors()->GetFieldType( | 
| -                    descriptor)->NowContains(value)); | 
| -            properties.Add(value, zone()); | 
| -            map = target; | 
| -            descriptor++; | 
| -            continue; | 
| -          } else { | 
| -            transitioning = false; | 
| -          } | 
| +      Runtime::DefineObjectProperty(json_object, key, value, NONE).Check(); | 
| +    } while (transitioning && MatchSkipWhiteSpace(',')); | 
| + | 
| +    // If we transitioned until the very end, transition the map now. | 
| +    if (transitioning) { | 
| +      CommitStateToJsonObject(json_object, map, &properties); | 
| +    } else { | 
| +      while (MatchSkipWhiteSpace(',')) { | 
| +        HandleScope local_scope(isolate()); | 
| +        if (c0_ != '"') return ReportUnexpectedCharacter(); | 
| + | 
| +        int start_position = position_; | 
| +        Advance(); | 
| + | 
| +        if (IsDecimalDigit(c0_)) { | 
| +          ParseElementResult element_result = ParseElement(json_object); | 
| +          if (element_result == kNullHandle) return Handle<Object>::null(); | 
| +          if (element_result == kElementFound) continue; | 
| } | 
| +        // Not an index, fallback to the slow path. | 
| + | 
| +        position_ = start_position; | 
| +#ifdef DEBUG | 
| +        c0_ = '"'; | 
| +#endif | 
| + | 
| +        Handle<String> key; | 
| +        Handle<Object> value; | 
|  | 
| -        // Commit the intermediate state to the object and stop transitioning. | 
| -        CommitStateToJsonObject(json_object, map, &properties); | 
| -      } else { | 
| key = ParseJsonInternalizedString(); | 
| if (key.is_null() || c0_ != ':') return ReportUnexpectedCharacter(); | 
|  | 
| AdvanceSkipWhitespace(); | 
| value = ParseJsonValue(); | 
| if (value.is_null()) return ReportUnexpectedCharacter(); | 
| + | 
| +        Runtime::DefineObjectProperty(json_object, key, value, NONE).Check(); | 
| } | 
| +    } | 
|  | 
| -      Runtime::DefineObjectProperty(json_object, key, value, NONE).Check(); | 
| -    } while (MatchSkipWhiteSpace(',')); | 
| if (c0_ != '}') { | 
| return ReportUnexpectedCharacter(); | 
| } | 
| - | 
| -    // If we transitioned until the very end, transition the map now. | 
| -    if (transitioning) { | 
| -      CommitStateToJsonObject(json_object, map, &properties); | 
| -    } | 
| } | 
| AdvanceSkipWhitespace(); | 
| return scope.CloseAndEscape(json_object); | 
|  |