| Index: src/objects.cc | 
| diff --git a/src/objects.cc b/src/objects.cc | 
| index 627d371142e768a93ec1475e55bd08e185d395c6..6a36004c649995132fb8762ae81295ab176d11c1 100644 | 
| --- a/src/objects.cc | 
| +++ b/src/objects.cc | 
| @@ -5655,14 +5655,6 @@ void JSObject::SetObserved(Handle<JSObject> object) { | 
| } | 
|  | 
|  | 
| -Handle<JSObject> JSObject::Copy(Handle<JSObject> object, | 
| -                                Handle<AllocationSite> site) { | 
| -  Isolate* isolate = object->GetIsolate(); | 
| -  CALL_HEAP_FUNCTION(isolate, | 
| -                     isolate->heap()->CopyJSObject(*object, *site), JSObject); | 
| -} | 
| - | 
| - | 
| Handle<JSObject> JSObject::Copy(Handle<JSObject> object) { | 
| Isolate* isolate = object->GetIsolate(); | 
| CALL_HEAP_FUNCTION(isolate, | 
| @@ -5670,258 +5662,229 @@ Handle<JSObject> JSObject::Copy(Handle<JSObject> object) { | 
| } | 
|  | 
|  | 
| +template<class ContextObject> | 
| class JSObjectWalkVisitor { | 
| public: | 
| -  explicit JSObjectWalkVisitor(AllocationSiteContext* site_context) : | 
| -      site_context_(site_context) {} | 
| -  virtual ~JSObjectWalkVisitor() {} | 
| - | 
| -  Handle<JSObject> Visit(Handle<JSObject> object) { | 
| -    return StructureWalk(object); | 
| -  } | 
| - | 
| -  virtual bool is_copying() = 0; | 
| +  JSObjectWalkVisitor(ContextObject* site_context, bool copying, | 
| +                      JSObject::DeepCopyHints hints) | 
| +    : site_context_(site_context), | 
| +      copying_(copying), | 
| +      hints_(hints) {} | 
|  | 
| - protected: | 
| Handle<JSObject> StructureWalk(Handle<JSObject> object); | 
|  | 
| -  // The returned handle will be used for the object in all subsequent usages. | 
| -  // This allows VisitObject to make a copy of the object if desired. | 
| -  virtual Handle<JSObject> VisitObject(Handle<JSObject> object) = 0; | 
| -  virtual Handle<JSObject> VisitElementOrProperty(Handle<JSObject> object, | 
| -                                                  Handle<JSObject> value) = 0; | 
| - | 
| -  AllocationSiteContext* site_context() { return site_context_; } | 
| - | 
| - private: | 
| -  AllocationSiteContext* site_context_; | 
| -}; | 
| - | 
| - | 
| -class JSObjectCopyVisitor: public JSObjectWalkVisitor { | 
| - public: | 
| -  explicit JSObjectCopyVisitor(AllocationSiteContext* site_context) | 
| -      : JSObjectWalkVisitor(site_context) {} | 
| - | 
| -  virtual bool is_copying() V8_OVERRIDE { return true; } | 
| - | 
| -  // The returned handle will be used for the object in all | 
| -  // subsequent usages. This allows VisitObject to make a copy | 
| -  // of the object if desired. | 
| -  virtual Handle<JSObject> VisitObject(Handle<JSObject> object) V8_OVERRIDE { | 
| -    // Only create a memento if | 
| -    // 1) we have a JSArray, and | 
| -    // 2) the elements kind is palatable | 
| -    // 3) allow_mementos is true | 
| -    Handle<JSObject> copy; | 
| -    if (site_context()->activated() && | 
| -        AllocationSite::CanTrack(object->map()->instance_type()) && | 
| -        AllocationSite::GetMode(object->GetElementsKind()) == | 
| -        TRACK_ALLOCATION_SITE) { | 
| -      copy = JSObject::Copy(object, site_context()->current()); | 
| -    } else { | 
| -      copy = JSObject::Copy(object); | 
| -    } | 
| - | 
| -    return copy; | 
| -  } | 
| - | 
| -  virtual Handle<JSObject> VisitElementOrProperty( | 
| -      Handle<JSObject> object, | 
| -      Handle<JSObject> value) V8_OVERRIDE { | 
| + protected: | 
| +  inline Handle<JSObject> VisitElementOrProperty(Handle<JSObject> object, | 
| +                                                 Handle<JSObject> value) { | 
| Handle<AllocationSite> current_site = site_context()->EnterNewScope(); | 
| Handle<JSObject> copy_of_value = StructureWalk(value); | 
| site_context()->ExitScope(current_site, value); | 
| return copy_of_value; | 
| } | 
| -}; | 
|  | 
| +  inline ContextObject* site_context() { return site_context_; } | 
| +  inline Isolate* isolate() { return site_context()->isolate(); } | 
|  | 
| -class JSObjectCreateAllocationSitesVisitor: public JSObjectWalkVisitor { | 
| - public: | 
| -  explicit JSObjectCreateAllocationSitesVisitor( | 
| -      AllocationSiteContext* site_context) | 
| -      : JSObjectWalkVisitor(site_context) {} | 
| +  inline bool copying() const { return copying_; } | 
|  | 
| -  virtual bool is_copying() V8_OVERRIDE { return false; } | 
| + private: | 
| +  ContextObject* site_context_; | 
| +  const bool copying_; | 
| +  const JSObject::DeepCopyHints hints_; | 
| +}; | 
|  | 
| -  // The returned handle will be used for the object in all | 
| -  // subsequent usages. This allows VisitObject to make a copy | 
| -  // of the object if desired. | 
| -  virtual Handle<JSObject> VisitObject(Handle<JSObject> object) V8_OVERRIDE { | 
| -    return object; | 
| -  } | 
|  | 
| -  virtual Handle<JSObject> VisitElementOrProperty( | 
| -      Handle<JSObject> object, | 
| -      Handle<JSObject> value) V8_OVERRIDE { | 
| -    Handle<AllocationSite> current_site = site_context()->EnterNewScope(); | 
| -    value = StructureWalk(value); | 
| -    site_context()->ExitScope(current_site, value); | 
| -    return value; | 
| -  } | 
| -}; | 
| +template <class ContextObject> | 
| +Handle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk( | 
| +    Handle<JSObject> object) { | 
| +  Isolate* isolate = this->isolate(); | 
| +  bool copying = this->copying(); | 
| +  bool shallow = hints_ == JSObject::kObjectIsShallowArray; | 
|  | 
| +  if (!shallow) { | 
| +    StackLimitCheck check(isolate); | 
|  | 
| -Handle<JSObject> JSObjectWalkVisitor::StructureWalk(Handle<JSObject> object) { | 
| -  bool copying = is_copying(); | 
| -  Isolate* isolate = object->GetIsolate(); | 
| -  StackLimitCheck check(isolate); | 
| -  if (check.HasOverflowed()) { | 
| -    isolate->StackOverflow(); | 
| -    return Handle<JSObject>::null(); | 
| +    if (check.HasOverflowed()) { | 
| +      isolate->StackOverflow(); | 
| +      return Handle<JSObject>::null(); | 
| +    } | 
| } | 
|  | 
| if (object->map()->is_deprecated()) { | 
| JSObject::MigrateInstance(object); | 
| } | 
|  | 
| -  Handle<JSObject> copy = VisitObject(object); | 
| +  Handle<JSObject> copy; | 
| +  if (copying) { | 
| +    Handle<AllocationSite> site_to_pass; | 
| +    if (site_context()->activated() && | 
| +        AllocationSite::CanTrack(object->map()->instance_type()) && | 
| +        AllocationSite::GetMode(object->GetElementsKind()) == | 
| +        TRACK_ALLOCATION_SITE) { | 
| +      site_to_pass = site_context()->current(); | 
| +    } | 
| +    CALL_AND_RETRY_OR_DIE(isolate, | 
| +                          isolate->heap()->CopyJSObject(*object, | 
| +                              site_to_pass.is_null() ? NULL : *site_to_pass), | 
| +                          { copy = Handle<JSObject>(JSObject::cast(__object__), | 
| +                                                    isolate); | 
| +                            break; | 
| +                          }, | 
| +                          return Handle<JSObject>()); | 
| +  } else { | 
| +    copy = object; | 
| +  } | 
| + | 
| ASSERT(copying || copy.is_identical_to(object)); | 
|  | 
| -  HandleScope scope(isolate); | 
| +  if (!shallow) { | 
| +    HandleScope scope(isolate); | 
|  | 
| -  // Deep copy local properties. | 
| -  if (copy->HasFastProperties()) { | 
| -    Handle<DescriptorArray> descriptors(copy->map()->instance_descriptors()); | 
| -    int limit = copy->map()->NumberOfOwnDescriptors(); | 
| -    for (int i = 0; i < limit; i++) { | 
| -      PropertyDetails details = descriptors->GetDetails(i); | 
| -      if (details.type() != FIELD) continue; | 
| -      int index = descriptors->GetFieldIndex(i); | 
| -      Handle<Object> value(object->RawFastPropertyAt(index), isolate); | 
| -      if (value->IsJSObject()) { | 
| -        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); | 
| -      } | 
| -      if (copying) { | 
| -        copy->FastPropertyAtPut(index, *value); | 
| -      } | 
| -    } | 
| -  } else { | 
| -    Handle<FixedArray> names = | 
| -        isolate->factory()->NewFixedArray(copy->NumberOfLocalProperties()); | 
| -    copy->GetLocalPropertyNames(*names, 0); | 
| -    for (int i = 0; i < names->length(); i++) { | 
| -      ASSERT(names->get(i)->IsString()); | 
| -      Handle<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; | 
| -      Handle<Object> value( | 
| -          copy->GetProperty(*key_string, &attributes)->ToObjectUnchecked(), | 
| -          isolate); | 
| -      if (value->IsJSObject()) { | 
| -        Handle<JSObject> result = VisitElementOrProperty( | 
| -            copy, Handle<JSObject>::cast(value)); | 
| -        RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<JSObject>()); | 
| +    // Deep copy local properties. | 
| +    if (copy->HasFastProperties()) { | 
| +      Handle<DescriptorArray> descriptors(copy->map()->instance_descriptors()); | 
| +      int limit = copy->map()->NumberOfOwnDescriptors(); | 
| +      for (int i = 0; i < limit; i++) { | 
| +        PropertyDetails details = descriptors->GetDetails(i); | 
| +        if (details.type() != FIELD) continue; | 
| +        int index = descriptors->GetFieldIndex(i); | 
| +        Handle<Object> value(object->RawFastPropertyAt(index), isolate); | 
| +        if (value->IsJSObject()) { | 
| +          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); | 
| +        } | 
| if (copying) { | 
| -          // Creating object copy for literals. No strict mode needed. | 
| -          CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetProperty( | 
| -              copy, key_string, result, NONE, kNonStrictMode)); | 
| +          copy->FastPropertyAtPut(index, *value); | 
| +        } | 
| +      } | 
| +    } else { | 
| +      Handle<FixedArray> names = | 
| +          isolate->factory()->NewFixedArray(copy->NumberOfLocalProperties()); | 
| +      copy->GetLocalPropertyNames(*names, 0); | 
| +      for (int i = 0; i < names->length(); i++) { | 
| +        ASSERT(names->get(i)->IsString()); | 
| +        Handle<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; | 
| +        Handle<Object> value( | 
| +            copy->GetProperty(*key_string, &attributes)->ToObjectUnchecked(), | 
| +            isolate); | 
| +        if (value->IsJSObject()) { | 
| +          Handle<JSObject> result = VisitElementOrProperty( | 
| +              copy, Handle<JSObject>::cast(value)); | 
| +          RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<JSObject>()); | 
| +          if (copying) { | 
| +            // Creating object copy for literals. No strict mode needed. | 
| +            CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetProperty( | 
| +                copy, key_string, result, NONE, kNonStrictMode)); | 
| +          } | 
| } | 
| } | 
| } | 
| -  } | 
|  | 
| -  // 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: { | 
| -      Handle<FixedArray> elements(FixedArray::cast(copy->elements())); | 
| -      if (elements->map() == isolate->heap()->fixed_cow_array_map()) { | 
| -        if (copying) { | 
| -          isolate->counters()->cow_arrays_created_runtime()->Increment(); | 
| -        } | 
| +    // 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: { | 
| +        Handle<FixedArray> elements(FixedArray::cast(copy->elements())); | 
| +        if (elements->map() == isolate->heap()->fixed_cow_array_map()) { | 
| +          if (copying) { | 
| +            isolate->counters()->cow_arrays_created_runtime()->Increment(); | 
| +          } | 
| #ifdef DEBUG | 
| -        for (int i = 0; i < elements->length(); i++) { | 
| -          ASSERT(!elements->get(i)->IsJSObject()); | 
| -        } | 
| +          for (int i = 0; i < elements->length(); i++) { | 
| +            ASSERT(!elements->get(i)->IsJSObject()); | 
| +          } | 
| #endif | 
| -      } else { | 
| -        for (int i = 0; i < elements->length(); i++) { | 
| -          Handle<Object> value(elements->get(i), isolate); | 
| -          ASSERT(value->IsSmi() || | 
| -                 value->IsTheHole() || | 
| -                 (IsFastObjectElementsKind(copy->GetElementsKind()))); | 
| -          if (value->IsJSObject()) { | 
| -            Handle<JSObject> result = VisitElementOrProperty( | 
| -                copy, Handle<JSObject>::cast(value)); | 
| -            RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<JSObject>()); | 
| -            if (copying) { | 
| -              elements->set(i, *result); | 
| +        } else { | 
| +          for (int i = 0; i < elements->length(); i++) { | 
| +            Handle<Object> value(elements->get(i), isolate); | 
| +            ASSERT(value->IsSmi() || | 
| +                   value->IsTheHole() || | 
| +                   (IsFastObjectElementsKind(copy->GetElementsKind()))); | 
| +            if (value->IsJSObject()) { | 
| +              Handle<JSObject> result = VisitElementOrProperty( | 
| +                  copy, Handle<JSObject>::cast(value)); | 
| +              RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<JSObject>()); | 
| +              if (copying) { | 
| +                elements->set(i, *result); | 
| +              } | 
| } | 
| } | 
| } | 
| +        break; | 
| } | 
| -      break; | 
| -    } | 
| -    case DICTIONARY_ELEMENTS: { | 
| -      Handle<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)) { | 
| -          Handle<Object> value(element_dictionary->ValueAt(i), isolate); | 
| -          if (value->IsJSObject()) { | 
| -            Handle<JSObject> result = VisitElementOrProperty( | 
| -                copy, Handle<JSObject>::cast(value)); | 
| -            RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<JSObject>()); | 
| -            if (copying) { | 
| -              element_dictionary->ValueAtPut(i, *result); | 
| +      case DICTIONARY_ELEMENTS: { | 
| +        Handle<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)) { | 
| +            Handle<Object> value(element_dictionary->ValueAt(i), isolate); | 
| +            if (value->IsJSObject()) { | 
| +              Handle<JSObject> result = VisitElementOrProperty( | 
| +                  copy, Handle<JSObject>::cast(value)); | 
| +              RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<JSObject>()); | 
| +              if (copying) { | 
| +                element_dictionary->ValueAtPut(i, *result); | 
| +              } | 
| } | 
| } | 
| } | 
| +        break; | 
| } | 
| -      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; | 
| } | 
| -    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; | 
| } | 
|  | 
|  | 
| -Handle<JSObject> JSObject::DeepWalk(Handle<JSObject> object, | 
| -                                    AllocationSiteContext* site_context) { | 
| -  JSObjectCreateAllocationSitesVisitor v(site_context); | 
| -  Handle<JSObject> result = v.Visit(object); | 
| -  ASSERT(!v.is_copying() && | 
| -         (result.is_null() || result.is_identical_to(object))); | 
| +Handle<JSObject> JSObject::DeepWalk( | 
| +    Handle<JSObject> object, | 
| +    AllocationSiteCreationContext* site_context) { | 
| +  JSObjectWalkVisitor<AllocationSiteCreationContext> v(site_context, false, | 
| +                                                       kNoHints); | 
| +  Handle<JSObject> result = v.StructureWalk(object); | 
| +  ASSERT(result.is_null() || result.is_identical_to(object)); | 
| return result; | 
| } | 
|  | 
|  | 
| Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object, | 
| -                                    AllocationSiteContext* site_context) { | 
| -  JSObjectCopyVisitor v(site_context); | 
| -  Handle<JSObject> copy = v.Visit(object); | 
| -  ASSERT(v.is_copying() && !copy.is_identical_to(object)); | 
| +                                    AllocationSiteUsageContext* site_context, | 
| +                                    DeepCopyHints hints) { | 
| +  JSObjectWalkVisitor<AllocationSiteUsageContext> v(site_context, true, hints); | 
| +  Handle<JSObject> copy = v.StructureWalk(object); | 
| +  ASSERT(!copy.is_identical_to(object)); | 
| return copy; | 
| } | 
|  | 
|  |