Use a walking visitor to traverse JSObject structure. The purpose is to prepare for...
authormvstanton@chromium.org <mvstanton@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 30 Sep 2013 11:36:50 +0000 (11:36 +0000)
committermvstanton@chromium.org <mvstanton@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 30 Sep 2013 11:36:50 +0000 (11:36 +0000)
BUG=
R=yangguo@chromium.org

Review URL: https://codereview.chromium.org/25025002

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

src/objects.cc
test/mjsunit/big-array-literal.js
test/mjsunit/big-object-literal.js

index 1399e33..6ca8bdf 100644 (file)
@@ -5583,7 +5583,53 @@ Handle<JSObject> JSObject::Copy(Handle<JSObject> object) {
 }
 
 
-Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object) {
+class JSObjectWalkVisitor {
+ public:
+  explicit JSObjectWalkVisitor() {}
+  virtual ~JSObjectWalkVisitor() {}
+
+  Handle<JSObject> Visit(Handle<JSObject> object) {
+    return StructureWalk(object);
+  }
+
+  // Returns true if the visitor is a copying visitor.
+  virtual bool is_copying() = 0;
+
+ protected:
+  Handle<JSObject> StructureWalk(Handle<JSObject> object);
+
+  // The returned handle should point to a new object if the visitor is a
+  // copying visitor, otherwise it should be the same as the input object.
+  virtual Handle<JSObject> VisitObject(Handle<JSObject> object) = 0;
+
+  // The returned handle should point to a new value if the visitor is a
+  // copying visitor, otherwise it should be the same as the input value.
+  virtual Handle<JSObject> VisitElementOrProperty(Handle<JSObject> object,
+                                                  Handle<JSObject> value) = 0;
+};
+
+
+class JSObjectCopyVisitor: public JSObjectWalkVisitor {
+ public:
+  explicit JSObjectCopyVisitor() {}
+
+  virtual bool is_copying() V8_OVERRIDE { return true; }
+
+ protected:
+  virtual Handle<JSObject> VisitObject(Handle<JSObject> object) V8_OVERRIDE {
+    return JSObject::Copy(object);
+  }
+
+  virtual Handle<JSObject> VisitElementOrProperty(
+      Handle<JSObject> object,
+      Handle<JSObject> value) V8_OVERRIDE {
+    return StructureWalk(value);
+  }
+};
+
+
+Handle<JSObject> JSObjectWalkVisitor::StructureWalk(Handle<JSObject> object) {
+  bool copying = is_copying();
   Isolate* isolate = object->GetIsolate();
   StackLimitCheck check(isolate);
   if (check.HasOverflowed()) {
@@ -5592,10 +5638,11 @@ Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object) {
   }
 
   if (object->map()->is_deprecated()) {
-    MigrateInstance(object);
+    JSObject::MigrateInstance(object);
   }
 
-  Handle<JSObject> copy = Copy(object);
+  Handle<JSObject> copy = VisitObject(object);
+  ASSERT(copying || copy.is_identical_to(object));
 
   HandleScope scope(isolate);
 
@@ -5609,13 +5656,15 @@ Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object) {
       int index = descriptors->GetFieldIndex(i);
       Handle<Object> value(object->RawFastPropertyAt(index), isolate);
       if (value->IsJSObject()) {
-        value = DeepCopy(Handle<JSObject>::cast(value));
+        value = VisitElementOrProperty(copy, Handle<JSObject>::cast(value));
         RETURN_IF_EMPTY_HANDLE_VALUE(isolate, value, Handle<JSObject>());
       } else {
         Representation representation = details.representation();
         value = NewStorageFor(isolate, value, representation);
       }
-      copy->FastPropertyAtPut(index, *value);
+      if (copying) {
+        copy->FastPropertyAtPut(index, *value);
+      }
     }
   } else {
     Handle<FixedArray> names =
@@ -5634,11 +5683,14 @@ Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object) {
           copy->GetProperty(*key_string, &attributes)->ToObjectUnchecked(),
           isolate);
       if (value->IsJSObject()) {
-        Handle<Object> result = DeepCopy(Handle<JSObject>::cast(value));
+        Handle<JSObject> result = VisitElementOrProperty(
+            copy, Handle<JSObject>::cast(value));
         RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<JSObject>());
-        // Creating object copy for literals. No strict mode needed.
-        CHECK_NOT_EMPTY_HANDLE(isolate, SetProperty(
-            copy, key_string, result, NONE, kNonStrictMode));
+        if (copying) {
+          // Creating object copy for literals. No strict mode needed.
+          CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetProperty(
+              copy, key_string, result, NONE, kNonStrictMode));
+        }
       }
     }
   }
@@ -5666,9 +5718,12 @@ Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object) {
                  value->IsTheHole() ||
                  (IsFastObjectElementsKind(copy->GetElementsKind())));
           if (value->IsJSObject()) {
-            Handle<Object> result = DeepCopy(Handle<JSObject>::cast(value));
+            Handle<JSObject> result = VisitElementOrProperty(
+                copy, Handle<JSObject>::cast(value));
             RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<JSObject>());
-            elements->set(i, *result);
+            if (copying) {
+              elements->set(i, *result);
+            }
           }
         }
       }
@@ -5683,9 +5738,12 @@ Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object) {
         if (element_dictionary->IsKey(k)) {
           Handle<Object> value(element_dictionary->ValueAt(i), isolate);
           if (value->IsJSObject()) {
-            Handle<Object> result = DeepCopy(Handle<JSObject>::cast(value));
+            Handle<JSObject> result = VisitElementOrProperty(
+                copy, Handle<JSObject>::cast(value));
             RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<JSObject>());
-            element_dictionary->ValueAtPut(i, *result);
+            if (copying) {
+              element_dictionary->ValueAtPut(i, *result);
+            }
           }
         }
       }
@@ -5712,6 +5770,14 @@ Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object) {
 }
 
 
+Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object) {
+  JSObjectCopyVisitor v;
+  Handle<JSObject> copy = v.Visit(object);
+  ASSERT(v.is_copying() && !copy.is_identical_to(object));
+  return copy;
+}
+
+
 // Tests for the fast common case for property enumeration:
 // - This object and all prototypes has an enum cache (which means that
 //   it is no proxy, has no interceptors and needs no access checks).
index 9f06179..13f91f8 100644 (file)
@@ -92,16 +92,25 @@ for (var i = 0; i < sizes.length; i++) {
   testLiteral(sizes[i], true);
 }
 
+
+function checkExpectedException(e) {
+  assertInstanceof(e, RangeError);
+  assertTrue(e.message.indexOf("Maximum call stack size exceeded") >= 0);
+}
+
+
 function testLiteralAndCatch(size) {
   var big_enough = false;
   try {
     testLiteral(size, false);
   } catch (e) {
+    checkExpectedException(e);
     big_enough = true;
   }
   try {
     testLiteral(size, true);
   } catch (e) {
+    checkExpectedException(e);
     big_enough = true;
   }
   return big_enough;
index c937f54..92c6ab7 100644 (file)
@@ -92,16 +92,25 @@ for (var i = 0; i < sizes.length; i++) {
   testLiteral(sizes[i], true);
 }
 
+
+function checkExpectedException(e) {
+  assertInstanceof(e, RangeError);
+  assertTrue(e.message.indexOf("Maximum call stack size exceeded") >= 0);
+}
+
+
 function testLiteralAndCatch(size) {
   var big_enough = false;
   try {
     testLiteral(size, false);
   } catch (e) {
+    checkExpectedException(e);
     big_enough = true;
   }
   try {
     testLiteral(size, true);
   } catch (e) {
+    checkExpectedException(e);
     big_enough = true;
   }
   return big_enough;