From d7e099889efe7ff9dc738e908852736efb18ed89 Mon Sep 17 00:00:00 2001 From: "mstarzinger@chromium.org" Date: Mon, 21 Nov 2011 13:27:44 +0000 Subject: [PATCH] Implement code stub for object literal creation. This generates code stubs for cloning of shallow object literal boilerplates that have no elements and only fast properties. Improves splay performance because object literals are created frequently. R=fschneider@chromium.org Review URL: http://codereview.chromium.org/8598014 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10036 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/code-stubs.h | 25 ++++++++++++++++++++-- src/ia32/code-stubs-ia32.cc | 46 ++++++++++++++++++++++++++++++++++++++++ src/ia32/full-codegen-ia32.cc | 10 +++++++-- src/ia32/lithium-codegen-ia32.cc | 14 +++++++++--- src/x64/code-stubs-x64.cc | 43 +++++++++++++++++++++++++++++++++++++ src/x64/full-codegen-x64.cc | 10 +++++++-- src/x64/lithium-codegen-x64.cc | 20 ++++++++++++++--- 7 files changed, 156 insertions(+), 12 deletions(-) diff --git a/src/code-stubs.h b/src/code-stubs.h index 16826db..63e292a 100644 --- a/src/code-stubs.h +++ b/src/code-stubs.h @@ -58,6 +58,7 @@ namespace internal { V(FastNewContext) \ V(FastNewBlockContext) \ V(FastCloneShallowArray) \ + V(FastCloneShallowObject) \ V(ToBoolean) \ V(ToNumber) \ V(ArgumentsAccess) \ @@ -362,8 +363,8 @@ class FastCloneShallowArrayStub : public CodeStub { FastCloneShallowArrayStub(Mode mode, int length) : mode_(mode), length_((mode == COPY_ON_WRITE_ELEMENTS) ? 0 : length) { - ASSERT(length_ >= 0); - ASSERT(length_ <= kMaximumClonedLength); + ASSERT_GE(length_, 0); + ASSERT_LE(length_, kMaximumClonedLength); } void Generate(MacroAssembler* masm); @@ -380,6 +381,26 @@ class FastCloneShallowArrayStub : public CodeStub { }; +class FastCloneShallowObjectStub : public CodeStub { + public: + // Maximum number of properties in copied object. + static const int kMaximumClonedProperties = 6; + + FastCloneShallowObjectStub(int length) : length_(length) { + ASSERT_GE(length_, 0); + ASSERT_LE(length_, kMaximumClonedProperties); + } + + void Generate(MacroAssembler* masm); + + private: + int length_; + + Major MajorKey() { return FastCloneShallowObject; } + int MinorKey() { return length_; } +}; + + class InstanceofStub: public CodeStub { public: enum Flags { diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc index 27b127d..c6c1009 100644 --- a/src/ia32/code-stubs-ia32.cc +++ b/src/ia32/code-stubs-ia32.cc @@ -368,6 +368,52 @@ void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { } +void FastCloneShallowObjectStub::Generate(MacroAssembler* masm) { + // Stack layout on entry: + // + // [esp + kPointerSize]: object literal flags. + // [esp + (2 * kPointerSize)]: constant properties. + // [esp + (3 * kPointerSize)]: literal index. + // [esp + (4 * kPointerSize)]: literals array. + + // Load boilerplate object into ecx and check if we need to create a + // boilerplate. + Label slow_case; + __ mov(ecx, Operand(esp, 4 * kPointerSize)); + __ mov(eax, Operand(esp, 3 * kPointerSize)); + STATIC_ASSERT(kPointerSize == 4); + STATIC_ASSERT(kSmiTagSize == 1); + STATIC_ASSERT(kSmiTag == 0); + __ mov(ecx, FieldOperand(ecx, eax, times_half_pointer_size, + FixedArray::kHeaderSize)); + Factory* factory = masm->isolate()->factory(); + __ cmp(ecx, factory->undefined_value()); + __ j(equal, &slow_case); + + // Check that the boilerplate contains only fast properties and we can + // statically determine the instance size. + int size = JSObject::kHeaderSize + length_ * kPointerSize; + __ mov(eax, FieldOperand(ecx, HeapObject::kMapOffset)); + __ movzx_b(eax, FieldOperand(eax, Map::kInstanceSizeOffset)); + __ cmp(eax, Immediate(size >> kPointerSizeLog2)); + __ j(not_equal, &slow_case); + + // Allocate the JS object and copy header together with all in-object + // properties from the boilerplate. + __ AllocateInNewSpace(size, eax, ebx, edx, &slow_case, TAG_OBJECT); + for (int i = 0; i < size; i += kPointerSize) { + __ mov(ebx, FieldOperand(ecx, i)); + __ mov(FieldOperand(eax, i), ebx); + } + + // Return and remove the on-stack parameters. + __ ret(4 * kPointerSize); + + __ bind(&slow_case); + __ TailCallRuntime(Runtime::kCreateObjectLiteralShallow, 4, 1); +} + + // The stub expects its argument on the stack and returns its result in tos_: // zero for false, and a non-zero value for true. void ToBooleanStub::Generate(MacroAssembler* masm) { diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index c1ef22e..c178b7f 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -1374,10 +1374,11 @@ void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { Comment cmnt(masm_, "[ ObjectLiteral"); + Handle constant_properties = expr->constant_properties(); __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); __ push(FieldOperand(edi, JSFunction::kLiteralsOffset)); __ push(Immediate(Smi::FromInt(expr->literal_index()))); - __ push(Immediate(expr->constant_properties())); + __ push(Immediate(constant_properties)); int flags = expr->fast_elements() ? ObjectLiteral::kFastElements : ObjectLiteral::kNoFlags; @@ -1385,10 +1386,15 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { ? ObjectLiteral::kHasFunction : ObjectLiteral::kNoFlags; __ push(Immediate(Smi::FromInt(flags))); + int properties_count = constant_properties->length() / 2; if (expr->depth() > 1) { __ CallRuntime(Runtime::kCreateObjectLiteral, 4); - } else { + } else if (flags != ObjectLiteral::kFastElements || + properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) { __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 4); + } else { + FastCloneShallowObjectStub stub(properties_count); + __ CallStub(&stub); } // If result_saved is true the result is on top of the stack. If diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index 40d5dec..841be73 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -4163,11 +4163,14 @@ void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) { void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) { ASSERT(ToRegister(instr->context()).is(esi)); + Handle constant_properties = + instr->hydrogen()->constant_properties(); + // Setup the parameters to the stub/runtime call. __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); __ push(FieldOperand(eax, JSFunction::kLiteralsOffset)); __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index()))); - __ push(Immediate(instr->hydrogen()->constant_properties())); + __ push(Immediate(constant_properties)); int flags = instr->hydrogen()->fast_elements() ? ObjectLiteral::kFastElements : ObjectLiteral::kNoFlags; @@ -4176,11 +4179,16 @@ void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) { : ObjectLiteral::kNoFlags; __ push(Immediate(Smi::FromInt(flags))); - // Pick the right runtime function to call. + // Pick the right runtime function or stub to call. + int properties_count = constant_properties->length() / 2; if (instr->hydrogen()->depth() > 1) { CallRuntime(Runtime::kCreateObjectLiteral, 4, instr); - } else { + } else if (flags != ObjectLiteral::kFastElements || + properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) { CallRuntime(Runtime::kCreateObjectLiteralShallow, 4, instr); + } else { + FastCloneShallowObjectStub stub(properties_count); + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); } } diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc index a30d62f..b8f820d 100644 --- a/src/x64/code-stubs-x64.cc +++ b/src/x64/code-stubs-x64.cc @@ -354,6 +354,49 @@ void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { } +void FastCloneShallowObjectStub::Generate(MacroAssembler* masm) { + // Stack layout on entry: + // + // [rsp + kPointerSize]: object literal flags. + // [rsp + (2 * kPointerSize)]: constant properties. + // [rsp + (3 * kPointerSize)]: literal index. + // [rsp + (4 * kPointerSize)]: literals array. + + // Load boilerplate object into ecx and check if we need to create a + // boilerplate. + Label slow_case; + __ movq(rcx, Operand(rsp, 4 * kPointerSize)); + __ movq(rax, Operand(rsp, 3 * kPointerSize)); + SmiIndex index = masm->SmiToIndex(rax, rax, kPointerSizeLog2); + __ movq(rcx, + FieldOperand(rcx, index.reg, index.scale, FixedArray::kHeaderSize)); + __ CompareRoot(rcx, Heap::kUndefinedValueRootIndex); + __ j(equal, &slow_case); + + // Check that the boilerplate contains only fast properties and we can + // statically determine the instance size. + int size = JSObject::kHeaderSize + length_ * kPointerSize; + __ movq(rax, FieldOperand(rcx, HeapObject::kMapOffset)); + __ movzxbq(rax, FieldOperand(rax, Map::kInstanceSizeOffset)); + __ cmpq(rax, Immediate(size >> kPointerSizeLog2)); + __ j(not_equal, &slow_case); + + // Allocate the JS object and copy header together with all in-object + // properties from the boilerplate. + __ AllocateInNewSpace(size, rax, rbx, rdx, &slow_case, TAG_OBJECT); + for (int i = 0; i < size; i += kPointerSize) { + __ movq(rbx, FieldOperand(rcx, i)); + __ movq(FieldOperand(rax, i), rbx); + } + + // Return and remove the on-stack parameters. + __ ret(4 * kPointerSize); + + __ bind(&slow_case); + __ TailCallRuntime(Runtime::kCreateObjectLiteralShallow, 4, 1); +} + + // The stub expects its argument on the stack and returns its result in tos_: // zero for false, and a non-zero value for true. void ToBooleanStub::Generate(MacroAssembler* masm) { diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index 35b902d..728f181 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -1376,10 +1376,11 @@ void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { Comment cmnt(masm_, "[ ObjectLiteral"); + Handle constant_properties = expr->constant_properties(); __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); __ push(FieldOperand(rdi, JSFunction::kLiteralsOffset)); __ Push(Smi::FromInt(expr->literal_index())); - __ Push(expr->constant_properties()); + __ Push(constant_properties); int flags = expr->fast_elements() ? ObjectLiteral::kFastElements : ObjectLiteral::kNoFlags; @@ -1387,10 +1388,15 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { ? ObjectLiteral::kHasFunction : ObjectLiteral::kNoFlags; __ Push(Smi::FromInt(flags)); + int properties_count = constant_properties->length() / 2; if (expr->depth() > 1) { __ CallRuntime(Runtime::kCreateObjectLiteral, 4); - } else { + } else if (flags != ObjectLiteral::kFastElements || + properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) { __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 4); + } else { + FastCloneShallowObjectStub stub(properties_count); + __ CallStub(&stub); } // If result_saved is true the result is on top of the stack. If diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc index fd88b9d..27ed3b5 100644 --- a/src/x64/lithium-codegen-x64.cc +++ b/src/x64/lithium-codegen-x64.cc @@ -3927,18 +3927,32 @@ void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) { void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) { + Handle constant_properties = + instr->hydrogen()->constant_properties(); + // Setup the parameters to the stub/runtime call. __ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); __ push(FieldOperand(rax, JSFunction::kLiteralsOffset)); __ Push(Smi::FromInt(instr->hydrogen()->literal_index())); - __ Push(instr->hydrogen()->constant_properties()); - __ Push(Smi::FromInt(instr->hydrogen()->fast_elements() ? 1 : 0)); + __ Push(constant_properties); + int flags = instr->hydrogen()->fast_elements() + ? ObjectLiteral::kFastElements + : ObjectLiteral::kNoFlags; + flags |= instr->hydrogen()->has_function() + ? ObjectLiteral::kHasFunction + : ObjectLiteral::kNoFlags; + __ Push(Smi::FromInt(flags)); // Pick the right runtime function to call. + int properties_count = constant_properties->length() / 2; if (instr->hydrogen()->depth() > 1) { CallRuntime(Runtime::kCreateObjectLiteral, 4, instr); - } else { + } else if (flags != ObjectLiteral::kFastElements || + properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) { CallRuntime(Runtime::kCreateObjectLiteralShallow, 4, instr); + } else { + FastCloneShallowObjectStub stub(properties_count); + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); } } -- 2.7.4