Add fast path for FastProperty objects in JSON.stringify.
authoryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 5 Nov 2012 12:59:35 +0000 (12:59 +0000)
committeryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 5 Nov 2012 12:59:35 +0000 (12:59 +0000)
R=verwaest@chromium.org
BUG=

Review URL: https://chromiumcodereview.appspot.com/11363078

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12853 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/json-stringifier.h
test/mjsunit/harmony/proxies-json.js
test/mjsunit/json2.js

index 728575b..f083ff4 100644 (file)
@@ -560,36 +560,68 @@ BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSObject(
                  JSObject::cast(object->GetPrototype()), isolate_);
     ASSERT(object->IsGlobalObject());
   }
-  bool has_exception = false;
-  Handle<FixedArray> contents =
-      GetKeysInFixedArrayFor(object, LOCAL_ONLY, &has_exception);
-  if (has_exception) return EXCEPTION;
+
   Append('{');
   bool comma = false;
-  for (int i = 0; i < contents->length(); i++) {
-    Object* key = contents->get(i);
-    Handle<String> key_handle;
-    Handle<Object> property;
-    if (key->IsString()) {
-      key_handle = Handle<String>(String::cast(key), isolate_);
-      property = GetProperty(object, key_handle);
-    } else {
-      ASSERT(key->IsNumber());
-      key_handle = factory_->NumberToString(Handle<Object>(key, isolate_));
-      uint32_t index;
-      if (key->IsSmi()) {
-        property = Object::GetElement(object, Smi::cast(key)->value());
-      } else if (key_handle->AsArrayIndex(&index)) {
-        property = Object::GetElement(object, index);
+
+  if (object->HasFastProperties() &&
+      !object->HasIndexedInterceptor() &&
+      !object->HasNamedInterceptor() &&
+      object->elements() == isolate_->heap()->empty_fixed_array()) {
+    Handle<DescriptorArray> descs(
+        object->map()->instance_descriptors(), isolate_);
+    int num_desc = object->map()->NumberOfOwnDescriptors();
+    Handle<Map> map(object->map());
+    bool map_changed = false;
+    for (int i = 0; i < num_desc; i++) {
+      Handle<String> key(descs->GetKey(i), isolate_);
+      PropertyDetails details = descs->GetDetails(i);
+      if (details.IsDontEnum() || details.IsDeleted()) continue;
+      Handle<Object> property;
+      if (details.type() == FIELD && !map_changed) {
+        property = Handle<Object>(
+            object->FastPropertyAt(descs->GetFieldIndex(i)), isolate_);
       } else {
+        property = GetProperty(object, key);
+      }
+      if (property.is_null()) return EXCEPTION;
+      Result result = SerializeProperty(property, comma, key);
+      if (!comma && result == SUCCESS) comma = true;
+      if (result >= EXCEPTION) return result;
+      if (*map != object->map()) map_changed = true;
+    }
+  } else {
+    bool has_exception = false;
+    Handle<FixedArray> contents =
+        GetKeysInFixedArrayFor(object, LOCAL_ONLY, &has_exception);
+    if (has_exception) return EXCEPTION;
+
+    for (int i = 0; i < contents->length(); i++) {
+      Object* key = contents->get(i);
+      Handle<String> key_handle;
+      Handle<Object> property;
+      if (key->IsString()) {
+        key_handle = Handle<String>(String::cast(key), isolate_);
         property = GetProperty(object, key_handle);
+      } else {
+        ASSERT(key->IsNumber());
+        key_handle = factory_->NumberToString(Handle<Object>(key, isolate_));
+        uint32_t index;
+        if (key->IsSmi()) {
+          property = Object::GetElement(object, Smi::cast(key)->value());
+        } else if (key_handle->AsArrayIndex(&index)) {
+          property = Object::GetElement(object, index);
+        } else {
+          property = GetProperty(object, key_handle);
+        }
       }
+      if (property.is_null()) return EXCEPTION;
+      Result result = SerializeProperty(property, comma, key_handle);
+      if (!comma && result == SUCCESS) comma = true;
+      if (result >= EXCEPTION) return result;
     }
-    if (property.is_null()) return EXCEPTION;
-    Result result = SerializeProperty(property, comma, key_handle);
-    if (!comma && result == SUCCESS) comma = true;
-    if (result >= EXCEPTION) return result;
   }
+
   Append('}');
   StackPop();
   current_part_ = handle_scope.CloseAndEscape(current_part_);
index 0a5be65..539c5a8 100644 (file)
@@ -154,3 +154,25 @@ var proxy6 = Proxy.create(handler6);
 testStringify('[1,null,true]', [1, proxy6, true]);
 testStringify('{"a":1,"c":true}', {a: 1, b: proxy6, c: true});
 
+// Object containing a proxy that changes the parent's properties.
+var handler7 = {
+  get: function(target, name) {
+    delete parent7.a;
+    delete parent7.c;
+    parent7.e = "5";
+    return name.toUpperCase();
+  },
+  enumerate: function(target) {
+    return ['a', 'b', 'c'];
+  },
+  getOwnPropertyDescriptor: function(target, name) {
+    return { enumerable: true };
+  }
+}
+
+var proxy7 = Proxy.create(handler7);
+var parent7 = { a: "1", b: proxy7, c: "3", d: "4" };
+assertEquals('{"a":"1","b":{"a":"A","b":"B","c":"C"},"d":"4"}',
+             JSON.stringify(parent7));
+assertEquals('{"b":{"a":"A","b":"B","c":"C"},"d":"4","e":"5"}',
+             JSON.stringify(parent7));
index 82ff572..4c0b8f5 100644 (file)
@@ -133,3 +133,21 @@ fast_obj.__proto__ = [7, 7, 7, 7];
 delete fast_obj[2];
 assertTrue(%HasFastObjectElements(fast_obj));
 assertEquals("[1,2,7,{}]", JSON.stringify(fast_obj));
+
+var getter_side_effect = { a: 1,
+                           get b() {
+                             delete this.a;
+                             delete this.c;
+                             this.e = 5;
+                             return 2;
+                           },
+                           c: 3,
+                           d: 4 };
+assertEquals('{"a":1,"b":2,"d":4}', JSON.stringify(getter_side_effect));
+assertEquals('{"b":2,"d":4,"e":5}', JSON.stringify(getter_side_effect));
+
+var non_enum = {};
+non_enum.a = 1;
+Object.defineProperty(non_enum, "b", { value: 2, enumerable: false });
+non_enum.c = 3;
+assertEquals('{"a":1,"c":3}', JSON.stringify(non_enum));