[json] More feedback-guided json parsing

Use feedback from adjecent array elements to speed up object creation.

Change-Id: Ib5c1b07cc63afb1a4b0cf194144a0ecd31139cb6
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1612898
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61538}
diff --git a/src/json-parser.cc b/src/json-parser.cc
index e41a097..26e1417 100644
--- a/src/json-parser.cc
+++ b/src/json-parser.cc
@@ -387,10 +387,21 @@
   return ScanJsonString(true);
 }
 
+namespace {
+Handle<Map> ParentOfDescriptorOwner(Isolate* isolate, Handle<Map> maybe_root,
+                                    Handle<Map> source, int descriptor) {
+  if (descriptor == 0) {
+    DCHECK_EQ(0, maybe_root->NumberOfOwnDescriptors());
+    return maybe_root;
+  }
+  return handle(source->FindFieldOwner(isolate, descriptor - 1), isolate);
+}
+}  // namespace
+
 template <typename Char>
 Handle<Object> JsonParser<Char>::BuildJsonObject(
     const JsonContinuation& cont,
-    const std::vector<JsonProperty>& property_stack) {
+    const std::vector<JsonProperty>& property_stack, Handle<Map> feedback) {
   size_t start = cont.index;
   int length = static_cast<int>(property_stack.size() - start);
   int named_length = length - cont.elements;
@@ -435,6 +446,13 @@
     }
   }
 
+  int feedback_descriptors =
+      (feedback.is_null() ||
+       feedback->elements_kind() != map->elements_kind() ||
+       feedback->instance_size() != map->instance_size())
+          ? 0
+          : feedback->NumberOfOwnDescriptors();
+
   int i;
   int descriptor = 0;
   for (i = 0; i < length; i++) {
@@ -442,7 +460,11 @@
     if (property.string.is_index()) continue;
     Handle<String> expected;
     Handle<Map> target;
-    {
+    if (descriptor < feedback_descriptors) {
+      expected = handle(
+          String::cast(feedback->instance_descriptors().GetKey(descriptor)),
+          isolate_);
+    } else {
       DisallowHeapAllocation no_gc;
       TransitionsAccessor transitions(isolate(), *map, &no_gc);
       expected = transitions.ExpectedTransitionKey();
@@ -455,10 +477,18 @@
     }
 
     Handle<String> key = MakeString(property.string, expected);
-    if (!key.is_identical_to(expected) && !TransitionsAccessor(isolate(), map)
-                                               .FindTransitionToField(key)
-                                               .ToHandle(&target)) {
-      break;
+    if (key.is_identical_to(expected)) {
+      if (descriptor < feedback_descriptors) target = feedback;
+    } else {
+      if (descriptor < feedback_descriptors) {
+        map = ParentOfDescriptorOwner(isolate_, map, feedback, descriptor);
+        feedback_descriptors = 0;
+      }
+      if (!TransitionsAccessor(isolate(), map)
+               .FindTransitionToField(key)
+               .ToHandle(&target)) {
+        break;
+      }
     }
 
     Handle<Object> value = property.value;
@@ -469,7 +499,10 @@
     if (!value->FitsRepresentation(expected_representation)) {
       Representation representation = value->OptimalRepresentation();
       representation = representation.generalize(expected_representation);
-      if (!expected_representation.CanBeInPlaceChangedTo(representation)) break;
+      if (!expected_representation.CanBeInPlaceChangedTo(representation)) {
+        map = ParentOfDescriptorOwner(isolate_, map, target, descriptor);
+        break;
+      }
       Handle<FieldType> value_type =
           value->OptimalType(isolate(), representation);
       Map::GeneralizeField(isolate(), target, descriptor, details.constness(),
@@ -497,6 +530,9 @@
   object->set_elements(*elements);
 
   // Fast path: Write all transitioned named properties.
+  if (i == length && descriptor < feedback_descriptors) {
+    map = ParentOfDescriptorOwner(isolate_, map, map, descriptor);
+  }
   descriptor = 0;
   for (int j = 0; j < i; j++) {
     const JsonProperty& property = property_stack[start + j];
@@ -726,7 +762,15 @@
             break;
           }
 
-          value = BuildJsonObject(cont, property_stack);
+          Handle<Map> feedback;
+          if (cont_stack.size() > 0 &&
+              cont_stack.back().type() == JsonContinuation::kArrayElement &&
+              cont_stack.back().index < element_stack.size() &&
+              element_stack.back()->IsJSObject()) {
+            feedback =
+                handle(JSObject::cast(*element_stack.back())->map(), isolate_);
+          }
+          value = BuildJsonObject(cont, property_stack, feedback);
           property_stack.resize(cont.index);
           Expect(JsonToken::RBRACE);
 
diff --git a/src/json-parser.h b/src/json-parser.h
index 0399a91..34ace53 100644
--- a/src/json-parser.h
+++ b/src/json-parser.h
@@ -287,7 +287,7 @@
 
   Handle<Object> BuildJsonObject(
       const JsonContinuation& cont,
-      const std::vector<JsonProperty>& property_stack);
+      const std::vector<JsonProperty>& property_stack, Handle<Map> feedback);
   Handle<Object> BuildJsonArray(
       const JsonContinuation& cont,
       const std::vector<Handle<Object>>& element_stack);