| Index: src/code-stubs.cc
|
| diff --git a/src/code-stubs.cc b/src/code-stubs.cc
|
| index e41145e69b43bc18bd74ea1769058a51232ea9ed..9481ace5e7c45d7c54599ed276fe6e3abe075c81 100644
|
| --- a/src/code-stubs.cc
|
| +++ b/src/code-stubs.cc
|
| @@ -3747,13 +3747,34 @@ void LoadIndexedInterceptorStub::GenerateAssembly(
|
| slot, vector);
|
| }
|
|
|
| -void FastCloneShallowObjectStub::GenerateAssembly(
|
| - CodeStubAssembler* assembler) const {
|
| - typedef CodeStubAssembler::Label Label;
|
| +// static
|
| +bool FastCloneShallowObjectStub::IsSupported(ObjectLiteral* expr) {
|
| + // FastCloneShallowObjectStub doesn't copy elements, and object literals don't
|
| + // support copy-on-write (COW) elements for now.
|
| + // TODO(mvstanton): make object literals support COW elements.
|
| + return expr->fast_elements() && expr->has_shallow_properties() &&
|
| + expr->properties_count() <= kMaximumClonedProperties;
|
| +}
|
| +
|
| +// static
|
| +int FastCloneShallowObjectStub::PropertiesCount(int literal_length) {
|
| + // This heuristic of setting empty literals to have
|
| + // kInitialGlobalObjectUnusedPropertiesCount must remain in-sync with the
|
| + // runtime.
|
| + // TODO(verwaest): Unify this with the heuristic in the runtime.
|
| + return literal_length == 0
|
| + ? JSObject::kInitialGlobalObjectUnusedPropertiesCount
|
| + : literal_length;
|
| +}
|
| +
|
| +// static
|
| +compiler::Node* FastCloneShallowObjectStub::GenerateFastPath(
|
| + CodeStubAssembler* assembler, compiler::CodeAssembler::Label* call_runtime,
|
| + compiler::Node* closure, compiler::Node* literals_index,
|
| + compiler::Node* properties_count) {
|
| typedef compiler::Node Node;
|
| - Label call_runtime(assembler);
|
| - Node* closure = assembler->Parameter(0);
|
| - Node* literals_index = assembler->Parameter(1);
|
| + typedef compiler::CodeAssembler::Label Label;
|
| + typedef compiler::CodeAssembler::Variable Variable;
|
|
|
| Node* undefined = assembler->UndefinedConstant();
|
| Node* literals_array =
|
| @@ -3762,38 +3783,52 @@ void FastCloneShallowObjectStub::GenerateAssembly(
|
| literals_array, literals_index,
|
| LiteralsArray::kFirstLiteralIndex * kPointerSize);
|
| assembler->GotoIf(assembler->WordEqual(allocation_site, undefined),
|
| - &call_runtime);
|
| + call_runtime);
|
|
|
| - Node* boilerplate = assembler->LoadObjectField(
|
| - allocation_site, AllocationSite::kTransitionInfoOffset);
|
| -
|
| - int length = this->length();
|
| - if (length == 0) {
|
| - length = JSObject::kInitialGlobalObjectUnusedPropertiesCount;
|
| - }
|
| - int allocation_size = JSObject::kHeaderSize + length * kPointerSize;
|
| - int object_size = allocation_size;
|
| + // Calculate the object and allocation size based on the properties count.
|
| + Node* object_size = assembler->IntPtrAdd(
|
| + assembler->WordShl(properties_count, kPointerSizeLog2),
|
| + assembler->IntPtrConstant(JSObject::kHeaderSize));
|
| + Node* allocation_size = object_size;
|
| if (FLAG_allocation_site_pretenuring) {
|
| - allocation_size += AllocationMemento::kSize;
|
| + allocation_size = assembler->IntPtrAdd(
|
| + object_size, assembler->IntPtrConstant(AllocationMemento::kSize));
|
| }
|
| -
|
| + Node* boilerplate = assembler->LoadObjectField(
|
| + allocation_site, AllocationSite::kTransitionInfoOffset);
|
| Node* boilerplate_map = assembler->LoadMap(boilerplate);
|
| Node* instance_size = assembler->LoadMapInstanceSize(boilerplate_map);
|
| - Node* size_in_words =
|
| - assembler->Int32Constant(object_size >> kPointerSizeLog2);
|
| + Node* size_in_words = assembler->WordShr(object_size, kPointerSizeLog2);
|
| assembler->GotoUnless(assembler->Word32Equal(instance_size, size_in_words),
|
| - &call_runtime);
|
| + call_runtime);
|
|
|
| Node* copy = assembler->Allocate(allocation_size);
|
|
|
| - for (int i = 0; i < object_size; i += kPointerSize) {
|
| + // Copy boilerplate elements.
|
| + Variable offset(assembler, MachineType::PointerRepresentation());
|
| + offset.Bind(assembler->IntPtrConstant(-kHeapObjectTag));
|
| + Node* end_offset = assembler->IntPtrAdd(object_size, offset.value());
|
| + Label loop_body(assembler, &offset), loop_check(assembler, &offset);
|
| + // We should always have an object size greater than zero.
|
| + assembler->Goto(&loop_body);
|
| + assembler->Bind(&loop_body);
|
| + {
|
| // The Allocate above guarantees that the copy lies in new space. This
|
| // allows us to skip write barriers. This is necessary since we may also be
|
| // copying unboxed doubles.
|
| Node* field =
|
| - assembler->LoadObjectField(boilerplate, i, MachineType::IntPtr());
|
| - assembler->StoreObjectFieldNoWriteBarrier(
|
| - copy, i, field, MachineType::PointerRepresentation());
|
| + assembler->Load(MachineType::IntPtr(), boilerplate, offset.value());
|
| + assembler->StoreNoWriteBarrier(MachineType::PointerRepresentation(), copy,
|
| + offset.value(), field);
|
| + assembler->Goto(&loop_check);
|
| + }
|
| + assembler->Bind(&loop_check);
|
| + {
|
| + offset.Bind(assembler->IntPtrAdd(offset.value(),
|
| + assembler->IntPtrConstant(kPointerSize)));
|
| + assembler->GotoUnless(
|
| + assembler->IntPtrGreaterThanOrEqual(offset.value(), end_offset),
|
| + &loop_body);
|
| }
|
|
|
| if (FLAG_allocation_site_pretenuring) {
|
| @@ -3813,6 +3848,21 @@ void FastCloneShallowObjectStub::GenerateAssembly(
|
| }
|
|
|
| // TODO(verwaest): Allocate and fill in double boxes.
|
| + return copy;
|
| +}
|
| +
|
| +void FastCloneShallowObjectStub::GenerateAssembly(
|
| + CodeStubAssembler* assembler) const {
|
| + typedef CodeStubAssembler::Label Label;
|
| + typedef compiler::Node Node;
|
| + Label call_runtime(assembler);
|
| + Node* closure = assembler->Parameter(0);
|
| + Node* literals_index = assembler->Parameter(1);
|
| +
|
| + Node* properties_count =
|
| + assembler->IntPtrConstant(PropertiesCount(this->length()));
|
| + Node* copy = GenerateFastPath(assembler, &call_runtime, closure,
|
| + literals_index, properties_count);
|
| assembler->Return(copy);
|
|
|
| assembler->Bind(&call_runtime);
|
|
|