Index: src/x64/codegen-x64.cc |
=================================================================== |
--- src/x64/codegen-x64.cc (revision 3863) |
+++ src/x64/codegen-x64.cc (working copy) |
@@ -7401,30 +7401,107 @@ |
void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) { |
+ // rsp[0] : return address |
+ // rsp[8] : number of parameters |
+ // rsp[16] : receiver displacement |
+ // rsp[24] : function |
+ |
// The displacement is used for skipping the return address and the |
// frame pointer on the stack. It is the offset of the last |
// parameter (if any) relative to the frame pointer. |
static const int kDisplacement = 2 * kPointerSize; |
// Check if the calling frame is an arguments adaptor frame. |
- Label runtime; |
+ Label adaptor_frame, try_allocate, runtime; |
__ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); |
__ SmiCompare(Operand(rdx, StandardFrameConstants::kContextOffset), |
Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); |
- __ j(not_equal, &runtime); |
- // Value in rcx is Smi encoded. |
+ __ j(equal, &adaptor_frame); |
+ // Get the length from the frame. |
+ __ movq(rcx, Operand(rsp, 1 * kPointerSize)); |
+ __ jmp(&try_allocate); |
+ |
// Patch the arguments.length and the parameters pointer. |
+ __ bind(&adaptor_frame); |
__ movq(rcx, Operand(rdx, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
__ movq(Operand(rsp, 1 * kPointerSize), rcx); |
- SmiIndex index = masm->SmiToIndex(rcx, rcx, kPointerSizeLog2); |
+ // Do not clobber the length index for the indexing operation since |
+ // it is used compute the size for allocation later. |
+ SmiIndex index = masm->SmiToIndex(rbx, rcx, kPointerSizeLog2); |
__ lea(rdx, Operand(rdx, index.reg, index.scale, kDisplacement)); |
__ movq(Operand(rsp, 2 * kPointerSize), rdx); |
+ // 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); |
+ __ testq(rcx, rcx); |
+ __ j(zero, &add_arguments_object); |
+ index = masm->SmiToIndex(rcx, rcx, kPointerSizeLog2); |
+ __ lea(rcx, Operand(index.reg, index.scale, FixedArray::kHeaderSize)); |
+ __ bind(&add_arguments_object); |
+ __ addq(rcx, Immediate(Heap::kArgumentsObjectSize)); |
+ |
+ // Do the allocation of both objects in one go. |
+ __ AllocateInNewSpace(rcx, rax, rdx, rbx, &runtime, TAG_OBJECT); |
+ |
+ // Get the arguments boilerplate from the current (global) context. |
+ int offset = Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX); |
+ __ movq(rdi, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX))); |
+ __ movq(rdi, FieldOperand(rdi, GlobalObject::kGlobalContextOffset)); |
+ __ movq(rdi, Operand(rdi, offset)); |
+ |
+ // Copy the JS object part. |
+ for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) { |
+ __ movq(kScratchRegister, FieldOperand(rdi, i)); |
+ __ movq(FieldOperand(rax, i), kScratchRegister); |
+ } |
+ |
+ // Setup the callee in-object property. |
+ ASSERT(Heap::arguments_callee_index == 0); |
+ __ movq(kScratchRegister, Operand(rsp, 3 * kPointerSize)); |
+ __ movq(FieldOperand(rax, JSObject::kHeaderSize), kScratchRegister); |
+ |
+ // Get the length (smi tagged) and set that as an in-object property too. |
+ ASSERT(Heap::arguments_length_index == 1); |
+ __ movq(rcx, Operand(rsp, 1 * kPointerSize)); |
+ __ movq(FieldOperand(rax, JSObject::kHeaderSize + kPointerSize), rcx); |
+ |
+ // If there are no actual arguments, we're done. |
+ Label done; |
+ __ testq(rcx, rcx); |
+ __ j(zero, &done); |
+ |
+ // Get the parameters pointer from the stack and untag the length. |
+ __ movq(rdx, Operand(rsp, 2 * kPointerSize)); |
+ __ SmiToInteger32(rcx, rcx); |
+ |
+ // Setup the elements pointer in the allocated arguments object and |
+ // initialize the header in the elements fixed array. |
+ __ lea(rdi, Operand(rax, Heap::kArgumentsObjectSize)); |
+ __ movq(FieldOperand(rax, JSObject::kElementsOffset), rdi); |
+ __ LoadRoot(kScratchRegister, Heap::kFixedArrayMapRootIndex); |
+ __ movq(FieldOperand(rdi, FixedArray::kMapOffset), kScratchRegister); |
+ __ movq(FieldOperand(rdi, FixedArray::kLengthOffset), rcx); |
+ |
+ // Copy the fixed array slots. |
+ Label loop; |
+ __ bind(&loop); |
+ __ movq(kScratchRegister, Operand(rdx, -1 * kPointerSize)); // Skip receiver. |
+ __ movq(FieldOperand(rdi, FixedArray::kHeaderSize), kScratchRegister); |
+ __ addq(rdi, Immediate(kPointerSize)); |
+ __ subq(rdx, Immediate(kPointerSize)); |
+ __ decq(rcx); |
+ __ 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. |
__ bind(&runtime); |
- Runtime::Function* f = Runtime::FunctionForId(Runtime::kNewArgumentsFast); |
- __ TailCallRuntime(ExternalReference(f), 3, f->result_size); |
+ __ TailCallRuntime(ExternalReference(Runtime::kNewArgumentsFast), 3, 1); |
} |