| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index 627d371142e768a93ec1475e55bd08e185d395c6..a856766d479d9abdcdc1d9bb129de051093dddd1 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,226 @@ 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);
|
| - }
|
| + JSObjectWalkVisitor(ContextObject* site_context, bool copying) :
|
| + site_context_(site_context),
|
| + copying_(copying) {}
|
|
|
| - virtual bool is_copying() = 0;
|
| + Handle<JSObject> StructureWalk(Handle<JSObject> object,
|
| + bool object_is_shallow_array = false);
|
|
|
| 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 {
|
| + 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_;
|
| +};
|
|
|
| - // 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, bool object_is_shallow_array) {
|
| + Isolate* isolate = this->isolate();
|
| + bool copying = this->copying();
|
| + bool shallow = object_is_shallow_array;
|
|
|
| + 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);
|
| + }
|
| }
|
|
|
| - if (object->map()->is_deprecated()) {
|
| - JSObject::MigrateInstance(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;
|
| }
|
|
|
| - Handle<JSObject> copy = VisitObject(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);
|
| + 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,
|
| + bool hint_object_is_shallow_array) {
|
| + JSObjectWalkVisitor<AllocationSiteUsageContext> v(site_context, true);
|
| + Handle<JSObject> copy = v.StructureWalk(object, hint_object_is_shallow_array);
|
| + ASSERT(!copy.is_identical_to(object));
|
| return copy;
|
| }
|
|
|
|
|