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
This commit is contained in:
mstarzinger@chromium.org 2011-11-21 13:27:44 +00:00
parent fa7ae22f4f
commit d7e099889e
7 changed files with 156 additions and 12 deletions

View File

@ -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 {

View File

@ -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) {

View File

@ -1374,10 +1374,11 @@ void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
Comment cmnt(masm_, "[ ObjectLiteral");
Handle<FixedArray> 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

View File

@ -4163,11 +4163,14 @@ void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
ASSERT(ToRegister(instr->context()).is(esi));
Handle<FixedArray> 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);
}
}

View File

@ -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) {

View File

@ -1376,10 +1376,11 @@ void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
Comment cmnt(masm_, "[ ObjectLiteral");
Handle<FixedArray> 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

View File

@ -3927,18 +3927,32 @@ void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
Handle<FixedArray> 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);
}
}