[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:
parent
8038e5cac4
commit
bfa319e5d3
@ -157,9 +157,20 @@ void CallTrampolineDescriptor::InitializePlatformSpecific(
|
|||||||
|
|
||||||
void CallForwardVarargsDescriptor::InitializePlatformSpecific(
|
void CallForwardVarargsDescriptor::InitializePlatformSpecific(
|
||||||
CallInterfaceDescriptorData* data) {
|
CallInterfaceDescriptorData* data) {
|
||||||
|
// r0 : number of arguments
|
||||||
// r2 : start index (to support rest parameters)
|
// r2 : start index (to support rest parameters)
|
||||||
// r1 : the target to call
|
// 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);
|
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,8 +177,19 @@ void CallTrampolineDescriptor::InitializePlatformSpecific(
|
|||||||
void CallForwardVarargsDescriptor::InitializePlatformSpecific(
|
void CallForwardVarargsDescriptor::InitializePlatformSpecific(
|
||||||
CallInterfaceDescriptorData* data) {
|
CallInterfaceDescriptorData* data) {
|
||||||
// x1: target
|
// x1: target
|
||||||
|
// x0: number of arguments
|
||||||
// x2: start index (to supported rest parameters)
|
// 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);
|
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2153,54 +2153,54 @@ void Builtins::Generate_Apply(MacroAssembler* masm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void Builtins::Generate_CallForwardVarargs(MacroAssembler* masm,
|
void Builtins::Generate_ForwardVarargs(MacroAssembler* masm,
|
||||||
Handle<Code> code) {
|
Handle<Code> code) {
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
// -- r1 : the target to call (can be any Object)
|
// -- r0 : the number of arguments (not including the receiver)
|
||||||
// -- r2 : start index (to support rest parameters)
|
// -- r3 : the new.target (for [[Construct]] calls)
|
||||||
// -- lr : return address.
|
// -- r1 : the target to call (can be any Object)
|
||||||
// -- sp[0] : thisArgument
|
// -- r2 : start index (to support rest parameters)
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
|
|
||||||
// Check if we have an arguments adaptor frame below the function frame.
|
// Check if we have an arguments adaptor frame below the function frame.
|
||||||
Label arguments_adaptor, arguments_done;
|
Label arguments_adaptor, arguments_done;
|
||||||
__ ldr(r3, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
|
__ ldr(r4, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
|
||||||
__ ldr(ip, MemOperand(r3, CommonFrameConstants::kContextOrFrameTypeOffset));
|
__ ldr(ip, MemOperand(r4, CommonFrameConstants::kContextOrFrameTypeOffset));
|
||||||
__ cmp(ip, Operand(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)));
|
__ cmp(ip, Operand(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)));
|
||||||
__ b(eq, &arguments_adaptor);
|
__ b(eq, &arguments_adaptor);
|
||||||
{
|
{
|
||||||
__ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
__ ldr(r5, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
||||||
__ ldr(r0, FieldMemOperand(r0, JSFunction::kSharedFunctionInfoOffset));
|
__ ldr(r5, FieldMemOperand(r5, JSFunction::kSharedFunctionInfoOffset));
|
||||||
__ ldr(r0, FieldMemOperand(
|
__ ldr(r5, FieldMemOperand(
|
||||||
r0, SharedFunctionInfo::kFormalParameterCountOffset));
|
r5, SharedFunctionInfo::kFormalParameterCountOffset));
|
||||||
__ mov(r3, fp);
|
__ mov(r4, fp);
|
||||||
}
|
}
|
||||||
__ b(&arguments_done);
|
__ b(&arguments_done);
|
||||||
__ bind(&arguments_adaptor);
|
__ bind(&arguments_adaptor);
|
||||||
{
|
{
|
||||||
// Load the length from the ArgumentsAdaptorFrame.
|
// Load the length from the ArgumentsAdaptorFrame.
|
||||||
__ ldr(r0, MemOperand(r3, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
__ ldr(r5, MemOperand(r4, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||||
}
|
}
|
||||||
__ bind(&arguments_done);
|
__ bind(&arguments_done);
|
||||||
|
|
||||||
Label stack_empty, stack_done, stack_overflow;
|
Label stack_done, stack_overflow;
|
||||||
__ SmiUntag(r0);
|
__ SmiUntag(r5);
|
||||||
__ sub(r0, r0, r2, SetCC);
|
__ sub(r5, r5, r2, SetCC);
|
||||||
__ b(le, &stack_empty);
|
__ b(le, &stack_done);
|
||||||
{
|
{
|
||||||
// Check for stack overflow.
|
// 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.
|
// Forward the arguments from the caller frame.
|
||||||
{
|
{
|
||||||
Label loop;
|
Label loop;
|
||||||
__ add(r3, r3, Operand(kPointerSize));
|
__ add(r4, r4, Operand(kPointerSize));
|
||||||
__ mov(r2, r0);
|
__ add(r0, r0, r5);
|
||||||
__ bind(&loop);
|
__ bind(&loop);
|
||||||
{
|
{
|
||||||
__ ldr(ip, MemOperand(r3, r2, LSL, kPointerSizeLog2));
|
__ ldr(ip, MemOperand(r4, r5, LSL, kPointerSizeLog2));
|
||||||
__ push(ip);
|
__ push(ip);
|
||||||
__ sub(r2, r2, Operand(1), SetCC);
|
__ sub(r5, r5, Operand(1), SetCC);
|
||||||
__ b(ne, &loop);
|
__ b(ne, &loop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2208,13 +2208,9 @@ void Builtins::Generate_CallForwardVarargs(MacroAssembler* masm,
|
|||||||
__ b(&stack_done);
|
__ b(&stack_done);
|
||||||
__ bind(&stack_overflow);
|
__ bind(&stack_overflow);
|
||||||
__ TailCallRuntime(Runtime::kThrowStackOverflow);
|
__ TailCallRuntime(Runtime::kThrowStackOverflow);
|
||||||
__ bind(&stack_empty);
|
|
||||||
{
|
|
||||||
// We just pass the receiver, which is already on the stack.
|
|
||||||
__ mov(r0, Operand(0));
|
|
||||||
}
|
|
||||||
__ bind(&stack_done);
|
__ bind(&stack_done);
|
||||||
|
|
||||||
|
// Tail-call to the {code} handler.
|
||||||
__ Jump(code, RelocInfo::CODE_TARGET);
|
__ Jump(code, RelocInfo::CODE_TARGET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2286,54 +2286,54 @@ void Builtins::Generate_Apply(MacroAssembler* masm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void Builtins::Generate_CallForwardVarargs(MacroAssembler* masm,
|
void Builtins::Generate_ForwardVarargs(MacroAssembler* masm,
|
||||||
Handle<Code> code) {
|
Handle<Code> code) {
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
// -- x1 : the target to call (can be any Object)
|
// -- x0 : the number of arguments (not including the receiver)
|
||||||
// -- x2 : start index (to support rest parameters)
|
// -- x3 : the new.target (for [[Construct]] calls)
|
||||||
// -- lr : return address.
|
// -- x1 : the target to call (can be any Object)
|
||||||
// -- sp[0] : thisArgument
|
// -- x2 : start index (to support rest parameters)
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
|
|
||||||
// Check if we have an arguments adaptor frame below the function frame.
|
// Check if we have an arguments adaptor frame below the function frame.
|
||||||
Label arguments_adaptor, arguments_done;
|
Label arguments_adaptor, arguments_done;
|
||||||
__ Ldr(x3, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
|
__ Ldr(x5, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
|
||||||
__ Ldr(x4, MemOperand(x3, CommonFrameConstants::kContextOrFrameTypeOffset));
|
__ Ldr(x4, MemOperand(x5, CommonFrameConstants::kContextOrFrameTypeOffset));
|
||||||
__ Cmp(x4, StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR));
|
__ Cmp(x4, StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR));
|
||||||
__ B(eq, &arguments_adaptor);
|
__ B(eq, &arguments_adaptor);
|
||||||
{
|
{
|
||||||
__ Ldr(x0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
__ Ldr(x6, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
||||||
__ Ldr(x0, FieldMemOperand(x0, JSFunction::kSharedFunctionInfoOffset));
|
__ Ldr(x6, FieldMemOperand(x6, JSFunction::kSharedFunctionInfoOffset));
|
||||||
__ Ldrsw(x0, FieldMemOperand(
|
__ Ldrsw(x6, FieldMemOperand(
|
||||||
x0, SharedFunctionInfo::kFormalParameterCountOffset));
|
x6, SharedFunctionInfo::kFormalParameterCountOffset));
|
||||||
__ Mov(x3, fp);
|
__ Mov(x5, fp);
|
||||||
}
|
}
|
||||||
__ B(&arguments_done);
|
__ B(&arguments_done);
|
||||||
__ Bind(&arguments_adaptor);
|
__ Bind(&arguments_adaptor);
|
||||||
{
|
{
|
||||||
// Just load the length from ArgumentsAdaptorFrame.
|
// Just load the length from ArgumentsAdaptorFrame.
|
||||||
__ Ldrsw(x0, UntagSmiMemOperand(
|
__ Ldrsw(x6, UntagSmiMemOperand(
|
||||||
x3, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
x5, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||||
}
|
}
|
||||||
__ Bind(&arguments_done);
|
__ Bind(&arguments_done);
|
||||||
|
|
||||||
Label stack_empty, stack_done, stack_overflow;
|
Label stack_done, stack_overflow;
|
||||||
__ Subs(x0, x0, x2);
|
__ Subs(x6, x6, x2);
|
||||||
__ B(le, &stack_empty);
|
__ B(le, &stack_done);
|
||||||
{
|
{
|
||||||
// Check for stack overflow.
|
// 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.
|
// Forward the arguments from the caller frame.
|
||||||
{
|
{
|
||||||
Label loop;
|
Label loop;
|
||||||
__ Add(x3, x3, kPointerSize);
|
__ Add(x5, x5, kPointerSize);
|
||||||
__ Mov(x2, x0);
|
__ Add(x0, x0, x6);
|
||||||
__ bind(&loop);
|
__ bind(&loop);
|
||||||
{
|
{
|
||||||
__ Ldr(x4, MemOperand(x3, x2, LSL, kPointerSizeLog2));
|
__ Ldr(x4, MemOperand(x5, x6, LSL, kPointerSizeLog2));
|
||||||
__ Push(x4);
|
__ Push(x4);
|
||||||
__ Subs(x2, x2, 1);
|
__ Subs(x6, x6, 1);
|
||||||
__ B(ne, &loop);
|
__ B(ne, &loop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2341,11 +2341,6 @@ void Builtins::Generate_CallForwardVarargs(MacroAssembler* masm,
|
|||||||
__ B(&stack_done);
|
__ B(&stack_done);
|
||||||
__ Bind(&stack_overflow);
|
__ Bind(&stack_overflow);
|
||||||
__ TailCallRuntime(Runtime::kThrowStackOverflow);
|
__ TailCallRuntime(Runtime::kThrowStackOverflow);
|
||||||
__ Bind(&stack_empty);
|
|
||||||
{
|
|
||||||
// We just pass the receiver, which is already on the stack.
|
|
||||||
__ Mov(x0, 0);
|
|
||||||
}
|
|
||||||
__ Bind(&stack_done);
|
__ Bind(&stack_done);
|
||||||
|
|
||||||
__ Jump(code, RelocInfo::CODE_TARGET);
|
__ Jump(code, RelocInfo::CODE_TARGET);
|
||||||
|
@ -83,12 +83,11 @@ void Builtins::Generate_TailCall_ReceiverIsAny(MacroAssembler* masm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Builtins::Generate_CallForwardVarargs(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) {
|
void Builtins::Generate_CallFunctionForwardVarargs(MacroAssembler* masm) {
|
||||||
Generate_CallForwardVarargs(masm,
|
Generate_ForwardVarargs(masm, masm->isolate()->builtins()->CallFunction());
|
||||||
masm->isolate()->builtins()->CallFunction());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
@ -17,6 +17,15 @@
|
|||||||
namespace v8 {
|
namespace v8 {
|
||||||
namespace internal {
|
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;
|
typedef compiler::Node Node;
|
||||||
|
|
||||||
Node* ConstructorBuiltinsAssembler::EmitFastNewClosure(Node* shared_info,
|
Node* ConstructorBuiltinsAssembler::EmitFastNewClosure(Node* shared_info,
|
||||||
|
@ -90,6 +90,8 @@ namespace internal {
|
|||||||
/* ES6 section 7.3.13 Construct (F, [argumentsList], [newTarget]) */ \
|
/* ES6 section 7.3.13 Construct (F, [argumentsList], [newTarget]) */ \
|
||||||
ASM(Construct) \
|
ASM(Construct) \
|
||||||
ASM(ConstructWithSpread) \
|
ASM(ConstructWithSpread) \
|
||||||
|
ASM(ConstructForwardVarargs) \
|
||||||
|
ASM(ConstructFunctionForwardVarargs) \
|
||||||
ASM(JSConstructStubApi) \
|
ASM(JSConstructStubApi) \
|
||||||
ASM(JSConstructStubGenericRestrictedReturn) \
|
ASM(JSConstructStubGenericRestrictedReturn) \
|
||||||
ASM(JSConstructStubGenericUnrestrictedReturn) \
|
ASM(JSConstructStubGenericUnrestrictedReturn) \
|
||||||
|
@ -124,8 +124,8 @@ class Builtins {
|
|||||||
|
|
||||||
static void Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
|
static void Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
|
||||||
TailCallMode tail_call_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(
|
static void Generate_InterpreterPushArgsThenCallImpl(
|
||||||
MacroAssembler* masm, ConvertReceiverMode receiver_mode,
|
MacroAssembler* masm, ConvertReceiverMode receiver_mode,
|
||||||
|
@ -2309,15 +2309,18 @@ void Builtins::Generate_Apply(MacroAssembler* masm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void Builtins::Generate_CallForwardVarargs(MacroAssembler* masm,
|
void Builtins::Generate_ForwardVarargs(MacroAssembler* masm,
|
||||||
Handle<Code> code) {
|
Handle<Code> code) {
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
// -- edi : the target to call (can be any Object)
|
// -- eax : the number of arguments (not including the receiver)
|
||||||
// -- ecx : start index (to support rest parameters)
|
// -- edi : the target to call (can be any Object)
|
||||||
// -- esp[0] : return address.
|
// -- edx : the new target (for [[Construct]] calls)
|
||||||
// -- esp[4] : thisArgument
|
// -- 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.
|
// Check if we have an arguments adaptor frame below the function frame.
|
||||||
Label arguments_adaptor, arguments_done;
|
Label arguments_adaptor, arguments_done;
|
||||||
__ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
|
__ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
|
||||||
@ -2325,24 +2328,24 @@ void Builtins::Generate_CallForwardVarargs(MacroAssembler* masm,
|
|||||||
Immediate(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)));
|
Immediate(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)));
|
||||||
__ j(equal, &arguments_adaptor, Label::kNear);
|
__ j(equal, &arguments_adaptor, Label::kNear);
|
||||||
{
|
{
|
||||||
__ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
|
__ mov(edx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
|
||||||
__ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
|
__ mov(edx, FieldOperand(edx, JSFunction::kSharedFunctionInfoOffset));
|
||||||
__ mov(eax,
|
__ mov(edx,
|
||||||
FieldOperand(eax, SharedFunctionInfo::kFormalParameterCountOffset));
|
FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
|
||||||
__ mov(ebx, ebp);
|
__ mov(ebx, ebp);
|
||||||
}
|
}
|
||||||
__ jmp(&arguments_done, Label::kNear);
|
__ jmp(&arguments_done, Label::kNear);
|
||||||
__ bind(&arguments_adaptor);
|
__ bind(&arguments_adaptor);
|
||||||
{
|
{
|
||||||
// Just load the length from the ArgumentsAdaptorFrame.
|
// Just load the length from the ArgumentsAdaptorFrame.
|
||||||
__ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
__ mov(edx, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||||
}
|
}
|
||||||
__ bind(&arguments_done);
|
__ bind(&arguments_done);
|
||||||
|
|
||||||
Label stack_empty, stack_done;
|
Label stack_done;
|
||||||
__ SmiUntag(eax);
|
__ SmiUntag(edx);
|
||||||
__ sub(eax, ecx);
|
__ sub(edx, ecx);
|
||||||
__ j(less_equal, &stack_empty);
|
__ j(less_equal, &stack_done);
|
||||||
{
|
{
|
||||||
// Check for stack overflow.
|
// Check for stack overflow.
|
||||||
{
|
{
|
||||||
@ -2357,7 +2360,7 @@ void Builtins::Generate_CallForwardVarargs(MacroAssembler* masm,
|
|||||||
__ add(ecx, esp);
|
__ add(ecx, esp);
|
||||||
__ sar(ecx, kPointerSizeLog2);
|
__ sar(ecx, kPointerSizeLog2);
|
||||||
// Check if the arguments will overflow the stack.
|
// Check if the arguments will overflow the stack.
|
||||||
__ cmp(ecx, eax);
|
__ cmp(ecx, edx);
|
||||||
__ j(greater, &done, Label::kNear); // Signed comparison.
|
__ j(greater, &done, Label::kNear); // Signed comparison.
|
||||||
__ TailCallRuntime(Runtime::kThrowStackOverflow);
|
__ TailCallRuntime(Runtime::kThrowStackOverflow);
|
||||||
__ bind(&done);
|
__ bind(&done);
|
||||||
@ -2366,25 +2369,23 @@ void Builtins::Generate_CallForwardVarargs(MacroAssembler* masm,
|
|||||||
// Forward the arguments from the caller frame.
|
// Forward the arguments from the caller frame.
|
||||||
{
|
{
|
||||||
Label loop;
|
Label loop;
|
||||||
__ mov(ecx, eax);
|
__ add(eax, edx);
|
||||||
__ pop(edx);
|
__ PopReturnAddressTo(ecx);
|
||||||
__ bind(&loop);
|
__ bind(&loop);
|
||||||
{
|
{
|
||||||
__ Push(Operand(ebx, ecx, times_pointer_size, 1 * kPointerSize));
|
__ Push(Operand(ebx, edx, times_pointer_size, 1 * kPointerSize));
|
||||||
__ dec(ecx);
|
__ dec(edx);
|
||||||
__ j(not_zero, &loop);
|
__ 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);
|
__ bind(&stack_done);
|
||||||
|
|
||||||
|
// Restore new.target (in case of [[Construct]]).
|
||||||
|
__ movd(edx, xmm0);
|
||||||
|
|
||||||
|
// Tail-call to the {code} handler.
|
||||||
__ Jump(code, RelocInfo::CODE_TARGET);
|
__ Jump(code, RelocInfo::CODE_TARGET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2168,68 +2168,64 @@ void Builtins::Generate_Apply(MacroAssembler* masm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void Builtins::Generate_CallForwardVarargs(MacroAssembler* masm,
|
void Builtins::Generate_ForwardVarargs(MacroAssembler* masm,
|
||||||
Handle<Code> code) {
|
Handle<Code> code) {
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
// -- a1 : the target to call (can be any Object)
|
// -- a0 : the number of arguments (not including the receiver)
|
||||||
// -- a2 : start index (to support rest parameters)
|
// -- a3 : the new.target (for [[Construct]] calls)
|
||||||
// -- ra : return address.
|
// -- a1 : the target to call (can be any Object)
|
||||||
// -- sp[0] : thisArgument
|
// -- a2 : start index (to support rest parameters)
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
|
|
||||||
// Check if we have an arguments adaptor frame below the function frame.
|
// Check if we have an arguments adaptor frame below the function frame.
|
||||||
Label arguments_adaptor, arguments_done;
|
Label arguments_adaptor, arguments_done;
|
||||||
__ lw(a3, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
|
__ lw(t3, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
|
||||||
__ lw(a0, MemOperand(a3, CommonFrameConstants::kContextOrFrameTypeOffset));
|
__ lw(t2, MemOperand(t3, CommonFrameConstants::kContextOrFrameTypeOffset));
|
||||||
__ Branch(&arguments_adaptor, eq, a0,
|
__ Branch(&arguments_adaptor, eq, t2,
|
||||||
Operand(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)));
|
Operand(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)));
|
||||||
{
|
{
|
||||||
__ lw(a0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
__ lw(t2, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
||||||
__ lw(a0, FieldMemOperand(a0, JSFunction::kSharedFunctionInfoOffset));
|
__ lw(t2, FieldMemOperand(t2, JSFunction::kSharedFunctionInfoOffset));
|
||||||
__ lw(a0,
|
__ lw(t2,
|
||||||
FieldMemOperand(a0, SharedFunctionInfo::kFormalParameterCountOffset));
|
FieldMemOperand(t2, SharedFunctionInfo::kFormalParameterCountOffset));
|
||||||
__ mov(a3, fp);
|
__ mov(t3, fp);
|
||||||
}
|
}
|
||||||
__ Branch(&arguments_done);
|
__ Branch(&arguments_done);
|
||||||
__ bind(&arguments_adaptor);
|
__ bind(&arguments_adaptor);
|
||||||
{
|
{
|
||||||
// Just get the length from the ArgumentsAdaptorFrame.
|
// Just get the length from the ArgumentsAdaptorFrame.
|
||||||
__ lw(a0, MemOperand(a3, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
__ lw(t2, MemOperand(t3, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||||
}
|
}
|
||||||
__ bind(&arguments_done);
|
__ bind(&arguments_done);
|
||||||
|
|
||||||
Label stack_empty, stack_done, stack_overflow;
|
Label stack_done, stack_overflow;
|
||||||
__ SmiUntag(a0);
|
__ SmiUntag(t2);
|
||||||
__ Subu(a0, a0, a2);
|
__ Subu(t2, t2, a2);
|
||||||
__ Branch(&stack_empty, le, a0, Operand(zero_reg));
|
__ Branch(&stack_done, le, t2, Operand(zero_reg));
|
||||||
{
|
{
|
||||||
// Check for stack overflow.
|
// 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.
|
// Forward the arguments from the caller frame.
|
||||||
{
|
{
|
||||||
Label loop;
|
Label loop;
|
||||||
__ mov(a2, a0);
|
__ Addu(a0, a0, t2);
|
||||||
__ bind(&loop);
|
__ bind(&loop);
|
||||||
{
|
{
|
||||||
__ Lsa(at, a3, a2, kPointerSizeLog2);
|
__ Lsa(at, t3, t2, kPointerSizeLog2);
|
||||||
__ lw(at, MemOperand(at, 1 * kPointerSize));
|
__ lw(at, MemOperand(at, 1 * kPointerSize));
|
||||||
__ push(at);
|
__ push(at);
|
||||||
__ Subu(a2, a2, Operand(1));
|
__ Subu(t2, t2, Operand(1));
|
||||||
__ Branch(&loop, ne, a2, Operand(zero_reg));
|
__ Branch(&loop, ne, t2, Operand(zero_reg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
__ Branch(&stack_done);
|
__ Branch(&stack_done);
|
||||||
__ bind(&stack_overflow);
|
__ bind(&stack_overflow);
|
||||||
__ TailCallRuntime(Runtime::kThrowStackOverflow);
|
__ TailCallRuntime(Runtime::kThrowStackOverflow);
|
||||||
__ bind(&stack_empty);
|
|
||||||
{
|
|
||||||
// We just pass the receiver, which is already on the stack.
|
|
||||||
__ li(a0, Operand(0));
|
|
||||||
}
|
|
||||||
__ bind(&stack_done);
|
__ bind(&stack_done);
|
||||||
|
|
||||||
|
// Tail-call to the {code} handler.
|
||||||
__ Jump(code, RelocInfo::CODE_TARGET);
|
__ Jump(code, RelocInfo::CODE_TARGET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2209,68 +2209,64 @@ void Builtins::Generate_Apply(MacroAssembler* masm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void Builtins::Generate_CallForwardVarargs(MacroAssembler* masm,
|
void Builtins::Generate_ForwardVarargs(MacroAssembler* masm,
|
||||||
Handle<Code> code) {
|
Handle<Code> code) {
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
// -- a1 : the target to call (can be any Object)
|
// -- a0 : the number of arguments (not including the receiver)
|
||||||
// -- a2 : start index (to support rest parameters)
|
// -- a3 : the new.target (for [[Construct]] calls)
|
||||||
// -- ra : return address.
|
// -- a1 : the target to call (can be any Object)
|
||||||
// -- sp[0] : thisArgument
|
// -- a2 : start index (to support rest parameters)
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
|
|
||||||
// Check if we have an arguments adaptor frame below the function frame.
|
// Check if we have an arguments adaptor frame below the function frame.
|
||||||
Label arguments_adaptor, arguments_done;
|
Label arguments_adaptor, arguments_done;
|
||||||
__ Ld(a3, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
|
__ Ld(a6, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
|
||||||
__ Ld(a0, MemOperand(a3, CommonFrameConstants::kContextOrFrameTypeOffset));
|
__ Ld(a7, MemOperand(a6, CommonFrameConstants::kContextOrFrameTypeOffset));
|
||||||
__ Branch(&arguments_adaptor, eq, a0,
|
__ Branch(&arguments_adaptor, eq, a7,
|
||||||
Operand(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)));
|
Operand(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)));
|
||||||
{
|
{
|
||||||
__ Ld(a0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
__ Ld(a7, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
||||||
__ Ld(a0, FieldMemOperand(a0, JSFunction::kSharedFunctionInfoOffset));
|
__ Ld(a7, FieldMemOperand(a7, JSFunction::kSharedFunctionInfoOffset));
|
||||||
__ Lw(a0,
|
__ Lw(a7,
|
||||||
FieldMemOperand(a0, SharedFunctionInfo::kFormalParameterCountOffset));
|
FieldMemOperand(a7, SharedFunctionInfo::kFormalParameterCountOffset));
|
||||||
__ mov(a3, fp);
|
__ mov(a6, fp);
|
||||||
}
|
}
|
||||||
__ Branch(&arguments_done);
|
__ Branch(&arguments_done);
|
||||||
__ bind(&arguments_adaptor);
|
__ bind(&arguments_adaptor);
|
||||||
{
|
{
|
||||||
// Just get the length from the ArgumentsAdaptorFrame.
|
// Just get the length from the ArgumentsAdaptorFrame.
|
||||||
__ Lw(a0, UntagSmiMemOperand(
|
__ Lw(a7, UntagSmiMemOperand(
|
||||||
a3, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
a6, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||||
}
|
}
|
||||||
__ bind(&arguments_done);
|
__ bind(&arguments_done);
|
||||||
|
|
||||||
Label stack_empty, stack_done, stack_overflow;
|
Label stack_done, stack_overflow;
|
||||||
__ Subu(a0, a0, a2);
|
__ Subu(a7, a7, a2);
|
||||||
__ Branch(&stack_empty, le, a0, Operand(zero_reg));
|
__ Branch(&stack_done, le, a7, Operand(zero_reg));
|
||||||
{
|
{
|
||||||
// Check for stack overflow.
|
// 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.
|
// Forward the arguments from the caller frame.
|
||||||
{
|
{
|
||||||
Label loop;
|
Label loop;
|
||||||
__ mov(a2, a0);
|
__ Daddu(a0, a0, a7);
|
||||||
__ bind(&loop);
|
__ bind(&loop);
|
||||||
{
|
{
|
||||||
__ Dlsa(at, a3, a2, kPointerSizeLog2);
|
__ Dlsa(at, a6, a7, kPointerSizeLog2);
|
||||||
__ Ld(at, MemOperand(at, 1 * kPointerSize));
|
__ Ld(at, MemOperand(at, 1 * kPointerSize));
|
||||||
__ push(at);
|
__ push(at);
|
||||||
__ Subu(a2, a2, Operand(1));
|
__ Subu(a7, a7, Operand(1));
|
||||||
__ Branch(&loop, ne, a2, Operand(zero_reg));
|
__ Branch(&loop, ne, a7, Operand(zero_reg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
__ Branch(&stack_done);
|
__ Branch(&stack_done);
|
||||||
__ bind(&stack_overflow);
|
__ bind(&stack_overflow);
|
||||||
__ TailCallRuntime(Runtime::kThrowStackOverflow);
|
__ TailCallRuntime(Runtime::kThrowStackOverflow);
|
||||||
__ bind(&stack_empty);
|
|
||||||
{
|
|
||||||
// We just pass the receiver, which is already on the stack.
|
|
||||||
__ mov(a0, zero_reg);
|
|
||||||
}
|
|
||||||
__ bind(&stack_done);
|
__ bind(&stack_done);
|
||||||
|
|
||||||
|
// Tail-call to the {code} handler.
|
||||||
__ Jump(code, RelocInfo::CODE_TARGET);
|
__ Jump(code, RelocInfo::CODE_TARGET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2416,13 +2416,13 @@ void Builtins::Generate_Apply(MacroAssembler* masm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void Builtins::Generate_CallForwardVarargs(MacroAssembler* masm,
|
void Builtins::Generate_ForwardVarargs(MacroAssembler* masm,
|
||||||
Handle<Code> code) {
|
Handle<Code> code) {
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
// -- rdi : the target to call (can be any Object)
|
// -- rax : the number of arguments (not including the receiver)
|
||||||
// -- rcx : start index (to support rest parameters)
|
// -- rdx : the new target (for [[Construct]] calls)
|
||||||
// -- rsp[0] : return address.
|
// -- rdi : the target to call (can be any Object)
|
||||||
// -- rsp[8] : thisArgument
|
// -- rcx : start index (to support rest parameters)
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
|
|
||||||
// Check if we have an arguments adaptor frame below the function frame.
|
// 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)));
|
Immediate(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)));
|
||||||
__ j(equal, &arguments_adaptor, Label::kNear);
|
__ j(equal, &arguments_adaptor, Label::kNear);
|
||||||
{
|
{
|
||||||
__ movp(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
|
__ movp(r8, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
|
||||||
__ movp(rax, FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset));
|
__ movp(r8, FieldOperand(r8, JSFunction::kSharedFunctionInfoOffset));
|
||||||
__ LoadSharedFunctionInfoSpecialField(
|
__ LoadSharedFunctionInfoSpecialField(
|
||||||
rax, rax, SharedFunctionInfo::kFormalParameterCountOffset);
|
r8, r8, SharedFunctionInfo::kFormalParameterCountOffset);
|
||||||
__ movp(rbx, rbp);
|
__ movp(rbx, rbp);
|
||||||
}
|
}
|
||||||
__ jmp(&arguments_done, Label::kNear);
|
__ jmp(&arguments_done, Label::kNear);
|
||||||
__ bind(&arguments_adaptor);
|
__ bind(&arguments_adaptor);
|
||||||
{
|
{
|
||||||
__ SmiToInteger32(
|
__ SmiToInteger32(
|
||||||
rax, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
r8, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||||
}
|
}
|
||||||
__ bind(&arguments_done);
|
__ bind(&arguments_done);
|
||||||
|
|
||||||
Label stack_empty, stack_done, stack_overflow;
|
Label stack_done, stack_overflow;
|
||||||
__ subl(rax, rcx);
|
__ subl(r8, rcx);
|
||||||
__ j(less_equal, &stack_empty);
|
__ j(less_equal, &stack_done);
|
||||||
{
|
{
|
||||||
// Check for stack overflow.
|
// 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.
|
// Forward the arguments from the caller frame.
|
||||||
{
|
{
|
||||||
Label loop;
|
Label loop;
|
||||||
__ movl(rcx, rax);
|
__ addl(rax, r8);
|
||||||
__ Pop(r8);
|
__ PopReturnAddressTo(rcx);
|
||||||
__ bind(&loop);
|
__ bind(&loop);
|
||||||
{
|
{
|
||||||
StackArgumentsAccessor args(rbx, rcx, ARGUMENTS_DONT_CONTAIN_RECEIVER);
|
StackArgumentsAccessor args(rbx, r8, ARGUMENTS_DONT_CONTAIN_RECEIVER);
|
||||||
__ Push(args.GetArgumentOperand(0));
|
__ Push(args.GetArgumentOperand(0));
|
||||||
__ decl(rcx);
|
__ decl(r8);
|
||||||
__ j(not_zero, &loop);
|
__ j(not_zero, &loop);
|
||||||
}
|
}
|
||||||
__ Push(r8);
|
__ PushReturnAddressFrom(rcx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
__ jmp(&stack_done, Label::kNear);
|
__ jmp(&stack_done, Label::kNear);
|
||||||
__ bind(&stack_overflow);
|
__ bind(&stack_overflow);
|
||||||
__ TailCallRuntime(Runtime::kThrowStackOverflow);
|
__ TailCallRuntime(Runtime::kThrowStackOverflow);
|
||||||
__ bind(&stack_empty);
|
|
||||||
{
|
|
||||||
// We just pass the receiver, which is already on the stack.
|
|
||||||
__ Set(rax, 0);
|
|
||||||
}
|
|
||||||
__ bind(&stack_done);
|
__ bind(&stack_done);
|
||||||
|
|
||||||
|
// Tail-call to the {code} handler.
|
||||||
__ Jump(code, RelocInfo::CODE_TARGET);
|
__ Jump(code, RelocInfo::CODE_TARGET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -457,6 +457,18 @@ Callable CodeFactory::ConstructFunction(Isolate* isolate) {
|
|||||||
ConstructTrampolineDescriptor(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
|
// static
|
||||||
Callable CodeFactory::InterpreterPushArgsThenCall(
|
Callable CodeFactory::InterpreterPushArgsThenCall(
|
||||||
Isolate* isolate, ConvertReceiverMode receiver_mode,
|
Isolate* isolate, ConvertReceiverMode receiver_mode,
|
||||||
|
@ -167,6 +167,8 @@ class V8_EXPORT_PRIVATE CodeFactory final {
|
|||||||
static Callable Construct(Isolate* isolate);
|
static Callable Construct(Isolate* isolate);
|
||||||
static Callable ConstructWithSpread(Isolate* isolate);
|
static Callable ConstructWithSpread(Isolate* isolate);
|
||||||
static Callable ConstructFunction(Isolate* isolate);
|
static Callable ConstructFunction(Isolate* isolate);
|
||||||
|
static Callable ConstructForwardVarargs(Isolate* isolate);
|
||||||
|
static Callable ConstructFunctionForwardVarargs(Isolate* isolate);
|
||||||
static Callable CreateIterResultObject(Isolate* isolate);
|
static Callable CreateIterResultObject(Isolate* isolate);
|
||||||
static Callable HasProperty(Isolate* isolate);
|
static Callable HasProperty(Isolate* isolate);
|
||||||
static Callable ForInFilter(Isolate* isolate);
|
static Callable ForInFilter(Isolate* isolate);
|
||||||
|
@ -124,7 +124,8 @@ Reduction JSCallReducer::ReduceFunctionPrototypeApply(Node* node) {
|
|||||||
Node* arg_array = NodeProperties::GetValueInput(node, 3);
|
Node* arg_array = NodeProperties::GetValueInput(node, 3);
|
||||||
if (arg_array->opcode() != IrOpcode::kJSCreateArguments) return NoChange();
|
if (arg_array->opcode() != IrOpcode::kJSCreateArguments) return NoChange();
|
||||||
for (Edge edge : arg_array->use_edges()) {
|
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.
|
// Ignore uses as frame state's locals or parameters.
|
||||||
if (user->opcode() == IrOpcode::kStateValues) continue;
|
if (user->opcode() == IrOpcode::kStateValues) continue;
|
||||||
// Ignore uses as frame state's accumulator.
|
// Ignore uses as frame state's accumulator.
|
||||||
@ -133,7 +134,6 @@ Reduction JSCallReducer::ReduceFunctionPrototypeApply(Node* node) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!NodeProperties::IsValueEdge(edge)) continue;
|
if (!NodeProperties::IsValueEdge(edge)) continue;
|
||||||
if (edge.from() == node) continue;
|
|
||||||
return NoChange();
|
return NoChange();
|
||||||
}
|
}
|
||||||
// Check if the arguments can be handled in the fast case (i.e. we don't
|
// 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(0); // Function.prototype.apply
|
||||||
node->RemoveInput(2); // arguments
|
node->RemoveInput(2); // arguments
|
||||||
NodeProperties::ChangeOp(node, javascript()->CallForwardVarargs(
|
NodeProperties::ChangeOp(node, javascript()->CallForwardVarargs(
|
||||||
start_index, p.tail_call_mode()));
|
2, start_index, p.tail_call_mode()));
|
||||||
return Changed(node);
|
return Changed(node);
|
||||||
}
|
}
|
||||||
// Get to the actual frame state from which to extract the arguments;
|
// 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).
|
// of spread (except for value uses in frame states).
|
||||||
if (spread->opcode() != IrOpcode::kJSCreateArguments) return NoChange();
|
if (spread->opcode() != IrOpcode::kJSCreateArguments) return NoChange();
|
||||||
for (Edge edge : spread->use_edges()) {
|
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 (!NodeProperties::IsValueEdge(edge)) continue;
|
||||||
if (edge.from() == node) continue;
|
|
||||||
return NoChange();
|
return NoChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get to the actual frame state from which to extract the arguments;
|
// 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
|
// we can only optimize this in case the {node} was already inlined into
|
||||||
// some other function (and same for the {spread}).
|
// 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);
|
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);
|
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);
|
FrameStateInfo outer_info = OpParameter<FrameStateInfo>(outer_state);
|
||||||
if (outer_info.type() == FrameStateType::kArgumentsAdaptor) {
|
if (outer_info.type() == FrameStateType::kArgumentsAdaptor) {
|
||||||
// Need to take the parameters from the arguments adaptor.
|
// Need to take the parameters from the arguments adaptor.
|
||||||
frame_state = outer_state;
|
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.
|
// Add the actual parameters to the {node}, skipping the receiver.
|
||||||
Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
|
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),
|
node->InsertInput(graph()->zone(), static_cast<int>(++arity),
|
||||||
parameters->InputAt(i));
|
parameters->InputAt(i));
|
||||||
}
|
}
|
||||||
|
@ -523,6 +523,28 @@ void JSGenericLowering::LowerJSCreateScriptContext(Node* node) {
|
|||||||
ReplaceWithRuntimeCall(node, Runtime::kNewScriptContext);
|
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) {
|
void JSGenericLowering::LowerJSConstruct(Node* node) {
|
||||||
ConstructParameters const& p = ConstructParametersOf(node->op());
|
ConstructParameters const& p = ConstructParametersOf(node->op());
|
||||||
int const arg_count = static_cast<int>(p.arity() - 2);
|
int const arg_count = static_cast<int>(p.arity() - 2);
|
||||||
@ -563,17 +585,20 @@ void JSGenericLowering::LowerJSConstructWithSpread(Node* node) {
|
|||||||
|
|
||||||
void JSGenericLowering::LowerJSCallForwardVarargs(Node* node) {
|
void JSGenericLowering::LowerJSCallForwardVarargs(Node* node) {
|
||||||
CallForwardVarargsParameters p = CallForwardVarargsParametersOf(node->op());
|
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);
|
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
||||||
|
Callable callable = CodeFactory::CallForwardVarargs(isolate());
|
||||||
if (p.tail_call_mode() == TailCallMode::kAllow) {
|
if (p.tail_call_mode() == TailCallMode::kAllow) {
|
||||||
flags |= CallDescriptor::kSupportsTailCalls;
|
flags |= CallDescriptor::kSupportsTailCalls;
|
||||||
}
|
}
|
||||||
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
|
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_code = jsgraph()->HeapConstant(callable.code());
|
||||||
|
Node* stub_arity = jsgraph()->Int32Constant(arg_count);
|
||||||
Node* start_index = jsgraph()->Uint32Constant(p.start_index());
|
Node* start_index = jsgraph()->Uint32Constant(p.start_index());
|
||||||
node->InsertInput(zone(), 0, stub_code);
|
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));
|
NodeProperties::ChangeOp(node, common()->Call(desc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,6 +57,17 @@ ToBooleanHints ToBooleanHintsOf(Operator const* op) {
|
|||||||
return OpParameter<ToBooleanHints>(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,
|
bool operator==(ConstructParameters const& lhs,
|
||||||
ConstructParameters const& rhs) {
|
ConstructParameters const& rhs) {
|
||||||
return lhs.arity() == rhs.arity() && lhs.frequency() == rhs.frequency() &&
|
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,
|
std::ostream& operator<<(std::ostream& os,
|
||||||
CallForwardVarargsParameters const& p) {
|
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(
|
CallForwardVarargsParameters const& CallForwardVarargsParametersOf(
|
||||||
@ -743,12 +755,12 @@ const Operator* JSOperatorBuilder::ToBoolean(ToBooleanHints hints) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Operator* JSOperatorBuilder::CallForwardVarargs(
|
const Operator* JSOperatorBuilder::CallForwardVarargs(
|
||||||
uint32_t start_index, TailCallMode tail_call_mode) {
|
size_t arity, uint32_t start_index, TailCallMode tail_call_mode) {
|
||||||
CallForwardVarargsParameters parameters(start_index, tail_call_mode);
|
CallForwardVarargsParameters parameters(arity, start_index, tail_call_mode);
|
||||||
return new (zone()) Operator1<CallForwardVarargsParameters>( // --
|
return new (zone()) Operator1<CallForwardVarargsParameters>( // --
|
||||||
IrOpcode::kJSCallForwardVarargs, Operator::kNoProperties, // opcode
|
IrOpcode::kJSCallForwardVarargs, Operator::kNoProperties, // opcode
|
||||||
"JSCallForwardVarargs", // name
|
"JSCallForwardVarargs", // name
|
||||||
2, 1, 1, 1, 1, 2, // counts
|
parameters.arity(), 1, 1, 1, 1, 2, // counts
|
||||||
parameters); // parameter
|
parameters); // parameter
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -798,6 +810,16 @@ const Operator* JSOperatorBuilder::CallRuntime(const Runtime::Function* f,
|
|||||||
parameters); // parameter
|
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,
|
const Operator* JSOperatorBuilder::Construct(uint32_t arity,
|
||||||
CallFrequency frequency,
|
CallFrequency frequency,
|
||||||
VectorSlotPair const& feedback) {
|
VectorSlotPair const& feedback) {
|
||||||
|
@ -90,6 +90,40 @@ ConvertReceiverMode ConvertReceiverModeOf(Operator const* op);
|
|||||||
// The ToBooleanHints are used as parameter by JSToBoolean operators.
|
// The ToBooleanHints are used as parameter by JSToBoolean operators.
|
||||||
ToBooleanHints ToBooleanHintsOf(Operator const* op);
|
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
|
// Defines the arity and the feedback for a JavaScript constructor call. This is
|
||||||
// used as a parameter by JSConstruct operators.
|
// used as a parameter by JSConstruct operators.
|
||||||
@ -146,11 +180,13 @@ SpreadWithArityParameter const& SpreadWithArityParameterOf(Operator const*);
|
|||||||
// is used as parameter by JSCallForwardVarargs operators.
|
// is used as parameter by JSCallForwardVarargs operators.
|
||||||
class CallForwardVarargsParameters final {
|
class CallForwardVarargsParameters final {
|
||||||
public:
|
public:
|
||||||
CallForwardVarargsParameters(uint32_t start_index,
|
CallForwardVarargsParameters(size_t arity, uint32_t start_index,
|
||||||
TailCallMode tail_call_mode)
|
TailCallMode tail_call_mode)
|
||||||
: bit_field_(StartIndexField::encode(start_index) |
|
: bit_field_(ArityField::encode(arity) |
|
||||||
|
StartIndexField::encode(start_index) |
|
||||||
TailCallModeField::encode(tail_call_mode)) {}
|
TailCallModeField::encode(tail_call_mode)) {}
|
||||||
|
|
||||||
|
size_t arity() const { return ArityField::decode(bit_field_); }
|
||||||
uint32_t start_index() const { return StartIndexField::decode(bit_field_); }
|
uint32_t start_index() const { return StartIndexField::decode(bit_field_); }
|
||||||
TailCallMode tail_call_mode() const {
|
TailCallMode tail_call_mode() const {
|
||||||
return TailCallModeField::decode(bit_field_);
|
return TailCallModeField::decode(bit_field_);
|
||||||
@ -168,8 +204,9 @@ class CallForwardVarargsParameters final {
|
|||||||
return p.bit_field_;
|
return p.bit_field_;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef BitField<uint32_t, 0, 30> StartIndexField;
|
typedef BitField<size_t, 0, 15> ArityField;
|
||||||
typedef BitField<TailCallMode, 31, 1> TailCallModeField;
|
typedef BitField<uint32_t, 15, 15> StartIndexField;
|
||||||
|
typedef BitField<TailCallMode, 30, 1> TailCallModeField;
|
||||||
|
|
||||||
uint32_t const bit_field_;
|
uint32_t const bit_field_;
|
||||||
};
|
};
|
||||||
@ -665,7 +702,7 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final
|
|||||||
const Operator* CreateLiteralRegExp(Handle<String> constant_pattern,
|
const Operator* CreateLiteralRegExp(Handle<String> constant_pattern,
|
||||||
int literal_flags, int literal_index);
|
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);
|
TailCallMode tail_call_mode);
|
||||||
const Operator* Call(
|
const Operator* Call(
|
||||||
size_t arity, CallFrequency frequency = CallFrequency(),
|
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);
|
||||||
const Operator* CallRuntime(Runtime::FunctionId id, size_t arity);
|
const Operator* CallRuntime(Runtime::FunctionId id, size_t arity);
|
||||||
const Operator* CallRuntime(const Runtime::Function* function, 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,
|
const Operator* Construct(uint32_t arity,
|
||||||
CallFrequency frequency = CallFrequency(),
|
CallFrequency frequency = CallFrequency(),
|
||||||
VectorSlotPair const& feedback = VectorSlotPair());
|
VectorSlotPair const& feedback = VectorSlotPair());
|
||||||
|
@ -1703,6 +1703,38 @@ bool NeedsArgumentAdaptorFrame(Handle<SharedFunctionInfo> shared, int arity) {
|
|||||||
|
|
||||||
} // namespace
|
} // 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) {
|
Reduction JSTypedLowering::ReduceJSConstruct(Node* node) {
|
||||||
DCHECK_EQ(IrOpcode::kJSConstruct, node->opcode());
|
DCHECK_EQ(IrOpcode::kJSConstruct, node->opcode());
|
||||||
ConstructParameters const& p = ConstructParametersOf(node->op());
|
ConstructParameters const& p = ConstructParametersOf(node->op());
|
||||||
@ -1781,6 +1813,9 @@ Reduction JSTypedLowering::ReduceJSConstruct(Node* node) {
|
|||||||
Reduction JSTypedLowering::ReduceJSCallForwardVarargs(Node* node) {
|
Reduction JSTypedLowering::ReduceJSCallForwardVarargs(Node* node) {
|
||||||
DCHECK_EQ(IrOpcode::kJSCallForwardVarargs, node->opcode());
|
DCHECK_EQ(IrOpcode::kJSCallForwardVarargs, node->opcode());
|
||||||
CallForwardVarargsParameters p = CallForwardVarargsParametersOf(node->op());
|
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);
|
Node* target = NodeProperties::GetValueInput(node, 0);
|
||||||
Type* target_type = NodeProperties::GetType(target);
|
Type* target_type = NodeProperties::GetType(target);
|
||||||
|
|
||||||
@ -1796,11 +1831,12 @@ Reduction JSTypedLowering::ReduceJSCallForwardVarargs(Node* node) {
|
|||||||
Callable callable = CodeFactory::CallFunctionForwardVarargs(isolate());
|
Callable callable = CodeFactory::CallFunctionForwardVarargs(isolate());
|
||||||
node->InsertInput(graph()->zone(), 0,
|
node->InsertInput(graph()->zone(), 0,
|
||||||
jsgraph()->HeapConstant(callable.code()));
|
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(
|
NodeProperties::ChangeOp(
|
||||||
node,
|
node, common()->Call(Linkage::GetStubCallDescriptor(
|
||||||
common()->Call(Linkage::GetStubCallDescriptor(
|
isolate(), graph()->zone(), callable.descriptor(), arity + 1,
|
||||||
isolate(), graph()->zone(), callable.descriptor(), 1, flags)));
|
flags)));
|
||||||
return Changed(node);
|
return Changed(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2176,6 +2212,8 @@ Reduction JSTypedLowering::Reduce(Node* node) {
|
|||||||
return ReduceJSStoreModule(node);
|
return ReduceJSStoreModule(node);
|
||||||
case IrOpcode::kJSConvertReceiver:
|
case IrOpcode::kJSConvertReceiver:
|
||||||
return ReduceJSConvertReceiver(node);
|
return ReduceJSConvertReceiver(node);
|
||||||
|
case IrOpcode::kJSConstructForwardVarargs:
|
||||||
|
return ReduceJSConstructForwardVarargs(node);
|
||||||
case IrOpcode::kJSConstruct:
|
case IrOpcode::kJSConstruct:
|
||||||
return ReduceJSConstruct(node);
|
return ReduceJSConstruct(node);
|
||||||
case IrOpcode::kJSCallForwardVarargs:
|
case IrOpcode::kJSCallForwardVarargs:
|
||||||
|
@ -69,6 +69,7 @@ class V8_EXPORT_PRIVATE JSTypedLowering final
|
|||||||
Reduction ReduceJSToString(Node* node);
|
Reduction ReduceJSToString(Node* node);
|
||||||
Reduction ReduceJSToObject(Node* node);
|
Reduction ReduceJSToObject(Node* node);
|
||||||
Reduction ReduceJSConvertReceiver(Node* node);
|
Reduction ReduceJSConvertReceiver(Node* node);
|
||||||
|
Reduction ReduceJSConstructForwardVarargs(Node* node);
|
||||||
Reduction ReduceJSConstruct(Node* node);
|
Reduction ReduceJSConstruct(Node* node);
|
||||||
Reduction ReduceJSCallForwardVarargs(Node* node);
|
Reduction ReduceJSCallForwardVarargs(Node* node);
|
||||||
Reduction ReduceJSCall(Node* node);
|
Reduction ReduceJSCall(Node* node);
|
||||||
|
@ -159,6 +159,7 @@
|
|||||||
V(JSCreateScriptContext)
|
V(JSCreateScriptContext)
|
||||||
|
|
||||||
#define JS_OTHER_OP_LIST(V) \
|
#define JS_OTHER_OP_LIST(V) \
|
||||||
|
V(JSConstructForwardVarargs) \
|
||||||
V(JSConstruct) \
|
V(JSConstruct) \
|
||||||
V(JSConstructWithSpread) \
|
V(JSConstructWithSpread) \
|
||||||
V(JSCallForwardVarargs) \
|
V(JSCallForwardVarargs) \
|
||||||
|
@ -96,6 +96,7 @@ bool OperatorProperties::HasFrameStateInput(const Operator* op) {
|
|||||||
case IrOpcode::kJSToString:
|
case IrOpcode::kJSToString:
|
||||||
|
|
||||||
// Call operations
|
// Call operations
|
||||||
|
case IrOpcode::kJSConstructForwardVarargs:
|
||||||
case IrOpcode::kJSConstruct:
|
case IrOpcode::kJSConstruct:
|
||||||
case IrOpcode::kJSConstructWithSpread:
|
case IrOpcode::kJSConstructWithSpread:
|
||||||
case IrOpcode::kJSCallForwardVarargs:
|
case IrOpcode::kJSCallForwardVarargs:
|
||||||
|
@ -1335,6 +1335,10 @@ Type* Typer::Visitor::TypeJSCreateScriptContext(Node* node) {
|
|||||||
|
|
||||||
// JS other operators.
|
// JS other operators.
|
||||||
|
|
||||||
|
Type* Typer::Visitor::TypeJSConstructForwardVarargs(Node* node) {
|
||||||
|
return Type::Receiver();
|
||||||
|
}
|
||||||
|
|
||||||
Type* Typer::Visitor::TypeJSConstruct(Node* node) { return Type::Receiver(); }
|
Type* Typer::Visitor::TypeJSConstruct(Node* node) { return Type::Receiver(); }
|
||||||
|
|
||||||
Type* Typer::Visitor::TypeJSConstructWithSpread(Node* node) {
|
Type* Typer::Visitor::TypeJSConstructWithSpread(Node* node) {
|
||||||
|
@ -700,6 +700,7 @@ void Verifier::Visitor::Check(Node* node) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case IrOpcode::kJSConstructForwardVarargs:
|
||||||
case IrOpcode::kJSConstruct:
|
case IrOpcode::kJSConstruct:
|
||||||
case IrOpcode::kJSConstructWithSpread:
|
case IrOpcode::kJSConstructWithSpread:
|
||||||
case IrOpcode::kJSConvertReceiver:
|
case IrOpcode::kJSConvertReceiver:
|
||||||
|
@ -156,9 +156,20 @@ void CallTrampolineDescriptor::InitializePlatformSpecific(
|
|||||||
|
|
||||||
void CallForwardVarargsDescriptor::InitializePlatformSpecific(
|
void CallForwardVarargsDescriptor::InitializePlatformSpecific(
|
||||||
CallInterfaceDescriptorData* data) {
|
CallInterfaceDescriptorData* data) {
|
||||||
|
// eax : number of arguments
|
||||||
// ecx : start index (to support rest parameters)
|
// ecx : start index (to support rest parameters)
|
||||||
// edi : the target to call
|
// 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);
|
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,8 +447,18 @@ void CallTrampolineDescriptor::InitializePlatformIndependent(
|
|||||||
|
|
||||||
void CallForwardVarargsDescriptor::InitializePlatformIndependent(
|
void CallForwardVarargsDescriptor::InitializePlatformIndependent(
|
||||||
CallInterfaceDescriptorData* data) {
|
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 machine_types[] = {MachineType::AnyTagged(),
|
||||||
|
MachineType::AnyTagged(), MachineType::Int32(),
|
||||||
MachineType::Int32()};
|
MachineType::Int32()};
|
||||||
data->InitializePlatformIndependent(arraysize(machine_types), 0,
|
data->InitializePlatformIndependent(arraysize(machine_types), 0,
|
||||||
machine_types);
|
machine_types);
|
||||||
|
@ -48,6 +48,7 @@ class PlatformInterfaceDescriptor;
|
|||||||
V(CallConstruct) \
|
V(CallConstruct) \
|
||||||
V(CallTrampoline) \
|
V(CallTrampoline) \
|
||||||
V(ConstructStub) \
|
V(ConstructStub) \
|
||||||
|
V(ConstructForwardVarargs) \
|
||||||
V(ConstructTrampoline) \
|
V(ConstructTrampoline) \
|
||||||
V(TransitionElementsKind) \
|
V(TransitionElementsKind) \
|
||||||
V(AllocateHeapNumber) \
|
V(AllocateHeapNumber) \
|
||||||
@ -575,11 +576,18 @@ class CallTrampolineDescriptor : public CallInterfaceDescriptor {
|
|||||||
|
|
||||||
class CallForwardVarargsDescriptor : public CallInterfaceDescriptor {
|
class CallForwardVarargsDescriptor : public CallInterfaceDescriptor {
|
||||||
public:
|
public:
|
||||||
DEFINE_PARAMETERS(kTarget, kStartIndex)
|
DEFINE_PARAMETERS(kTarget, kActualArgumentsCount, kStartIndex)
|
||||||
DECLARE_DESCRIPTOR_WITH_CUSTOM_FUNCTION_TYPE(CallForwardVarargsDescriptor,
|
DECLARE_DESCRIPTOR_WITH_CUSTOM_FUNCTION_TYPE(CallForwardVarargsDescriptor,
|
||||||
CallInterfaceDescriptor)
|
CallInterfaceDescriptor)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ConstructForwardVarargsDescriptor : public CallInterfaceDescriptor {
|
||||||
|
public:
|
||||||
|
DEFINE_PARAMETERS(kTarget, kNewTarget, kActualArgumentsCount, kStartIndex)
|
||||||
|
DECLARE_DESCRIPTOR_WITH_CUSTOM_FUNCTION_TYPE(
|
||||||
|
ConstructForwardVarargsDescriptor, CallInterfaceDescriptor)
|
||||||
|
};
|
||||||
|
|
||||||
class ConstructStubDescriptor : public CallInterfaceDescriptor {
|
class ConstructStubDescriptor : public CallInterfaceDescriptor {
|
||||||
public:
|
public:
|
||||||
DEFINE_PARAMETERS(kFunction, kNewTarget, kActualArgumentsCount,
|
DEFINE_PARAMETERS(kFunction, kNewTarget, kActualArgumentsCount,
|
||||||
|
@ -156,8 +156,19 @@ void CallTrampolineDescriptor::InitializePlatformSpecific(
|
|||||||
void CallForwardVarargsDescriptor::InitializePlatformSpecific(
|
void CallForwardVarargsDescriptor::InitializePlatformSpecific(
|
||||||
CallInterfaceDescriptorData* data) {
|
CallInterfaceDescriptorData* data) {
|
||||||
// a1: the target to call
|
// a1: the target to call
|
||||||
|
// a0: number of arguments
|
||||||
// a2: start index (to support rest parameters)
|
// 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);
|
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,8 +156,19 @@ void CallTrampolineDescriptor::InitializePlatformSpecific(
|
|||||||
void CallForwardVarargsDescriptor::InitializePlatformSpecific(
|
void CallForwardVarargsDescriptor::InitializePlatformSpecific(
|
||||||
CallInterfaceDescriptorData* data) {
|
CallInterfaceDescriptorData* data) {
|
||||||
// a1: the target to call
|
// a1: the target to call
|
||||||
|
// a0: number of arguments
|
||||||
// a2: start index (to support rest parameters)
|
// 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);
|
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,9 +155,20 @@ void CallTrampolineDescriptor::InitializePlatformSpecific(
|
|||||||
|
|
||||||
void CallForwardVarargsDescriptor::InitializePlatformSpecific(
|
void CallForwardVarargsDescriptor::InitializePlatformSpecific(
|
||||||
CallInterfaceDescriptorData* data) {
|
CallInterfaceDescriptorData* data) {
|
||||||
|
// rax : number of arguments
|
||||||
// rcx : start index (to support rest parameters)
|
// rcx : start index (to support rest parameters)
|
||||||
// rdi : the target to call
|
// 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);
|
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user