[turbofan] Avoid allocating rest parameters for spread calls.

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.

BUG=v8:6407,v8:6278,v8:6344
R=jarin@chromium.org

Review-Url: https://codereview.chromium.org/2890023004
Cr-Commit-Position: refs/heads/master@{#45388}
This commit is contained in:
bmeurer 2017-05-18 00:32:22 -07:00 committed by Commit bot
parent 8038e5cac4
commit bfa319e5d3
30 changed files with 476 additions and 225 deletions

View File

@ -157,9 +157,20 @@ void CallTrampolineDescriptor::InitializePlatformSpecific(
void CallForwardVarargsDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
// r0 : number of arguments
// r2 : start index (to support rest parameters)
// r1 : the target to call
Register registers[] = {r1, r2};
Register registers[] = {r1, r0, r2};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void ConstructForwardVarargsDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
// r0 : number of arguments
// r3 : the new target
// r2 : start index (to support rest parameters)
// r1 : the target to call
Register registers[] = {r1, r3, r0, r2};
data->InitializePlatformSpecific(arraysize(registers), registers);
}

View File

@ -177,8 +177,19 @@ void CallTrampolineDescriptor::InitializePlatformSpecific(
void CallForwardVarargsDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
// x1: target
// x0: number of arguments
// x2: start index (to supported rest parameters)
Register registers[] = {x1, x2};
Register registers[] = {x1, x0, x2};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void ConstructForwardVarargsDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
// x3: new target
// x1: target
// x0: number of arguments
// x2: start index (to supported rest parameters)
Register registers[] = {x1, x3, x0, x2};
data->InitializePlatformSpecific(arraysize(registers), registers);
}

View File

@ -2153,54 +2153,54 @@ 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 -------------
// -- r1 : the target to call (can be any Object)
// -- r2 : start index (to support rest parameters)
// -- lr : return address.
// -- sp[0] : thisArgument
// -- r0 : the number of arguments (not including the receiver)
// -- r3 : the new.target (for [[Construct]] calls)
// -- r1 : the target to call (can be any Object)
// -- r2 : start index (to support rest parameters)
// -----------------------------------
// Check if we have an arguments adaptor frame below the function frame.
Label arguments_adaptor, arguments_done;
__ ldr(r3, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
__ ldr(ip, MemOperand(r3, CommonFrameConstants::kContextOrFrameTypeOffset));
__ ldr(r4, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
__ ldr(ip, MemOperand(r4, CommonFrameConstants::kContextOrFrameTypeOffset));
__ cmp(ip, Operand(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)));
__ b(eq, &arguments_adaptor);
{
__ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
__ ldr(r0, FieldMemOperand(r0, JSFunction::kSharedFunctionInfoOffset));
__ ldr(r0, FieldMemOperand(
r0, SharedFunctionInfo::kFormalParameterCountOffset));
__ mov(r3, fp);
__ ldr(r5, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
__ ldr(r5, FieldMemOperand(r5, JSFunction::kSharedFunctionInfoOffset));
__ ldr(r5, FieldMemOperand(
r5, SharedFunctionInfo::kFormalParameterCountOffset));
__ mov(r4, fp);
}
__ b(&arguments_done);
__ bind(&arguments_adaptor);
{
// Load the length from the ArgumentsAdaptorFrame.
__ ldr(r0, MemOperand(r3, ArgumentsAdaptorFrameConstants::kLengthOffset));
__ ldr(r5, MemOperand(r4, ArgumentsAdaptorFrameConstants::kLengthOffset));
}
__ bind(&arguments_done);
Label stack_empty, stack_done, stack_overflow;
__ SmiUntag(r0);
__ sub(r0, r0, r2, SetCC);
__ b(le, &stack_empty);
Label stack_done, stack_overflow;
__ SmiUntag(r5);
__ sub(r5, r5, r2, SetCC);
__ b(le, &stack_done);
{
// Check for stack overflow.
Generate_StackOverflowCheck(masm, r0, r2, &stack_overflow);
Generate_StackOverflowCheck(masm, r5, r2, &stack_overflow);
// Forward the arguments from the caller frame.
{
Label loop;
__ add(r3, r3, Operand(kPointerSize));
__ mov(r2, r0);
__ add(r4, r4, Operand(kPointerSize));
__ add(r0, r0, r5);
__ bind(&loop);
{
__ ldr(ip, MemOperand(r3, r2, LSL, kPointerSizeLog2));
__ ldr(ip, MemOperand(r4, r5, LSL, kPointerSizeLog2));
__ push(ip);
__ sub(r2, r2, Operand(1), SetCC);
__ sub(r5, r5, Operand(1), SetCC);
__ b(ne, &loop);
}
}
@ -2208,13 +2208,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(r0, Operand(0));
}
__ bind(&stack_done);
// Tail-call to the {code} handler.
__ Jump(code, RelocInfo::CODE_TARGET);
}

View File

@ -2286,54 +2286,54 @@ 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 -------------
// -- x1 : the target to call (can be any Object)
// -- x2 : start index (to support rest parameters)
// -- lr : return address.
// -- sp[0] : thisArgument
// -- x0 : the number of arguments (not including the receiver)
// -- x3 : the new.target (for [[Construct]] calls)
// -- x1 : the target to call (can be any Object)
// -- x2 : start index (to support rest parameters)
// -----------------------------------
// Check if we have an arguments adaptor frame below the function frame.
Label arguments_adaptor, arguments_done;
__ Ldr(x3, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
__ Ldr(x4, MemOperand(x3, CommonFrameConstants::kContextOrFrameTypeOffset));
__ Ldr(x5, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
__ Ldr(x4, MemOperand(x5, CommonFrameConstants::kContextOrFrameTypeOffset));
__ Cmp(x4, StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR));
__ B(eq, &arguments_adaptor);
{
__ Ldr(x0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
__ Ldr(x0, FieldMemOperand(x0, JSFunction::kSharedFunctionInfoOffset));
__ Ldrsw(x0, FieldMemOperand(
x0, SharedFunctionInfo::kFormalParameterCountOffset));
__ Mov(x3, fp);
__ Ldr(x6, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
__ Ldr(x6, FieldMemOperand(x6, JSFunction::kSharedFunctionInfoOffset));
__ Ldrsw(x6, FieldMemOperand(
x6, SharedFunctionInfo::kFormalParameterCountOffset));
__ Mov(x5, fp);
}
__ B(&arguments_done);
__ Bind(&arguments_adaptor);
{
// Just load the length from ArgumentsAdaptorFrame.
__ Ldrsw(x0, UntagSmiMemOperand(
x3, ArgumentsAdaptorFrameConstants::kLengthOffset));
__ Ldrsw(x6, UntagSmiMemOperand(
x5, ArgumentsAdaptorFrameConstants::kLengthOffset));
}
__ Bind(&arguments_done);
Label stack_empty, stack_done, stack_overflow;
__ Subs(x0, x0, x2);
__ B(le, &stack_empty);
Label stack_done, stack_overflow;
__ Subs(x6, x6, x2);
__ B(le, &stack_done);
{
// Check for stack overflow.
Generate_StackOverflowCheck(masm, x0, x2, &stack_overflow);
Generate_StackOverflowCheck(masm, x6, x2, &stack_overflow);
// Forward the arguments from the caller frame.
{
Label loop;
__ Add(x3, x3, kPointerSize);
__ Mov(x2, x0);
__ Add(x5, x5, kPointerSize);
__ Add(x0, x0, x6);
__ bind(&loop);
{
__ Ldr(x4, MemOperand(x3, x2, LSL, kPointerSizeLog2));
__ Ldr(x4, MemOperand(x5, x6, LSL, kPointerSizeLog2));
__ Push(x4);
__ Subs(x2, x2, 1);
__ Subs(x6, x6, 1);
__ B(ne, &loop);
}
}
@ -2341,11 +2341,6 @@ 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(x0, 0);
}
__ Bind(&stack_done);
__ Jump(code, RelocInfo::CODE_TARGET);

View File

@ -83,12 +83,11 @@ void Builtins::Generate_TailCall_ReceiverIsAny(MacroAssembler* masm) {
}
void Builtins::Generate_CallForwardVarargs(MacroAssembler* masm) {
Generate_CallForwardVarargs(masm, masm->isolate()->builtins()->Call());
Generate_ForwardVarargs(masm, masm->isolate()->builtins()->Call());
}
void Builtins::Generate_CallFunctionForwardVarargs(MacroAssembler* masm) {
Generate_CallForwardVarargs(masm,
masm->isolate()->builtins()->CallFunction());
Generate_ForwardVarargs(masm, masm->isolate()->builtins()->CallFunction());
}
} // namespace internal

View File

@ -17,6 +17,15 @@
namespace v8 {
namespace internal {
void Builtins::Generate_ConstructForwardVarargs(MacroAssembler* masm) {
Generate_ForwardVarargs(masm, masm->isolate()->builtins()->Construct());
}
void Builtins::Generate_ConstructFunctionForwardVarargs(MacroAssembler* masm) {
Generate_ForwardVarargs(masm,
masm->isolate()->builtins()->ConstructFunction());
}
typedef compiler::Node Node;
Node* ConstructorBuiltinsAssembler::EmitFastNewClosure(Node* shared_info,

View File

@ -90,6 +90,8 @@ namespace internal {
/* ES6 section 7.3.13 Construct (F, [argumentsList], [newTarget]) */ \
ASM(Construct) \
ASM(ConstructWithSpread) \
ASM(ConstructForwardVarargs) \
ASM(ConstructFunctionForwardVarargs) \
ASM(JSConstructStubApi) \
ASM(JSConstructStubGenericRestrictedReturn) \
ASM(JSConstructStubGenericUnrestrictedReturn) \

View File

@ -124,8 +124,8 @@ class Builtins {
static void Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
TailCallMode tail_call_mode);
static void Generate_CallForwardVarargs(MacroAssembler* masm,
Handle<Code> code);
static void Generate_ForwardVarargs(MacroAssembler* masm, Handle<Code> code);
static void Generate_InterpreterPushArgsThenCallImpl(
MacroAssembler* masm, ConvertReceiverMode receiver_mode,

View File

@ -2309,15 +2309,18 @@ 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 -------------
// -- edi : the target to call (can be any Object)
// -- ecx : start index (to support rest parameters)
// -- esp[0] : return address.
// -- esp[4] : thisArgument
// -- eax : the number of arguments (not including the receiver)
// -- edi : the target to call (can be any Object)
// -- edx : the new target (for [[Construct]] calls)
// -- ecx : start index (to support rest parameters)
// -----------------------------------
// Preserve new.target (in case of [[Construct]]).
__ movd(xmm0, edx);
// Check if we have an arguments adaptor frame below the function frame.
Label arguments_adaptor, arguments_done;
__ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
@ -2325,24 +2328,24 @@ void Builtins::Generate_CallForwardVarargs(MacroAssembler* masm,
Immediate(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)));
__ j(equal, &arguments_adaptor, Label::kNear);
{
__ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
__ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
__ mov(eax,
FieldOperand(eax, SharedFunctionInfo::kFormalParameterCountOffset));
__ mov(edx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
__ mov(edx, FieldOperand(edx, JSFunction::kSharedFunctionInfoOffset));
__ mov(edx,
FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
__ mov(ebx, ebp);
}
__ jmp(&arguments_done, Label::kNear);
__ bind(&arguments_adaptor);
{
// Just load the length from the ArgumentsAdaptorFrame.
__ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
__ mov(edx, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
}
__ bind(&arguments_done);
Label stack_empty, stack_done;
__ SmiUntag(eax);
__ sub(eax, ecx);
__ j(less_equal, &stack_empty);
Label stack_done;
__ SmiUntag(edx);
__ sub(edx, ecx);
__ j(less_equal, &stack_done);
{
// Check for stack overflow.
{
@ -2357,7 +2360,7 @@ void Builtins::Generate_CallForwardVarargs(MacroAssembler* masm,
__ add(ecx, esp);
__ sar(ecx, kPointerSizeLog2);
// Check if the arguments will overflow the stack.
__ cmp(ecx, eax);
__ cmp(ecx, edx);
__ j(greater, &done, Label::kNear); // Signed comparison.
__ TailCallRuntime(Runtime::kThrowStackOverflow);
__ bind(&done);
@ -2366,25 +2369,23 @@ void Builtins::Generate_CallForwardVarargs(MacroAssembler* masm,
// Forward the arguments from the caller frame.
{
Label loop;
__ mov(ecx, eax);
__ pop(edx);
__ add(eax, edx);
__ PopReturnAddressTo(ecx);
__ bind(&loop);
{
__ Push(Operand(ebx, ecx, times_pointer_size, 1 * kPointerSize));
__ dec(ecx);
__ Push(Operand(ebx, edx, times_pointer_size, 1 * kPointerSize));
__ dec(edx);
__ j(not_zero, &loop);
}
__ push(edx);
__ PushReturnAddressFrom(ecx);
}
}
__ jmp(&stack_done, Label::kNear);
__ bind(&stack_empty);
{
// We just pass the receiver, which is already on the stack.
__ Move(eax, Immediate(0));
}
__ bind(&stack_done);
// Restore new.target (in case of [[Construct]]).
__ movd(edx, xmm0);
// Tail-call to the {code} handler.
__ Jump(code, RelocInfo::CODE_TARGET);
}

View File

@ -2168,68 +2168,64 @@ 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 -------------
// -- a1 : the target to call (can be any Object)
// -- a2 : start index (to support rest parameters)
// -- ra : return address.
// -- sp[0] : thisArgument
// -- a0 : the number of arguments (not including the receiver)
// -- a3 : the new.target (for [[Construct]] calls)
// -- a1 : the target to call (can be any Object)
// -- a2 : start index (to support rest parameters)
// -----------------------------------
// Check if we have an arguments adaptor frame below the function frame.
Label arguments_adaptor, arguments_done;
__ lw(a3, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
__ lw(a0, MemOperand(a3, CommonFrameConstants::kContextOrFrameTypeOffset));
__ Branch(&arguments_adaptor, eq, a0,
__ lw(t3, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
__ lw(t2, MemOperand(t3, CommonFrameConstants::kContextOrFrameTypeOffset));
__ Branch(&arguments_adaptor, eq, t2,
Operand(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)));
{
__ lw(a0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
__ lw(a0, FieldMemOperand(a0, JSFunction::kSharedFunctionInfoOffset));
__ lw(a0,
FieldMemOperand(a0, SharedFunctionInfo::kFormalParameterCountOffset));
__ mov(a3, fp);
__ lw(t2, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
__ lw(t2, FieldMemOperand(t2, JSFunction::kSharedFunctionInfoOffset));
__ lw(t2,
FieldMemOperand(t2, SharedFunctionInfo::kFormalParameterCountOffset));
__ mov(t3, fp);
}
__ Branch(&arguments_done);
__ bind(&arguments_adaptor);
{
// Just get the length from the ArgumentsAdaptorFrame.
__ lw(a0, MemOperand(a3, ArgumentsAdaptorFrameConstants::kLengthOffset));
__ lw(t2, MemOperand(t3, ArgumentsAdaptorFrameConstants::kLengthOffset));
}
__ bind(&arguments_done);
Label stack_empty, stack_done, stack_overflow;
__ SmiUntag(a0);
__ Subu(a0, a0, a2);
__ Branch(&stack_empty, le, a0, Operand(zero_reg));
Label stack_done, stack_overflow;
__ SmiUntag(t2);
__ Subu(t2, t2, a2);
__ Branch(&stack_done, le, t2, Operand(zero_reg));
{
// Check for stack overflow.
Generate_StackOverflowCheck(masm, a0, t0, t1, &stack_overflow);
Generate_StackOverflowCheck(masm, t2, t0, t1, &stack_overflow);
// Forward the arguments from the caller frame.
{
Label loop;
__ mov(a2, a0);
__ Addu(a0, a0, t2);
__ bind(&loop);
{
__ Lsa(at, a3, a2, kPointerSizeLog2);
__ Lsa(at, t3, t2, kPointerSizeLog2);
__ lw(at, MemOperand(at, 1 * kPointerSize));
__ push(at);
__ Subu(a2, a2, Operand(1));
__ Branch(&loop, ne, a2, Operand(zero_reg));
__ Subu(t2, t2, Operand(1));
__ Branch(&loop, ne, t2, Operand(zero_reg));
}
}
}
__ Branch(&stack_done);
__ bind(&stack_overflow);
__ TailCallRuntime(Runtime::kThrowStackOverflow);
__ bind(&stack_empty);
{
// We just pass the receiver, which is already on the stack.
__ li(a0, Operand(0));
}
__ bind(&stack_done);
// Tail-call to the {code} handler.
__ Jump(code, RelocInfo::CODE_TARGET);
}

View File

@ -2209,68 +2209,64 @@ 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 -------------
// -- a1 : the target to call (can be any Object)
// -- a2 : start index (to support rest parameters)
// -- ra : return address.
// -- sp[0] : thisArgument
// -- a0 : the number of arguments (not including the receiver)
// -- a3 : the new.target (for [[Construct]] calls)
// -- a1 : the target to call (can be any Object)
// -- a2 : start index (to support rest parameters)
// -----------------------------------
// Check if we have an arguments adaptor frame below the function frame.
Label arguments_adaptor, arguments_done;
__ Ld(a3, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
__ Ld(a0, MemOperand(a3, CommonFrameConstants::kContextOrFrameTypeOffset));
__ Branch(&arguments_adaptor, eq, a0,
__ Ld(a6, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
__ Ld(a7, MemOperand(a6, CommonFrameConstants::kContextOrFrameTypeOffset));
__ Branch(&arguments_adaptor, eq, a7,
Operand(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)));
{
__ Ld(a0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
__ Ld(a0, FieldMemOperand(a0, JSFunction::kSharedFunctionInfoOffset));
__ Lw(a0,
FieldMemOperand(a0, SharedFunctionInfo::kFormalParameterCountOffset));
__ mov(a3, fp);
__ Ld(a7, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
__ Ld(a7, FieldMemOperand(a7, JSFunction::kSharedFunctionInfoOffset));
__ Lw(a7,
FieldMemOperand(a7, SharedFunctionInfo::kFormalParameterCountOffset));
__ mov(a6, fp);
}
__ Branch(&arguments_done);
__ bind(&arguments_adaptor);
{
// Just get the length from the ArgumentsAdaptorFrame.
__ Lw(a0, UntagSmiMemOperand(
a3, ArgumentsAdaptorFrameConstants::kLengthOffset));
__ Lw(a7, UntagSmiMemOperand(
a6, ArgumentsAdaptorFrameConstants::kLengthOffset));
}
__ bind(&arguments_done);
Label stack_empty, stack_done, stack_overflow;
__ Subu(a0, a0, a2);
__ Branch(&stack_empty, le, a0, Operand(zero_reg));
Label stack_done, stack_overflow;
__ Subu(a7, a7, a2);
__ Branch(&stack_done, le, a7, Operand(zero_reg));
{
// Check for stack overflow.
Generate_StackOverflowCheck(masm, a0, a4, a5, &stack_overflow);
Generate_StackOverflowCheck(masm, a7, a4, a5, &stack_overflow);
// Forward the arguments from the caller frame.
{
Label loop;
__ mov(a2, a0);
__ Daddu(a0, a0, a7);
__ bind(&loop);
{
__ Dlsa(at, a3, a2, kPointerSizeLog2);
__ Dlsa(at, a6, a7, kPointerSizeLog2);
__ Ld(at, MemOperand(at, 1 * kPointerSize));
__ push(at);
__ Subu(a2, a2, Operand(1));
__ Branch(&loop, ne, a2, Operand(zero_reg));
__ Subu(a7, a7, Operand(1));
__ Branch(&loop, ne, a7, Operand(zero_reg));
}
}
}
__ Branch(&stack_done);
__ bind(&stack_overflow);
__ TailCallRuntime(Runtime::kThrowStackOverflow);
__ bind(&stack_empty);
{
// We just pass the receiver, which is already on the stack.
__ mov(a0, zero_reg);
}
__ bind(&stack_done);
// Tail-call to the {code} handler.
__ Jump(code, RelocInfo::CODE_TARGET);
}

View File

@ -2416,13 +2416,13 @@ 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 -------------
// -- rdi : the target to call (can be any Object)
// -- rcx : start index (to support rest parameters)
// -- rsp[0] : return address.
// -- rsp[8] : thisArgument
// -- rax : the number of arguments (not including the receiver)
// -- rdx : the new target (for [[Construct]] calls)
// -- rdi : the target to call (can be any Object)
// -- rcx : start index (to support rest parameters)
// -----------------------------------
// Check if we have an arguments adaptor frame below the function frame.
@ -2432,52 +2432,48 @@ void Builtins::Generate_CallForwardVarargs(MacroAssembler* masm,
Immediate(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)));
__ j(equal, &arguments_adaptor, Label::kNear);
{
__ movp(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
__ movp(rax, FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset));
__ movp(r8, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
__ movp(r8, FieldOperand(r8, JSFunction::kSharedFunctionInfoOffset));
__ LoadSharedFunctionInfoSpecialField(
rax, rax, SharedFunctionInfo::kFormalParameterCountOffset);
r8, r8, SharedFunctionInfo::kFormalParameterCountOffset);
__ movp(rbx, rbp);
}
__ jmp(&arguments_done, Label::kNear);
__ bind(&arguments_adaptor);
{
__ SmiToInteger32(
rax, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset));
r8, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset));
}
__ bind(&arguments_done);
Label stack_empty, stack_done, stack_overflow;
__ subl(rax, rcx);
__ j(less_equal, &stack_empty);
Label stack_done, stack_overflow;
__ subl(r8, rcx);
__ j(less_equal, &stack_done);
{
// Check for stack overflow.
Generate_StackOverflowCheck(masm, rax, rcx, &stack_overflow, Label::kNear);
Generate_StackOverflowCheck(masm, r8, rcx, &stack_overflow, Label::kNear);
// Forward the arguments from the caller frame.
{
Label loop;
__ movl(rcx, rax);
__ Pop(r8);
__ addl(rax, r8);
__ PopReturnAddressTo(rcx);
__ bind(&loop);
{
StackArgumentsAccessor args(rbx, rcx, ARGUMENTS_DONT_CONTAIN_RECEIVER);
StackArgumentsAccessor args(rbx, r8, ARGUMENTS_DONT_CONTAIN_RECEIVER);
__ Push(args.GetArgumentOperand(0));
__ decl(rcx);
__ decl(r8);
__ j(not_zero, &loop);
}
__ Push(r8);
__ PushReturnAddressFrom(rcx);
}
}
__ jmp(&stack_done, Label::kNear);
__ bind(&stack_overflow);
__ TailCallRuntime(Runtime::kThrowStackOverflow);
__ bind(&stack_empty);
{
// We just pass the receiver, which is already on the stack.
__ Set(rax, 0);
}
__ bind(&stack_done);
// Tail-call to the {code} handler.
__ Jump(code, RelocInfo::CODE_TARGET);
}

View File

@ -457,6 +457,18 @@ Callable CodeFactory::ConstructFunction(Isolate* isolate) {
ConstructTrampolineDescriptor(isolate));
}
// static
Callable CodeFactory::ConstructForwardVarargs(Isolate* isolate) {
return Callable(isolate->builtins()->ConstructForwardVarargs(),
ConstructForwardVarargsDescriptor(isolate));
}
// static
Callable CodeFactory::ConstructFunctionForwardVarargs(Isolate* isolate) {
return Callable(isolate->builtins()->ConstructFunctionForwardVarargs(),
ConstructForwardVarargsDescriptor(isolate));
}
// static
Callable CodeFactory::InterpreterPushArgsThenCall(
Isolate* isolate, ConvertReceiverMode receiver_mode,

View File

@ -167,6 +167,8 @@ class V8_EXPORT_PRIVATE CodeFactory final {
static Callable Construct(Isolate* isolate);
static Callable ConstructWithSpread(Isolate* isolate);
static Callable ConstructFunction(Isolate* isolate);
static Callable ConstructForwardVarargs(Isolate* isolate);
static Callable ConstructFunctionForwardVarargs(Isolate* isolate);
static Callable CreateIterResultObject(Isolate* isolate);
static Callable HasProperty(Isolate* isolate);
static Callable ForInFilter(Isolate* isolate);

View File

@ -124,7 +124,8 @@ Reduction JSCallReducer::ReduceFunctionPrototypeApply(Node* node) {
Node* arg_array = NodeProperties::GetValueInput(node, 3);
if (arg_array->opcode() != IrOpcode::kJSCreateArguments) return NoChange();
for (Edge edge : arg_array->use_edges()) {
Node* user = edge.from();
Node* const user = edge.from();
if (user == node) continue;
// Ignore uses as frame state's locals or parameters.
if (user->opcode() == IrOpcode::kStateValues) continue;
// Ignore uses as frame state's accumulator.
@ -133,7 +134,6 @@ Reduction JSCallReducer::ReduceFunctionPrototypeApply(Node* node) {
continue;
}
if (!NodeProperties::IsValueEdge(edge)) continue;
if (edge.from() == node) continue;
return NoChange();
}
// Check if the arguments can be handled in the fast case (i.e. we don't
@ -173,7 +173,7 @@ Reduction JSCallReducer::ReduceFunctionPrototypeApply(Node* node) {
node->RemoveInput(0); // Function.prototype.apply
node->RemoveInput(2); // arguments
NodeProperties::ChangeOp(node, javascript()->CallForwardVarargs(
start_index, p.tail_call_mode()));
2, start_index, p.tail_call_mode()));
return Changed(node);
}
// Get to the actual frame state from which to extract the arguments;
@ -454,50 +454,81 @@ Reduction JSCallReducer::ReduceSpreadCall(Node* node, int arity) {
// of spread (except for value uses in frame states).
if (spread->opcode() != IrOpcode::kJSCreateArguments) return NoChange();
for (Edge edge : spread->use_edges()) {
if (edge.from()->opcode() == IrOpcode::kStateValues) continue;
Node* const user = edge.from();
if (user == node) continue;
// Ignore uses as frame state's locals or parameters.
if (user->opcode() == IrOpcode::kStateValues) continue;
// Ignore uses as frame state's accumulator.
if (user->opcode() == IrOpcode::kFrameState && user->InputAt(2) == spread) {
continue;
}
if (!NodeProperties::IsValueEdge(edge)) continue;
if (edge.from() == node) continue;
return NoChange();
}
// Get to the actual frame state from which to extract the arguments;
// we can only optimize this in case the {node} was already inlined into
// some other function (and same for the {spread}).
CreateArgumentsType type = CreateArgumentsTypeOf(spread->op());
CreateArgumentsType const type = CreateArgumentsTypeOf(spread->op());
Node* frame_state = NodeProperties::GetFrameStateInput(spread);
FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
int start_index = 0;
// Determine the formal parameter count;
Handle<SharedFunctionInfo> shared;
if (!state_info.shared_info().ToHandle(&shared)) return NoChange();
int formal_parameter_count = shared->internal_formal_parameter_count();
if (type == CreateArgumentsType::kMappedArguments) {
// Mapped arguments (sloppy mode) that are aliased can only be handled
// here if there's no side-effect between the {node} and the {arg_array}.
// TODO(turbofan): Further relax this constraint.
if (formal_parameter_count != 0) {
Node* effect = NodeProperties::GetEffectInput(node);
while (effect != spread) {
if (effect->op()->EffectInputCount() != 1 ||
!(effect->op()->properties() & Operator::kNoWrite)) {
return NoChange();
}
effect = NodeProperties::GetEffectInput(effect);
}
}
} else if (type == CreateArgumentsType::kRestParameter) {
start_index = formal_parameter_count;
// Only check the array iterator protector when we have a rest object.
if (!isolate()->IsArrayIteratorLookupChainIntact()) return NoChange();
}
// Install appropriate code dependencies.
dependencies()->AssumeMapStable(
isolate()->initial_array_iterator_prototype_map());
if (type == CreateArgumentsType::kRestParameter) {
dependencies()->AssumePropertyCell(factory()->array_iterator_protector());
}
// Remove the spread input from the {node}.
node->RemoveInput(arity--);
// Check if are spreading to inlined arguments or to the arguments of
// the outermost function.
Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
if (outer_state->opcode() != IrOpcode::kFrameState) return NoChange();
if (outer_state->opcode() != IrOpcode::kFrameState) {
Operator const* op =
(node->opcode() == IrOpcode::kJSCallWithSpread)
? javascript()->CallForwardVarargs(arity + 1, start_index,
TailCallMode::kDisallow)
: javascript()->ConstructForwardVarargs(arity + 2, start_index);
NodeProperties::ChangeOp(node, op);
return Changed(node);
}
// Get to the actual frame state from which to extract the arguments;
// we can only optimize this in case the {node} was already inlined into
// some other function (and same for the {arg_array}).
FrameStateInfo outer_info = OpParameter<FrameStateInfo>(outer_state);
if (outer_info.type() == FrameStateType::kArgumentsAdaptor) {
// Need to take the parameters from the arguments adaptor.
frame_state = outer_state;
}
FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
int start_index = 0;
if (type == CreateArgumentsType::kMappedArguments) {
// Mapped arguments (sloppy mode) cannot be handled if they are aliased.
Handle<SharedFunctionInfo> shared;
if (!state_info.shared_info().ToHandle(&shared)) return NoChange();
if (shared->internal_formal_parameter_count() != 0) return NoChange();
} else if (type == CreateArgumentsType::kRestParameter) {
Handle<SharedFunctionInfo> shared;
if (!state_info.shared_info().ToHandle(&shared)) return NoChange();
start_index = shared->internal_formal_parameter_count();
// Only check the array iterator protector when we have a rest object.
if (!isolate()->IsArrayIteratorLookupChainIntact()) return NoChange();
// Add a code dependency on the array iterator protector.
dependencies()->AssumePropertyCell(factory()->array_iterator_protector());
}
dependencies()->AssumeMapStable(
isolate()->initial_array_iterator_prototype_map());
node->RemoveInput(arity--);
// Add the actual parameters to the {node}, skipping the receiver.
Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
for (int i = start_index + 1; i < state_info.parameter_count(); ++i) {
for (int i = start_index + 1; i < parameters->InputCount(); ++i) {
node->InsertInput(graph()->zone(), static_cast<int>(++arity),
parameters->InputAt(i));
}

View File

@ -523,6 +523,28 @@ void JSGenericLowering::LowerJSCreateScriptContext(Node* node) {
ReplaceWithRuntimeCall(node, Runtime::kNewScriptContext);
}
void JSGenericLowering::LowerJSConstructForwardVarargs(Node* node) {
ConstructForwardVarargsParameters p =
ConstructForwardVarargsParametersOf(node->op());
int const arg_count = static_cast<int>(p.arity() - 2);
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
Callable callable = CodeFactory::ConstructForwardVarargs(isolate());
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
isolate(), zone(), callable.descriptor(), arg_count + 1, flags);
Node* stub_code = jsgraph()->HeapConstant(callable.code());
Node* stub_arity = jsgraph()->Int32Constant(arg_count);
Node* start_index = jsgraph()->Uint32Constant(p.start_index());
Node* new_target = node->InputAt(arg_count + 1);
Node* receiver = jsgraph()->UndefinedConstant();
node->RemoveInput(arg_count + 1); // Drop new target.
node->InsertInput(zone(), 0, stub_code);
node->InsertInput(zone(), 2, new_target);
node->InsertInput(zone(), 3, stub_arity);
node->InsertInput(zone(), 4, start_index);
node->InsertInput(zone(), 5, receiver);
NodeProperties::ChangeOp(node, common()->Call(desc));
}
void JSGenericLowering::LowerJSConstruct(Node* node) {
ConstructParameters const& p = ConstructParametersOf(node->op());
int const arg_count = static_cast<int>(p.arity() - 2);
@ -563,17 +585,20 @@ void JSGenericLowering::LowerJSConstructWithSpread(Node* node) {
void JSGenericLowering::LowerJSCallForwardVarargs(Node* node) {
CallForwardVarargsParameters p = CallForwardVarargsParametersOf(node->op());
Callable callable = CodeFactory::CallForwardVarargs(isolate());
int const arg_count = static_cast<int>(p.arity() - 2);
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
Callable callable = CodeFactory::CallForwardVarargs(isolate());
if (p.tail_call_mode() == TailCallMode::kAllow) {
flags |= CallDescriptor::kSupportsTailCalls;
}
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
isolate(), zone(), callable.descriptor(), 1, flags);
isolate(), zone(), callable.descriptor(), arg_count + 1, flags);
Node* stub_code = jsgraph()->HeapConstant(callable.code());
Node* stub_arity = jsgraph()->Int32Constant(arg_count);
Node* start_index = jsgraph()->Uint32Constant(p.start_index());
node->InsertInput(zone(), 0, stub_code);
node->InsertInput(zone(), 2, start_index);
node->InsertInput(zone(), 2, stub_arity);
node->InsertInput(zone(), 3, start_index);
NodeProperties::ChangeOp(node, common()->Call(desc));
}

View File

@ -57,6 +57,17 @@ ToBooleanHints ToBooleanHintsOf(Operator const* op) {
return OpParameter<ToBooleanHints>(op);
}
std::ostream& operator<<(std::ostream& os,
ConstructForwardVarargsParameters const& p) {
return os << p.arity() << ", " << p.start_index();
}
ConstructForwardVarargsParameters const& ConstructForwardVarargsParametersOf(
Operator const* op) {
DCHECK_EQ(IrOpcode::kJSConstructForwardVarargs, op->opcode());
return OpParameter<ConstructForwardVarargsParameters>(op);
}
bool operator==(ConstructParameters const& lhs,
ConstructParameters const& rhs) {
return lhs.arity() == rhs.arity() && lhs.frequency() == rhs.frequency() &&
@ -118,7 +129,8 @@ const CallParameters& CallParametersOf(const Operator* op) {
std::ostream& operator<<(std::ostream& os,
CallForwardVarargsParameters const& p) {
return os << p.start_index() << ", " << p.tail_call_mode();
return os << p.arity() << ", " << p.start_index() << ", "
<< p.tail_call_mode();
}
CallForwardVarargsParameters const& CallForwardVarargsParametersOf(
@ -743,12 +755,12 @@ const Operator* JSOperatorBuilder::ToBoolean(ToBooleanHints hints) {
}
const Operator* JSOperatorBuilder::CallForwardVarargs(
uint32_t start_index, TailCallMode tail_call_mode) {
CallForwardVarargsParameters parameters(start_index, tail_call_mode);
size_t arity, uint32_t start_index, TailCallMode tail_call_mode) {
CallForwardVarargsParameters parameters(arity, start_index, tail_call_mode);
return new (zone()) Operator1<CallForwardVarargsParameters>( // --
IrOpcode::kJSCallForwardVarargs, Operator::kNoProperties, // opcode
"JSCallForwardVarargs", // name
2, 1, 1, 1, 1, 2, // counts
parameters.arity(), 1, 1, 1, 1, 2, // counts
parameters); // parameter
}
@ -798,6 +810,16 @@ const Operator* JSOperatorBuilder::CallRuntime(const Runtime::Function* f,
parameters); // parameter
}
const Operator* JSOperatorBuilder::ConstructForwardVarargs(
size_t arity, uint32_t start_index) {
ConstructForwardVarargsParameters parameters(arity, start_index);
return new (zone()) Operator1<ConstructForwardVarargsParameters>( // --
IrOpcode::kJSConstructForwardVarargs, Operator::kNoProperties, // opcode
"JSConstructForwardVarargs", // name
parameters.arity(), 1, 1, 1, 1, 2, // counts
parameters); // parameter
}
const Operator* JSOperatorBuilder::Construct(uint32_t arity,
CallFrequency frequency,
VectorSlotPair const& feedback) {

View File

@ -90,6 +90,40 @@ ConvertReceiverMode ConvertReceiverModeOf(Operator const* op);
// The ToBooleanHints are used as parameter by JSToBoolean operators.
ToBooleanHints ToBooleanHintsOf(Operator const* op);
// Defines the flags for a JavaScript call forwarding parameters. This
// is used as parameter by JSConstructForwardVarargs operators.
class ConstructForwardVarargsParameters final {
public:
ConstructForwardVarargsParameters(size_t arity, uint32_t start_index)
: bit_field_(ArityField::encode(arity) |
StartIndexField::encode(start_index)) {}
size_t arity() const { return ArityField::decode(bit_field_); }
uint32_t start_index() const { return StartIndexField::decode(bit_field_); }
bool operator==(ConstructForwardVarargsParameters const& that) const {
return this->bit_field_ == that.bit_field_;
}
bool operator!=(ConstructForwardVarargsParameters const& that) const {
return !(*this == that);
}
private:
friend size_t hash_value(ConstructForwardVarargsParameters const& p) {
return p.bit_field_;
}
typedef BitField<size_t, 0, 16> ArityField;
typedef BitField<uint32_t, 16, 16> StartIndexField;
uint32_t const bit_field_;
};
std::ostream& operator<<(std::ostream&,
ConstructForwardVarargsParameters const&);
ConstructForwardVarargsParameters const& ConstructForwardVarargsParametersOf(
Operator const*) WARN_UNUSED_RESULT;
// Defines the arity and the feedback for a JavaScript constructor call. This is
// used as a parameter by JSConstruct operators.
@ -146,11 +180,13 @@ SpreadWithArityParameter const& SpreadWithArityParameterOf(Operator const*);
// is used as parameter by JSCallForwardVarargs operators.
class CallForwardVarargsParameters final {
public:
CallForwardVarargsParameters(uint32_t start_index,
CallForwardVarargsParameters(size_t arity, uint32_t start_index,
TailCallMode tail_call_mode)
: bit_field_(StartIndexField::encode(start_index) |
: bit_field_(ArityField::encode(arity) |
StartIndexField::encode(start_index) |
TailCallModeField::encode(tail_call_mode)) {}
size_t arity() const { return ArityField::decode(bit_field_); }
uint32_t start_index() const { return StartIndexField::decode(bit_field_); }
TailCallMode tail_call_mode() const {
return TailCallModeField::decode(bit_field_);
@ -168,8 +204,9 @@ class CallForwardVarargsParameters final {
return p.bit_field_;
}
typedef BitField<uint32_t, 0, 30> StartIndexField;
typedef BitField<TailCallMode, 31, 1> TailCallModeField;
typedef BitField<size_t, 0, 15> ArityField;
typedef BitField<uint32_t, 15, 15> StartIndexField;
typedef BitField<TailCallMode, 30, 1> TailCallModeField;
uint32_t const bit_field_;
};
@ -665,7 +702,7 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final
const Operator* CreateLiteralRegExp(Handle<String> constant_pattern,
int literal_flags, int literal_index);
const Operator* CallForwardVarargs(uint32_t start_index,
const Operator* CallForwardVarargs(size_t arity, uint32_t start_index,
TailCallMode tail_call_mode);
const Operator* Call(
size_t arity, CallFrequency frequency = CallFrequency(),
@ -676,6 +713,8 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final
const Operator* CallRuntime(Runtime::FunctionId id);
const Operator* CallRuntime(Runtime::FunctionId id, size_t arity);
const Operator* CallRuntime(const Runtime::Function* function, size_t arity);
const Operator* ConstructForwardVarargs(size_t arity, uint32_t start_index);
const Operator* Construct(uint32_t arity,
CallFrequency frequency = CallFrequency(),
VectorSlotPair const& feedback = VectorSlotPair());

View File

@ -1703,6 +1703,38 @@ bool NeedsArgumentAdaptorFrame(Handle<SharedFunctionInfo> shared, int arity) {
} // namespace
Reduction JSTypedLowering::ReduceJSConstructForwardVarargs(Node* node) {
DCHECK_EQ(IrOpcode::kJSConstructForwardVarargs, node->opcode());
ConstructForwardVarargsParameters p =
ConstructForwardVarargsParametersOf(node->op());
DCHECK_LE(2u, p.arity());
int const arity = static_cast<int>(p.arity() - 2);
int const start_index = static_cast<int>(p.start_index());
Node* target = NodeProperties::GetValueInput(node, 0);
Type* target_type = NodeProperties::GetType(target);
Node* new_target = NodeProperties::GetValueInput(node, arity + 1);
// Check if {target} is a JSFunction.
if (target_type->Is(Type::Function())) {
// Patch {node} to an indirect call via ConstructFunctionForwardVarargs.
Callable callable = CodeFactory::ConstructFunctionForwardVarargs(isolate());
node->RemoveInput(arity + 1);
node->InsertInput(graph()->zone(), 0,
jsgraph()->HeapConstant(callable.code()));
node->InsertInput(graph()->zone(), 2, new_target);
node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity));
node->InsertInput(graph()->zone(), 4, jsgraph()->Constant(start_index));
node->InsertInput(graph()->zone(), 5, jsgraph()->UndefinedConstant());
NodeProperties::ChangeOp(
node, common()->Call(Linkage::GetStubCallDescriptor(
isolate(), graph()->zone(), callable.descriptor(), arity + 1,
CallDescriptor::kNeedsFrameState)));
return Changed(node);
}
return NoChange();
}
Reduction JSTypedLowering::ReduceJSConstruct(Node* node) {
DCHECK_EQ(IrOpcode::kJSConstruct, node->opcode());
ConstructParameters const& p = ConstructParametersOf(node->op());
@ -1781,6 +1813,9 @@ Reduction JSTypedLowering::ReduceJSConstruct(Node* node) {
Reduction JSTypedLowering::ReduceJSCallForwardVarargs(Node* node) {
DCHECK_EQ(IrOpcode::kJSCallForwardVarargs, node->opcode());
CallForwardVarargsParameters p = CallForwardVarargsParametersOf(node->op());
DCHECK_LE(2u, p.arity());
int const arity = static_cast<int>(p.arity() - 2);
int const start_index = static_cast<int>(p.start_index());
Node* target = NodeProperties::GetValueInput(node, 0);
Type* target_type = NodeProperties::GetType(target);
@ -1796,11 +1831,12 @@ Reduction JSTypedLowering::ReduceJSCallForwardVarargs(Node* node) {
Callable callable = CodeFactory::CallFunctionForwardVarargs(isolate());
node->InsertInput(graph()->zone(), 0,
jsgraph()->HeapConstant(callable.code()));
node->InsertInput(graph()->zone(), 2, jsgraph()->Constant(p.start_index()));
node->InsertInput(graph()->zone(), 2, jsgraph()->Constant(arity));
node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(start_index));
NodeProperties::ChangeOp(
node,
common()->Call(Linkage::GetStubCallDescriptor(
isolate(), graph()->zone(), callable.descriptor(), 1, flags)));
node, common()->Call(Linkage::GetStubCallDescriptor(
isolate(), graph()->zone(), callable.descriptor(), arity + 1,
flags)));
return Changed(node);
}
@ -2176,6 +2212,8 @@ Reduction JSTypedLowering::Reduce(Node* node) {
return ReduceJSStoreModule(node);
case IrOpcode::kJSConvertReceiver:
return ReduceJSConvertReceiver(node);
case IrOpcode::kJSConstructForwardVarargs:
return ReduceJSConstructForwardVarargs(node);
case IrOpcode::kJSConstruct:
return ReduceJSConstruct(node);
case IrOpcode::kJSCallForwardVarargs:

View File

@ -69,6 +69,7 @@ class V8_EXPORT_PRIVATE JSTypedLowering final
Reduction ReduceJSToString(Node* node);
Reduction ReduceJSToObject(Node* node);
Reduction ReduceJSConvertReceiver(Node* node);
Reduction ReduceJSConstructForwardVarargs(Node* node);
Reduction ReduceJSConstruct(Node* node);
Reduction ReduceJSCallForwardVarargs(Node* node);
Reduction ReduceJSCall(Node* node);

View File

@ -159,6 +159,7 @@
V(JSCreateScriptContext)
#define JS_OTHER_OP_LIST(V) \
V(JSConstructForwardVarargs) \
V(JSConstruct) \
V(JSConstructWithSpread) \
V(JSCallForwardVarargs) \

View File

@ -96,6 +96,7 @@ bool OperatorProperties::HasFrameStateInput(const Operator* op) {
case IrOpcode::kJSToString:
// Call operations
case IrOpcode::kJSConstructForwardVarargs:
case IrOpcode::kJSConstruct:
case IrOpcode::kJSConstructWithSpread:
case IrOpcode::kJSCallForwardVarargs:

View File

@ -1335,6 +1335,10 @@ Type* Typer::Visitor::TypeJSCreateScriptContext(Node* node) {
// JS other operators.
Type* Typer::Visitor::TypeJSConstructForwardVarargs(Node* node) {
return Type::Receiver();
}
Type* Typer::Visitor::TypeJSConstruct(Node* node) { return Type::Receiver(); }
Type* Typer::Visitor::TypeJSConstructWithSpread(Node* node) {

View File

@ -700,6 +700,7 @@ void Verifier::Visitor::Check(Node* node) {
break;
}
case IrOpcode::kJSConstructForwardVarargs:
case IrOpcode::kJSConstruct:
case IrOpcode::kJSConstructWithSpread:
case IrOpcode::kJSConvertReceiver:

View File

@ -156,9 +156,20 @@ void CallTrampolineDescriptor::InitializePlatformSpecific(
void CallForwardVarargsDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
// eax : number of arguments
// ecx : start index (to support rest parameters)
// edi : the target to call
Register registers[] = {edi, ecx};
Register registers[] = {edi, eax, ecx};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void ConstructForwardVarargsDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
// eax : number of arguments
// edx : the new target
// ecx : start index (to support rest parameters)
// edi : the target to call
Register registers[] = {edi, edx, eax, ecx};
data->InitializePlatformSpecific(arraysize(registers), registers);
}

View File

@ -447,8 +447,18 @@ void CallTrampolineDescriptor::InitializePlatformIndependent(
void CallForwardVarargsDescriptor::InitializePlatformIndependent(
CallInterfaceDescriptorData* data) {
// kTarget, kStartIndex
// kTarget, kActualArgumentsCount, kStartIndex
MachineType machine_types[] = {MachineType::AnyTagged(), MachineType::Int32(),
MachineType::Int32()};
data->InitializePlatformIndependent(arraysize(machine_types), 0,
machine_types);
}
void ConstructForwardVarargsDescriptor::InitializePlatformIndependent(
CallInterfaceDescriptorData* data) {
// kTarget, kNewTarget, kActualArgumentsCount, kStartIndex
MachineType machine_types[] = {MachineType::AnyTagged(),
MachineType::AnyTagged(), MachineType::Int32(),
MachineType::Int32()};
data->InitializePlatformIndependent(arraysize(machine_types), 0,
machine_types);

View File

@ -48,6 +48,7 @@ class PlatformInterfaceDescriptor;
V(CallConstruct) \
V(CallTrampoline) \
V(ConstructStub) \
V(ConstructForwardVarargs) \
V(ConstructTrampoline) \
V(TransitionElementsKind) \
V(AllocateHeapNumber) \
@ -575,11 +576,18 @@ class CallTrampolineDescriptor : public CallInterfaceDescriptor {
class CallForwardVarargsDescriptor : public CallInterfaceDescriptor {
public:
DEFINE_PARAMETERS(kTarget, kStartIndex)
DEFINE_PARAMETERS(kTarget, kActualArgumentsCount, kStartIndex)
DECLARE_DESCRIPTOR_WITH_CUSTOM_FUNCTION_TYPE(CallForwardVarargsDescriptor,
CallInterfaceDescriptor)
};
class ConstructForwardVarargsDescriptor : public CallInterfaceDescriptor {
public:
DEFINE_PARAMETERS(kTarget, kNewTarget, kActualArgumentsCount, kStartIndex)
DECLARE_DESCRIPTOR_WITH_CUSTOM_FUNCTION_TYPE(
ConstructForwardVarargsDescriptor, CallInterfaceDescriptor)
};
class ConstructStubDescriptor : public CallInterfaceDescriptor {
public:
DEFINE_PARAMETERS(kFunction, kNewTarget, kActualArgumentsCount,

View File

@ -156,8 +156,19 @@ void CallTrampolineDescriptor::InitializePlatformSpecific(
void CallForwardVarargsDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
// a1: the target to call
// a0: number of arguments
// a2: start index (to support rest parameters)
Register registers[] = {a1, a2};
Register registers[] = {a1, a0, a2};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void ConstructForwardVarargsDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
// a1: the target to call
// a3: new target
// a0: number of arguments
// a2: start index (to support rest parameters)
Register registers[] = {a1, a3, a0, a2};
data->InitializePlatformSpecific(arraysize(registers), registers);
}

View File

@ -156,8 +156,19 @@ void CallTrampolineDescriptor::InitializePlatformSpecific(
void CallForwardVarargsDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
// a1: the target to call
// a0: number of arguments
// a2: start index (to support rest parameters)
Register registers[] = {a1, a2};
Register registers[] = {a1, a0, a2};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void ConstructForwardVarargsDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
// a1: the target to call
// a3: new target
// a0: number of arguments
// a2: start index (to support rest parameters)
Register registers[] = {a1, a3, a0, a2};
data->InitializePlatformSpecific(arraysize(registers), registers);
}

View File

@ -155,9 +155,20 @@ void CallTrampolineDescriptor::InitializePlatformSpecific(
void CallForwardVarargsDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
// rax : number of arguments
// rcx : start index (to support rest parameters)
// rdi : the target to call
Register registers[] = {rdi, rcx};
Register registers[] = {rdi, rax, rcx};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void ConstructForwardVarargsDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
// rax : number of arguments
// rdx : the new target
// rcx : start index (to support rest parameters)
// rdi : the target to call
Register registers[] = {rdi, rdx, rax, rcx};
data->InitializePlatformSpecific(arraysize(registers), registers);
}