Refactor the arguments access code to make it easier to read.
Review URL: http://codereview.chromium.org/6491 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@442 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
bc66e45c53
commit
892b0cac3c
@ -4403,102 +4403,96 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
|
||||
}
|
||||
|
||||
|
||||
void ArgumentsAccessStub::Generate(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- r0: formal number of parameters for the calling function
|
||||
// -- r1: key (if value access)
|
||||
// -- lr: return address
|
||||
// -----------------------------------
|
||||
|
||||
// If we're reading an element we need to check that the key is a smi.
|
||||
Label slow;
|
||||
if (type_ == READ_ELEMENT) {
|
||||
__ tst(r1, Operand(kSmiTagMask));
|
||||
__ b(ne, &slow);
|
||||
}
|
||||
|
||||
void ArgumentsAccessStub::GenerateReadLength(MacroAssembler* masm) {
|
||||
// Check if the calling frame is an arguments adaptor frame.
|
||||
// r0: formal number of parameters
|
||||
// r1: key (if access)
|
||||
Label adaptor;
|
||||
__ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
|
||||
__ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset));
|
||||
__ cmp(r3, Operand(ArgumentsAdaptorFrame::SENTINEL));
|
||||
if (type_ == NEW_OBJECT) {
|
||||
__ b(ne, &slow);
|
||||
} else {
|
||||
__ b(eq, &adaptor);
|
||||
}
|
||||
__ b(eq, &adaptor);
|
||||
|
||||
static const int kParamDisplacement =
|
||||
// Nothing to do: The formal number of parameters has already been
|
||||
// passed in register r0 by calling function. Just return it.
|
||||
__ mov(pc, lr);
|
||||
|
||||
// Arguments adaptor case: Read the arguments length from the
|
||||
// adaptor frame and return it.
|
||||
__ bind(&adaptor);
|
||||
__ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||
__ mov(pc, lr);
|
||||
}
|
||||
|
||||
|
||||
void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
|
||||
// The displacement is the offset of the last parameter (if any)
|
||||
// relative to the frame pointer.
|
||||
static const int kDisplacement =
|
||||
StandardFrameConstants::kCallerSPOffset - kPointerSize;
|
||||
|
||||
if (type_ == READ_LENGTH) {
|
||||
// Nothing to do: The formal number of parameters has already been
|
||||
// passed in register r0 by calling function. Just return it.
|
||||
__ mov(pc, lr);
|
||||
} else if (type_ == READ_ELEMENT) {
|
||||
// Check index against formal parameter count. Use unsigned comparison to
|
||||
// get the negative check for free.
|
||||
// r0: formal number of parameters
|
||||
// r1: index
|
||||
__ cmp(r1, r0);
|
||||
__ b(cs, &slow);
|
||||
// Check that the key is a smi.
|
||||
Label slow;
|
||||
__ tst(r1, Operand(kSmiTagMask));
|
||||
__ b(ne, &slow);
|
||||
|
||||
// Read the argument from the current frame and return it.
|
||||
__ sub(r3, r0, r1);
|
||||
__ add(r3, fp, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize));
|
||||
__ ldr(r0, MemOperand(r3, kParamDisplacement));
|
||||
__ mov(pc, lr);
|
||||
} else {
|
||||
ASSERT(type_ == NEW_OBJECT);
|
||||
// Do nothing here.
|
||||
}
|
||||
// Check if the calling frame is an arguments adaptor frame.
|
||||
Label adaptor;
|
||||
__ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
|
||||
__ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset));
|
||||
__ cmp(r3, Operand(ArgumentsAdaptorFrame::SENTINEL));
|
||||
__ b(eq, &adaptor);
|
||||
|
||||
// An arguments adaptor frame is present. Find the length or the actual
|
||||
// argument in the calling frame.
|
||||
// r0: formal number of parameters
|
||||
// r1: key
|
||||
// r2: adaptor frame pointer
|
||||
// Check index against formal parameters count limit passed in
|
||||
// through register eax. Use unsigned comparison to get negative
|
||||
// check for free.
|
||||
__ cmp(r1, r0);
|
||||
__ b(cs, &slow);
|
||||
|
||||
// Read the argument from the stack and return it.
|
||||
__ sub(r3, r0, r1);
|
||||
__ add(r3, fp, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize));
|
||||
__ ldr(r0, MemOperand(r3, kDisplacement));
|
||||
__ mov(pc, lr);
|
||||
|
||||
// Arguments adaptor case: Check index against actual arguments
|
||||
// limit found in the arguments adaptor frame. Use unsigned
|
||||
// comparison to get negative check for free.
|
||||
__ bind(&adaptor);
|
||||
// Read the arguments length from the adaptor frame. This is the result if
|
||||
// only accessing the length, otherwise it is used in accessing the value
|
||||
__ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||
__ cmp(r1, r0);
|
||||
__ b(cs, &slow);
|
||||
|
||||
if (type_ == READ_LENGTH) {
|
||||
// Return the length in r0.
|
||||
__ mov(pc, lr);
|
||||
} else if (type_ == READ_ELEMENT) {
|
||||
// Check index against actual arguments count. Use unsigned comparison to
|
||||
// get the negative check for free.
|
||||
// r0: actual number of parameter
|
||||
// r1: index
|
||||
// r2: adaptor frame point
|
||||
__ cmp(r1, r0);
|
||||
__ b(cs, &slow);
|
||||
// Read the argument from the adaptor frame and return it.
|
||||
__ sub(r3, r0, r1);
|
||||
__ add(r3, r2, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize));
|
||||
__ ldr(r0, MemOperand(r3, kDisplacement));
|
||||
__ mov(pc, lr);
|
||||
|
||||
// Read the argument from the adaptor frame and return it.
|
||||
__ sub(r3, r0, r1);
|
||||
__ add(r3, r2, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize));
|
||||
__ ldr(r0, MemOperand(r3, kParamDisplacement));
|
||||
__ mov(pc, lr);
|
||||
} else {
|
||||
ASSERT(type_ == NEW_OBJECT);
|
||||
// Patch the arguments.length and the parameters pointer.
|
||||
__ str(r0, MemOperand(sp, 0 * kPointerSize));
|
||||
__ add(r3, r2, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize));
|
||||
__ add(r3, r3, Operand(kParamDisplacement + 1 * kPointerSize));
|
||||
__ str(r3, MemOperand(sp, 1 * kPointerSize));
|
||||
__ bind(&slow);
|
||||
__ TailCallRuntime(ExternalReference(Runtime::kNewArgumentsFast), 3);
|
||||
}
|
||||
// Slow-case: Handle non-smi or out-of-bounds access to arguments
|
||||
// by calling the runtime system.
|
||||
__ bind(&slow);
|
||||
__ push(r1);
|
||||
__ TailCallRuntime(ExternalReference(Runtime::kGetArgumentsProperty), 1);
|
||||
}
|
||||
|
||||
// Return to the calling function.
|
||||
if (type_ == READ_ELEMENT) {
|
||||
__ bind(&slow);
|
||||
__ push(r1);
|
||||
__ TailCallRuntime(ExternalReference(Runtime::kGetArgumentsProperty), 1);
|
||||
}
|
||||
|
||||
void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
|
||||
// Check if the calling frame is an arguments adaptor frame.
|
||||
Label runtime;
|
||||
__ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
|
||||
__ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset));
|
||||
__ cmp(r3, Operand(ArgumentsAdaptorFrame::SENTINEL));
|
||||
__ b(ne, &runtime);
|
||||
|
||||
// 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));
|
||||
__ add(r3, r3, Operand(StandardFrameConstants::kCallerSPOffset));
|
||||
__ str(r3, MemOperand(sp, 1 * kPointerSize));
|
||||
|
||||
// Do the runtime call to allocate the arguments object.
|
||||
__ bind(&runtime);
|
||||
__ TailCallRuntime(ExternalReference(Runtime::kNewArgumentsFast), 3);
|
||||
}
|
||||
|
||||
|
||||
|
@ -4795,90 +4795,102 @@ void UnarySubStub::Generate(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
|
||||
void ArgumentsAccessStub::Generate(MacroAssembler* masm) {
|
||||
// If we're reading an element we need to check that the key is a smi.
|
||||
void ArgumentsAccessStub::GenerateReadLength(MacroAssembler* masm) {
|
||||
// Check if the calling frame is an arguments adaptor frame.
|
||||
Label adaptor;
|
||||
__ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
|
||||
__ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
|
||||
__ cmp(ecx, ArgumentsAdaptorFrame::SENTINEL);
|
||||
__ j(equal, &adaptor);
|
||||
|
||||
// Nothing to do: The formal number of parameters has already been
|
||||
// passed in register eax by calling function. Just return it.
|
||||
__ ret(0);
|
||||
|
||||
// Arguments adaptor case: Read the arguments length from the
|
||||
// adaptor frame and return it.
|
||||
__ bind(&adaptor);
|
||||
__ mov(eax, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||
__ ret(0);
|
||||
}
|
||||
|
||||
|
||||
void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
|
||||
// The displacement is used for skipping 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 = 1 * kPointerSize;
|
||||
|
||||
// Check that the key is a smi.
|
||||
Label slow;
|
||||
if (type_ == READ_ELEMENT) {
|
||||
__ mov(ebx, Operand(esp, 1 * kPointerSize)); // skip return address
|
||||
__ test(ebx, Immediate(kSmiTagMask));
|
||||
__ j(not_zero, &slow, not_taken);
|
||||
}
|
||||
__ mov(ebx, Operand(esp, 1 * kPointerSize)); // skip return address
|
||||
__ test(ebx, Immediate(kSmiTagMask));
|
||||
__ j(not_zero, &slow, not_taken);
|
||||
|
||||
// Check if the calling frame is an arguments adaptor frame.
|
||||
Label adaptor;
|
||||
__ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
|
||||
__ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
|
||||
__ cmp(ecx, ArgumentsAdaptorFrame::SENTINEL);
|
||||
if (type_ == NEW_OBJECT) {
|
||||
__ j(not_equal, &slow);
|
||||
} else {
|
||||
__ j(equal, &adaptor);
|
||||
}
|
||||
__ j(equal, &adaptor);
|
||||
|
||||
// The displacement is used for skipping the return address on the
|
||||
// stack. It is the offset of the last parameter (if any) relative
|
||||
// to the frame pointer.
|
||||
static const int kDisplacement = 1 * kPointerSize;
|
||||
// Check index against formal parameters count limit passed in
|
||||
// through register eax. Use unsigned comparison to get negative
|
||||
// check for free.
|
||||
__ cmp(ebx, Operand(eax));
|
||||
__ j(above_equal, &slow, not_taken);
|
||||
|
||||
// Read the argument from the stack and return it.
|
||||
ASSERT(kSmiTagSize == 1 && kSmiTag == 0); // shifting code depends on this
|
||||
__ lea(edx, Operand(ebp, eax, times_2, 0));
|
||||
__ neg(ebx);
|
||||
__ mov(eax, Operand(edx, ebx, times_2, kDisplacement));
|
||||
__ ret(0);
|
||||
|
||||
if (type_ == READ_LENGTH) {
|
||||
// Nothing to do: The formal number of parameters has already been
|
||||
// passed in register eax by calling function. Just return it.
|
||||
__ ret(0);
|
||||
} else if (type_ == READ_ELEMENT) {
|
||||
// Check index against formal parameters count limit passed in
|
||||
// through register eax. Use unsigned comparison to get negative
|
||||
// check for free.
|
||||
__ cmp(ebx, Operand(eax));
|
||||
__ j(above_equal, &slow, not_taken);
|
||||
|
||||
// Read the argument from the stack and return it.
|
||||
__ lea(edx, Operand(ebp, eax, times_2, 0));
|
||||
__ neg(ebx);
|
||||
__ mov(eax, Operand(edx, ebx, times_2, kDisplacement));
|
||||
__ ret(0);
|
||||
} else {
|
||||
ASSERT(type_ == NEW_OBJECT);
|
||||
// Do nothing here.
|
||||
}
|
||||
|
||||
// Arguments adaptor case: Find the length or the actual argument in
|
||||
// the calling frame.
|
||||
// Arguments adaptor case: Check index against actual arguments
|
||||
// limit found in the arguments adaptor frame. Use unsigned
|
||||
// comparison to get negative check for free.
|
||||
__ bind(&adaptor);
|
||||
if (type_ == READ_LENGTH) {
|
||||
// Read the arguments length from the adaptor frame and return it.
|
||||
__ mov(eax, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||
__ ret(0);
|
||||
} else if (type_ == READ_ELEMENT) {
|
||||
// Check index against actual arguments limit found in the
|
||||
// arguments adaptor frame. Use unsigned comparison to get
|
||||
// negative check for free.
|
||||
__ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||
__ cmp(ebx, Operand(ecx));
|
||||
__ j(above_equal, &slow, not_taken);
|
||||
__ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||
__ cmp(ebx, Operand(ecx));
|
||||
__ j(above_equal, &slow, not_taken);
|
||||
|
||||
// Read the argument from the stack and return it.
|
||||
__ lea(edx, Operand(edx, ecx, times_2, 0));
|
||||
__ neg(ebx);
|
||||
__ mov(eax, Operand(edx, ebx, times_2, kDisplacement));
|
||||
__ ret(0);
|
||||
} else {
|
||||
ASSERT(type_ == NEW_OBJECT);
|
||||
// Patch the arguments.length and the parameters pointer.
|
||||
__ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||
__ mov(Operand(esp, 1 * kPointerSize), ecx);
|
||||
__ lea(edx, Operand(edx, ecx, times_2, kDisplacement + 1 * kPointerSize));
|
||||
__ mov(Operand(esp, 2 * kPointerSize), edx);
|
||||
__ bind(&slow);
|
||||
__ TailCallRuntime(ExternalReference(Runtime::kNewArgumentsFast), 3);
|
||||
}
|
||||
// Read the argument from the stack and return it.
|
||||
ASSERT(kSmiTagSize == 1 && kSmiTag == 0); // shifting code depends on this
|
||||
__ lea(edx, Operand(edx, ecx, times_2, 0));
|
||||
__ neg(ebx);
|
||||
__ mov(eax, Operand(edx, ebx, times_2, kDisplacement));
|
||||
__ ret(0);
|
||||
|
||||
// Slow-case: Handle non-smi or out-of-bounds access to arguments
|
||||
// by calling the runtime system.
|
||||
if (type_ == READ_ELEMENT) {
|
||||
__ bind(&slow);
|
||||
__ TailCallRuntime(ExternalReference(Runtime::kGetArgumentsProperty), 1);
|
||||
}
|
||||
__ bind(&slow);
|
||||
__ TailCallRuntime(ExternalReference(Runtime::kGetArgumentsProperty), 1);
|
||||
}
|
||||
|
||||
|
||||
void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
|
||||
// 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;
|
||||
__ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
|
||||
__ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
|
||||
__ cmp(ecx, ArgumentsAdaptorFrame::SENTINEL);
|
||||
__ j(not_equal, &runtime);
|
||||
|
||||
// Patch the arguments.length and the parameters pointer.
|
||||
__ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||
__ mov(Operand(esp, 1 * kPointerSize), ecx);
|
||||
__ lea(edx, Operand(edx, ecx, times_2, kDisplacement));
|
||||
__ mov(Operand(esp, 2 * kPointerSize), edx);
|
||||
|
||||
// Do the runtime call to allocate the arguments object.
|
||||
__ bind(&runtime);
|
||||
__ TailCallRuntime(ExternalReference(Runtime::kNewArgumentsFast), 3);
|
||||
}
|
||||
|
||||
|
||||
|
@ -362,4 +362,13 @@ void RuntimeStub::Generate(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
|
||||
void ArgumentsAccessStub::Generate(MacroAssembler* masm) {
|
||||
switch (type_) {
|
||||
case READ_LENGTH: GenerateReadLength(masm); break;
|
||||
case READ_ELEMENT: GenerateReadElement(masm); break;
|
||||
case NEW_OBJECT: GenerateNewObject(masm); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
@ -357,7 +357,11 @@ class ArgumentsAccessStub: public CodeStub {
|
||||
|
||||
Major MajorKey() { return ArgumentsAccess; }
|
||||
int MinorKey() { return type_; }
|
||||
|
||||
void Generate(MacroAssembler* masm);
|
||||
void GenerateReadLength(MacroAssembler* masm);
|
||||
void GenerateReadElement(MacroAssembler* masm);
|
||||
void GenerateNewObject(MacroAssembler* masm);
|
||||
|
||||
const char* GetName() { return "ArgumentsAccessStub"; }
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user