Commit 914d4f80 authored by kasperl@chromium.org's avatar kasperl@chromium.org

Optimize the allocation of small, non-nested literal

arrays and argument objects on IA-32.
Review URL: http://codereview.chromium.org/503042

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3485 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 6af6a82a
...@@ -45,6 +45,7 @@ namespace internal { ...@@ -45,6 +45,7 @@ namespace internal {
V(StackCheck) \ V(StackCheck) \
V(FastNewClosure) \ V(FastNewClosure) \
V(FastNewContext) \ V(FastNewContext) \
V(FastCloneShallowArray) \
V(UnarySub) \ V(UnarySub) \
V(RevertToNumber) \ V(RevertToNumber) \
V(ToBoolean) \ V(ToBoolean) \
......
...@@ -263,6 +263,25 @@ class FastNewContextStub : public CodeStub { ...@@ -263,6 +263,25 @@ class FastNewContextStub : public CodeStub {
}; };
class FastCloneShallowArrayStub : public CodeStub {
public:
static const int kMaximumLength = 8;
explicit FastCloneShallowArrayStub(int length) : length_(length) {
ASSERT(length >= 0 && length <= kMaximumLength);
}
void Generate(MacroAssembler* masm);
private:
int length_;
const char* GetName() { return "FastCloneShallowArrayStub"; }
Major MajorKey() { return FastCloneShallowArray; }
int MinorKey() { return length_; }
};
class InstanceofStub: public CodeStub { class InstanceofStub: public CodeStub {
public: public:
InstanceofStub() { } InstanceofStub() { }
......
...@@ -2261,10 +2261,14 @@ Object* Heap::AllocateArgumentsObject(Object* callee, int length) { ...@@ -2261,10 +2261,14 @@ Object* Heap::AllocateArgumentsObject(Object* callee, int length) {
JSObject* boilerplate = JSObject* boilerplate =
Top::context()->global_context()->arguments_boilerplate(); Top::context()->global_context()->arguments_boilerplate();
// Make the clone. // Check that the size of the boilerplate matches our
Map* map = boilerplate->map(); // expectations. The ArgumentsAccessStub::GenerateNewObject relies
int object_size = map->instance_size(); // on the size being a known constant.
Object* result = AllocateRaw(object_size, NEW_SPACE, OLD_POINTER_SPACE); ASSERT(kArgumentsObjectSize == boilerplate->map()->instance_size());
// Do the allocation.
Object* result =
AllocateRaw(kArgumentsObjectSize, NEW_SPACE, OLD_POINTER_SPACE);
if (result->IsFailure()) return result; if (result->IsFailure()) return result;
// Copy the content. The arguments boilerplate doesn't have any // Copy the content. The arguments boilerplate doesn't have any
...@@ -2272,7 +2276,7 @@ Object* Heap::AllocateArgumentsObject(Object* callee, int length) { ...@@ -2272,7 +2276,7 @@ Object* Heap::AllocateArgumentsObject(Object* callee, int length) {
// barrier here. // barrier here.
CopyBlock(reinterpret_cast<Object**>(HeapObject::cast(result)->address()), CopyBlock(reinterpret_cast<Object**>(HeapObject::cast(result)->address()),
reinterpret_cast<Object**>(boilerplate->address()), reinterpret_cast<Object**>(boilerplate->address()),
object_size); kArgumentsObjectSize);
// Set the two properties. // Set the two properties.
JSObject::cast(result)->InObjectPropertyAtPut(arguments_callee_index, JSObject::cast(result)->InObjectPropertyAtPut(arguments_callee_index,
......
...@@ -491,6 +491,8 @@ class Heap : public AllStatic { ...@@ -491,6 +491,8 @@ class Heap : public AllStatic {
PretenureFlag pretenure = TENURED); PretenureFlag pretenure = TENURED);
// Indicies for direct access into argument objects. // Indicies for direct access into argument objects.
static const int kArgumentsObjectSize =
JSObject::kHeaderSize + 2 * kPointerSize;
static const int arguments_callee_index = 0; static const int arguments_callee_index = 0;
static const int arguments_length_index = 1; static const int arguments_length_index = 1;
......
...@@ -4320,18 +4320,23 @@ void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { ...@@ -4320,18 +4320,23 @@ void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
// Push the resulting array literal boilerplate on the stack. // Push the resulting array literal boilerplate on the stack.
frame_->Push(&boilerplate); frame_->Push(&boilerplate);
// Clone the boilerplate object. // Clone the boilerplate object.
Runtime::FunctionId clone_function_id = Runtime::kCloneLiteralBoilerplate; int length = node->values()->length();
if (node->depth() == 1) { Result clone;
clone_function_id = Runtime::kCloneShallowLiteralBoilerplate; if (node->depth() == 1 &&
length <= FastCloneShallowArrayStub::kMaximumLength) {
FastCloneShallowArrayStub stub(length);
clone = frame_->CallStub(&stub, 1);
} else {
clone = frame_->CallRuntime(Runtime::kCloneLiteralBoilerplate, 1);
} }
Result clone = frame_->CallRuntime(clone_function_id, 1);
// Push the newly cloned literal object as the result. // Push the newly cloned literal object as the result.
frame_->Push(&clone); frame_->Push(&clone);
// Generate code to set the elements in the array that are not // Generate code to set the elements in the array that are not
// literals. // literals.
for (int i = 0; i < node->values()->length(); i++) { for (int i = 0; i < length; i++) {
Expression* value = node->values()->at(i); Expression* value = node->values()->at(i);
// If value is a literal the property value is already set in the // If value is a literal the property value is already set in the
...@@ -6637,6 +6642,49 @@ void FastNewContextStub::Generate(MacroAssembler* masm) { ...@@ -6637,6 +6642,49 @@ void FastNewContextStub::Generate(MacroAssembler* masm) {
} }
void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) {
int elements_size = (length_ > 0) ? FixedArray::SizeFor(length_) : 0;
int size = JSArray::kSize + elements_size;
// Allocate both the JS array and the elements array in one big
// allocation. This avoid multiple limit checks.
Label gc;
__ AllocateInNewSpace(size, eax, ebx, ecx, &gc, TAG_OBJECT);
// Get the boilerplate from the stack.
__ mov(ecx, Operand(esp, 1 * kPointerSize));
// Copy the JS array part.
for (int i = 0; i < JSArray::kSize; i += kPointerSize) {
if ((i != JSArray::kElementsOffset) || (length_ == 0)) {
__ mov(ebx, FieldOperand(ecx, i));
__ mov(FieldOperand(eax, i), ebx);
}
}
if (length_ > 0) {
// Get hold of the elements array of the boilerplate and setup the
// elements pointer in the resulting object.
__ mov(ecx, FieldOperand(ecx, JSArray::kElementsOffset));
__ lea(edx, Operand(eax, JSArray::kSize));
__ mov(FieldOperand(eax, JSArray::kElementsOffset), edx);
// Copy the elements array.
for (int i = 0; i < elements_size; i += kPointerSize) {
__ mov(ebx, FieldOperand(ecx, i));
__ mov(FieldOperand(edx, i), ebx);
}
}
// Return and remove the on-stack parameter.
__ ret(1 * kPointerSize);
__ bind(&gc);
ExternalReference runtime(Runtime::kCloneShallowLiteralBoilerplate);
__ TailCallRuntime(runtime, 1, 1);
}
// NOTE: The stub does not handle the inlined cases (Smis, Booleans, undefined). // NOTE: The stub does not handle the inlined cases (Smis, Booleans, undefined).
void ToBooleanStub::Generate(MacroAssembler* masm) { void ToBooleanStub::Generate(MacroAssembler* masm) {
Label false_result, true_result, not_string; Label false_result, true_result, not_string;
...@@ -7549,18 +7597,90 @@ void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) { ...@@ -7549,18 +7597,90 @@ void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
static const int kDisplacement = 2 * kPointerSize; static const int kDisplacement = 2 * kPointerSize;
// Check if the calling frame is an arguments adaptor frame. // Check if the calling frame is an arguments adaptor frame.
Label runtime; Label adaptor_frame, try_allocate, runtime;
__ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
__ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset)); __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
__ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); __ cmp(Operand(ecx), Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
__ j(not_equal, &runtime); __ j(equal, &adaptor_frame);
// Get the length from the frame.
__ mov(ecx, Operand(esp, 1 * kPointerSize));
__ jmp(&try_allocate);
// Patch the arguments.length and the parameters pointer. // Patch the arguments.length and the parameters pointer.
__ bind(&adaptor_frame);
__ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
__ mov(Operand(esp, 1 * kPointerSize), ecx); __ mov(Operand(esp, 1 * kPointerSize), ecx);
__ lea(edx, Operand(edx, ecx, times_2, kDisplacement)); __ lea(edx, Operand(edx, ecx, times_2, kDisplacement));
__ mov(Operand(esp, 2 * kPointerSize), edx); __ mov(Operand(esp, 2 * kPointerSize), edx);
// Try the new space allocation. Start out with computing the size of
// the arguments object and the elements array.
Label add_arguments_object;
__ bind(&try_allocate);
__ test(ecx, Operand(ecx));
__ j(zero, &add_arguments_object);
__ lea(ecx, Operand(ecx, times_2, FixedArray::kHeaderSize));
__ bind(&add_arguments_object);
__ add(Operand(ecx), Immediate(Heap::kArgumentsObjectSize));
// Do the allocation of both objects in one go.
__ AllocateInNewSpace(ecx, eax, edx, ebx, &runtime, TAG_OBJECT);
// Get the arguments boilerplate from the current (global) context.
int offset = Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX);
__ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
__ mov(edi, FieldOperand(edi, GlobalObject::kGlobalContextOffset));
__ mov(edi, Operand(edi, offset));
// Copy the JS object part.
for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) {
__ mov(ebx, FieldOperand(edi, i));
__ mov(FieldOperand(eax, i), ebx);
}
// Setup the callee in-object property.
ASSERT(Heap::arguments_callee_index == 0);
__ mov(ebx, Operand(esp, 3 * kPointerSize));
__ mov(FieldOperand(eax, JSObject::kHeaderSize), ebx);
// Get the length (smi tagged) and set that as an in-object property too.
ASSERT(Heap::arguments_length_index == 1);
__ mov(ecx, Operand(esp, 1 * kPointerSize));
__ mov(FieldOperand(eax, JSObject::kHeaderSize + kPointerSize), ecx);
// If there are no actual arguments, we're done.
Label done;
__ test(ecx, Operand(ecx));
__ j(zero, &done);
// Get the parameters pointer from the stack and untag the length.
__ mov(edx, Operand(esp, 2 * kPointerSize));
__ sar(ecx, kSmiTagSize);
// Setup the elements pointer in the allocated arguments object and
// initialize the header in the elements fixed array.
__ lea(edi, Operand(eax, Heap::kArgumentsObjectSize));
__ mov(FieldOperand(eax, JSObject::kElementsOffset), edi);
__ mov(FieldOperand(edi, FixedArray::kMapOffset),
Immediate(Factory::fixed_array_map()));
__ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx);
// Copy the fixed array slots.
Label loop;
__ bind(&loop);
__ mov(ebx, Operand(edx, -1 * kPointerSize)); // Skip receiver.
__ mov(FieldOperand(edi, FixedArray::kHeaderSize), ebx);
__ add(Operand(edi), Immediate(kPointerSize));
__ sub(Operand(edx), Immediate(kPointerSize));
__ dec(ecx);
__ test(ecx, Operand(ecx));
__ j(not_zero, &loop);
// Return and remove the on-stack parameters.
__ bind(&done);
__ ret(3 * kPointerSize);
// Do the runtime call to allocate the arguments object. // Do the runtime call to allocate the arguments object.
__ bind(&runtime); __ bind(&runtime);
__ TailCallRuntime(ExternalReference(Runtime::kNewArgumentsFast), 3, 1); __ TailCallRuntime(ExternalReference(Runtime::kNewArgumentsFast), 3, 1);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment