Commit f4da4361 authored by bjaideep's avatar bjaideep Committed by Commit bot

PPC/s390: [turbofan] Avoid allocating rest parameters for spread calls.

Port bfa319e5

Original Commit Message:

    We already had an optimization to turn Function.prototype.apply with
    arguments object, i.e.

      function foo() { return bar.apply(this, arguments); }

    into a special operator JSCallForwardVarargs, which avoids the
    allocation and deconstruction of the arguments object, but just passes
    along the incoming parameters. We can do the same for rest parameters
    and spread calls/constructs, i.e.

      class A extends B {
        constructor(...args) { super(...args); }
      }

    or

      function foo(...args) { return bar(1, 2, 3, ...args); }

    where we basically pass along the parameters (plus maybe additional
    statically known parameters).

    For this, we introduce a new JSConstructForwardVarargs operator and
    generalize the CallForwardVarargs builtins that are backing this.

R=bmeurer@chromium.org, joransiu@ca.ibm.com, jyan@ca.ibm.com, michael_dawson@ca.ibm.com
BUG=v8:6407,v8:6278,v8:6344
LOG=N

Review-Url: https://codereview.chromium.org/2887153004
Cr-Commit-Position: refs/heads/master@{#45402}
parent 72edb754
......@@ -2198,63 +2198,63 @@ void Builtins::Generate_Apply(MacroAssembler* masm) {
}
// static
void Builtins::Generate_CallForwardVarargs(MacroAssembler* masm,
Handle<Code> code) {
void Builtins::Generate_ForwardVarargs(MacroAssembler* masm,
Handle<Code> code) {
// ----------- S t a t e -------------
// -- r4 : the target to call (can be any Object)
// -- r5 : start index (to support rest parameters)
// -- lr : return address.
// -- sp[0] : thisArgument
// -- r3 : the number of arguments (not including the receiver)
// -- r6 : the new.target (for [[Construct]] calls)
// -- r4 : the target to call (can be any Object)
// -- r5 : start index (to support rest parameters)
// -----------------------------------
// Check if we have an arguments adaptor frame below the function frame.
Label arguments_adaptor, arguments_done;
__ LoadP(r6, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
__ LoadP(ip, MemOperand(r6, CommonFrameConstants::kContextOrFrameTypeOffset));
__ LoadP(r7, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
__ LoadP(ip, MemOperand(r7, CommonFrameConstants::kContextOrFrameTypeOffset));
__ cmpi(ip, Operand(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)));
__ beq(&arguments_adaptor);
{
__ LoadP(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
__ LoadP(r3, FieldMemOperand(r3, JSFunction::kSharedFunctionInfoOffset));
__ LoadP(r8, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
__ LoadP(r8, FieldMemOperand(r8, JSFunction::kSharedFunctionInfoOffset));
__ LoadWordArith(
r3,
FieldMemOperand(r3, SharedFunctionInfo::kFormalParameterCountOffset));
__ mr(r6, fp);
r8,
FieldMemOperand(r8, SharedFunctionInfo::kFormalParameterCountOffset));
__ mr(r7, fp);
}
__ b(&arguments_done);
__ bind(&arguments_adaptor);
{
// Load the length from the ArgumentsAdaptorFrame.
__ LoadP(r3, MemOperand(r6, ArgumentsAdaptorFrameConstants::kLengthOffset));
__ LoadP(r8, MemOperand(r7, ArgumentsAdaptorFrameConstants::kLengthOffset));
#if V8_TARGET_ARCH_PPC64
__ SmiUntag(r3);
__ SmiUntag(r8);
#endif
}
__ bind(&arguments_done);
Label stack_empty, stack_done, stack_overflow;
Label stack_done, stack_overflow;
#if !V8_TARGET_ARCH_PPC64
__ SmiUntag(r3);
__ SmiUntag(r8);
#endif
__ sub(r3, r3, r5);
__ cmpi(r3, Operand::Zero());
__ ble(&stack_empty);
__ sub(r8, r8, r5);
__ cmpi(r8, Operand::Zero());
__ ble(&stack_done);
{
// Check for stack overflow.
Generate_StackOverflowCheck(masm, r3, r5, &stack_overflow);
Generate_StackOverflowCheck(masm, r8, r5, &stack_overflow);
// Forward the arguments from the caller frame.
{
Label loop;
__ addi(r6, r6, Operand(kPointerSize));
__ mr(r5, r3);
__ addi(r7, r7, Operand(kPointerSize));
__ add(r3, r3, r8);
__ bind(&loop);
{
__ ShiftLeftImm(ip, r5, Operand(kPointerSizeLog2));
__ LoadPX(ip, MemOperand(r6, ip));
__ ShiftLeftImm(ip, r8, Operand(kPointerSizeLog2));
__ LoadPX(ip, MemOperand(r7, ip));
__ push(ip);
__ subi(r5, r5, Operand(1));
__ cmpi(r5, Operand::Zero());
__ subi(r8, r8, Operand(1));
__ cmpi(r8, Operand::Zero());
__ bne(&loop);
}
}
......@@ -2262,13 +2262,9 @@ void Builtins::Generate_CallForwardVarargs(MacroAssembler* masm,
__ b(&stack_done);
__ bind(&stack_overflow);
__ TailCallRuntime(Runtime::kThrowStackOverflow);
__ bind(&stack_empty);
{
// We just pass the receiver, which is already on the stack.
__ mov(r3, Operand::Zero());
}
__ bind(&stack_done);
// Tail-call to the {code} handler.
__ Jump(code, RelocInfo::CODE_TARGET);
}
......
......@@ -2197,62 +2197,62 @@ void Builtins::Generate_Apply(MacroAssembler* masm) {
}
// static
void Builtins::Generate_CallForwardVarargs(MacroAssembler* masm,
Handle<Code> code) {
void Builtins::Generate_ForwardVarargs(MacroAssembler* masm,
Handle<Code> code) {
// ----------- S t a t e -------------
// -- r3 : the target to call (can be any Object)
// -- r4 : start index (to support rest parameters)
// -- lr : return address.
// -- sp[0] : thisArgument
// -- r2 : the number of arguments (not including the receiver)
// -- r5 : the new.target (for [[Construct]] calls)
// -- r3 : the target to call (can be any Object)
// -- r4 : start index (to support rest parameters)
// -----------------------------------
// Check if we have an arguments adaptor frame below the function frame.
Label arguments_adaptor, arguments_done;
__ LoadP(r5, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
__ LoadP(ip, MemOperand(r5, CommonFrameConstants::kContextOrFrameTypeOffset));
__ LoadP(r6, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
__ LoadP(ip, MemOperand(r6, CommonFrameConstants::kContextOrFrameTypeOffset));
__ CmpP(ip, Operand(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)));
__ beq(&arguments_adaptor);
{
__ LoadP(r2, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
__ LoadP(r2, FieldMemOperand(r2, JSFunction::kSharedFunctionInfoOffset));
__ LoadW(r2, FieldMemOperand(
r2, SharedFunctionInfo::kFormalParameterCountOffset));
__ LoadRR(r5, fp);
__ LoadP(r7, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
__ LoadP(r7, FieldMemOperand(r7, JSFunction::kSharedFunctionInfoOffset));
__ LoadW(r7, FieldMemOperand(
r7, SharedFunctionInfo::kFormalParameterCountOffset));
__ LoadRR(r6, fp);
}
__ b(&arguments_done);
__ bind(&arguments_adaptor);
{
// Load the length from the ArgumentsAdaptorFrame.
__ LoadP(r2, MemOperand(r5, ArgumentsAdaptorFrameConstants::kLengthOffset));
__ LoadP(r7, MemOperand(r6, ArgumentsAdaptorFrameConstants::kLengthOffset));
#if V8_TARGET_ARCH_S390X
__ SmiUntag(r2);
__ SmiUntag(r7);
#endif
}
__ bind(&arguments_done);
Label stack_empty, stack_done, stack_overflow;
Label stack_done, stack_overflow;
#if !V8_TARGET_ARCH_S390X
__ SmiUntag(r2);
__ SmiUntag(r7);
#endif
__ SubP(r2, r2, r4);
__ CmpP(r2, Operand::Zero());
__ ble(&stack_empty);
__ SubP(r7, r7, r4);
__ CmpP(r7, Operand::Zero());
__ ble(&stack_done);
{
// Check for stack overflow.
Generate_StackOverflowCheck(masm, r2, r4, &stack_overflow);
Generate_StackOverflowCheck(masm, r7, r4, &stack_overflow);
// Forward the arguments from the caller frame.
{
Label loop;
__ AddP(r5, r5, Operand(kPointerSize));
__ LoadRR(r4, r2);
__ AddP(r6, r6, Operand(kPointerSize));
__ AddP(r2, r2, r7);
__ bind(&loop);
{
__ ShiftLeftP(ip, r4, Operand(kPointerSizeLog2));
__ LoadP(ip, MemOperand(r5, ip));
__ ShiftLeftP(ip, r7, Operand(kPointerSizeLog2));
__ LoadP(ip, MemOperand(r6, ip));
__ push(ip);
__ SubP(r4, r4, Operand(1));
__ CmpP(r4, Operand::Zero());
__ SubP(r7, r7, Operand(1));
__ CmpP(r7, Operand::Zero());
__ bne(&loop);
}
}
......@@ -2260,13 +2260,9 @@ void Builtins::Generate_CallForwardVarargs(MacroAssembler* masm,
__ b(&stack_done);
__ bind(&stack_overflow);
__ TailCallRuntime(Runtime::kThrowStackOverflow);
__ bind(&stack_empty);
{
// We just pass the receiver, which is already on the stack.
__ mov(r2, Operand::Zero());
}
__ bind(&stack_done);
// Tail-call to the {code} handler.
__ Jump(code, RelocInfo::CODE_TARGET);
}
......
......@@ -155,9 +155,20 @@ void CallTrampolineDescriptor::InitializePlatformSpecific(
void CallForwardVarargsDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
// r3 : number of arguments
// r5 : start index (to support rest parameters)
// r4 : the target to call
Register registers[] = {r4, r3, r5};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void ConstructForwardVarargsDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
// r3 : number of arguments
// r6 : the new target
// r5 : start index (to support rest parameters)
// r4 : the target to call
Register registers[] = {r4, r5};
Register registers[] = {r4, r6, r3, r5};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
......
......@@ -145,9 +145,20 @@ void CallTrampolineDescriptor::InitializePlatformSpecific(
void CallForwardVarargsDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
// r2 : number of arguments
// r4 : start index (to support rest parameters)
// r3 : the target to call
Register registers[] = {r3, r2, r4};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void ConstructForwardVarargsDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
// r2 : number of arguments
// r5 : the new target
// r4 : start index (to support rest parameters)
// r3 : the target to call
Register registers[] = {r3, r4};
Register registers[] = {r3, r5, r2, r4};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
......
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