[asm] Add StackArgumentsAccessor to ia32

This add StackArgumentsAccessor class to ia32, which slighty increases
abstraction when accessing arguments in the stack.

Bug: v8:10201
Change-Id: I4ee0323022d9334cb0b2af63a9c1f437eed9a079
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2073762
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Commit-Queue: Victor Gomes <victorgomes@chromium.org>
Auto-Submit: Victor Gomes <victorgomes@chromium.org>
Cr-Commit-Position: refs/heads/master@{#66518}
This commit is contained in:
Victor Gomes 2020-02-27 12:43:33 +01:00 committed by Commit Bot
parent 5f5bcace28
commit 7750311321
6 changed files with 146 additions and 120 deletions

View File

@ -1599,9 +1599,10 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : argc
// -- esp[0] : return address
// -- esp[4] : argArray
// -- esp[8] : thisArg
// -- esp[12] : receiver
// The order of args depends on V8_REVERSE_JSARGS
// -- args[0] : receiver
// -- args[1] : thisArg
// -- args[2] : argArray
// -----------------------------------
// 1. Load receiver into xmm0, argArray into edx (if present), remove all
@ -1609,20 +1610,19 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
// present) instead.
{
Label no_arg_array, no_this_arg;
StackArgumentsAccessor args(eax);
// Spill receiver to allow the usage of edi as a scratch register.
__ movd(xmm0,
Operand(esp, eax, times_system_pointer_size, kSystemPointerSize));
__ movd(xmm0, args[0]);
__ LoadRoot(edx, RootIndex::kUndefinedValue);
__ mov(edi, edx);
__ test(eax, eax);
__ j(zero, &no_this_arg, Label::kNear);
{
__ mov(edi, Operand(esp, eax, times_system_pointer_size, 0));
__ mov(edi, args[1]);
__ cmp(eax, Immediate(1));
__ j(equal, &no_arg_array, Label::kNear);
__ mov(edx,
Operand(esp, eax, times_system_pointer_size, -kSystemPointerSize));
__ mov(edx, args[2]);
__ bind(&no_arg_array);
}
__ bind(&no_this_arg);
@ -1690,7 +1690,10 @@ void Builtins::Generate_FunctionPrototypeCall(MacroAssembler* masm) {
}
// 2. Get the callable to call (passed as receiver) from the stack.
__ mov(edi, Operand(esp, eax, times_system_pointer_size, kSystemPointerSize));
{
StackArgumentsAccessor args(eax);
__ mov(edi, args.GetReceiverOperand());
}
// 3. Shift arguments and return address one slot down on the stack
// (overwriting the original receiver). Adjust argument count to make
@ -1716,10 +1719,11 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : argc
// -- esp[0] : return address
// -- esp[4] : argumentsList
// -- esp[8] : thisArgument
// -- esp[12] : target
// -- esp[16] : receiver
// The order of args depends on V8_REVERSE_JSARGS
// -- args[0] : receiver
// -- args[1] : target
// -- args[2] : thisArgument
// -- args[3] : argumentsList
// -----------------------------------
// 1. Load target into edi (if present), argumentsList into edx (if present),
@ -1727,20 +1731,18 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
// thisArgument (if present) instead.
{
Label done;
StackArgumentsAccessor args(eax);
__ LoadRoot(edi, RootIndex::kUndefinedValue);
__ mov(edx, edi);
__ mov(ecx, edi);
__ cmp(eax, Immediate(1));
__ j(below, &done, Label::kNear);
__ mov(edi, Operand(esp, eax, times_system_pointer_size,
-0 * kSystemPointerSize));
__ mov(edi, args[1]); // target
__ j(equal, &done, Label::kNear);
__ mov(ecx, Operand(esp, eax, times_system_pointer_size,
-1 * kSystemPointerSize));
__ mov(ecx, args[2]); // thisArgument
__ cmp(eax, Immediate(3));
__ j(below, &done, Label::kNear);
__ mov(edx, Operand(esp, eax, times_system_pointer_size,
-2 * kSystemPointerSize));
__ mov(edx, args[3]); // argumentsList
__ bind(&done);
// Spill argumentsList to use edx as a scratch register.
@ -1776,10 +1778,11 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : argc
// -- esp[0] : return address
// -- esp[4] : new.target (optional)
// -- esp[8] : argumentsList
// -- esp[12] : target
// -- esp[16] : receiver
// The order of args depends on V8_REVERSE_JSARGS
// -- args[0] : receiver
// -- args[1] : target
// -- args[2] : argumentsList
// -- args[3] : new.target (optional)
// -----------------------------------
// 1. Load target into edi (if present), argumentsList into ecx (if present),
@ -1788,21 +1791,19 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
// (if present) instead.
{
Label done;
StackArgumentsAccessor args(eax);
__ LoadRoot(edi, RootIndex::kUndefinedValue);
__ mov(edx, edi);
__ mov(ecx, edi);
__ cmp(eax, Immediate(1));
__ j(below, &done, Label::kNear);
__ mov(edi, Operand(esp, eax, times_system_pointer_size,
-0 * kSystemPointerSize));
__ mov(edi, args[1]); // target
__ mov(edx, edi);
__ j(equal, &done, Label::kNear);
__ mov(ecx, Operand(esp, eax, times_system_pointer_size,
-1 * kSystemPointerSize));
__ mov(ecx, args[2]); // argumentsList
__ cmp(eax, Immediate(3));
__ j(below, &done, Label::kNear);
__ mov(edx, Operand(esp, eax, times_system_pointer_size,
-2 * kSystemPointerSize));
__ mov(edx, args[3]); // new.target
__ bind(&done);
// Spill argumentsList to use ecx as a scratch register.
@ -2064,6 +2065,7 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm,
// -- eax : the number of arguments (not including the receiver)
// -- edi : the function to call (checked to be a JSFunction)
// -----------------------------------
StackArgumentsAccessor args(eax);
__ AssertFunction(edi);
// See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList)
@ -2097,15 +2099,13 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm,
__ LoadGlobalProxy(ecx);
} else {
Label convert_to_object, convert_receiver;
__ mov(ecx,
Operand(esp, eax, times_system_pointer_size, kSystemPointerSize));
__ mov(ecx, args.GetReceiverOperand());
__ JumpIfSmi(ecx, &convert_to_object, Label::kNear);
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
__ CmpObjectType(ecx, FIRST_JS_RECEIVER_TYPE, ecx); // Clobbers ecx.
__ j(above_equal, &done_convert);
// Reload the receiver (it was clobbered by CmpObjectType).
__ mov(ecx,
Operand(esp, eax, times_system_pointer_size, kSystemPointerSize));
__ mov(ecx, args.GetReceiverOperand());
if (mode != ConvertReceiverMode::kNotNullOrUndefined) {
Label convert_global_proxy;
__ JumpIfRoot(ecx, RootIndex::kUndefinedValue, &convert_global_proxy,
@ -2141,8 +2141,7 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm,
__ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
__ bind(&convert_receiver);
}
__ mov(Operand(esp, eax, times_system_pointer_size, kSystemPointerSize),
ecx);
__ mov(args.GetReceiverOperand(), ecx);
}
__ bind(&done_convert);
@ -2277,8 +2276,9 @@ void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm) {
__ AssertBoundFunction(edi);
// Patch the receiver to [[BoundThis]].
StackArgumentsAccessor args(eax);
__ mov(ecx, FieldOperand(edi, JSBoundFunction::kBoundThisOffset));
__ mov(Operand(esp, eax, times_system_pointer_size, kSystemPointerSize), ecx);
__ mov(args.GetReceiverOperand(), ecx);
// Push the [[BoundArguments]] onto the stack.
Generate_PushBoundArguments(masm);
@ -2295,6 +2295,7 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
// -- eax : the number of arguments (not including the receiver)
// -- edi : the target to call (can be any Object).
// -----------------------------------
StackArgumentsAccessor args(eax);
Label non_callable, non_function, non_smi, non_jsfunction,
non_jsboundfunction;
@ -2326,7 +2327,7 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
// not we raise an exception).
__ bind(&non_function);
// Overwrite the original receiver with the (original) target.
__ mov(Operand(esp, eax, times_system_pointer_size, kSystemPointerSize), edi);
__ mov(args.GetReceiverOperand(), edi);
// Let the "call_as_function_delegate" take care of the rest.
__ LoadNativeContextSlot(edi, Context::CALL_AS_FUNCTION_DELEGATE_INDEX);
__ Jump(masm->isolate()->builtins()->CallFunction(
@ -2409,6 +2410,7 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
// the JSFunction on which new was invoked initially)
// -- edi : the constructor to call (can be any Object)
// -----------------------------------
StackArgumentsAccessor args(eax);
// Check if target is a Smi.
Label non_constructor, non_proxy, non_jsfunction, non_jsboundfunction;
@ -2445,8 +2447,7 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
__ bind(&non_proxy);
{
// Overwrite the original receiver with the (original) target.
__ mov(Operand(esp, eax, times_system_pointer_size, kSystemPointerSize),
edi);
__ mov(args.GetReceiverOperand(), edi);
// Let the "call_as_constructor_delegate" take care of the rest.
__ LoadNativeContextSlot(edi, Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX);
__ Jump(masm->isolate()->builtins()->CallFunction(),

View File

@ -1605,9 +1605,10 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rax : argc
// -- rsp[0] : return address
// -- rsp[8] : argArray
// -- rsp[16] : thisArg
// -- rsp[24] : receiver
// The order of args depends on V8_REVERSE_JSARGS
// -- args[0] : receiver
// -- args[1] : thisArg
// -- args[2] : argArray
// -----------------------------------
// 1. Load receiver into rdi, argArray into rbx (if present), remove all
@ -1615,17 +1616,17 @@ void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
// present) instead.
{
Label no_arg_array, no_this_arg;
StackArgumentsAccessor args(rsp, rax);
StackArgumentsAccessor args(rax);
__ LoadRoot(rdx, RootIndex::kUndefinedValue);
__ movq(rbx, rdx);
__ movq(rdi, args.GetReceiverOperand());
__ movq(rdi, args[0]);
__ testq(rax, rax);
__ j(zero, &no_this_arg, Label::kNear);
{
__ movq(rdx, args.GetArgumentOperand(1));
__ movq(rdx, args[1]);
__ cmpq(rax, Immediate(1));
__ j(equal, &no_arg_array, Label::kNear);
__ movq(rbx, args.GetArgumentOperand(2));
__ movq(rbx, args[2]);
__ bind(&no_arg_array);
}
__ bind(&no_this_arg);
@ -1692,7 +1693,7 @@ void Builtins::Generate_FunctionPrototypeCall(MacroAssembler* masm) {
// 2. Get the callable to call (passed as receiver) from the stack.
{
StackArgumentsAccessor args(rsp, rax);
StackArgumentsAccessor args(rax);
__ movq(rdi, args.GetReceiverOperand());
}
@ -1702,10 +1703,10 @@ void Builtins::Generate_FunctionPrototypeCall(MacroAssembler* masm) {
{
Label loop;
__ movq(rcx, rax);
StackArgumentsAccessor args(rsp, rcx);
StackArgumentsAccessor args(rcx);
__ bind(&loop);
__ movq(rbx, args.GetArgumentOperand(1));
__ movq(args.GetArgumentOperand(0), rbx);
__ movq(rbx, args[1]);
__ movq(args[0], rbx);
__ decq(rcx);
__ j(not_zero, &loop); // While non-zero.
__ DropUnderReturnAddress(1, rbx); // Drop one slot under return address.
@ -1722,10 +1723,11 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rax : argc
// -- rsp[0] : return address
// -- rsp[8] : argumentsList
// -- rsp[16] : thisArgument
// -- rsp[24] : target
// -- rsp[32] : receiver
// The order of args depends on V8_REVERSE_JSARGS
// -- args[0] : receiver
// -- args[1] : target
// -- args[2] : thisArgument
// -- args[3] : argumentsList
// -----------------------------------
// 1. Load target into rdi (if present), argumentsList into rbx (if present),
@ -1733,18 +1735,18 @@ void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
// thisArgument (if present) instead.
{
Label done;
StackArgumentsAccessor args(rsp, rax);
StackArgumentsAccessor args(rax);
__ LoadRoot(rdi, RootIndex::kUndefinedValue);
__ movq(rdx, rdi);
__ movq(rbx, rdi);
__ cmpq(rax, Immediate(1));
__ j(below, &done, Label::kNear);
__ movq(rdi, args.GetArgumentOperand(1)); // target
__ movq(rdi, args[1]); // target
__ j(equal, &done, Label::kNear);
__ movq(rdx, args.GetArgumentOperand(2)); // thisArgument
__ movq(rdx, args[2]); // thisArgument
__ cmpq(rax, Immediate(3));
__ j(below, &done, Label::kNear);
__ movq(rbx, args.GetArgumentOperand(3)); // argumentsList
__ movq(rbx, args[3]); // argumentsList
__ bind(&done);
__ PopReturnAddressTo(rcx);
__ leaq(rsp,
@ -1773,10 +1775,11 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rax : argc
// -- rsp[0] : return address
// -- rsp[8] : new.target (optional)
// -- rsp[16] : argumentsList
// -- rsp[24] : target
// -- rsp[32] : receiver
// The order of args depends on V8_REVERSE_JSARGS
// -- args[0] : receiver
// -- args[1] : target
// -- args[2] : argumentsList
// -- args[3] : new.target (optional)
// -----------------------------------
// 1. Load target into rdi (if present), argumentsList into rbx (if present),
@ -1785,19 +1788,19 @@ void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
// (if present) instead.
{
Label done;
StackArgumentsAccessor args(rsp, rax);
StackArgumentsAccessor args(rax);
__ LoadRoot(rdi, RootIndex::kUndefinedValue);
__ movq(rdx, rdi);
__ movq(rbx, rdi);
__ cmpq(rax, Immediate(1));
__ j(below, &done, Label::kNear);
__ movq(rdi, args.GetArgumentOperand(1)); // target
__ movq(rdi, args[1]); // target
__ movq(rdx, rdi); // new.target defaults to target
__ j(equal, &done, Label::kNear);
__ movq(rbx, args.GetArgumentOperand(2)); // argumentsList
__ movq(rbx, args[2]); // argumentsList
__ cmpq(rax, Immediate(3));
__ j(below, &done, Label::kNear);
__ movq(rdx, args.GetArgumentOperand(3)); // new.target
__ movq(rdx, args[3]); // new.target
__ bind(&done);
__ PopReturnAddressTo(rcx);
__ leaq(rsp,
@ -2137,9 +2140,9 @@ void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm,
__ PopReturnAddressTo(rcx);
__ bind(&loop);
{
StackArgumentsAccessor args(rbx, r8, ARGUMENTS_DONT_CONTAIN_RECEIVER);
__ Push(args.GetArgumentOperand(0));
__ decl(r8);
__ Push(Operand(rbx, r8, times_system_pointer_size,
kFPOnStackSize + kPCOnStackSize));
__ j(not_zero, &loop);
}
__ PushReturnAddressFrom(rcx);
@ -2162,7 +2165,7 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm,
// -- rdi : the function to call (checked to be a JSFunction)
// -----------------------------------
StackArgumentsAccessor args(rsp, rax);
StackArgumentsAccessor args(rax);
__ AssertFunction(rdi);
// ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList)
@ -2375,7 +2378,7 @@ void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm) {
__ AssertBoundFunction(rdi);
// Patch the receiver to [[BoundThis]].
StackArgumentsAccessor args(rsp, rax);
StackArgumentsAccessor args(rax);
__ LoadAnyTaggedField(rbx,
FieldOperand(rdi, JSBoundFunction::kBoundThisOffset));
__ movq(args.GetReceiverOperand(), rbx);
@ -2396,7 +2399,7 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
// -- rax : the number of arguments (not including the receiver)
// -- rdi : the target to call (can be any Object)
// -----------------------------------
StackArgumentsAccessor args(rsp, rax);
StackArgumentsAccessor args(rax);
Label non_callable;
__ JumpIfSmi(rdi, &non_callable);
@ -2501,7 +2504,7 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
// the JSFunction on which new was invoked initially)
// -- rdi : the constructor to call (can be any Object)
// -----------------------------------
StackArgumentsAccessor args(rsp, rax);
StackArgumentsAccessor args(rax);
// Check if target is a Smi.
Label non_constructor;

View File

@ -31,6 +31,20 @@
namespace v8 {
namespace internal {
Operand StackArgumentsAccessor::GetArgumentOperand(int index) const {
DCHECK_GE(index, 0);
#ifdef V8_REVERSE_JSARGS
// arg[0] = esp + kPCOnStackSize;
// arg[i] = arg[0] + i * kSystemPointerSize;
return Operand(esp, kPCOnStackSize + index * kSystemPointerSize);
#else
// arg[0] = (esp + kPCOnStackSize) + argc * kSystemPointerSize;
// arg[i] = arg[0] - i * kSystemPointerSize;
return Operand(esp, argc_, times_system_pointer_size,
kPCOnStackSize - index * kSystemPointerSize);
#endif
}
// -------------------------------------------------------------------------
// MacroAssembler implementation.
@ -1095,9 +1109,14 @@ void MacroAssembler::CallDebugOnFunctionCall(Register fun, Register new_target,
}
Push(fun);
Push(fun);
// Arguments are located 2 words below the base pointer.
#ifdef V8_REVERSE_JSARGS
Operand receiver_op = Operand(ebp, kSystemPointerSize * 2);
#else
Operand receiver_op =
Operand(ebp, actual_parameter_count, times_system_pointer_size,
kSystemPointerSize * 2);
#endif
Push(receiver_op);
CallRuntime(Runtime::kDebugOnFunctionCall);
Pop(fun);

View File

@ -24,6 +24,26 @@ using MemOperand = Operand;
enum RememberedSetAction { EMIT_REMEMBERED_SET, OMIT_REMEMBERED_SET };
enum SmiCheck { INLINE_SMI_CHECK, OMIT_SMI_CHECK };
// Convenient class to access arguments below the stack pointer.
class StackArgumentsAccessor {
public:
// argc = the number of arguments not including the receiver.
explicit StackArgumentsAccessor(Register argc) : argc_(argc) {
DCHECK_NE(argc_, no_reg);
}
// Argument 0 is the receiver (despite argc not including the receiver).
Operand operator[](int index) const { return GetArgumentOperand(index); }
Operand GetArgumentOperand(int index) const;
Operand GetReceiverOperand() const { return GetArgumentOperand(0); }
private:
const Register argc_;
DISALLOW_IMPLICIT_CONSTRUCTORS(StackArgumentsAccessor);
};
class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
public:
using TurboAssemblerBase::TurboAssemblerBase;

View File

@ -34,28 +34,18 @@
namespace v8 {
namespace internal {
Operand StackArgumentsAccessor::GetArgumentOperand(int index) {
Operand StackArgumentsAccessor::GetArgumentOperand(int index) const {
DCHECK_GE(index, 0);
int receiver = (receiver_mode_ == ARGUMENTS_CONTAIN_RECEIVER) ? 1 : 0;
int displacement_to_last_argument =
base_reg_ == rsp ? kPCOnStackSize : kFPOnStackSize + kPCOnStackSize;
displacement_to_last_argument += extra_displacement_to_last_argument_;
if (argument_count_reg_ == no_reg) {
// argument[0] is at base_reg_ + displacement_to_last_argument +
// (argument_count_immediate_ + receiver - 1) * kSystemPointerSize.
DCHECK_GT(argument_count_immediate_ + receiver, 0);
return Operand(base_reg_,
displacement_to_last_argument +
(argument_count_immediate_ + receiver - 1 - index) *
kSystemPointerSize);
} else {
// argument[0] is at base_reg_ + displacement_to_last_argument +
// argument_count_reg_ * times_system_pointer_size + (receiver - 1) *
// kSystemPointerSize.
return Operand(base_reg_, argument_count_reg_, times_system_pointer_size,
displacement_to_last_argument +
(receiver - 1 - index) * kSystemPointerSize);
}
#ifdef V8_REVERSE_JSARGS
// arg[0] = rsp + kPCOnStackSize;
// arg[i] = arg[0] + i * kSystemPointerSize;
return Operand(rsp, kPCOnStackSize + index * kSystemPointerSize);
#else
// arg[0] = (rsp + kPCOnStackSize) + argc * kSystemPointerSize;
// arg[i] = arg[0] - i * kSystemPointerSize;
return Operand(rsp, argc_, times_system_pointer_size,
kPCOnStackSize - index * kSystemPointerSize);
#endif
}
void MacroAssembler::Load(Register destination, ExternalReference source) {
@ -2371,8 +2361,15 @@ void MacroAssembler::CallDebugOnFunctionCall(Register fun, Register new_target,
}
Push(fun);
Push(fun);
Push(
StackArgumentsAccessor(rbp, actual_parameter_count).GetReceiverOperand());
// Arguments are located 2 words below the base pointer.
#ifdef V8_REVERSE_JSARGS
Operand receiver_op = Operand(rbp, kSystemPointerSize * 2);
#else
Operand receiver_op =
Operand(rbp, actual_parameter_count, times_system_pointer_size,
kSystemPointerSize * 2);
#endif
Push(receiver_op);
CallRuntime(Runtime::kDebugOnFunctionCall);
Pop(fun);
if (new_target.is_valid()) {

View File

@ -33,36 +33,22 @@ struct SmiIndex {
ScaleFactor scale;
};
enum StackArgumentsAccessorReceiverMode {
ARGUMENTS_CONTAIN_RECEIVER,
ARGUMENTS_DONT_CONTAIN_RECEIVER
};
// Convenient class to access arguments below the stack pointer.
class StackArgumentsAccessor {
public:
StackArgumentsAccessor(Register base_reg, Register argument_count_reg,
StackArgumentsAccessorReceiverMode receiver_mode =
ARGUMENTS_CONTAIN_RECEIVER,
int extra_displacement_to_last_argument = 0)
: base_reg_(base_reg),
argument_count_reg_(argument_count_reg),
argument_count_immediate_(0),
receiver_mode_(receiver_mode),
extra_displacement_to_last_argument_(
extra_displacement_to_last_argument) {}
Operand GetArgumentOperand(int index);
Operand GetReceiverOperand() {
DCHECK(receiver_mode_ == ARGUMENTS_CONTAIN_RECEIVER);
return GetArgumentOperand(0);
// argc = the number of arguments not including the receiver.
explicit StackArgumentsAccessor(Register argc) : argc_(argc) {
DCHECK_NE(argc_, no_reg);
}
// Argument 0 is the receiver (despite argc not including the receiver).
Operand operator[](int index) const { return GetArgumentOperand(index); }
Operand GetArgumentOperand(int index) const;
Operand GetReceiverOperand() const { return GetArgumentOperand(0); }
private:
const Register base_reg_;
const Register argument_count_reg_;
const int argument_count_immediate_;
const StackArgumentsAccessorReceiverMode receiver_mode_;
const int extra_displacement_to_last_argument_;
const Register argc_;
DISALLOW_IMPLICIT_CONSTRUCTORS(StackArgumentsAccessor);
};