Commit 51b5df38 authored by ager@chromium.org's avatar ager@chromium.org

Port arguments object allocation in generated code to ARM and x64.

BUG=v8:611
Review URL: http://codereview.chromium.org/605024

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3867 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 0630b1fd
......@@ -4486,7 +4486,7 @@ void FastNewContextStub::Generate(MacroAssembler* masm) {
TAG_OBJECT);
// Load the function from the stack.
__ ldr(r3, MemOperand(sp, 0 * kPointerSize));
__ ldr(r3, MemOperand(sp, 0));
// Setup the object header.
__ LoadRoot(r2, Heap::kContextMapRootIndex);
......@@ -6653,7 +6653,7 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
__ b(gt, &slow);
// Get the prototype of the function (r4 is result, r2 is scratch).
__ ldr(r1, MemOperand(sp, 0 * kPointerSize));
__ ldr(r1, MemOperand(sp, 0));
__ TryGetFunctionPrototype(r1, r4, r2, &slow);
// Check that the function prototype is a JS object.
......@@ -6768,20 +6768,102 @@ void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
// sp[0] : number of parameters
// sp[4] : receiver displacement
// sp[8] : function
// Check if the calling frame is an arguments adaptor frame.
Label runtime;
Label adaptor_frame, try_allocate, runtime;
__ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
__ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset));
__ cmp(r3, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
__ b(ne, &runtime);
__ b(eq, &adaptor_frame);
// Get the length from the frame.
__ ldr(r1, MemOperand(sp, 0));
__ b(&try_allocate);
// Patch the arguments.length and the parameters pointer.
__ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset));
__ str(r0, MemOperand(sp, 0 * kPointerSize));
__ add(r3, r2, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize));
__ bind(&adaptor_frame);
__ ldr(r1, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset));
__ str(r1, MemOperand(sp, 0));
__ add(r3, r2, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize));
__ add(r3, r3, Operand(StandardFrameConstants::kCallerSPOffset));
__ str(r3, MemOperand(sp, 1 * kPointerSize));
// Try the new space allocation. Start out with computing the size
// of the arguments object and the elements array (in words, not
// bytes because AllocateInNewSpace expects words).
Label add_arguments_object;
__ bind(&try_allocate);
__ cmp(r1, Operand(0));
__ b(eq, &add_arguments_object);
__ mov(r1, Operand(r1, LSR, kSmiTagSize));
__ add(r1, r1, Operand(FixedArray::kHeaderSize / kPointerSize));
__ bind(&add_arguments_object);
__ add(r1, r1, Operand(Heap::kArgumentsObjectSize / kPointerSize));
// Do the allocation of both objects in one go.
__ AllocateInNewSpace(r1, r0, r2, r3, &runtime, TAG_OBJECT);
// Get the arguments boilerplate from the current (global) context.
int offset = Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX);
__ ldr(r4, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
__ ldr(r4, FieldMemOperand(r4, GlobalObject::kGlobalContextOffset));
__ ldr(r4, MemOperand(r4, offset));
// Copy the JS object part.
for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) {
__ ldr(r3, FieldMemOperand(r4, i));
__ str(r3, FieldMemOperand(r0, i));
}
// Setup the callee in-object property.
ASSERT(Heap::arguments_callee_index == 0);
__ ldr(r3, MemOperand(sp, 2 * kPointerSize));
__ str(r3, FieldMemOperand(r0, JSObject::kHeaderSize));
// Get the length (smi tagged) and set that as an in-object property too.
ASSERT(Heap::arguments_length_index == 1);
__ ldr(r1, MemOperand(sp, 0 * kPointerSize));
__ str(r1, FieldMemOperand(r0, JSObject::kHeaderSize + kPointerSize));
// If there are no actual arguments, we're done.
Label done;
__ cmp(r1, Operand(0));
__ b(eq, &done);
// Get the parameters pointer from the stack and untag the length.
__ ldr(r2, MemOperand(sp, 1 * kPointerSize));
__ mov(r1, Operand(r1, LSR, kSmiTagSize));
// Setup the elements pointer in the allocated arguments object and
// initialize the header in the elements fixed array.
__ add(r4, r0, Operand(Heap::kArgumentsObjectSize));
__ str(r4, FieldMemOperand(r0, JSObject::kElementsOffset));
__ LoadRoot(r3, Heap::kFixedArrayMapRootIndex);
__ str(r3, FieldMemOperand(r4, FixedArray::kMapOffset));
__ str(r1, FieldMemOperand(r4, FixedArray::kLengthOffset));
// Copy the fixed array slots.
Label loop;
// Setup r4 to point to the first array slot.
__ add(r4, r4, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
__ bind(&loop);
// Pre-decrement r2 with kPointerSize on each iteration.
// Pre-decrement in order to skip receiver.
__ ldr(r3, MemOperand(r2, kPointerSize, NegPreIndex));
// Post-increment r4 with kPointerSize on each iteration.
__ str(r3, MemOperand(r4, kPointerSize, PostIndex));
__ sub(r1, r1, Operand(1));
__ cmp(r1, Operand(0));
__ b(ne, &loop);
// Return and remove the on-stack parameters.
__ bind(&done);
__ add(sp, sp, Operand(3 * kPointerSize));
__ Ret();
// Do the runtime call to allocate the arguments object.
__ bind(&runtime);
__ TailCallRuntime(ExternalReference(Runtime::kNewArgumentsFast), 3, 1);
......
......@@ -8503,6 +8503,11 @@ void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
// esp[0] : return address
// esp[4] : number of parameters
// esp[8] : receiver displacement
// esp[16] : 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.
......@@ -8586,7 +8591,6 @@ void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
__ 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.
......
......@@ -224,7 +224,7 @@ void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
// -----------------------------------------------------------------------------
// Implementation of Operand
Operand::Operand(Register base, int32_t disp): rex_(0) {
Operand::Operand(Register base, int32_t disp) : rex_(0) {
len_ = 1;
if (base.is(rsp) || base.is(r12)) {
// SIB byte is needed to encode (rsp + offset) or (r12 + offset).
......@@ -246,7 +246,7 @@ Operand::Operand(Register base, int32_t disp): rex_(0) {
Operand::Operand(Register base,
Register index,
ScaleFactor scale,
int32_t disp): rex_(0) {
int32_t disp) : rex_(0) {
ASSERT(!index.is(rsp));
len_ = 1;
set_sib(scale, index, base);
......@@ -264,6 +264,17 @@ Operand::Operand(Register base,
}
Operand::Operand(Register index,
ScaleFactor scale,
int32_t disp) : rex_(0) {
ASSERT(!index.is(rsp));
len_ = 1;
set_modrm(0, rsp);
set_sib(scale, index, rbp);
set_disp32(disp);
}
// -----------------------------------------------------------------------------
// Implementation of Assembler.
......
......@@ -7412,30 +7412,107 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
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);
}
......
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