Commit c005029a authored by rmcilroy's avatar rmcilroy Committed by Commit bot

[Interpreter] Use FastNewSloppyArguments when possible.

Use the FastNewSloppyArgumentsStub in the interpreter when function doesn't have
duplicate parameters.

BUG=v8:4280
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#35754}
parent d1fb8384
......@@ -4800,23 +4800,40 @@ void FastNewSloppyArgumentsStub::Generate(MacroAssembler* masm) {
// -----------------------------------
__ AssertFunction(r1);
// For Ignition we need to skip all possible handler/stub frames until
// we reach the JavaScript frame for the function (similar to what the
// runtime fallback implementation does). So make r9 point to that
// JavaScript frame.
{
Label loop, loop_entry;
__ mov(r9, fp);
__ b(&loop_entry);
__ bind(&loop);
__ ldr(r9, MemOperand(r9, StandardFrameConstants::kCallerFPOffset));
__ bind(&loop_entry);
__ ldr(ip, MemOperand(r9, StandardFrameConstants::kFunctionOffset));
__ cmp(ip, r1);
__ b(ne, &loop);
}
// TODO(bmeurer): Cleanup to match the FastNewStrictArgumentsStub.
__ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
__ ldr(r2,
FieldMemOperand(r2, SharedFunctionInfo::kFormalParameterCountOffset));
__ add(r3, fp, Operand(r2, LSL, kPointerSizeLog2 - 1));
__ add(r3, r9, Operand(r2, LSL, kPointerSizeLog2 - 1));
__ add(r3, r3, Operand(StandardFrameConstants::kCallerSPOffset));
// r1 : function
// r2 : number of parameters (tagged)
// r3 : parameters pointer
// r9 : JavaScript frame pointer
// Registers used over whole function:
// r5 : arguments count (tagged)
// r6 : mapped parameter count (tagged)
// Check if the calling frame is an arguments adaptor frame.
Label adaptor_frame, try_allocate, runtime;
__ ldr(r4, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
__ ldr(r4, MemOperand(r9, StandardFrameConstants::kCallerFPOffset));
__ ldr(r0, MemOperand(r4, CommonFrameConstants::kContextOrFrameTypeOffset));
__ cmp(r0, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
__ b(eq, &adaptor_frame);
......
......@@ -5076,17 +5076,34 @@ void FastNewSloppyArgumentsStub::Generate(MacroAssembler* masm) {
// -----------------------------------
__ AssertFunction(x1);
// For Ignition we need to skip all possible handler/stub frames until
// we reach the JavaScript frame for the function (similar to what the
// runtime fallback implementation does). So make x6 point to that
// JavaScript frame.
{
Label loop, loop_entry;
__ Mov(x6, fp);
__ B(&loop_entry);
__ Bind(&loop);
__ Ldr(x6, MemOperand(x6, StandardFrameConstants::kCallerFPOffset));
__ Bind(&loop_entry);
__ Ldr(x3, MemOperand(x6, StandardFrameConstants::kFunctionOffset));
__ Cmp(x3, x1);
__ B(ne, &loop);
}
// TODO(bmeurer): Cleanup to match the FastNewStrictArgumentsStub.
__ Ldr(x2, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset));
__ Ldrsw(
x2, FieldMemOperand(x2, SharedFunctionInfo::kFormalParameterCountOffset));
__ Add(x3, fp, Operand(x2, LSL, kPointerSizeLog2));
__ Add(x3, x6, Operand(x2, LSL, kPointerSizeLog2));
__ Add(x3, x3, Operand(StandardFrameConstants::kCallerSPOffset));
__ SmiTag(x2);
// x1 : function
// x2 : number of parameters (tagged)
// x3 : parameters pointer
// x6 : JavaScript frame pointer
//
// Returns pointer to result object in x0.
......@@ -5104,7 +5121,7 @@ void FastNewSloppyArgumentsStub::Generate(MacroAssembler* masm) {
Register caller_ctx = x12;
Label runtime;
Label adaptor_frame, try_allocate;
__ Ldr(caller_fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
__ Ldr(caller_fp, MemOperand(x6, StandardFrameConstants::kCallerFPOffset));
__ Ldr(
caller_ctx,
MemOperand(caller_fp, CommonFrameConstants::kContextOrFrameTypeOffset));
......
......@@ -4973,35 +4973,50 @@ void FastNewSloppyArgumentsStub::Generate(MacroAssembler* masm) {
// -----------------------------------
__ AssertFunction(edi);
// For Ignition we need to skip all possible handler/stub frames until
// we reach the JavaScript frame for the function (similar to what the
// runtime fallback implementation does). So make ebx point to that
// JavaScript frame.
{
Label loop, loop_entry;
__ mov(ecx, ebp);
__ jmp(&loop_entry, Label::kNear);
__ bind(&loop);
__ mov(ecx, Operand(ecx, StandardFrameConstants::kCallerFPOffset));
__ bind(&loop_entry);
__ cmp(edi, Operand(ecx, StandardFrameConstants::kFunctionOffset));
__ j(not_equal, &loop);
}
// TODO(bmeurer): Cleanup to match the FastNewStrictArgumentsStub.
__ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
__ mov(ecx,
FieldOperand(ecx, SharedFunctionInfo::kFormalParameterCountOffset));
__ lea(edx, Operand(ebp, ecx, times_half_pointer_size,
__ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
__ mov(ebx,
FieldOperand(ebx, SharedFunctionInfo::kFormalParameterCountOffset));
__ lea(edx, Operand(ecx, ebx, times_half_pointer_size,
StandardFrameConstants::kCallerSPOffset));
// ecx : number of parameters (tagged)
// ebx : number of parameters (tagged)
// edx : parameters pointer
// edi : function
// ecx : JavaScript frame pointer.
// esp[0] : return address
// Check if the calling frame is an arguments adaptor frame.
Label adaptor_frame, try_allocate, runtime;
__ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
__ mov(eax, Operand(ebx, CommonFrameConstants::kContextOrFrameTypeOffset));
__ mov(eax, Operand(ecx, StandardFrameConstants::kCallerFPOffset));
__ mov(eax, Operand(eax, CommonFrameConstants::kContextOrFrameTypeOffset));
__ cmp(eax, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
__ j(equal, &adaptor_frame, Label::kNear);
// No adaptor, parameter count = argument count.
__ mov(ebx, ecx);
__ push(ecx);
__ mov(ecx, ebx);
__ push(ebx);
__ 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));
__ push(ebx);
__ mov(edx, Operand(ecx, StandardFrameConstants::kCallerFPOffset));
__ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
__ lea(edx, Operand(edx, ecx, times_2,
StandardFrameConstants::kCallerSPOffset));
......
......@@ -22,6 +22,8 @@ namespace internal {
namespace interpreter {
using compiler::Node;
typedef CodeStubAssembler::Label Label;
typedef CodeStubAssembler::Variable Variable;
#define __ assembler->
......@@ -1471,9 +1473,40 @@ void Interpreter::DoCreateClosure(InterpreterAssembler* assembler) {
void Interpreter::DoCreateMappedArguments(InterpreterAssembler* assembler) {
Node* closure = __ LoadRegister(Register::function_closure());
Node* context = __ GetContext();
Node* result =
__ CallRuntime(Runtime::kNewSloppyArguments_Generic, context, closure);
__ SetAccumulator(result);
Variable result(assembler, MachineRepresentation::kTagged);
Label end(assembler), if_duplicate_parameters(assembler),
if_not_duplicate_parameters(assembler);
// Check if function has duplicate parameters.
// TODO(rmcilroy): Remove this check when FastNewSloppyArgumentsStub supports
// duplicate parameters.
Node* shared_info =
__ LoadObjectField(closure, JSFunction::kSharedFunctionInfoOffset);
Node* compiler_hints = __ LoadObjectField(
shared_info, SharedFunctionInfo::kHasDuplicateParametersByteOffset,
MachineType::Uint8());
Node* duplicate_parameters_bit = __ Int32Constant(
1 << SharedFunctionInfo::kHasDuplicateParametersBitWithinByte);
Node* compare = __ Word32And(compiler_hints, duplicate_parameters_bit);
__ BranchIf(compare, &if_duplicate_parameters, &if_not_duplicate_parameters);
__ Bind(&if_duplicate_parameters);
{
result.Bind(
__ CallRuntime(Runtime::kNewSloppyArguments_Generic, context, closure));
__ Goto(&end);
}
__ Bind(&if_not_duplicate_parameters);
{
Callable callable = CodeFactory::FastNewSloppyArguments(isolate_);
Node* target = __ HeapConstant(callable.code());
result.Bind(__ CallStub(callable.descriptor(), target, context, closure));
__ Goto(&end);
}
__ Bind(&end);
__ SetAccumulator(result.value());
__ Dispatch();
}
......
......@@ -4991,23 +4991,39 @@ void FastNewSloppyArgumentsStub::Generate(MacroAssembler* masm) {
// -----------------------------------
__ AssertFunction(a1);
// For Ignition we need to skip all possible handler/stub frames until
// we reach the JavaScript frame for the function (similar to what the
// runtime fallback implementation does). So make t0 point to that
// JavaScript frame.
{
Label loop, loop_entry;
__ Branch(USE_DELAY_SLOT, &loop_entry);
__ mov(t0, fp); // In delay slot.
__ bind(&loop);
__ lw(t0, MemOperand(t0, StandardFrameConstants::kCallerFPOffset));
__ bind(&loop_entry);
__ lw(a3, MemOperand(t0, StandardFrameConstants::kFunctionOffset));
__ Branch(&loop, ne, a1, Operand(a3));
}
// TODO(bmeurer): Cleanup to match the FastNewStrictArgumentsStub.
__ lw(a2, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
__ lw(a2,
FieldMemOperand(a2, SharedFunctionInfo::kFormalParameterCountOffset));
__ Lsa(a3, fp, a2, kPointerSizeLog2 - 1);
__ Lsa(a3, t0, a2, kPointerSizeLog2 - 1);
__ Addu(a3, a3, Operand(StandardFrameConstants::kCallerSPOffset));
// a1 : function
// a2 : number of parameters (tagged)
// a3 : parameters pointer
// t0 : Javascript frame pointer
// Registers used over whole function:
// t1 : arguments count (tagged)
// t2 : mapped parameter count (tagged)
// Check if the calling frame is an arguments adaptor frame.
Label adaptor_frame, try_allocate, runtime;
__ lw(t0, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
__ lw(t0, MemOperand(t0, StandardFrameConstants::kCallerFPOffset));
__ lw(a0, MemOperand(t0, CommonFrameConstants::kContextOrFrameTypeOffset));
__ Branch(&adaptor_frame, eq, a0,
Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
......
......@@ -5007,24 +5007,40 @@ void FastNewSloppyArgumentsStub::Generate(MacroAssembler* masm) {
// -----------------------------------
__ AssertFunction(a1);
// For Ignition we need to skip all possible handler/stub frames until
// we reach the JavaScript frame for the function (similar to what the
// runtime fallback implementation does). So make t0 point to that
// JavaScript frame.
{
Label loop, loop_entry;
__ Branch(USE_DELAY_SLOT, &loop_entry);
__ mov(t0, fp); // In delay slot.
__ bind(&loop);
__ ld(t0, MemOperand(t0, StandardFrameConstants::kCallerFPOffset));
__ bind(&loop_entry);
__ ld(a3, MemOperand(t0, StandardFrameConstants::kFunctionOffset));
__ Branch(&loop, ne, a1, Operand(a3));
}
// TODO(bmeurer): Cleanup to match the FastNewStrictArgumentsStub.
__ ld(a2, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
__ lw(a2,
FieldMemOperand(a2, SharedFunctionInfo::kFormalParameterCountOffset));
__ Lsa(a3, fp, a2, kPointerSizeLog2);
__ Lsa(a3, t0, a2, kPointerSizeLog2);
__ Addu(a3, a3, Operand(StandardFrameConstants::kCallerSPOffset));
__ SmiTag(a2);
// a1 : function
// a2 : number of parameters (tagged)
// a3 : parameters pointer
// t0 : Javascript frame pointer
// Registers used over whole function:
// a5 : arguments count (tagged)
// a6 : mapped parameter count (tagged)
// Check if the calling frame is an arguments adaptor frame.
Label adaptor_frame, try_allocate, runtime;
__ ld(a4, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
__ ld(a4, MemOperand(t0, StandardFrameConstants::kCallerFPOffset));
__ ld(a0, MemOperand(a4, CommonFrameConstants::kContextOrFrameTypeOffset));
__ Branch(&adaptor_frame, eq, a0,
Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
......
......@@ -7256,6 +7256,8 @@ class SharedFunctionInfo: public HeapObject {
static const int kStrictModeBit =
kStrictModeFunction + kCompilerHintsSmiTagSize;
static const int kNativeBit = kNative + kCompilerHintsSmiTagSize;
static const int kHasDuplicateParametersBit =
kHasDuplicateParameters + kCompilerHintsSmiTagSize;
static const int kClassConstructorBits =
FunctionKind::kClassConstructor
......@@ -7266,6 +7268,8 @@ class SharedFunctionInfo: public HeapObject {
// Allows to use byte-width instructions.
static const int kStrictModeBitWithinByte = kStrictModeBit % kBitsPerByte;
static const int kNativeBitWithinByte = kNativeBit % kBitsPerByte;
static const int kHasDuplicateParametersBitWithinByte =
kHasDuplicateParametersBit % kBitsPerByte;
static const int kClassConstructorBitsWithinByte =
FunctionKind::kClassConstructor << kCompilerHintsSmiTagSize;
......@@ -7285,6 +7289,8 @@ class SharedFunctionInfo: public HeapObject {
static const int kStrictModeByteOffset = BYTE_OFFSET(kStrictModeFunction);
static const int kNativeByteOffset = BYTE_OFFSET(kNative);
static const int kFunctionKindByteOffset = BYTE_OFFSET(kFunctionKind);
static const int kHasDuplicateParametersByteOffset =
BYTE_OFFSET(kHasDuplicateParameters);
#undef BYTE_OFFSET
private:
......
......@@ -4709,11 +4709,26 @@ void FastNewSloppyArgumentsStub::Generate(MacroAssembler* masm) {
// -----------------------------------
__ AssertFunction(rdi);
// For Ignition we need to skip all possible handler/stub frames until
// we reach the JavaScript frame for the function (similar to what the
// runtime fallback implementation does). So make r9 point to that
// JavaScript frame.
{
Label loop, loop_entry;
__ movp(r9, rbp);
__ jmp(&loop_entry, Label::kNear);
__ bind(&loop);
__ movp(r9, Operand(r9, StandardFrameConstants::kCallerFPOffset));
__ bind(&loop_entry);
__ cmpp(rdi, Operand(r9, StandardFrameConstants::kFunctionOffset));
__ j(not_equal, &loop);
}
// TODO(bmeurer): Cleanup to match the FastNewStrictArgumentsStub.
__ movp(rcx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
__ LoadSharedFunctionInfoSpecialField(
rcx, rcx, SharedFunctionInfo::kFormalParameterCountOffset);
__ leap(rdx, Operand(rbp, rcx, times_pointer_size,
__ leap(rdx, Operand(r9, rcx, times_pointer_size,
StandardFrameConstants::kCallerSPOffset));
__ Integer32ToSmi(rcx, rcx);
......@@ -4721,6 +4736,7 @@ void FastNewSloppyArgumentsStub::Generate(MacroAssembler* masm) {
// rdx : parameters pointer
// rdi : function
// rsp[0] : return address
// r9 : JavaScript frame pointer.
// Registers used over the whole function:
// rbx: the mapped parameter count (untagged)
// rax: the allocated object (tagged).
......@@ -4731,7 +4747,7 @@ void FastNewSloppyArgumentsStub::Generate(MacroAssembler* masm) {
// Check if the calling frame is an arguments adaptor frame.
Label adaptor_frame, try_allocate, runtime;
__ movp(rax, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
__ movp(rax, Operand(r9, StandardFrameConstants::kCallerFPOffset));
__ movp(r8, Operand(rax, CommonFrameConstants::kContextOrFrameTypeOffset));
__ Cmp(r8, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
__ j(equal, &adaptor_frame);
......
......@@ -2259,6 +2259,8 @@ TEST(InterpreterCreateArguments) {
std::make_pair("function f(a, b, c, d) {"
" 'use strict'; c = b; return arguments[2]; }",
2),
// Check arguments for duplicate parameters in sloppy mode.
std::make_pair("function f(a, a, b) { return arguments[1]; }", 1),
// check rest parameters
std::make_pair("function f(...restArray) { return restArray[0]; }", 0),
std::make_pair("function f(a, ...restArray) { return restArray[0]; }", 1),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment