Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index 1399e33ffab4acb74f42abd63ad646747b9b61cc..6ca8bdf4fd0bba1f18df887d5f7798eb5ea577d8 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -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). |