Revision: 14191
Author:   [email protected]
Date:     Tue Apr  9 09:49:28 2013
Log:      Eagerly parse expected transitions in JSON.

Review URL: https://chromiumcodereview.appspot.com/13741010
http://code.google.com/p/v8/source/detail?r=14191

Modified:
 /branches/bleeding_edge/src/json-parser.h
 /branches/bleeding_edge/src/objects-inl.h
 /branches/bleeding_edge/src/objects.cc
 /branches/bleeding_edge/src/objects.h

=======================================
--- /branches/bleeding_edge/src/json-parser.h   Thu Mar 28 04:19:38 2013
+++ /branches/bleeding_edge/src/json-parser.h   Tue Apr  9 09:49:28 2013
@@ -102,9 +102,37 @@
   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 @@
   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 @@
       c0_ = '"';
 #endif

-      Handle<String> key = ParseJsonInternalizedString();
-      if (key.is_null() || c0_ != ':') return ReportUnexpectedCharacter();
+      Handle<String> key;
+      Handle<Object> value;

-      AdvanceSkipWhitespace();
-      Handle<Object> value = ParseJsonValue();
-      if (value.is_null()) return ReportUnexpectedCharacter();
+ // 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();

-      if (JSObject::TryTransitionToField(json_object, key)) {
-        int index = json_object->LastAddedFieldIndex();
-        json_object->FastPropertyAtPut(index, *value);
+          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();
+        value = ParseJsonValue();
+        if (value.is_null()) return ReportUnexpectedCharacter();
+
+        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 @@
     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 @@
     }
   } 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();
=======================================
--- /branches/bleeding_edge/src/objects-inl.h   Wed Apr  3 10:06:22 2013
+++ /branches/bleeding_edge/src/objects-inl.h   Tue Apr  9 09:49:28 2013
@@ -1488,22 +1488,59 @@
 }


-bool JSObject::TryTransitionToField(Handle<JSObject> object,
-                                    Handle<Name> key) {
-  if (!object->map()->HasTransitionArray()) return false;
-  Handle<Map> target;
-  {
-    AssertNoAllocation no_allocation;
-    TransitionArray* transitions = object->map()->transitions();
-    int transition = transitions->Search(*key);
-    if (transition == TransitionArray::kNotFound) return false;
- PropertyDetails target_details = transitions->GetTargetDetails(transition);
-    if (target_details.type() != FIELD) return false;
-    if (target_details.attributes() != NONE) return false;
-    target = Handle<Map>(transitions->GetTarget(transition));
+MaybeObject* JSObject::TransitionToMap(Map* map) {
+  ASSERT(this->map()->inobject_properties() == map->inobject_properties());
+  ElementsKind expected_kind = this->map()->elements_kind();
+  if (map->elements_kind() != expected_kind) {
+    MaybeObject* maybe_map = map->AsElementsKind(expected_kind);
+    if (!maybe_map->To(&map)) return maybe_map;
   }
-  JSObject::AddFastPropertyUsingMap(object, target);
-  return true;
+  int total_size =
+      map->NumberOfOwnDescriptors() + map->unused_property_fields();
+  int out_of_object = total_size - map->inobject_properties();
+  if (out_of_object != properties()->length()) {
+    FixedArray* new_properties;
+    MaybeObject* maybe_properties = properties()->CopySize(out_of_object);
+    if (!maybe_properties->To(&new_properties)) return maybe_properties;
+    set_properties(new_properties);
+  }
+  set_map(map);
+  return this;
+}
+
+
+Handle<String> JSObject::ExpectedTransitionKey(Handle<Map> map) {
+  AssertNoAllocation no_gc;
+  if (!map->HasTransitionArray()) return Handle<String>::null();
+  TransitionArray* transitions = map->transitions();
+  if (!transitions->IsSimpleTransition()) return Handle<String>::null();
+  int transition = TransitionArray::kSimpleTransitionIndex;
+  PropertyDetails details = transitions->GetTargetDetails(transition);
+  Name* name = transitions->GetKey(transition);
+  if (details.type() != FIELD) return Handle<String>::null();
+  if (details.attributes() != NONE) return Handle<String>::null();
+  if (!name->IsString()) return Handle<String>::null();
+  return Handle<String>(String::cast(name));
+}
+
+
+Handle<Map> JSObject::ExpectedTransitionTarget(Handle<Map> map) {
+  ASSERT(!ExpectedTransitionKey(map).is_null());
+  return Handle<Map>(map->transitions()->GetTarget(
+      TransitionArray::kSimpleTransitionIndex));
+}
+
+
+Handle<Map> JSObject::FindTransitionToField(Handle<Map> map, Handle<Name> key) {
+  AssertNoAllocation no_allocation;
+  if (!map->HasTransitionArray()) return Handle<Map>::null();
+  TransitionArray* transitions = map->transitions();
+  int transition = transitions->Search(*key);
+  if (transition == TransitionArray::kNotFound) return Handle<Map>::null();
+ PropertyDetails target_details = transitions->GetTargetDetails(transition);
+  if (target_details.type() != FIELD) return Handle<Map>::null();
+  if (target_details.attributes() != NONE) return Handle<Map>::null();
+  return Handle<Map>(transitions->GetTarget(transition));
 }


=======================================
--- /branches/bleeding_edge/src/objects.cc      Thu Apr  4 12:12:59 2013
+++ /branches/bleeding_edge/src/objects.cc      Tue Apr  9 09:49:28 2013
@@ -2602,13 +2602,18 @@
     return start_map->CopyAsElementsKind(to_kind, OMIT_TRANSITION);
   }

-  Map* closest_map = FindClosestElementsTransition(start_map, to_kind);
+  return start_map->AsElementsKind(to_kind);
+}

-  if (closest_map->elements_kind() == to_kind) {
+
+MaybeObject* Map::AsElementsKind(ElementsKind kind) {
+  Map* closest_map = FindClosestElementsTransition(this, kind);
+
+  if (closest_map->elements_kind() == kind) {
     return closest_map;
   }

-  return AddMissingElementsTransitions(closest_map, to_kind);
+  return AddMissingElementsTransitions(closest_map, kind);
 }


@@ -3071,6 +3076,13 @@
       object->GetIsolate(),
       object->AddFastPropertyUsingMap(*map));
 }
+
+
+void JSObject::TransitionToMap(Handle<JSObject> object, Handle<Map> map) {
+  CALL_HEAP_FUNCTION_VOID(
+      object->GetIsolate(),
+      object->TransitionToMap(*map));
+}


 MaybeObject* JSObject::SetPropertyForResult(LookupResult* lookup,
=======================================
--- /branches/bleeding_edge/src/objects.h       Tue Apr  9 01:42:57 2013
+++ /branches/bleeding_edge/src/objects.h       Tue Apr  9 09:49:28 2013
@@ -1770,10 +1770,13 @@
       Handle<Object> value,
       PropertyAttributes attributes);

+  static inline Handle<String> ExpectedTransitionKey(Handle<Map> map);
+  static inline Handle<Map> ExpectedTransitionTarget(Handle<Map> map);
+
// Try to follow an existing transition to a field with attributes NONE. The
   // return value indicates whether the transition was successful.
-  static inline bool TryTransitionToField(Handle<JSObject> object,
-                                          Handle<Name> key);
+  static inline Handle<Map> FindTransitionToField(Handle<Map> map,
+                                                  Handle<Name> key);

   inline int LastAddedFieldIndex();

@@ -1781,6 +1784,8 @@
   // passed map. This also extends the property backing store if necessary.
static void AddFastPropertyUsingMap(Handle<JSObject> object, Handle<Map> map);
   inline MUST_USE_RESULT MaybeObject* AddFastPropertyUsingMap(Map* map);
+  static void TransitionToMap(Handle<JSObject> object, Handle<Map> map);
+  inline MUST_USE_RESULT MaybeObject* TransitionToMap(Map* map);

   // Can cause GC.
   MUST_USE_RESULT MaybeObject* SetLocalPropertyIgnoreAttributes(
@@ -5244,6 +5249,7 @@
       Descriptor* descriptor,
       int index,
       TransitionFlag flag);
+  MUST_USE_RESULT MaybeObject* AsElementsKind(ElementsKind kind);
   MUST_USE_RESULT MaybeObject* CopyAsElementsKind(ElementsKind kind,
                                                   TransitionFlag flag);

--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to