Introduce StackArgumentsAccessor class for X64

R=danno@chromium.org

Review URL: https://codereview.chromium.org/21123008

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16345 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
haitao.feng@intel.com 2013-08-27 01:21:39 +00:00
parent 432faaefb7
commit a6d17b4fb5
6 changed files with 236 additions and 125 deletions

View File

@ -708,7 +708,7 @@ static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
}
// Get the full codegen state from the stack and untag it.
__ SmiToInteger32(r10, Operand(rsp, 1 * kPointerSize));
__ SmiToInteger32(r10, Operand(rsp, kPCOnStackSize));
// Switch on the state.
Label not_no_registers, not_tos_rax;
@ -717,7 +717,7 @@ static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
__ ret(1 * kPointerSize); // Remove state.
__ bind(&not_no_registers);
__ movq(rax, Operand(rsp, 2 * kPointerSize));
__ movq(rax, Operand(rsp, kPCOnStackSize + kPointerSize));
__ cmpq(r10, Immediate(FullCodeGenerator::TOS_REG));
__ j(not_equal, &not_tos_rax, Label::kNear);
__ ret(2 * kPointerSize); // Remove state, rax.
@ -782,8 +782,8 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
// 2. Get the function to call (passed as receiver) from the stack, check
// if it is a function.
Label slow, non_function;
// The function to call is at position n+1 on the stack.
__ movq(rdi, Operand(rsp, rax, times_pointer_size, 1 * kPointerSize));
StackArgumentsAccessor args(rsp, rax);
__ movq(rdi, args.GetReceiverOperand());
__ JumpIfSmi(rdi, &non_function);
__ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
__ j(not_equal, &slow);
@ -808,7 +808,7 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
__ j(not_zero, &shift_arguments);
// Compute the receiver in non-strict mode.
__ movq(rbx, Operand(rsp, rax, times_pointer_size, 0));
__ movq(rbx, args.GetArgumentOperand(1));
__ JumpIfSmi(rbx, &convert_to_object, Label::kNear);
__ CompareRoot(rbx, Heap::kNullValueRootIndex);
@ -837,7 +837,7 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
}
// Restore the function to rdi.
__ movq(rdi, Operand(rsp, rax, times_pointer_size, 1 * kPointerSize));
__ movq(rdi, args.GetReceiverOperand());
__ jmp(&patch_receiver, Label::kNear);
// Use the global receiver object from the called function as the
@ -851,7 +851,7 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
__ movq(rbx, FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
__ bind(&patch_receiver);
__ movq(Operand(rsp, rax, times_pointer_size, 0), rbx);
__ movq(args.GetArgumentOperand(1), rbx);
__ jmp(&shift_arguments);
}
@ -868,7 +868,7 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
// CALL_NON_FUNCTION builtin expects the non-function callee as
// receiver, so overwrite the first argument which will ultimately
// become the receiver.
__ movq(Operand(rsp, rax, times_pointer_size, 0), rdi);
__ movq(args.GetArgumentOperand(1), rdi);
// 4. Shift arguments and return address one slot down on the stack
// (overwriting the original receiver). Adjust argument count to make
@ -1178,10 +1178,11 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
// Load the first argument into rax and get rid of the rest
// (including the receiver).
StackArgumentsAccessor args(rsp, rax);
Label no_arguments;
__ testq(rax, rax);
__ j(zero, &no_arguments);
__ movq(rbx, Operand(rsp, rax, times_pointer_size, 0));
__ movq(rbx, args.GetArgumentOperand(1));
__ PopReturnAddressTo(rcx);
__ lea(rsp, Operand(rsp, rax, times_pointer_size, kPointerSize));
__ PushReturnAddressFrom(rcx);

View File

@ -306,7 +306,8 @@ void FastNewClosureStub::Generate(MacroAssembler* masm) {
__ IncrementCounter(counters->fast_new_closure_total(), 1);
// Get the function info from the stack.
__ movq(rdx, Operand(rsp, 1 * kPointerSize));
StackArgumentsAccessor args(rsp, 1, ARGUMENTS_DONT_CONTAIN_RECEIVER);
__ movq(rdx, args.GetArgumentOperand(0));
int map_index = Context::FunctionMapIndex(language_mode_, is_generator_);
@ -414,7 +415,7 @@ void FastNewClosureStub::Generate(MacroAssembler* masm) {
__ ret(1 * kPointerSize);
__ bind(&restore);
__ movq(rdx, Operand(rsp, 1 * kPointerSize));
__ movq(rdx, args.GetArgumentOperand(0));
__ jmp(&install_unoptimized);
// Create a new closure through the slower runtime call.
@ -437,7 +438,8 @@ void FastNewContextStub::Generate(MacroAssembler* masm) {
rax, rbx, rcx, &gc, TAG_OBJECT);
// Get the function from the stack.
__ movq(rcx, Operand(rsp, 1 * kPointerSize));
StackArgumentsAccessor args(rsp, 1, ARGUMENTS_DONT_CONTAIN_RECEIVER);
__ movq(rcx, args.GetArgumentOperand(0));
// Set up the object header.
__ LoadRoot(kScratchRegister, Heap::kFunctionContextMapRootIndex);
@ -483,10 +485,10 @@ void FastNewBlockContextStub::Generate(MacroAssembler* masm) {
rax, rbx, rcx, &gc, TAG_OBJECT);
// Get the function from the stack.
__ movq(rcx, Operand(rsp, 1 * kPointerSize));
StackArgumentsAccessor args(rsp, 2, ARGUMENTS_DONT_CONTAIN_RECEIVER);
__ movq(rcx, args.GetArgumentOperand(1));
// Get the serialized scope info from the stack.
__ movq(rbx, Operand(rsp, 2 * kPointerSize));
__ movq(rbx, args.GetArgumentOperand(0));
// Set up the object header.
__ LoadRoot(kScratchRegister, Heap::kBlockContextMapRootIndex);
@ -1259,7 +1261,8 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
if (tagged) {
Label input_not_smi, loaded;
// Test that rax is a number.
__ movq(rax, Operand(rsp, kPointerSize));
StackArgumentsAccessor args(rsp, 1, ARGUMENTS_DONT_CONTAIN_RECEIVER);
__ movq(rax, args.GetArgumentOperand(0));
__ JumpIfNotSmi(rax, &input_not_smi, Label::kNear);
// Input is a smi. Untag and load it onto the FPU stack.
// Then load the bits of the double into rbx.
@ -1734,8 +1737,9 @@ void MathPowStub::Generate(MacroAssembler* masm) {
// The exponent and base are supplied as arguments on the stack.
// This can only happen if the stub is called from non-optimized code.
// Load input parameters from stack.
__ movq(base, Operand(rsp, 2 * kPointerSize));
__ movq(exponent, Operand(rsp, 1 * kPointerSize));
StackArgumentsAccessor args(rsp, 2, ARGUMENTS_DONT_CONTAIN_RECEIVER);
__ movq(base, args.GetArgumentOperand(0));
__ movq(exponent, args.GetArgumentOperand(1));
__ JumpIfSmi(base, &base_is_smi, Label::kNear);
__ CompareRoot(FieldOperand(base, HeapObject::kMapOffset),
Heap::kHeapNumberMapRootIndex);
@ -2168,7 +2172,8 @@ void ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) {
Factory* factory = masm->isolate()->factory();
__ SmiToInteger64(rbx, Operand(rsp, 1 * kPointerSize));
StackArgumentsAccessor args(rsp, 3, ARGUMENTS_DONT_CONTAIN_RECEIVER);
__ SmiToInteger64(rbx, args.GetArgumentOperand(2));
// rbx = parameter count (untagged)
// Check if the calling frame is an arguments adaptor frame.
@ -2190,7 +2195,7 @@ void ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) {
ArgumentsAdaptorFrameConstants::kLengthOffset));
__ lea(rdx, Operand(rdx, rcx, times_pointer_size,
StandardFrameConstants::kCallerSPOffset));
__ movq(Operand(rsp, 2 * kPointerSize), rdx);
__ movq(args.GetArgumentOperand(1), rdx);
// rbx = parameter count (untagged)
// rcx = argument count (untagged)
@ -2251,7 +2256,7 @@ void ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) {
// Set up the callee in-object property.
STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1);
__ movq(rdx, Operand(rsp, 3 * kPointerSize));
__ movq(rdx, args.GetArgumentOperand(0));
__ movq(FieldOperand(rax, JSObject::kHeaderSize +
Heap::kArgumentsCalleeIndex * kPointerSize),
rdx);
@ -2302,7 +2307,7 @@ void ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) {
// Load tagged parameter count into r9.
__ Integer32ToSmi(r9, rbx);
__ Move(r8, Smi::FromInt(Context::MIN_CONTEXT_SLOTS));
__ addq(r8, Operand(rsp, 1 * kPointerSize));
__ addq(r8, args.GetArgumentOperand(2));
__ subq(r8, r9);
__ Move(r11, factory->the_hole_value());
__ movq(rdx, rdi);
@ -2341,7 +2346,7 @@ void ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) {
Label arguments_loop, arguments_test;
__ movq(r8, rbx);
__ movq(rdx, Operand(rsp, 2 * kPointerSize));
__ movq(rdx, args.GetArgumentOperand(1));
// Untag rcx for the loop below.
__ SmiToInteger64(rcx, rcx);
__ lea(kScratchRegister, Operand(r8, times_pointer_size, 0));
@ -2368,7 +2373,7 @@ void ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) {
// rcx = argument count (untagged)
__ bind(&runtime);
__ Integer32ToSmi(rcx, rcx);
__ movq(Operand(rsp, 1 * kPointerSize), rcx); // Patch argument count.
__ movq(args.GetArgumentOperand(2), rcx); // Patch argument count.
__ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1);
}
@ -2387,12 +2392,13 @@ void ArgumentsAccessStub::GenerateNewNonStrictSlow(MacroAssembler* masm) {
__ j(not_equal, &runtime);
// Patch the arguments.length and the parameters pointer.
StackArgumentsAccessor args(rsp, 3, ARGUMENTS_DONT_CONTAIN_RECEIVER);
__ movq(rcx, Operand(rdx, ArgumentsAdaptorFrameConstants::kLengthOffset));
__ movq(Operand(rsp, 1 * kPointerSize), rcx);
__ movq(args.GetArgumentOperand(2), rcx);
__ SmiToInteger64(rcx, rcx);
__ lea(rdx, Operand(rdx, rcx, times_pointer_size,
StandardFrameConstants::kCallerSPOffset));
__ movq(Operand(rsp, 2 * kPointerSize), rdx);
__ movq(args.GetArgumentOperand(1), rdx);
__ bind(&runtime);
__ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1);
@ -2413,18 +2419,19 @@ void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
__ j(equal, &adaptor_frame);
// Get the length from the frame.
__ movq(rcx, Operand(rsp, 1 * kPointerSize));
StackArgumentsAccessor args(rsp, 3, ARGUMENTS_DONT_CONTAIN_RECEIVER);
__ movq(rcx, args.GetArgumentOperand(2));
__ SmiToInteger64(rcx, rcx);
__ 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);
__ movq(args.GetArgumentOperand(2), rcx);
__ SmiToInteger64(rcx, rcx);
__ lea(rdx, Operand(rdx, rcx, times_pointer_size,
StandardFrameConstants::kCallerSPOffset));
__ movq(Operand(rsp, 2 * kPointerSize), rdx);
__ movq(args.GetArgumentOperand(1), rdx);
// Try the new space allocation. Start out with computing the size of
// the arguments object and the elements array.
@ -2454,7 +2461,7 @@ void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
// Get the length (smi tagged) and set that as an in-object property too.
STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
__ movq(rcx, Operand(rsp, 1 * kPointerSize));
__ movq(rcx, args.GetArgumentOperand(2));
__ movq(FieldOperand(rax, JSObject::kHeaderSize +
Heap::kArgumentsLengthIndex * kPointerSize),
rcx);
@ -2465,7 +2472,7 @@ void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
__ j(zero, &done);
// Get the parameters pointer from the stack.
__ movq(rdx, Operand(rsp, 2 * kPointerSize));
__ movq(rdx, args.GetArgumentOperand(1));
// Set up the elements pointer in the allocated arguments object and
// initialize the header in the elements fixed array.
@ -2948,7 +2955,8 @@ void RegExpConstructResultStub::Generate(MacroAssembler* masm) {
const int kMaxInlineLength = 100;
Label slowcase;
Label done;
__ movq(r8, Operand(rsp, kPointerSize * 3));
StackArgumentsAccessor args(rsp, 3, ARGUMENTS_DONT_CONTAIN_RECEIVER);
__ movq(r8, args.GetArgumentOperand(0));
__ JumpIfNotSmi(r8, &slowcase);
__ SmiToInteger32(rbx, r8);
__ cmpl(rbx, Immediate(kMaxInlineLength));
@ -2986,11 +2994,11 @@ void RegExpConstructResultStub::Generate(MacroAssembler* masm) {
__ movq(FieldOperand(rax, JSObject::kElementsOffset), rcx);
// Set input, index and length fields from arguments.
__ movq(r8, Operand(rsp, kPointerSize * 1));
__ movq(r8, args.GetArgumentOperand(2));
__ movq(FieldOperand(rax, JSRegExpResult::kInputOffset), r8);
__ movq(r8, Operand(rsp, kPointerSize * 2));
__ movq(r8, args.GetArgumentOperand(1));
__ movq(FieldOperand(rax, JSRegExpResult::kIndexOffset), r8);
__ movq(r8, Operand(rsp, kPointerSize * 3));
__ movq(r8, args.GetArgumentOperand(0));
__ movq(FieldOperand(rax, JSArray::kLengthOffset), r8);
// Fill out the elements FixedArray.
@ -3121,7 +3129,8 @@ void NumberToStringStub::GenerateConvertHashCodeToIndex(MacroAssembler* masm,
void NumberToStringStub::Generate(MacroAssembler* masm) {
Label runtime;
__ movq(rbx, Operand(rsp, kPointerSize));
StackArgumentsAccessor args(rsp, 1, ARGUMENTS_DONT_CONTAIN_RECEIVER);
__ movq(rbx, args.GetArgumentOperand(0));
// Generate code to lookup number in the number string cache.
GenerateLookupNumberStringCache(masm, rbx, rax, r8, r9, &runtime);
@ -3532,6 +3541,7 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
// rdi : the function to call
Isolate* isolate = masm->isolate();
Label slow, non_function;
StackArgumentsAccessor args(rsp, argc_);
// The receiver might implicitly be the global object. This is
// indicated by passing the hole as the receiver to the call
@ -3539,15 +3549,14 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
if (ReceiverMightBeImplicit()) {
Label call;
// Get the receiver from the stack.
// +1 ~ return address
__ movq(rax, Operand(rsp, (argc_ + 1) * kPointerSize));
__ movq(rax, args.GetReceiverOperand());
// Call as function is indicated with the hole.
__ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
__ j(not_equal, &call, Label::kNear);
// Patch the receiver on the stack with the global receiver object.
__ movq(rcx, GlobalObjectOperand());
__ movq(rcx, FieldOperand(rcx, GlobalObject::kGlobalReceiverOffset));
__ movq(Operand(rsp, (argc_ + 1) * kPointerSize), rcx);
__ movq(args.GetReceiverOperand(), rcx);
__ bind(&call);
}
@ -3609,7 +3618,7 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
// CALL_NON_FUNCTION expects the non-function callee as receiver (instead
// of the original receiver from the call site).
__ bind(&non_function);
__ movq(Operand(rsp, (argc_ + 1) * kPointerSize), rdi);
__ movq(args.GetReceiverOperand(), rdi);
__ Set(rax, argc_);
__ Set(rbx, 0);
__ SetCallKind(rcx, CALL_AS_METHOD);
@ -4144,12 +4153,13 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
static const unsigned int kWordBeforeResultValue = 0x458B4909;
// Only the inline check flag is supported on X64.
ASSERT(flags_ == kNoFlags || HasCallSiteInlineCheck());
int extra_stack_space = HasCallSiteInlineCheck() ? kPointerSize : 0;
int extra_argument_offset = HasCallSiteInlineCheck() ? 1 : 0;
// Get the object - go slow case if it's a smi.
Label slow;
__ movq(rax, Operand(rsp, 2 * kPointerSize + extra_stack_space));
StackArgumentsAccessor args(rsp, 2 + extra_argument_offset,
ARGUMENTS_DONT_CONTAIN_RECEIVER);
__ movq(rax, args.GetArgumentOperand(0));
__ JumpIfSmi(rax, &slow);
// Check that the left hand is a JS object. Leave its map in rax.
@ -4159,7 +4169,7 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
__ j(above, &slow);
// Get the prototype of the function.
__ movq(rdx, Operand(rsp, 1 * kPointerSize + extra_stack_space));
__ movq(rdx, args.GetArgumentOperand(1));
// rdx is function, rax is map.
// If there is a call site cache don't look in the global cache, but do the
@ -4194,8 +4204,8 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
__ StoreRoot(rax, Heap::kInstanceofCacheMapRootIndex);
} else {
// Get return address and delta to inlined map check.
__ movq(kScratchRegister, Operand(rsp, 0 * kPointerSize));
__ subq(kScratchRegister, Operand(rsp, 1 * kPointerSize));
__ movq(kScratchRegister, StackOperandForReturnAddress(0));
__ subq(kScratchRegister, args.GetArgumentOperand(2));
if (FLAG_debug_code) {
__ movl(rdi, Immediate(kWordBeforeMapCheckValue));
__ cmpl(Operand(kScratchRegister, kOffsetToMapCheckValue - 4), rdi);
@ -4235,8 +4245,8 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
// Assert it is a 1-byte signed value.
ASSERT(true_offset >= 0 && true_offset < 0x100);
__ movl(rax, Immediate(true_offset));
__ movq(kScratchRegister, Operand(rsp, 0 * kPointerSize));
__ subq(kScratchRegister, Operand(rsp, 1 * kPointerSize));
__ movq(kScratchRegister, StackOperandForReturnAddress(0));
__ subq(kScratchRegister, args.GetArgumentOperand(2));
__ movb(Operand(kScratchRegister, kOffsetToResultValue), rax);
if (FLAG_debug_code) {
__ movl(rax, Immediate(kWordBeforeResultValue));
@ -4245,7 +4255,7 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
}
__ Set(rax, 0);
}
__ ret(2 * kPointerSize + extra_stack_space);
__ ret((2 + extra_argument_offset) * kPointerSize);
__ bind(&is_not_instance);
if (!HasCallSiteInlineCheck()) {
@ -4258,8 +4268,8 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
// Assert it is a 1-byte signed value.
ASSERT(false_offset >= 0 && false_offset < 0x100);
__ movl(rax, Immediate(false_offset));
__ movq(kScratchRegister, Operand(rsp, 0 * kPointerSize));
__ subq(kScratchRegister, Operand(rsp, 1 * kPointerSize));
__ movq(kScratchRegister, StackOperandForReturnAddress(0));
__ subq(kScratchRegister, args.GetArgumentOperand(2));
__ movb(Operand(kScratchRegister, kOffsetToResultValue), rax);
if (FLAG_debug_code) {
__ movl(rax, Immediate(kWordBeforeResultValue));
@ -4267,7 +4277,7 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
__ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheMov);
}
}
__ ret(2 * kPointerSize + extra_stack_space);
__ ret((2 + extra_argument_offset) * kPointerSize);
// Slow-case: Go through the JavaScript implementation.
__ bind(&slow);
@ -4425,8 +4435,9 @@ void StringAddStub::Generate(MacroAssembler* masm) {
Builtins::JavaScript builtin_id = Builtins::ADD;
// Load the two arguments.
__ movq(rax, Operand(rsp, 2 * kPointerSize)); // First argument (left).
__ movq(rdx, Operand(rsp, 1 * kPointerSize)); // Second argument (right).
StackArgumentsAccessor args(rsp, 2, ARGUMENTS_DONT_CONTAIN_RECEIVER);
__ movq(rax, args.GetArgumentOperand(0)); // First argument (left).
__ movq(rdx, args.GetArgumentOperand(1)); // Second argument (right).
// Make sure that both arguments are strings if not known in advance.
// Otherwise, at least one of the arguments is definitely a string,
@ -5433,8 +5444,9 @@ void StringCompareStub::Generate(MacroAssembler* masm) {
// rsp[8] : right string
// rsp[16] : left string
__ movq(rdx, Operand(rsp, 2 * kPointerSize)); // left
__ movq(rax, Operand(rsp, 1 * kPointerSize)); // right
StackArgumentsAccessor args(rsp, 2, ARGUMENTS_DONT_CONTAIN_RECEIVER);
__ movq(rdx, args.GetArgumentOperand(0)); // left
__ movq(rax, args.GetArgumentOperand(1)); // right
// Check for identity.
Label not_same;
@ -5947,9 +5959,11 @@ void NameDictionaryLookupStub::Generate(MacroAssembler* masm) {
// undefined value), it guarantees the hash table doesn't contain the
// property. It's true even if some slots represent deleted properties
// (their names are the null value).
StackArgumentsAccessor args(rsp, 2, ARGUMENTS_DONT_CONTAIN_RECEIVER,
kPointerSize);
for (int i = kInlinedProbes; i < kTotalProbes; i++) {
// Compute the masked index: (hash + i + i * i) & mask.
__ movq(scratch, Operand(rsp, 2 * kPointerSize));
__ movq(scratch, args.GetArgumentOperand(1));
if (i > 0) {
__ addl(scratch, Immediate(NameDictionary::GetProbeOffset(i)));
}
@ -5969,7 +5983,7 @@ void NameDictionaryLookupStub::Generate(MacroAssembler* masm) {
__ j(equal, &not_in_dictionary);
// Stop if found the property.
__ cmpq(scratch, Operand(rsp, 3 * kPointerSize));
__ cmpq(scratch, args.GetArgumentOperand(0));
__ j(equal, &in_dictionary);
if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) {
@ -6321,8 +6335,9 @@ void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
Label fast_elements;
// Get array literal index, array literal and its map.
__ movq(rdx, Operand(rsp, 1 * kPointerSize));
__ movq(rbx, Operand(rsp, 2 * kPointerSize));
StackArgumentsAccessor args(rsp, 2, ARGUMENTS_DONT_CONTAIN_RECEIVER);
__ movq(rdx, args.GetArgumentOperand(1));
__ movq(rbx, args.GetArgumentOperand(0));
__ movq(rdi, FieldOperand(rbx, JSObject::kMapOffset));
__ CheckFastElements(rdi, &double_elements);
@ -6489,7 +6504,8 @@ static void CreateArrayDispatchOneArgument(MacroAssembler* masm) {
__ j(not_zero, &normal_sequence);
// look at the first argument
__ movq(rcx, Operand(rsp, kPointerSize));
StackArgumentsAccessor args(rsp, 1, ARGUMENTS_DONT_CONTAIN_RECEIVER);
__ movq(rcx, args.GetArgumentOperand(0));
__ testq(rcx, rcx);
__ j(zero, &normal_sequence);
@ -6668,7 +6684,8 @@ void InternalArrayConstructorStub::GenerateCase(
if (IsFastPackedElementsKind(kind)) {
// We might need to create a holey array
// look at the first argument
__ movq(rcx, Operand(rsp, kPointerSize));
StackArgumentsAccessor args(rsp, 1, ARGUMENTS_DONT_CONTAIN_RECEIVER);
__ movq(rcx, args.GetArgumentOperand(0));
__ testq(rcx, rcx);
__ j(zero, &normal_sequence);

View File

@ -744,6 +744,28 @@ void Code::PatchPlatformCodeAge(byte* sequence,
}
Operand StackArgumentsAccessor::GetArgumentOperand(int index) {
ASSERT(index >= 0);
ASSERT(base_reg_.is(rsp) || base_reg_.is(rbp));
int receiver = (receiver_mode_ == ARGUMENTS_CONTAIN_RECEIVER) ? 1 : 0;
int displacement_to_last_argument = base_reg_.is(rsp) ?
kPCOnStackSize : kFPOnStackSize + kPCOnStackSize;
displacement_to_last_argument += extra_displacement_to_last_argument_;
if (argument_count_reg_.is(no_reg)) {
// argument[0] is at base_reg_ + displacement_to_last_argument +
// (argument_count_immediate_ + receiver - 1) * kPointerSize.
ASSERT(argument_count_immediate_ + receiver > 0);
return Operand(base_reg_, displacement_to_last_argument +
(argument_count_immediate_ + receiver - 1 - index) * kPointerSize);
} else {
// argument[0] is at base_reg_ + displacement_to_last_argument +
// argument_count_reg_ * times_pointer_size + (receiver - 1) * kPointerSize.
return Operand(base_reg_, argument_count_reg_, times_pointer_size,
displacement_to_last_argument + (receiver - 1 - index) * kPointerSize);
}
}
} } // namespace v8::internal
#endif // V8_TARGET_ARCH_X64

View File

@ -103,6 +103,73 @@ class MathExpGenerator : public AllStatic {
DISALLOW_COPY_AND_ASSIGN(MathExpGenerator);
};
enum StackArgumentsAccessorReceiverMode {
ARGUMENTS_CONTAIN_RECEIVER,
ARGUMENTS_DONT_CONTAIN_RECEIVER
};
class StackArgumentsAccessor BASE_EMBEDDED {
public:
StackArgumentsAccessor(
Register base_reg,
int argument_count_immediate,
StackArgumentsAccessorReceiverMode receiver_mode =
ARGUMENTS_CONTAIN_RECEIVER,
int extra_displacement_to_last_argument = 0)
: base_reg_(base_reg),
argument_count_reg_(no_reg),
argument_count_immediate_(argument_count_immediate),
receiver_mode_(receiver_mode),
extra_displacement_to_last_argument_(
extra_displacement_to_last_argument) { }
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) { }
StackArgumentsAccessor(
Register base_reg,
const ParameterCount& parameter_count,
StackArgumentsAccessorReceiverMode receiver_mode =
ARGUMENTS_CONTAIN_RECEIVER,
int extra_displacement_to_last_argument = 0)
: base_reg_(base_reg),
argument_count_reg_(parameter_count.is_reg() ?
parameter_count.reg() : no_reg),
argument_count_immediate_(parameter_count.is_immediate() ?
parameter_count.immediate() : 0),
receiver_mode_(receiver_mode),
extra_displacement_to_last_argument_(
extra_displacement_to_last_argument) { }
Operand GetArgumentOperand(int index);
Operand GetReceiverOperand() {
ASSERT(receiver_mode_ == ARGUMENTS_CONTAIN_RECEIVER);
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_;
DISALLOW_IMPLICIT_CONSTRUCTORS(StackArgumentsAccessor);
};
} } // namespace v8::internal
#endif // V8_X64_CODEGEN_X64_H_

View File

@ -904,8 +904,8 @@ void CallICBase::GenerateNormal(MacroAssembler* masm, int argc) {
// -----------------------------------
Label miss;
// Get the receiver of the function from the stack.
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
StackArgumentsAccessor args(rsp, argc);
__ movq(rdx, args.GetReceiverOperand());
GenerateNameDictionaryReceiverCheck(masm, rdx, rax, rbx, &miss);
@ -940,8 +940,8 @@ void CallICBase::GenerateMiss(MacroAssembler* masm,
__ IncrementCounter(counters->keyed_call_miss(), 1);
}
// Get the receiver of the function from the stack; 1 ~ return address.
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
StackArgumentsAccessor args(rsp, argc);
__ movq(rdx, args.GetReceiverOperand());
// Enter an internal frame.
{
@ -965,7 +965,7 @@ void CallICBase::GenerateMiss(MacroAssembler* masm,
// This can happen only for regular CallIC but not KeyedCallIC.
if (id == IC::kCallIC_Miss) {
Label invoke, global;
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); // receiver
__ movq(rdx, args.GetReceiverOperand());
__ JumpIfSmi(rdx, &invoke);
__ CmpObjectType(rdx, JS_GLOBAL_OBJECT_TYPE, rcx);
__ j(equal, &global);
@ -975,7 +975,7 @@ void CallICBase::GenerateMiss(MacroAssembler* masm,
// Patch the receiver on the stack.
__ bind(&global);
__ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
__ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
__ movq(args.GetReceiverOperand(), rdx);
__ bind(&invoke);
}
@ -1005,8 +1005,8 @@ void CallIC::GenerateMegamorphic(MacroAssembler* masm,
// rsp[(argc + 1) * 8] : argument 0 = receiver
// -----------------------------------
// Get the receiver of the function from the stack; 1 ~ return address.
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
StackArgumentsAccessor args(rsp, argc);
__ movq(rdx, args.GetReceiverOperand());
GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC, extra_ic_state);
GenerateMiss(masm, argc, extra_ic_state);
}
@ -1023,8 +1023,8 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
// rsp[(argc + 1) * 8] : argument 0 = receiver
// -----------------------------------
// Get the receiver of the function from the stack; 1 ~ return address.
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
StackArgumentsAccessor args(rsp, argc);
__ movq(rdx, args.GetReceiverOperand());
Label do_call, slow_call, slow_load;
Label check_number_dictionary, check_name, lookup_monomorphic_cache;
@ -1302,7 +1302,8 @@ void KeyedCallIC::GenerateNonStrictArguments(MacroAssembler* masm,
// rsp[(argc + 1) * 8] : argument 0 = receiver
// -----------------------------------
Label slow, notin;
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
StackArgumentsAccessor args(rsp, argc);
__ movq(rdx, args.GetReceiverOperand());
Operand mapped_location = GenerateMappedArgumentsLookup(
masm, rdx, rcx, rbx, rax, r8, &notin, &slow);
__ movq(rdi, mapped_location);

View File

@ -414,8 +414,10 @@ static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
__ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
__ movq(StackOperandForReturnAddress(0), scratch);
__ Move(scratch, Smi::FromInt(0));
for (int i = 1; i <= kFastApiCallArguments; i++) {
__ movq(Operand(rsp, i * kPointerSize), scratch);
StackArgumentsAccessor args(rsp, kFastApiCallArguments,
ARGUMENTS_DONT_CONTAIN_RECEIVER);
for (int i = 0; i < kFastApiCallArguments; i++) {
__ movq(args.GetArgumentOperand(i), scratch);
}
}
@ -464,23 +466,26 @@ static void GenerateFastApiCall(MacroAssembler* masm,
__ LoadHeapObject(rdi, function);
__ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
int api_call_argc = argc + kFastApiCallArguments;
StackArgumentsAccessor args(rsp, api_call_argc);
// Pass the additional arguments.
__ movq(Operand(rsp, 2 * kPointerSize), rdi);
__ movq(args.GetArgumentOperand(api_call_argc - 1), rdi);
Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
Handle<Object> call_data(api_call_info->data(), masm->isolate());
if (masm->isolate()->heap()->InNewSpace(*call_data)) {
__ Move(rcx, api_call_info);
__ movq(rbx, FieldOperand(rcx, CallHandlerInfo::kDataOffset));
__ movq(Operand(rsp, 3 * kPointerSize), rbx);
__ movq(args.GetArgumentOperand(api_call_argc - 2), rbx);
} else {
__ Move(Operand(rsp, 3 * kPointerSize), call_data);
__ Move(args.GetArgumentOperand(api_call_argc - 2), call_data);
}
__ movq(kScratchRegister,
ExternalReference::isolate_address(masm->isolate()));
__ movq(Operand(rsp, 4 * kPointerSize), kScratchRegister);
__ movq(args.GetArgumentOperand(api_call_argc - 3), kScratchRegister);
__ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
__ movq(Operand(rsp, 5 * kPointerSize), kScratchRegister);
__ movq(Operand(rsp, 6 * kPointerSize), kScratchRegister);
__ movq(args.GetArgumentOperand(api_call_argc - 4), kScratchRegister);
__ movq(args.GetArgumentOperand(api_call_argc - 5), kScratchRegister);
// Prepare arguments.
STATIC_ASSERT(kFastApiCallArguments == 6);
@ -526,7 +531,7 @@ static void GenerateFastApiCall(MacroAssembler* masm,
__ CallApiFunctionAndReturn(function_address,
thunk_address,
callback_arg,
argc + kFastApiCallArguments + 1,
api_call_argc + 1,
returns_handle,
kFastApiCallArguments + 1);
}
@ -1075,7 +1080,7 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
int depth = 0;
if (save_at_depth == depth) {
__ movq(Operand(rsp, kPointerSize), object_reg);
__ movq(Operand(rsp, kPCOnStackSize), object_reg);
}
// Check the maps in the prototype chain.
@ -1135,7 +1140,7 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
}
if (save_at_depth == depth) {
__ movq(Operand(rsp, kPointerSize), reg);
__ movq(Operand(rsp, kPCOnStackSize), reg);
}
// Go to the next object in the prototype chain.
@ -1470,11 +1475,8 @@ void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
Label* miss) {
ASSERT(holder->IsGlobalObject());
// Get the number of arguments.
const int argc = arguments().immediate();
// Get the receiver from the stack.
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
StackArgumentsAccessor args(rsp, arguments());
__ movq(rdx, args.GetReceiverOperand());
// Check that the maps haven't changed.
@ -1538,9 +1540,8 @@ Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
GenerateNameCheck(name, &miss);
// Get the receiver from the stack.
const int argc = arguments().immediate();
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
StackArgumentsAccessor args(rsp, arguments());
__ movq(rdx, args.GetReceiverOperand());
// Check that the receiver isn't a smi.
__ JumpIfSmi(rdx, &miss);
@ -1561,7 +1562,7 @@ Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
// necessary.
if (object->IsGlobalObject()) {
__ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
__ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
__ movq(args.GetReceiverOperand(), rdx);
}
// Invoke the function.
@ -1591,11 +1592,11 @@ Handle<Code> CallStubCompiler::CompileArrayCodeCall(
// Check that function is still array
const int argc = arguments().immediate();
StackArgumentsAccessor args(rsp, argc);
GenerateNameCheck(name, &miss);
if (cell.is_null()) {
// Get the receiver from the stack.
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
__ movq(rdx, args.GetReceiverOperand());
// Check that the receiver isn't a smi.
__ JumpIfSmi(rdx, &miss);
@ -1647,9 +1648,9 @@ Handle<Code> CallStubCompiler::CompileArrayPushCall(
Label miss;
GenerateNameCheck(name, &miss);
// Get the receiver from the stack.
const int argc = arguments().immediate();
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
StackArgumentsAccessor args(rsp, argc);
__ movq(rdx, args.GetReceiverOperand());
// Check that the receiver isn't a smi.
__ JumpIfSmi(rdx, &miss);
@ -1688,7 +1689,7 @@ Handle<Code> CallStubCompiler::CompileArrayPushCall(
__ j(greater, &attempt_to_grow_elements);
// Check if value is a smi.
__ movq(rcx, Operand(rsp, argc * kPointerSize));
__ movq(rcx, args.GetArgumentOperand(1));
__ JumpIfNotSmi(rcx, &with_write_barrier);
// Save new length.
@ -1723,7 +1724,7 @@ Handle<Code> CallStubCompiler::CompileArrayPushCall(
__ cmpl(rax, rcx);
__ j(greater, &call_builtin);
__ movq(rcx, Operand(rsp, argc * kPointerSize));
__ movq(rcx, args.GetArgumentOperand(1));
__ StoreNumberToDoubleElements(
rcx, rdi, rax, xmm0, &call_builtin, argc * kDoubleSize);
@ -1800,7 +1801,7 @@ Handle<Code> CallStubCompiler::CompileArrayPushCall(
__ jmp(&call_builtin);
}
__ movq(rbx, Operand(rsp, argc * kPointerSize));
__ movq(rbx, args.GetArgumentOperand(1));
// Growing elements that are SMI-only requires special handling in case
// the new element is non-Smi. For now, delegate to the builtin.
Label no_fast_elements_check;
@ -1849,7 +1850,7 @@ Handle<Code> CallStubCompiler::CompileArrayPushCall(
__ RecordWrite(rdi, rdx, rbx, kDontSaveFPRegs, OMIT_REMEMBERED_SET);
// Restore receiver to rdx as finish sequence assumes it's here.
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
__ movq(rdx, args.GetReceiverOperand());
// Increment element's and array's sizes.
__ SmiAddConstant(FieldOperand(rdi, FixedArray::kLengthOffset),
@ -1898,9 +1899,9 @@ Handle<Code> CallStubCompiler::CompileArrayPopCall(
Label miss, return_undefined, call_builtin;
GenerateNameCheck(name, &miss);
// Get the receiver from the stack.
const int argc = arguments().immediate();
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
StackArgumentsAccessor args(rsp, argc);
__ movq(rdx, args.GetReceiverOperand());
// Check that the receiver isn't a smi.
__ JumpIfSmi(rdx, &miss);
@ -1978,6 +1979,7 @@ Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
const int argc = arguments().immediate();
StackArgumentsAccessor args(rsp, argc);
Label miss;
Label name_miss;
@ -2003,9 +2005,9 @@ Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
Register receiver = rbx;
Register index = rdi;
Register result = rax;
__ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize));
__ movq(receiver, args.GetReceiverOperand());
if (argc > 0) {
__ movq(index, Operand(rsp, (argc - 0) * kPointerSize));
__ movq(index, args.GetArgumentOperand(1));
} else {
__ LoadRoot(index, Heap::kUndefinedValueRootIndex);
}
@ -2059,6 +2061,8 @@ Handle<Code> CallStubCompiler::CompileStringCharAtCall(
if (!object->IsString() || !cell.is_null()) return Handle<Code>::null();
const int argc = arguments().immediate();
StackArgumentsAccessor args(rsp, argc);
Label miss;
Label name_miss;
Label index_out_of_range;
@ -2084,9 +2088,9 @@ Handle<Code> CallStubCompiler::CompileStringCharAtCall(
Register index = rdi;
Register scratch = rdx;
Register result = rax;
__ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize));
__ movq(receiver, args.GetReceiverOperand());
if (argc > 0) {
__ movq(index, Operand(rsp, (argc - 0) * kPointerSize));
__ movq(index, args.GetArgumentOperand(1));
} else {
__ LoadRoot(index, Heap::kUndefinedValueRootIndex);
}
@ -2139,13 +2143,14 @@ Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
// If the object is not a JSObject or we got an unexpected number of
// arguments, bail out to the regular call.
const int argc = arguments().immediate();
StackArgumentsAccessor args(rsp, argc);
if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
Label miss;
GenerateNameCheck(name, &miss);
if (cell.is_null()) {
__ movq(rdx, Operand(rsp, 2 * kPointerSize));
__ movq(rdx, args.GetArgumentOperand(argc - 1));
__ JumpIfSmi(rdx, &miss);
CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi,
name, &miss);
@ -2158,7 +2163,7 @@ Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
// Load the char code argument.
Register code = rbx;
__ movq(code, Operand(rsp, 1 * kPointerSize));
__ movq(code, args.GetArgumentOperand(argc));
// Check the code is a smi.
Label slow;
@ -2345,13 +2350,14 @@ Handle<Code> CallStubCompiler::CompileMathAbsCall(
// If the object is not a JSObject or we got an unexpected number of
// arguments, bail out to the regular call.
const int argc = arguments().immediate();
StackArgumentsAccessor args(rsp, argc);
if (!object->IsJSObject() || argc != 1) return Handle<Code>::null();
Label miss;
GenerateNameCheck(name, &miss);
if (cell.is_null()) {
__ movq(rdx, Operand(rsp, 2 * kPointerSize));
__ movq(rdx, args.GetArgumentOperand(argc - 1));
__ JumpIfSmi(rdx, &miss);
CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi,
name, &miss);
@ -2362,7 +2368,7 @@ Handle<Code> CallStubCompiler::CompileMathAbsCall(
GenerateLoadFunctionFromCell(cell, function, &miss);
}
// Load the (only) argument into rax.
__ movq(rax, Operand(rsp, 1 * kPointerSize));
__ movq(rax, args.GetArgumentOperand(argc));
// Check if the argument is a smi.
Label not_smi;
@ -2452,9 +2458,9 @@ Handle<Code> CallStubCompiler::CompileFastApiCall(
Label miss, miss_before_stack_reserved;
GenerateNameCheck(name, &miss_before_stack_reserved);
// Get the receiver from the stack.
const int argc = arguments().immediate();
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
StackArgumentsAccessor args(rsp, argc);
__ movq(rdx, args.GetReceiverOperand());
// Check that the receiver isn't a smi.
__ JumpIfSmi(rdx, &miss_before_stack_reserved);
@ -2506,9 +2512,8 @@ void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
Label miss;
GenerateNameCheck(name, &miss);
// Get the receiver from the stack.
const int argc = arguments().immediate();
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
StackArgumentsAccessor args(rsp, arguments());
__ movq(rdx, args.GetReceiverOperand());
// Check that the receiver isn't a smi.
if (check != NUMBER_CHECK) {
@ -2532,7 +2537,7 @@ void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
// necessary.
if (object->IsGlobalObject()) {
__ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
__ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
__ movq(args.GetReceiverOperand(), rdx);
}
break;
@ -2652,21 +2657,20 @@ Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
Label miss;
GenerateNameCheck(name, &miss);
// Get the number of arguments.
const int argc = arguments().immediate();
LookupResult lookup(isolate());
LookupPostInterceptor(holder, name, &lookup);
// Get the receiver from the stack.
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
StackArgumentsAccessor args(rsp, arguments());
__ movq(rdx, args.GetReceiverOperand());
CallInterceptorCompiler compiler(this, arguments(), rcx, extra_state_);
compiler.Compile(masm(), object, holder, name, &lookup, rdx, rbx, rdi, rax,
&miss);
// Restore receiver.
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
__ movq(rdx, args.GetReceiverOperand());
// Check that the function really is a function.
__ JumpIfSmi(rax, &miss);
@ -2677,7 +2681,7 @@ Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
// necessary.
if (object->IsGlobalObject()) {
__ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
__ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
__ movq(args.GetReceiverOperand(), rdx);
}
// Invoke the function.
@ -2724,15 +2728,14 @@ Handle<Code> CallStubCompiler::CompileCallGlobal(
Label miss;
GenerateNameCheck(name, &miss);
// Get the number of arguments.
const int argc = arguments().immediate();
StackArgumentsAccessor args(rsp, arguments());
GenerateGlobalReceiverCheck(object, holder, name, &miss);
GenerateLoadFunctionFromCell(cell, function, &miss);
// Patch the receiver on the stack with the global proxy.
if (object->IsGlobalObject()) {
__ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
__ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
__ movq(args.GetReceiverOperand(), rdx);
}
// Set up the context (function already in rdi).