Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index a3163eb619c6d76ff18ab33db93ded19414542c3..f3e7471c07b74a43421ae1c90f110d9374211ec5 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -4689,6 +4689,145 @@ MaybeObject* JSObject::PreventExtensions() { |
} |
+MUST_USE_RESULT MaybeObject* JSObject::DeepCopy(Isolate* isolate) { |
+ StackLimitCheck check(isolate); |
+ if (check.HasOverflowed()) return isolate->StackOverflow(); |
+ |
+ Heap* heap = isolate->heap(); |
+ Object* result; |
+ { MaybeObject* maybe_result = heap->CopyJSObject(this); |
+ if (!maybe_result->ToObject(&result)) return maybe_result; |
+ } |
+ JSObject* copy = JSObject::cast(result); |
+ |
+ // Deep copy local properties. |
+ if (copy->HasFastProperties()) { |
+ FixedArray* properties = copy->properties(); |
+ for (int i = 0; i < properties->length(); i++) { |
+ Object* value = properties->get(i); |
+ if (value->IsJSObject()) { |
+ JSObject* js_object = JSObject::cast(value); |
+ { MaybeObject* maybe_result = js_object->DeepCopy(isolate); |
+ if (!maybe_result->ToObject(&result)) return maybe_result; |
+ } |
+ properties->set(i, result); |
+ } |
+ } |
+ int nof = copy->map()->inobject_properties(); |
+ for (int i = 0; i < nof; i++) { |
+ Object* value = copy->InObjectPropertyAt(i); |
+ if (value->IsJSObject()) { |
+ JSObject* js_object = JSObject::cast(value); |
+ { MaybeObject* maybe_result = js_object->DeepCopy(isolate); |
+ if (!maybe_result->ToObject(&result)) return maybe_result; |
+ } |
+ copy->InObjectPropertyAtPut(i, result); |
+ } |
+ } |
+ } else { |
+ { MaybeObject* maybe_result = |
+ heap->AllocateFixedArray(copy->NumberOfLocalProperties()); |
+ if (!maybe_result->ToObject(&result)) return maybe_result; |
+ } |
+ FixedArray* names = FixedArray::cast(result); |
+ copy->GetLocalPropertyNames(names, 0); |
+ for (int i = 0; i < names->length(); i++) { |
+ ASSERT(names->get(i)->IsString()); |
+ String* key_string = String::cast(names->get(i)); |
+ PropertyAttributes attributes = |
+ copy->GetLocalPropertyAttribute(key_string); |
+ // Only deep copy fields from the object literal expression. |
+ // In particular, don't try to copy the length attribute of |
+ // an array. |
+ if (attributes != NONE) continue; |
+ Object* value = |
+ copy->GetProperty(key_string, &attributes)->ToObjectUnchecked(); |
+ if (value->IsJSObject()) { |
+ JSObject* js_object = JSObject::cast(value); |
+ { MaybeObject* maybe_result = js_object->DeepCopy(isolate); |
+ if (!maybe_result->ToObject(&result)) return maybe_result; |
+ } |
+ { MaybeObject* maybe_result = |
+ // Creating object copy for literals. No strict mode needed. |
+ copy->SetProperty(key_string, result, NONE, kNonStrictMode); |
+ if (!maybe_result->ToObject(&result)) return maybe_result; |
+ } |
+ } |
+ } |
+ } |
+ |
+ // Deep copy local elements. |
+ // Pixel elements cannot be created using an object literal. |
+ ASSERT(!copy->HasExternalArrayElements()); |
+ switch (copy->GetElementsKind()) { |
+ case FAST_SMI_ELEMENTS: |
+ case FAST_ELEMENTS: |
+ case FAST_HOLEY_SMI_ELEMENTS: |
+ case FAST_HOLEY_ELEMENTS: { |
+ FixedArray* elements = FixedArray::cast(copy->elements()); |
+ if (elements->map() == heap->fixed_cow_array_map()) { |
+ isolate->counters()->cow_arrays_created_runtime()->Increment(); |
+#ifdef DEBUG |
+ for (int i = 0; i < elements->length(); i++) { |
+ ASSERT(!elements->get(i)->IsJSObject()); |
+ } |
+#endif |
+ } else { |
+ for (int i = 0; i < elements->length(); i++) { |
+ Object* value = elements->get(i); |
+ ASSERT(value->IsSmi() || |
+ value->IsTheHole() || |
+ (IsFastObjectElementsKind(copy->GetElementsKind()))); |
+ if (value->IsJSObject()) { |
+ JSObject* js_object = JSObject::cast(value); |
+ { MaybeObject* maybe_result = js_object->DeepCopy(isolate); |
+ if (!maybe_result->ToObject(&result)) return maybe_result; |
+ } |
+ elements->set(i, result); |
+ } |
+ } |
+ } |
+ break; |
+ } |
+ case DICTIONARY_ELEMENTS: { |
+ SeededNumberDictionary* element_dictionary = copy->element_dictionary(); |
+ int capacity = element_dictionary->Capacity(); |
+ for (int i = 0; i < capacity; i++) { |
+ Object* k = element_dictionary->KeyAt(i); |
+ if (element_dictionary->IsKey(k)) { |
+ Object* value = element_dictionary->ValueAt(i); |
+ if (value->IsJSObject()) { |
+ JSObject* js_object = JSObject::cast(value); |
+ { MaybeObject* maybe_result = js_object->DeepCopy(isolate); |
+ if (!maybe_result->ToObject(&result)) return maybe_result; |
+ } |
+ element_dictionary->ValueAtPut(i, result); |
+ } |
+ } |
+ } |
+ break; |
+ } |
+ case NON_STRICT_ARGUMENTS_ELEMENTS: |
+ UNIMPLEMENTED(); |
+ break; |
+ case EXTERNAL_PIXEL_ELEMENTS: |
+ case EXTERNAL_BYTE_ELEMENTS: |
+ case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
+ case EXTERNAL_SHORT_ELEMENTS: |
+ case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
+ case EXTERNAL_INT_ELEMENTS: |
+ case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
+ case EXTERNAL_FLOAT_ELEMENTS: |
+ case EXTERNAL_DOUBLE_ELEMENTS: |
+ case FAST_DOUBLE_ELEMENTS: |
+ case FAST_HOLEY_DOUBLE_ELEMENTS: |
+ // No contained objects, nothing to do. |
+ break; |
+ } |
+ 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). |