X87: [turbofan] Call ArgumentsAccessStub to materialize arguments.

port 9b12ec9ac2 (r30919)

original commit message:

    This lowers JSCreateArgument nodes to call the ArgumentsAccessStub for
    help with materializing arguments objects when possible. Along the way
    this changes the calling convention of said stub to take parameters in
    registers instead of on the stack.

R=weiliang.lin@intel.com
BUG=

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

Cr-Commit-Position: refs/heads/master@{#30923}
This commit is contained in:
chunyang.dai 2015-09-24 20:00:27 -07:00 committed by Commit bot
parent ab9898980e
commit 8322defdb9
3 changed files with 115 additions and 102 deletions

View File

@ -280,31 +280,25 @@ void FullCodeGenerator::Generate() {
if (arguments != NULL) {
// Function uses arguments object.
Comment cmnt(masm_, "[ Allocate arguments object");
if (function_in_register) {
__ push(edi);
} else {
__ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
DCHECK(edi.is(ArgumentsAccessNewDescriptor::function()));
if (!function_in_register) {
__ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
}
// Receiver is just before the parameters on the caller's stack.
int num_parameters = info->scope()->num_parameters();
int offset = num_parameters * kPointerSize;
__ lea(edx,
__ mov(ArgumentsAccessNewDescriptor::parameter_count(),
Immediate(Smi::FromInt(num_parameters)));
__ lea(ArgumentsAccessNewDescriptor::parameter_pointer(),
Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset));
__ push(edx);
__ push(Immediate(Smi::FromInt(num_parameters)));
// Arguments to ArgumentsAccessStub:
// function, receiver address, parameter count.
// The stub will rewrite receiver and parameter count if the previous
// stack frame was an arguments adapter frame.
ArgumentsAccessStub::Type type;
if (is_strict(language_mode()) || !has_simple_parameters()) {
type = ArgumentsAccessStub::NEW_STRICT;
} else if (literal()->has_duplicate_parameters()) {
type = ArgumentsAccessStub::NEW_SLOPPY_SLOW;
} else {
type = ArgumentsAccessStub::NEW_SLOPPY_FAST;
}
// Arguments to ArgumentsAccessStub:
// function, parameter pointer, parameter count.
// The stub will rewrite parameter pointer and parameter count if the
// previous stack frame was an arguments adapter frame.
bool is_unmapped = is_strict(language_mode()) || !has_simple_parameters();
ArgumentsAccessStub::Type type = ArgumentsAccessStub::ComputeType(
is_unmapped, literal()->has_duplicate_parameters());
ArgumentsAccessStub stub(isolate(), type);
__ CallStub(&stub);

View File

@ -493,72 +493,78 @@ void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
void ArgumentsAccessStub::GenerateNewSloppySlow(MacroAssembler* masm) {
// ecx : number of parameters (tagged)
// edx : parameters pointer
// edi : function
// esp[0] : return address
// esp[4] : number of parameters
// esp[8] : receiver displacement
// esp[12] : function
DCHECK(edi.is(ArgumentsAccessNewDescriptor::function()));
DCHECK(ecx.is(ArgumentsAccessNewDescriptor::parameter_count()));
DCHECK(edx.is(ArgumentsAccessNewDescriptor::parameter_pointer()));
// 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, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
__ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
__ mov(eax, Operand(ebx, StandardFrameConstants::kContextOffset));
__ cmp(eax, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
__ j(not_equal, &runtime, Label::kNear);
// 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,
StandardFrameConstants::kCallerSPOffset));
__ mov(Operand(esp, 2 * kPointerSize), edx);
__ mov(ecx, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
__ lea(edx,
Operand(ebx, ecx, times_2, StandardFrameConstants::kCallerSPOffset));
__ bind(&runtime);
__ pop(eax); // Pop return address.
__ push(edi); // Push function.
__ push(edx); // Push parameters pointer.
__ push(ecx); // Push parameter count.
__ push(eax); // Push return address.
__ TailCallRuntime(Runtime::kNewSloppyArguments, 3, 1);
}
void ArgumentsAccessStub::GenerateNewSloppyFast(MacroAssembler* masm) {
// ecx : number of parameters (tagged)
// edx : parameters pointer
// edi : function
// esp[0] : return address
// esp[4] : number of parameters (tagged)
// esp[8] : receiver displacement
// esp[12] : function
// ebx = parameter count (tagged)
__ mov(ebx, Operand(esp, 1 * kPointerSize));
DCHECK(edi.is(ArgumentsAccessNewDescriptor::function()));
DCHECK(ecx.is(ArgumentsAccessNewDescriptor::parameter_count()));
DCHECK(edx.is(ArgumentsAccessNewDescriptor::parameter_pointer()));
// Check if the calling frame is an arguments adaptor frame.
// TODO(rossberg): Factor out some of the bits that are shared with the other
// Generate* functions.
Label runtime;
Label adaptor_frame, try_allocate;
__ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
__ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
__ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
Label adaptor_frame, try_allocate, runtime;
__ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
__ mov(eax, Operand(ebx, StandardFrameConstants::kContextOffset));
__ cmp(eax, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
__ j(equal, &adaptor_frame, Label::kNear);
// No adaptor, parameter count = argument count.
__ mov(ecx, ebx);
__ mov(ebx, ecx);
__ push(ecx);
__ jmp(&try_allocate, Label::kNear);
// We have an adaptor frame. Patch the parameters pointer.
__ bind(&adaptor_frame);
__ mov(ebx, ecx);
__ push(ecx);
__ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
__ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
__ lea(edx, Operand(edx, ecx, times_2,
StandardFrameConstants::kCallerSPOffset));
__ mov(Operand(esp, 2 * kPointerSize), edx);
// ebx = parameter count (tagged)
// ecx = argument count (smi-tagged)
// esp[4] = parameter count (tagged)
// esp[8] = address of receiver argument
// Compute the mapped parameter count = min(ebx, ecx) in ebx.
__ cmp(ebx, ecx);
__ j(less_equal, &try_allocate, Label::kNear);
__ mov(ebx, ecx);
// Save mapped parameter count and function.
__ bind(&try_allocate);
// Save mapped parameter count.
__ push(edi);
__ push(ebx);
// Compute the sizes of backing store, parameter map, and arguments object.
@ -578,13 +584,13 @@ void ArgumentsAccessStub::GenerateNewSloppyFast(MacroAssembler* masm) {
__ add(ebx, Immediate(Heap::kSloppyArgumentsObjectSize));
// Do the allocation of all three objects in one go.
__ Allocate(ebx, eax, edx, edi, &runtime, TAG_OBJECT);
__ Allocate(ebx, eax, edi, no_reg, &runtime, TAG_OBJECT);
// eax = address of new object(s) (tagged)
// ecx = argument count (smi-tagged)
// esp[0] = mapped parameter count (tagged)
// esp[4] = function
// esp[8] = parameter count (tagged)
// esp[12] = address of receiver argument
// Get the arguments map from the current native context into edi.
Label has_mapped_parameters, instantiate;
__ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
@ -607,8 +613,8 @@ void ArgumentsAccessStub::GenerateNewSloppyFast(MacroAssembler* masm) {
// ecx = argument count (smi-tagged)
// edi = address of arguments map (tagged)
// esp[0] = mapped parameter count (tagged)
// esp[4] = function
// esp[8] = parameter count (tagged)
// esp[12] = address of receiver argument
// Copy the JS object part.
__ mov(FieldOperand(eax, JSObject::kMapOffset), edi);
__ mov(FieldOperand(eax, JSObject::kPropertiesOffset),
@ -618,11 +624,11 @@ void ArgumentsAccessStub::GenerateNewSloppyFast(MacroAssembler* masm) {
// Set up the callee in-object property.
STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1);
__ mov(edx, Operand(esp, 4 * kPointerSize));
__ AssertNotSmi(edx);
__ mov(edi, Operand(esp, 1 * kPointerSize));
__ AssertNotSmi(edi);
__ mov(FieldOperand(eax, JSObject::kHeaderSize +
Heap::kArgumentsCalleeIndex * kPointerSize),
edx);
Heap::kArgumentsCalleeIndex * kPointerSize),
edi);
// Use the length (smi tagged) and set that as an in-object property too.
__ AssertSmi(ecx);
@ -640,11 +646,13 @@ void ArgumentsAccessStub::GenerateNewSloppyFast(MacroAssembler* masm) {
// eax = address of new object (tagged)
// ebx = mapped parameter count (tagged)
// ecx = argument count (tagged)
// edx = address of receiver argument
// edi = address of parameter map or backing store (tagged)
// esp[0] = mapped parameter count (tagged)
// esp[4] = function
// esp[8] = parameter count (tagged)
// esp[12] = address of receiver argument
// Free a register.
// Free two registers.
__ push(edx);
__ push(eax);
// Initialize parameter map. If there are no mapped arguments, we're done.
@ -670,9 +678,9 @@ void ArgumentsAccessStub::GenerateNewSloppyFast(MacroAssembler* masm) {
// We loop from right to left.
Label parameters_loop, parameters_test;
__ push(ecx);
__ mov(eax, Operand(esp, 2 * kPointerSize));
__ mov(eax, Operand(esp, 3 * kPointerSize));
__ mov(ebx, Immediate(Smi::FromInt(Context::MIN_CONTEXT_SLOTS)));
__ add(ebx, Operand(esp, 4 * kPointerSize));
__ add(ebx, Operand(esp, 5 * kPointerSize));
__ sub(ebx, eax);
__ mov(ecx, isolate()->factory()->the_hole_value());
__ mov(edx, edi);
@ -684,9 +692,10 @@ void ArgumentsAccessStub::GenerateNewSloppyFast(MacroAssembler* masm) {
// edi = address of backing store (tagged)
// esp[0] = argument count (tagged)
// esp[4] = address of new object (tagged)
// esp[8] = mapped parameter count (tagged)
// esp[16] = parameter count (tagged)
// esp[20] = address of receiver argument
// esp[8] = address of receiver argument
// esp[12] = mapped parameter count (tagged)
// esp[16] = function
// esp[20] = parameter count (tagged)
__ jmp(&parameters_test, Label::kNear);
__ bind(&parameters_loop);
@ -704,17 +713,18 @@ void ArgumentsAccessStub::GenerateNewSloppyFast(MacroAssembler* masm) {
// ecx = argument count (tagged)
// edi = address of backing store (tagged)
// esp[0] = address of new object (tagged)
// esp[4] = mapped parameter count (tagged)
// esp[12] = parameter count (tagged)
// esp[16] = address of receiver argument
// esp[4] = address of receiver argument
// esp[8] = mapped parameter count (tagged)
// esp[12] = function
// esp[16] = parameter count (tagged)
// Copy arguments header and remaining slots (if there are any).
__ mov(FieldOperand(edi, FixedArray::kMapOffset),
Immediate(isolate()->factory()->fixed_array_map()));
__ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx);
Label arguments_loop, arguments_test;
__ mov(ebx, Operand(esp, 1 * kPointerSize));
__ mov(edx, Operand(esp, 4 * kPointerSize));
__ mov(ebx, Operand(esp, 2 * kPointerSize));
__ mov(edx, Operand(esp, 1 * kPointerSize));
__ sub(edx, ebx); // Is there a smarter way to do negative scaling?
__ sub(edx, ebx);
__ jmp(&arguments_test, Label::kNear);
@ -731,57 +741,60 @@ void ArgumentsAccessStub::GenerateNewSloppyFast(MacroAssembler* masm) {
// Restore.
__ pop(eax); // Address of arguments object.
__ pop(ebx); // Parameter count.
__ Drop(4);
// Return and remove the on-stack parameters.
__ ret(3 * kPointerSize);
// Return.
__ ret(0);
// Do the runtime call to allocate the arguments object.
__ bind(&runtime);
__ pop(eax); // Remove saved parameter count.
__ mov(Operand(esp, 1 * kPointerSize), ecx); // Patch argument count.
__ pop(eax); // Remove saved mapped parameter count.
__ pop(edi); // Pop saved function.
__ pop(eax); // Remove saved parameter count.
__ pop(eax); // Pop return address.
__ push(edi); // Push function.
__ push(edx); // Push parameters pointer.
__ push(ecx); // Push parameter count.
__ push(eax); // Push return address.
__ TailCallRuntime(Runtime::kNewSloppyArguments, 3, 1);
}
void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
// ecx : number of parameters (tagged)
// edx : parameters pointer
// edi : function
// esp[0] : return address
// esp[4] : number of parameters
// esp[8] : receiver displacement
// esp[12] : function
DCHECK(edi.is(ArgumentsAccessNewDescriptor::function()));
DCHECK(ecx.is(ArgumentsAccessNewDescriptor::parameter_count()));
DCHECK(edx.is(ArgumentsAccessNewDescriptor::parameter_pointer()));
// Check if the calling frame is an arguments adaptor frame.
Label adaptor_frame, try_allocate, runtime;
__ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
__ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
__ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
__ j(equal, &adaptor_frame, Label::kNear);
// Get the length from the frame.
__ mov(ecx, Operand(esp, 1 * kPointerSize));
__ jmp(&try_allocate, Label::kNear);
Label try_allocate, runtime;
__ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
__ mov(eax, Operand(ebx, StandardFrameConstants::kContextOffset));
__ cmp(eax, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
__ j(not_equal, &try_allocate, Label::kNear);
// Patch the arguments.length and the parameters pointer.
__ bind(&adaptor_frame);
__ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
__ lea(edx, Operand(edx, ecx, times_2,
StandardFrameConstants::kCallerSPOffset));
__ mov(Operand(esp, 1 * kPointerSize), ecx);
__ mov(Operand(esp, 2 * kPointerSize), edx);
__ mov(ecx, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
__ lea(edx,
Operand(ebx, ecx, times_2, StandardFrameConstants::kCallerSPOffset));
// 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);
__ test(ecx, ecx);
__ mov(eax, ecx);
__ test(eax, eax);
__ j(zero, &add_arguments_object, Label::kNear);
__ lea(ecx, Operand(ecx, times_2, FixedArray::kHeaderSize));
__ lea(eax, Operand(eax, times_2, FixedArray::kHeaderSize));
__ bind(&add_arguments_object);
__ add(ecx, Immediate(Heap::kStrictArgumentsObjectSize));
__ add(eax, Immediate(Heap::kStrictArgumentsObjectSize));
// Do the allocation of both objects in one go.
__ Allocate(ecx, eax, edx, ebx, &runtime, TAG_OBJECT);
__ Allocate(eax, eax, ebx, no_reg, &runtime, TAG_OBJECT);
// Get the arguments map from the current native context.
__ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
@ -797,7 +810,6 @@ void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
// Get the length (smi tagged) and set that as an in-object property too.
STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
__ mov(ecx, Operand(esp, 1 * kPointerSize));
__ AssertSmi(ecx);
__ mov(FieldOperand(eax, JSObject::kHeaderSize +
Heap::kArgumentsLengthIndex * kPointerSize),
@ -808,17 +820,14 @@ void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
__ test(ecx, ecx);
__ j(zero, &done, Label::kNear);
// Get the parameters pointer from the stack.
__ mov(edx, Operand(esp, 2 * kPointerSize));
// Set up the elements pointer in the allocated arguments object and
// initialize the header in the elements fixed array.
__ lea(edi, Operand(eax, Heap::kStrictArgumentsObjectSize));
__ mov(FieldOperand(eax, JSObject::kElementsOffset), edi);
__ mov(FieldOperand(edi, FixedArray::kMapOffset),
Immediate(isolate()->factory()->fixed_array_map()));
__ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx);
// Untag the length for the loop below.
__ SmiUntag(ecx);
@ -832,12 +841,17 @@ void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
__ dec(ecx);
__ j(not_zero, &loop);
// Return and remove the on-stack parameters.
// Return.
__ bind(&done);
__ ret(3 * kPointerSize);
__ ret(0);
// Do the runtime call to allocate the arguments object.
__ bind(&runtime);
__ pop(eax); // Pop return address.
__ push(edi); // Push function.
__ push(edx); // Push parameters pointer.
__ push(ecx); // Push parameter count.
__ push(eax); // Push return address.
__ TailCallRuntime(Runtime::kNewStrictArguments, 3, 1);
}

View File

@ -65,6 +65,11 @@ const Register ArgumentsAccessReadDescriptor::index() { return edx; }
const Register ArgumentsAccessReadDescriptor::parameter_count() { return eax; }
const Register ArgumentsAccessNewDescriptor::function() { return edi; }
const Register ArgumentsAccessNewDescriptor::parameter_count() { return ecx; }
const Register ArgumentsAccessNewDescriptor::parameter_pointer() { return edx; }
const Register ApiGetterDescriptor::function_address() { return edx; }