Chromium Code Reviews| Index: src/objects.cc |
| diff --git a/src/objects.cc b/src/objects.cc |
| index 1399e33ffab4acb74f42abd63ad646747b9b61cc..ddf02ff3ed7ef4eeab93c7d0ce43bf3afd08a789 100644 |
| --- a/src/objects.cc |
| +++ b/src/objects.cc |
| @@ -5583,7 +5583,56 @@ 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, this); |
| + } |
| + |
| + // Returns true if the visitor is a copying visitor. |
| + virtual bool is_copying() = 0; |
| + |
| + protected: |
| + Handle<JSObject> StructureWalk(Handle<JSObject> object, |
| + JSObjectWalkVisitor* visitor); |
| + |
| + // 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, this); |
|
Yang
2013/09/30 09:37:25
Why do you need to pass 'this' explicitly? The cop
mvstanton
2013/09/30 11:35:51
thx for that, first StructureWalk was a static fun
|
| + } |
| +}; |
| + |
| + |
| +Handle<JSObject> JSObjectWalkVisitor::StructureWalk( |
| + Handle<JSObject> object, |
| + JSObjectWalkVisitor* visitor) { |
| + bool is_copying = visitor->is_copying(); |
| Isolate* isolate = object->GetIsolate(); |
| StackLimitCheck check(isolate); |
| if (check.HasOverflowed()) { |
| @@ -5592,10 +5641,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 = visitor->VisitObject(object); |
| + ASSERT(visitor->is_copying() || copy.is_identical_to(object)); |
| HandleScope scope(isolate); |
| @@ -5609,13 +5659,16 @@ 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 = visitor->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 (is_copying) { |
| + copy->FastPropertyAtPut(index, *value); |
| + } |
| } |
| } else { |
| Handle<FixedArray> names = |
| @@ -5634,11 +5687,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 = visitor->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 (is_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 +5722,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 = visitor->VisitElementOrProperty( |
| + copy, Handle<JSObject>::cast(value)); |
| RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<JSObject>()); |
| - elements->set(i, *result); |
| + if (is_copying) { |
| + elements->set(i, *result); |
| + } |
| } |
| } |
| } |
| @@ -5683,9 +5742,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 = visitor->VisitElementOrProperty( |
| + copy, Handle<JSObject>::cast(value)); |
| RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<JSObject>()); |
| - element_dictionary->ValueAtPut(i, *result); |
| + if (is_copying) { |
| + element_dictionary->ValueAtPut(i, *result); |
| + } |
| } |
| } |
| } |
| @@ -5712,6 +5774,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). |