Commit f9367847 authored by petermarshall's avatar petermarshall Committed by Commit bot

[Turbofan] Implement call with spread bytecode in assembly code.

We can share almost all of the architecture-specific builtin code with super-call-with-spread.

Info to port-writers: The code in CheckSpreadAndPushToStack has changed slightly from what was in Generate_ConstructWithSpread, in that we take the length of the spreaded parameters from the JSArray rather than the FixedArray backing store.

BUG=v8:5511

Review-Url: https://codereview.chromium.org/2649143002
Cr-Commit-Position: refs/heads/master@{#42632}
parent 4aedeb1b
This diff is collapsed.
This diff is collapsed.
...@@ -8,18 +8,21 @@ ...@@ -8,18 +8,21 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
Handle<Code> Builtins::InterpreterPushArgsAndCall(TailCallMode tail_call_mode, Handle<Code> Builtins::InterpreterPushArgsAndCall(
CallableType function_type) { TailCallMode tail_call_mode, InterpreterPushArgsMode mode) {
switch (tail_call_mode) { switch (mode) {
case TailCallMode::kDisallow: case InterpreterPushArgsMode::kJSFunction:
if (function_type == CallableType::kJSFunction) { if (tail_call_mode == TailCallMode::kDisallow) {
return InterpreterPushArgsAndCallFunction(); return InterpreterPushArgsAndCallFunction();
} else { } else {
return InterpreterPushArgsAndCall();
}
case TailCallMode::kAllow:
if (function_type == CallableType::kJSFunction) {
return InterpreterPushArgsAndTailCallFunction(); return InterpreterPushArgsAndTailCallFunction();
}
case InterpreterPushArgsMode::kWithFinalSpread:
CHECK(tail_call_mode == TailCallMode::kDisallow);
return InterpreterPushArgsAndCallWithFinalSpread();
case InterpreterPushArgsMode::kOther:
if (tail_call_mode == TailCallMode::kDisallow) {
return InterpreterPushArgsAndCall();
} else { } else {
return InterpreterPushArgsAndTailCall(); return InterpreterPushArgsAndTailCall();
} }
...@@ -29,35 +32,41 @@ Handle<Code> Builtins::InterpreterPushArgsAndCall(TailCallMode tail_call_mode, ...@@ -29,35 +32,41 @@ Handle<Code> Builtins::InterpreterPushArgsAndCall(TailCallMode tail_call_mode,
} }
void Builtins::Generate_InterpreterPushArgsAndCall(MacroAssembler* masm) { void Builtins::Generate_InterpreterPushArgsAndCall(MacroAssembler* masm) {
return Generate_InterpreterPushArgsAndCallImpl(masm, TailCallMode::kDisallow, return Generate_InterpreterPushArgsAndCallImpl(
CallableType::kAny); masm, TailCallMode::kDisallow, InterpreterPushArgsMode::kOther);
} }
void Builtins::Generate_InterpreterPushArgsAndCallFunction( void Builtins::Generate_InterpreterPushArgsAndCallFunction(
MacroAssembler* masm) { MacroAssembler* masm) {
return Generate_InterpreterPushArgsAndCallImpl(masm, TailCallMode::kDisallow, return Generate_InterpreterPushArgsAndCallImpl(
CallableType::kJSFunction); masm, TailCallMode::kDisallow, InterpreterPushArgsMode::kJSFunction);
}
void Builtins::Generate_InterpreterPushArgsAndCallWithFinalSpread(
MacroAssembler* masm) {
return Generate_InterpreterPushArgsAndCallImpl(
masm, TailCallMode::kDisallow, InterpreterPushArgsMode::kWithFinalSpread);
} }
void Builtins::Generate_InterpreterPushArgsAndTailCall(MacroAssembler* masm) { void Builtins::Generate_InterpreterPushArgsAndTailCall(MacroAssembler* masm) {
return Generate_InterpreterPushArgsAndCallImpl(masm, TailCallMode::kAllow, return Generate_InterpreterPushArgsAndCallImpl(
CallableType::kAny); masm, TailCallMode::kAllow, InterpreterPushArgsMode::kOther);
} }
void Builtins::Generate_InterpreterPushArgsAndTailCallFunction( void Builtins::Generate_InterpreterPushArgsAndTailCallFunction(
MacroAssembler* masm) { MacroAssembler* masm) {
return Generate_InterpreterPushArgsAndCallImpl(masm, TailCallMode::kAllow, return Generate_InterpreterPushArgsAndCallImpl(
CallableType::kJSFunction); masm, TailCallMode::kAllow, InterpreterPushArgsMode::kJSFunction);
} }
Handle<Code> Builtins::InterpreterPushArgsAndConstruct( Handle<Code> Builtins::InterpreterPushArgsAndConstruct(
PushArgsConstructMode mode) { InterpreterPushArgsMode mode) {
switch (mode) { switch (mode) {
case PushArgsConstructMode::kJSFunction: case InterpreterPushArgsMode::kJSFunction:
return InterpreterPushArgsAndConstructFunction(); return InterpreterPushArgsAndConstructFunction();
case PushArgsConstructMode::kWithFinalSpread: case InterpreterPushArgsMode::kWithFinalSpread:
return InterpreterPushArgsAndConstructWithFinalSpread(); return InterpreterPushArgsAndConstructWithFinalSpread();
case PushArgsConstructMode::kOther: case InterpreterPushArgsMode::kOther:
return InterpreterPushArgsAndConstruct(); return InterpreterPushArgsAndConstruct();
} }
UNREACHABLE(); UNREACHABLE();
...@@ -66,19 +75,19 @@ Handle<Code> Builtins::InterpreterPushArgsAndConstruct( ...@@ -66,19 +75,19 @@ Handle<Code> Builtins::InterpreterPushArgsAndConstruct(
void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) { void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
return Generate_InterpreterPushArgsAndConstructImpl( return Generate_InterpreterPushArgsAndConstructImpl(
masm, PushArgsConstructMode::kOther); masm, InterpreterPushArgsMode::kOther);
} }
void Builtins::Generate_InterpreterPushArgsAndConstructWithFinalSpread( void Builtins::Generate_InterpreterPushArgsAndConstructWithFinalSpread(
MacroAssembler* masm) { MacroAssembler* masm) {
return Generate_InterpreterPushArgsAndConstructImpl( return Generate_InterpreterPushArgsAndConstructImpl(
masm, PushArgsConstructMode::kWithFinalSpread); masm, InterpreterPushArgsMode::kWithFinalSpread);
} }
void Builtins::Generate_InterpreterPushArgsAndConstructFunction( void Builtins::Generate_InterpreterPushArgsAndConstructFunction(
MacroAssembler* masm) { MacroAssembler* masm) {
return Generate_InterpreterPushArgsAndConstructImpl( return Generate_InterpreterPushArgsAndConstructImpl(
masm, PushArgsConstructMode::kJSFunction); masm, InterpreterPushArgsMode::kJSFunction);
} }
} // namespace internal } // namespace internal
......
...@@ -74,6 +74,7 @@ namespace internal { ...@@ -74,6 +74,7 @@ namespace internal {
ASM(TailCall_ReceiverIsNullOrUndefined) \ ASM(TailCall_ReceiverIsNullOrUndefined) \
ASM(TailCall_ReceiverIsNotNullOrUndefined) \ ASM(TailCall_ReceiverIsNotNullOrUndefined) \
ASM(TailCall_ReceiverIsAny) \ ASM(TailCall_ReceiverIsAny) \
ASM(CallWithSpread) \
\ \
/* Construct */ \ /* Construct */ \
/* ES6 section 9.2.2 [[Construct]] ( argumentsList, newTarget) */ \ /* ES6 section 9.2.2 [[Construct]] ( argumentsList, newTarget) */ \
...@@ -139,6 +140,7 @@ namespace internal { ...@@ -139,6 +140,7 @@ namespace internal {
ASM(InterpreterEntryTrampoline) \ ASM(InterpreterEntryTrampoline) \
ASM(InterpreterPushArgsAndCall) \ ASM(InterpreterPushArgsAndCall) \
ASM(InterpreterPushArgsAndCallFunction) \ ASM(InterpreterPushArgsAndCallFunction) \
ASM(InterpreterPushArgsAndCallWithFinalSpread) \
ASM(InterpreterPushArgsAndTailCall) \ ASM(InterpreterPushArgsAndTailCall) \
ASM(InterpreterPushArgsAndTailCallFunction) \ ASM(InterpreterPushArgsAndTailCallFunction) \
ASM(InterpreterPushArgsAndConstruct) \ ASM(InterpreterPushArgsAndConstruct) \
...@@ -805,7 +807,7 @@ namespace internal { ...@@ -805,7 +807,7 @@ namespace internal {
// Forward declarations. // Forward declarations.
class ObjectVisitor; class ObjectVisitor;
enum class PushArgsConstructMode : unsigned; enum class InterpreterPushArgsMode : unsigned;
namespace compiler { namespace compiler {
class CodeAssemblerState; class CodeAssemblerState;
} }
...@@ -847,10 +849,9 @@ class Builtins { ...@@ -847,10 +849,9 @@ class Builtins {
Handle<Code> NonPrimitiveToPrimitive( Handle<Code> NonPrimitiveToPrimitive(
ToPrimitiveHint hint = ToPrimitiveHint::kDefault); ToPrimitiveHint hint = ToPrimitiveHint::kDefault);
Handle<Code> OrdinaryToPrimitive(OrdinaryToPrimitiveHint hint); Handle<Code> OrdinaryToPrimitive(OrdinaryToPrimitiveHint hint);
Handle<Code> InterpreterPushArgsAndCall( Handle<Code> InterpreterPushArgsAndCall(TailCallMode tail_call_mode,
TailCallMode tail_call_mode, InterpreterPushArgsMode mode);
CallableType function_type = CallableType::kAny); Handle<Code> InterpreterPushArgsAndConstruct(InterpreterPushArgsMode mode);
Handle<Code> InterpreterPushArgsAndConstruct(PushArgsConstructMode mode);
Handle<Code> NewFunctionContext(ScopeType scope_type); Handle<Code> NewFunctionContext(ScopeType scope_type);
Handle<Code> NewCloneShallowArray(AllocationSiteMode allocation_mode); Handle<Code> NewCloneShallowArray(AllocationSiteMode allocation_mode);
Handle<Code> NewCloneShallowObject(int length); Handle<Code> NewCloneShallowObject(int length);
...@@ -905,10 +906,10 @@ class Builtins { ...@@ -905,10 +906,10 @@ class Builtins {
static void Generate_InterpreterPushArgsAndCallImpl( static void Generate_InterpreterPushArgsAndCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode, MacroAssembler* masm, TailCallMode tail_call_mode,
CallableType function_type); InterpreterPushArgsMode mode);
static void Generate_InterpreterPushArgsAndConstructImpl( static void Generate_InterpreterPushArgsAndConstructImpl(
MacroAssembler* masm, PushArgsConstructMode mode); MacroAssembler* masm, InterpreterPushArgsMode mode);
enum class MathMaxMinKind { kMax, kMin }; enum class MathMaxMinKind { kMax, kMin };
static void Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind); static void Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -1163,7 +1163,7 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm, ...@@ -1163,7 +1163,7 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm,
// static // static
void Builtins::Generate_InterpreterPushArgsAndCallImpl( void Builtins::Generate_InterpreterPushArgsAndCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode, MacroAssembler* masm, TailCallMode tail_call_mode,
CallableType function_type) { InterpreterPushArgsMode mode) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- r3 : the number of arguments (not including the receiver) // -- r3 : the number of arguments (not including the receiver)
// -- r5 : the address of the first argument to be pushed. Subsequent // -- r5 : the address of the first argument to be pushed. Subsequent
...@@ -1180,12 +1180,12 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl( ...@@ -1180,12 +1180,12 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
Generate_InterpreterPushArgs(masm, r6, r5, r6, r7, &stack_overflow); Generate_InterpreterPushArgs(masm, r6, r5, r6, r7, &stack_overflow);
// Call the target. // Call the target.
if (function_type == CallableType::kJSFunction) { if (mode == InterpreterPushArgsMode::kJSFunction) {
__ Jump(masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny, __ Jump(masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny,
tail_call_mode), tail_call_mode),
RelocInfo::CODE_TARGET); RelocInfo::CODE_TARGET);
} else { } else {
DCHECK_EQ(function_type, CallableType::kAny); DCHECK_EQ(mode, InterpreterPushArgsMode::kOther);
__ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny, __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
tail_call_mode), tail_call_mode),
RelocInfo::CODE_TARGET); RelocInfo::CODE_TARGET);
...@@ -1201,7 +1201,7 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl( ...@@ -1201,7 +1201,7 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
// static // static
void Builtins::Generate_InterpreterPushArgsAndConstructImpl( void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
MacroAssembler* masm, PushArgsConstructMode mode) { MacroAssembler* masm, InterpreterPushArgsMode mode) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- r3 : argument count (not including receiver) // -- r3 : argument count (not including receiver)
// -- r6 : new target // -- r6 : new target
...@@ -1224,7 +1224,7 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl( ...@@ -1224,7 +1224,7 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
__ bind(&skip); __ bind(&skip);
__ AssertUndefinedOrAllocationSite(r5, r8); __ AssertUndefinedOrAllocationSite(r5, r8);
if (mode == PushArgsConstructMode::kJSFunction) { if (mode == InterpreterPushArgsMode::kJSFunction) {
__ AssertFunction(r4); __ AssertFunction(r4);
// Tail call to the function-specific construct stub (still in the caller // Tail call to the function-specific construct stub (still in the caller
...@@ -1234,12 +1234,12 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl( ...@@ -1234,12 +1234,12 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
// Jump to the construct function. // Jump to the construct function.
__ addi(ip, r7, Operand(Code::kHeaderSize - kHeapObjectTag)); __ addi(ip, r7, Operand(Code::kHeaderSize - kHeapObjectTag));
__ Jump(ip); __ Jump(ip);
} else if (mode == PushArgsConstructMode::kWithFinalSpread) { } else if (mode == InterpreterPushArgsMode::kWithFinalSpread) {
// Call the constructor with r3, r4, and r6 unmodified. // Call the constructor with r3, r4, and r6 unmodified.
__ Jump(masm->isolate()->builtins()->ConstructWithSpread(), __ Jump(masm->isolate()->builtins()->ConstructWithSpread(),
RelocInfo::CODE_TARGET); RelocInfo::CODE_TARGET);
} else { } else {
DCHECK_EQ(PushArgsConstructMode::kOther, mode); DCHECK_EQ(InterpreterPushArgsMode::kOther, mode);
// Call the constructor with r3, r4, and r6 unmodified. // Call the constructor with r3, r4, and r6 unmodified.
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
} }
......
...@@ -1170,7 +1170,7 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm, ...@@ -1170,7 +1170,7 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm,
// static // static
void Builtins::Generate_InterpreterPushArgsAndCallImpl( void Builtins::Generate_InterpreterPushArgsAndCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode, MacroAssembler* masm, TailCallMode tail_call_mode,
CallableType function_type) { InterpreterPushArgsMode mode) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- r2 : the number of arguments (not including the receiver) // -- r2 : the number of arguments (not including the receiver)
// -- r4 : the address of the first argument to be pushed. Subsequent // -- r4 : the address of the first argument to be pushed. Subsequent
...@@ -1187,12 +1187,12 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl( ...@@ -1187,12 +1187,12 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
Generate_InterpreterPushArgs(masm, r5, r4, r5, r6, &stack_overflow); Generate_InterpreterPushArgs(masm, r5, r4, r5, r6, &stack_overflow);
// Call the target. // Call the target.
if (function_type == CallableType::kJSFunction) { if (mode == InterpreterPushArgsMode::kJSFunction) {
__ Jump(masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny, __ Jump(masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny,
tail_call_mode), tail_call_mode),
RelocInfo::CODE_TARGET); RelocInfo::CODE_TARGET);
} else { } else {
DCHECK_EQ(function_type, CallableType::kAny); DCHECK_EQ(mode, InterpreterPushArgsMode::kOther);
__ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny, __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
tail_call_mode), tail_call_mode),
RelocInfo::CODE_TARGET); RelocInfo::CODE_TARGET);
...@@ -1208,7 +1208,7 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl( ...@@ -1208,7 +1208,7 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
// static // static
void Builtins::Generate_InterpreterPushArgsAndConstructImpl( void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
MacroAssembler* masm, PushArgsConstructMode mode) { MacroAssembler* masm, InterpreterPushArgsMode mode) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- r2 : argument count (not including receiver) // -- r2 : argument count (not including receiver)
// -- r5 : new target // -- r5 : new target
...@@ -1230,7 +1230,7 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl( ...@@ -1230,7 +1230,7 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
__ bind(&skip); __ bind(&skip);
__ AssertUndefinedOrAllocationSite(r4, r7); __ AssertUndefinedOrAllocationSite(r4, r7);
if (mode == PushArgsConstructMode::kJSFunction) { if (mode == InterpreterPushArgsMode::kJSFunction) {
__ AssertFunction(r3); __ AssertFunction(r3);
// Tail call to the function-specific construct stub (still in the caller // Tail call to the function-specific construct stub (still in the caller
...@@ -1240,12 +1240,12 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl( ...@@ -1240,12 +1240,12 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
// Jump to the construct function. // Jump to the construct function.
__ AddP(ip, r6, Operand(Code::kHeaderSize - kHeapObjectTag)); __ AddP(ip, r6, Operand(Code::kHeaderSize - kHeapObjectTag));
__ Jump(ip); __ Jump(ip);
} else if (mode == PushArgsConstructMode::kWithFinalSpread) { } else if (mode == InterpreterPushArgsMode::kWithFinalSpread) {
// Call the constructor with r2, r3, and r5 unmodified. // Call the constructor with r2, r3, and r5 unmodified.
__ Jump(masm->isolate()->builtins()->ConstructWithSpread(), __ Jump(masm->isolate()->builtins()->ConstructWithSpread(),
RelocInfo::CODE_TARGET); RelocInfo::CODE_TARGET);
} else { } else {
DCHECK_EQ(PushArgsConstructMode::kOther, mode); DCHECK_EQ(InterpreterPushArgsMode::kOther, mode);
// Call the constructor with r2, r3, and r5 unmodified. // Call the constructor with r2, r3, and r5 unmodified.
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
} }
......
This diff is collapsed.
...@@ -694,7 +694,7 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm, ...@@ -694,7 +694,7 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm,
// static // static
void Builtins::Generate_InterpreterPushArgsAndCallImpl( void Builtins::Generate_InterpreterPushArgsAndCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode, MacroAssembler* masm, TailCallMode tail_call_mode,
CallableType function_type) { InterpreterPushArgsMode mode) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- eax : the number of arguments (not including the receiver) // -- eax : the number of arguments (not including the receiver)
// -- ebx : the address of the first argument to be pushed. Subsequent // -- ebx : the address of the first argument to be pushed. Subsequent
...@@ -726,12 +726,12 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl( ...@@ -726,12 +726,12 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
// Call the target. // Call the target.
__ Push(edx); // Re-push return address. __ Push(edx); // Re-push return address.
if (function_type == CallableType::kJSFunction) { if (mode == InterpreterPushArgsMode::kJSFunction) {
__ Jump(masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny, __ Jump(masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny,
tail_call_mode), tail_call_mode),
RelocInfo::CODE_TARGET); RelocInfo::CODE_TARGET);
} else { } else {
DCHECK_EQ(function_type, CallableType::kAny); DCHECK_EQ(mode, InterpreterPushArgsMode::kOther);
__ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny, __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
tail_call_mode), tail_call_mode),
RelocInfo::CODE_TARGET); RelocInfo::CODE_TARGET);
...@@ -844,7 +844,7 @@ void Generate_InterpreterPushArgsAndReturnAddress( ...@@ -844,7 +844,7 @@ void Generate_InterpreterPushArgsAndReturnAddress(
// static // static
void Builtins::Generate_InterpreterPushArgsAndConstructImpl( void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
MacroAssembler* masm, PushArgsConstructMode mode) { MacroAssembler* masm, InterpreterPushArgsMode mode) {
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- eax : the number of arguments (not including the receiver) // -- eax : the number of arguments (not including the receiver)
// -- edx : the new target // -- edx : the new target
...@@ -870,7 +870,7 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl( ...@@ -870,7 +870,7 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
__ Pop(edi); __ Pop(edi);
__ AssertUndefinedOrAllocationSite(ebx); __ AssertUndefinedOrAllocationSite(ebx);
if (mode == PushArgsConstructMode::kJSFunction) { if (mode == InterpreterPushArgsMode::kJSFunction) {
// Tail call to the function-specific construct stub (still in the caller // Tail call to the function-specific construct stub (still in the caller
// context at this point). // context at this point).
__ AssertFunction(edi); __ AssertFunction(edi);
...@@ -879,12 +879,12 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl( ...@@ -879,12 +879,12 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
__ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kConstructStubOffset)); __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kConstructStubOffset));
__ lea(ecx, FieldOperand(ecx, Code::kHeaderSize)); __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
__ jmp(ecx); __ jmp(ecx);
} else if (mode == PushArgsConstructMode::kWithFinalSpread) { } else if (mode == InterpreterPushArgsMode::kWithFinalSpread) {
// Call the constructor with unmodified eax, edi, edx values. // Call the constructor with unmodified eax, edi, edx values.
__ Jump(masm->isolate()->builtins()->ConstructWithSpread(), __ Jump(masm->isolate()->builtins()->ConstructWithSpread(),
RelocInfo::CODE_TARGET); RelocInfo::CODE_TARGET);
} else { } else {
DCHECK_EQ(PushArgsConstructMode::kOther, mode); DCHECK_EQ(InterpreterPushArgsMode::kOther, mode);
// Call the constructor with unmodified eax, edi, edx values. // Call the constructor with unmodified eax, edi, edx values.
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
} }
......
...@@ -373,6 +373,12 @@ Callable CodeFactory::Call(Isolate* isolate, ConvertReceiverMode mode, ...@@ -373,6 +373,12 @@ Callable CodeFactory::Call(Isolate* isolate, ConvertReceiverMode mode,
CallTrampolineDescriptor(isolate)); CallTrampolineDescriptor(isolate));
} }
// static
Callable CodeFactory::CallWithSpread(Isolate* isolate) {
return Callable(isolate->builtins()->CallWithSpread(),
CallTrampolineDescriptor(isolate));
}
// static // static
Callable CodeFactory::CallFunction(Isolate* isolate, ConvertReceiverMode mode) { Callable CodeFactory::CallFunction(Isolate* isolate, ConvertReceiverMode mode) {
return Callable(isolate->builtins()->CallFunction(mode), return Callable(isolate->builtins()->CallFunction(mode),
...@@ -400,15 +406,15 @@ Callable CodeFactory::ConstructFunction(Isolate* isolate) { ...@@ -400,15 +406,15 @@ Callable CodeFactory::ConstructFunction(Isolate* isolate) {
// static // static
Callable CodeFactory::InterpreterPushArgsAndCall(Isolate* isolate, Callable CodeFactory::InterpreterPushArgsAndCall(Isolate* isolate,
TailCallMode tail_call_mode, TailCallMode tail_call_mode,
CallableType function_type) { InterpreterPushArgsMode mode) {
return Callable(isolate->builtins()->InterpreterPushArgsAndCall( return Callable(
tail_call_mode, function_type), isolate->builtins()->InterpreterPushArgsAndCall(tail_call_mode, mode),
InterpreterPushArgsAndCallDescriptor(isolate)); InterpreterPushArgsAndCallDescriptor(isolate));
} }
// static // static
Callable CodeFactory::InterpreterPushArgsAndConstruct( Callable CodeFactory::InterpreterPushArgsAndConstruct(
Isolate* isolate, PushArgsConstructMode mode) { Isolate* isolate, InterpreterPushArgsMode mode) {
return Callable(isolate->builtins()->InterpreterPushArgsAndConstruct(mode), return Callable(isolate->builtins()->InterpreterPushArgsAndConstruct(mode),
InterpreterPushArgsAndConstructDescriptor(isolate)); InterpreterPushArgsAndConstructDescriptor(isolate));
} }
......
...@@ -165,6 +165,7 @@ class V8_EXPORT_PRIVATE CodeFactory final { ...@@ -165,6 +165,7 @@ class V8_EXPORT_PRIVATE CodeFactory final {
static Callable Call(Isolate* isolate, static Callable Call(Isolate* isolate,
ConvertReceiverMode mode = ConvertReceiverMode::kAny, ConvertReceiverMode mode = ConvertReceiverMode::kAny,
TailCallMode tail_call_mode = TailCallMode::kDisallow); TailCallMode tail_call_mode = TailCallMode::kDisallow);
static Callable CallWithSpread(Isolate* isolate);
static Callable CallFunction( static Callable CallFunction(
Isolate* isolate, ConvertReceiverMode mode = ConvertReceiverMode::kAny); Isolate* isolate, ConvertReceiverMode mode = ConvertReceiverMode::kAny);
static Callable Construct(Isolate* isolate); static Callable Construct(Isolate* isolate);
...@@ -174,11 +175,11 @@ class V8_EXPORT_PRIVATE CodeFactory final { ...@@ -174,11 +175,11 @@ class V8_EXPORT_PRIVATE CodeFactory final {
static Callable HasProperty(Isolate* isolate); static Callable HasProperty(Isolate* isolate);
static Callable ForInFilter(Isolate* isolate); static Callable ForInFilter(Isolate* isolate);
static Callable InterpreterPushArgsAndCall( static Callable InterpreterPushArgsAndCall(Isolate* isolate,
Isolate* isolate, TailCallMode tail_call_mode, TailCallMode tail_call_mode,
CallableType function_type = CallableType::kAny); InterpreterPushArgsMode mode);
static Callable InterpreterPushArgsAndConstruct(Isolate* isolate, static Callable InterpreterPushArgsAndConstruct(Isolate* isolate,
PushArgsConstructMode mode); InterpreterPushArgsMode mode);
static Callable InterpreterPushArgsAndConstructArray(Isolate* isolate); static Callable InterpreterPushArgsAndConstructArray(Isolate* isolate);
static Callable InterpreterCEntry(Isolate* isolate, int result_size = 1); static Callable InterpreterCEntry(Isolate* isolate, int result_size = 1);
static Callable InterpreterOnStackReplacement(Isolate* isolate); static Callable InterpreterOnStackReplacement(Isolate* isolate);
......
...@@ -1275,11 +1275,14 @@ void BytecodeGraphBuilder::VisitCall() { ...@@ -1275,11 +1275,14 @@ void BytecodeGraphBuilder::VisitCall() {
void BytecodeGraphBuilder::VisitCallWithSpread() { void BytecodeGraphBuilder::VisitCallWithSpread() {
PrepareEagerCheckpoint(); PrepareEagerCheckpoint();
interpreter::Register first_arg = bytecode_iterator().GetRegisterOperand(0); Node* callee =
size_t arg_count = bytecode_iterator().GetRegisterCountOperand(1); environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
const Operator* op = interpreter::Register receiver = bytecode_iterator().GetRegisterOperand(1);
javascript()->CallFunctionWithSpread(static_cast<int>(arg_count)); size_t arg_count = bytecode_iterator().GetRegisterCountOperand(2);
Node* value = ProcessCallRuntimeArguments(op, first_arg, arg_count); const Operator* call =
javascript()->CallFunctionWithSpread(static_cast<int>(arg_count + 1));
Node* value = ProcessCallArguments(call, callee, receiver, arg_count + 1);
environment()->BindAccumulator(value, Environment::kAttachFrameState); environment()->BindAccumulator(value, Environment::kAttachFrameState);
} }
......
...@@ -551,8 +551,16 @@ void JSGenericLowering::LowerJSCallFunction(Node* node) { ...@@ -551,8 +551,16 @@ void JSGenericLowering::LowerJSCallFunction(Node* node) {
void JSGenericLowering::LowerJSCallFunctionWithSpread(Node* node) { void JSGenericLowering::LowerJSCallFunctionWithSpread(Node* node) {
CallFunctionWithSpreadParameters const& p = CallFunctionWithSpreadParameters const& p =
CallFunctionWithSpreadParametersOf(node->op()); CallFunctionWithSpreadParametersOf(node->op());
ReplaceWithRuntimeCall(node, Runtime::kCallWithSpread, int const arg_count = static_cast<int>(p.arity() - 2);
static_cast<int>(p.arity())); Callable callable = CodeFactory::CallWithSpread(isolate());
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
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->InsertInput(zone(), 0, stub_code);
node->InsertInput(zone(), 2, stub_arity);
NodeProperties::ChangeOp(node, common()->Call(desc));
} }
void JSGenericLowering::LowerJSCallRuntime(Node* node) { void JSGenericLowering::LowerJSCallRuntime(Node* node) {
......
...@@ -1200,38 +1200,24 @@ inline bool IsConstructable(FunctionKind kind, LanguageMode mode) { ...@@ -1200,38 +1200,24 @@ inline bool IsConstructable(FunctionKind kind, LanguageMode mode) {
return true; return true;
} }
enum class CallableType : unsigned { kJSFunction, kAny }; enum class InterpreterPushArgsMode : unsigned {
inline size_t hash_value(CallableType type) { return bit_cast<unsigned>(type); }
inline std::ostream& operator<<(std::ostream& os, CallableType function_type) {
switch (function_type) {
case CallableType::kJSFunction:
return os << "JSFunction";
case CallableType::kAny:
return os << "Any";
}
UNREACHABLE();
return os;
}
enum class PushArgsConstructMode : unsigned {
kJSFunction, kJSFunction,
kWithFinalSpread, kWithFinalSpread,
kOther kOther
}; };
inline size_t hash_value(PushArgsConstructMode mode) { inline size_t hash_value(InterpreterPushArgsMode mode) {
return bit_cast<unsigned>(mode); return bit_cast<unsigned>(mode);
} }
inline std::ostream& operator<<(std::ostream& os, PushArgsConstructMode mode) { inline std::ostream& operator<<(std::ostream& os,
InterpreterPushArgsMode mode) {
switch (mode) { switch (mode) {
case PushArgsConstructMode::kJSFunction: case InterpreterPushArgsMode::kJSFunction:
return os << "JSFunction"; return os << "JSFunction";
case PushArgsConstructMode::kWithFinalSpread: case InterpreterPushArgsMode::kWithFinalSpread:
return os << "WithFinalSpread"; return os << "WithFinalSpread";
case PushArgsConstructMode::kOther: case InterpreterPushArgsMode::kOther:
return os << "Other"; return os << "Other";
} }
UNREACHABLE(); UNREACHABLE();
......
...@@ -891,8 +891,9 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable, ...@@ -891,8 +891,9 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable,
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::CallWithSpread(RegisterList args) { BytecodeArrayBuilder& BytecodeArrayBuilder::CallWithSpread(Register callable,
OutputCallWithSpread(args, args.register_count()); RegisterList args) {
OutputCallWithSpread(callable, args, args.register_count());
return *this; return *this;
} }
......
...@@ -214,9 +214,9 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final ...@@ -214,9 +214,9 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final
TailCallMode tail_call_mode = TailCallMode::kDisallow); TailCallMode tail_call_mode = TailCallMode::kDisallow);
// Call a JS function. The JSFunction or Callable to be called should be in // Call a JS function. The JSFunction or Callable to be called should be in
// |args[0]|, the receiver in |args[1]| and the arguments in |args[2]| // |callable|, the receiver in |args[0]| and the arguments in |args[1]|
// onwards. The final argument must be a spread. // onwards. The final argument must be a spread.
BytecodeArrayBuilder& CallWithSpread(RegisterList args); BytecodeArrayBuilder& CallWithSpread(Register callable, RegisterList args);
// Call the new operator. The accumulator holds the |new_target|. // Call the new operator. The accumulator holds the |new_target|.
// The |constructor| is in a register and arguments are in |args|. // The |constructor| is in a register and arguments are in |args|.
......
...@@ -2466,19 +2466,8 @@ void BytecodeGenerator::VisitCall(Call* expr) { ...@@ -2466,19 +2466,8 @@ void BytecodeGenerator::VisitCall(Call* expr) {
// the registers up-front. Otherwise these registers are unavailable during // the registers up-front. Otherwise these registers are unavailable during
// receiver / argument visiting and we can end up with memory leaks due to // receiver / argument visiting and we can end up with memory leaks due to
// registers keeping objects alive. // registers keeping objects alive.
RegisterList args; Register callee = register_allocator()->NewRegister();
Register callee; RegisterList args = register_allocator()->NewGrowableRegisterList();
// The CallWithSpread bytecode takes all arguments in a register list so that
// it can easily call into a runtime function for its implementation. This
// will change once CallWithSpread has an implementation in ASM.
// TODO(petermarshall): Remove this special path when CallWithSpread is done.
if (expr->only_last_arg_is_spread()) {
args = register_allocator()->NewGrowableRegisterList();
callee = register_allocator()->GrowRegisterList(&args);
} else {
callee = register_allocator()->NewRegister();
args = register_allocator()->NewGrowableRegisterList();
}
// TODO(petermarshall): We have a lot of call bytecodes that are very similar, // TODO(petermarshall): We have a lot of call bytecodes that are very similar,
// see if we can reduce the number by adding a separate argument which // see if we can reduce the number by adding a separate argument which
...@@ -2552,11 +2541,7 @@ void BytecodeGenerator::VisitCall(Call* expr) { ...@@ -2552,11 +2541,7 @@ void BytecodeGenerator::VisitCall(Call* expr) {
// Evaluate all arguments to the function call and store in sequential args // Evaluate all arguments to the function call and store in sequential args
// registers. // registers.
VisitArguments(expr->arguments(), &args); VisitArguments(expr->arguments(), &args);
// TODO(petermarshall): Check this for spread calls as well when CHECK_EQ(expr->arguments()->length() + 1, args.register_count());
// CallWithSpread is done.
if (!expr->only_last_arg_is_spread()) {
CHECK_EQ(expr->arguments()->length() + 1, args.register_count());
}
// Resolve callee for a potential direct eval call. This block will mutate the // Resolve callee for a potential direct eval call. This block will mutate the
// callee value. // callee value.
...@@ -2589,9 +2574,8 @@ void BytecodeGenerator::VisitCall(Call* expr) { ...@@ -2589,9 +2574,8 @@ void BytecodeGenerator::VisitCall(Call* expr) {
// When a call contains a spread, a Call AST node is only created if there is // When a call contains a spread, a Call AST node is only created if there is
// exactly one spread, and it is the last argument. // exactly one spread, and it is the last argument.
if (expr->only_last_arg_is_spread()) { if (expr->only_last_arg_is_spread()) {
CHECK_EQ(expr->arguments()->length() + 2, args.register_count());
DCHECK_EQ(TailCallMode::kDisallow, expr->tail_call_mode()); DCHECK_EQ(TailCallMode::kDisallow, expr->tail_call_mode());
builder()->CallWithSpread(args); builder()->CallWithSpread(callee, args);
} else { } else {
int const feedback_slot_index = feedback_index(expr->CallFeedbackICSlot()); int const feedback_slot_index = feedback_index(expr->CallFeedbackICSlot());
builder()->Call(callee, args, feedback_slot_index, call_type, builder()->Call(callee, args, feedback_slot_index, call_type,
......
...@@ -151,8 +151,8 @@ namespace interpreter { ...@@ -151,8 +151,8 @@ namespace interpreter {
OperandType::kRegCount, OperandType::kIdx) \ OperandType::kRegCount, OperandType::kIdx) \
V(CallProperty, AccumulatorUse::kWrite, OperandType::kReg, \ V(CallProperty, AccumulatorUse::kWrite, OperandType::kReg, \
OperandType::kRegList, OperandType::kRegCount, OperandType::kIdx) \ OperandType::kRegList, OperandType::kRegCount, OperandType::kIdx) \
V(CallWithSpread, AccumulatorUse::kWrite, OperandType::kRegList, \ V(CallWithSpread, AccumulatorUse::kWrite, OperandType::kReg, \
OperandType::kRegCount) \ OperandType::kRegList, OperandType::kRegCount) \
V(TailCall, AccumulatorUse::kWrite, OperandType::kReg, \ V(TailCall, AccumulatorUse::kWrite, OperandType::kReg, \
OperandType::kRegList, OperandType::kRegCount, OperandType::kIdx) \ OperandType::kRegList, OperandType::kRegCount, OperandType::kIdx) \
V(CallRuntime, AccumulatorUse::kWrite, OperandType::kRuntimeId, \ V(CallRuntime, AccumulatorUse::kWrite, OperandType::kRuntimeId, \
......
...@@ -543,7 +543,7 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context, ...@@ -543,7 +543,7 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context,
// Call using call function builtin. // Call using call function builtin.
Callable callable = CodeFactory::InterpreterPushArgsAndCall( Callable callable = CodeFactory::InterpreterPushArgsAndCall(
isolate(), tail_call_mode, CallableType::kJSFunction); isolate(), tail_call_mode, InterpreterPushArgsMode::kJSFunction);
Node* code_target = HeapConstant(callable.code()); Node* code_target = HeapConstant(callable.code());
Node* ret_value = CallStub(callable.descriptor(), code_target, context, Node* ret_value = CallStub(callable.descriptor(), code_target, context,
arg_count, first_arg, function); arg_count, first_arg, function);
...@@ -659,7 +659,7 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context, ...@@ -659,7 +659,7 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context,
// Call using call builtin. // Call using call builtin.
Callable callable_call = CodeFactory::InterpreterPushArgsAndCall( Callable callable_call = CodeFactory::InterpreterPushArgsAndCall(
isolate(), tail_call_mode, CallableType::kAny); isolate(), tail_call_mode, InterpreterPushArgsMode::kOther);
Node* code_target_call = HeapConstant(callable_call.code()); Node* code_target_call = HeapConstant(callable_call.code());
Node* ret_value = CallStub(callable_call.descriptor(), code_target_call, Node* ret_value = CallStub(callable_call.descriptor(), code_target_call,
context, arg_count, first_arg, function); context, arg_count, first_arg, function);
...@@ -675,7 +675,18 @@ Node* InterpreterAssembler::CallJS(Node* function, Node* context, ...@@ -675,7 +675,18 @@ Node* InterpreterAssembler::CallJS(Node* function, Node* context,
Node* first_arg, Node* arg_count, Node* first_arg, Node* arg_count,
TailCallMode tail_call_mode) { TailCallMode tail_call_mode) {
Callable callable = CodeFactory::InterpreterPushArgsAndCall( Callable callable = CodeFactory::InterpreterPushArgsAndCall(
isolate(), tail_call_mode, CallableType::kAny); isolate(), tail_call_mode, InterpreterPushArgsMode::kOther);
Node* code_target = HeapConstant(callable.code());
return CallStub(callable.descriptor(), code_target, context, arg_count,
first_arg, function);
}
Node* InterpreterAssembler::CallJSWithSpread(Node* function, Node* context,
Node* first_arg, Node* arg_count) {
Callable callable = CodeFactory::InterpreterPushArgsAndCall(
isolate(), TailCallMode::kDisallow,
InterpreterPushArgsMode::kWithFinalSpread);
Node* code_target = HeapConstant(callable.code()); Node* code_target = HeapConstant(callable.code());
return CallStub(callable.descriptor(), code_target, context, arg_count, return CallStub(callable.descriptor(), code_target, context, arg_count,
...@@ -718,7 +729,7 @@ Node* InterpreterAssembler::CallConstruct(Node* constructor, Node* context, ...@@ -718,7 +729,7 @@ Node* InterpreterAssembler::CallConstruct(Node* constructor, Node* context,
Comment("call using callConstructFunction"); Comment("call using callConstructFunction");
IncrementCallCount(type_feedback_vector, slot_id); IncrementCallCount(type_feedback_vector, slot_id);
Callable callable_function = CodeFactory::InterpreterPushArgsAndConstruct( Callable callable_function = CodeFactory::InterpreterPushArgsAndConstruct(
isolate(), PushArgsConstructMode::kJSFunction); isolate(), InterpreterPushArgsMode::kJSFunction);
return_value.Bind(CallStub(callable_function.descriptor(), return_value.Bind(CallStub(callable_function.descriptor(),
HeapConstant(callable_function.code()), context, HeapConstant(callable_function.code()), context,
arg_count, new_target, constructor, arg_count, new_target, constructor,
...@@ -821,7 +832,7 @@ Node* InterpreterAssembler::CallConstruct(Node* constructor, Node* context, ...@@ -821,7 +832,7 @@ Node* InterpreterAssembler::CallConstruct(Node* constructor, Node* context,
{ {
Comment("call using callConstruct builtin"); Comment("call using callConstruct builtin");
Callable callable = CodeFactory::InterpreterPushArgsAndConstruct( Callable callable = CodeFactory::InterpreterPushArgsAndConstruct(
isolate(), PushArgsConstructMode::kOther); isolate(), InterpreterPushArgsMode::kOther);
Node* code_target = HeapConstant(callable.code()); Node* code_target = HeapConstant(callable.code());
return_value.Bind(CallStub(callable.descriptor(), code_target, context, return_value.Bind(CallStub(callable.descriptor(), code_target, context,
arg_count, new_target, constructor, arg_count, new_target, constructor,
...@@ -841,7 +852,7 @@ Node* InterpreterAssembler::CallConstructWithSpread(Node* constructor, ...@@ -841,7 +852,7 @@ Node* InterpreterAssembler::CallConstructWithSpread(Node* constructor,
Variable return_value(this, MachineRepresentation::kTagged); Variable return_value(this, MachineRepresentation::kTagged);
Comment("call using ConstructWithSpread"); Comment("call using ConstructWithSpread");
Callable callable = CodeFactory::InterpreterPushArgsAndConstruct( Callable callable = CodeFactory::InterpreterPushArgsAndConstruct(
isolate(), PushArgsConstructMode::kWithFinalSpread); isolate(), InterpreterPushArgsMode::kWithFinalSpread);
Node* code_target = HeapConstant(callable.code()); Node* code_target = HeapConstant(callable.code());
return_value.Bind(CallStub(callable.descriptor(), code_target, context, return_value.Bind(CallStub(callable.descriptor(), code_target, context,
arg_count, new_target, constructor, arg_count, new_target, constructor,
......
...@@ -129,6 +129,14 @@ class V8_EXPORT_PRIVATE InterpreterAssembler : public CodeStubAssembler { ...@@ -129,6 +129,14 @@ class V8_EXPORT_PRIVATE InterpreterAssembler : public CodeStubAssembler {
compiler::Node* first_arg, compiler::Node* arg_count, compiler::Node* first_arg, compiler::Node* arg_count,
TailCallMode tail_call_mode); TailCallMode tail_call_mode);
// Call JSFunction or Callable |function| with |arg_count|
// arguments (not including receiver) and the first argument
// located at |first_arg|.
compiler::Node* CallJSWithSpread(compiler::Node* function,
compiler::Node* context,
compiler::Node* first_arg,
compiler::Node* arg_count);
// Call constructor |constructor| with |arg_count| arguments (not // Call constructor |constructor| with |arg_count| arguments (not
// including receiver) and the first argument located at // including receiver) and the first argument located at
// |first_arg|. The |new_target| is the same as the // |first_arg|. The |new_target| is the same as the
......
...@@ -2176,22 +2176,25 @@ void Interpreter::DoCallJSRuntime(InterpreterAssembler* assembler) { ...@@ -2176,22 +2176,25 @@ void Interpreter::DoCallJSRuntime(InterpreterAssembler* assembler) {
__ Dispatch(); __ Dispatch();
} }
// CallWithSpread <first_arg> <arg_count> // CallWithSpread <callable> <first_arg> <arg_count>
// //
// Call a JSfunction or Callable in |first_arg| with the receiver in // Call a JSfunction or Callable in |callable| with the receiver in
// |first_arg + 1| and |arg_count - 2| arguments in subsequent registers. The // |first_arg| and |arg_count - 1| arguments in subsequent registers. The
// final argument is always a spread. // final argument is always a spread.
// //
void Interpreter::DoCallWithSpread(InterpreterAssembler* assembler) { void Interpreter::DoCallWithSpread(InterpreterAssembler* assembler) {
Node* first_arg_reg = __ BytecodeOperandReg(0); Node* callable_reg = __ BytecodeOperandReg(0);
Node* first_arg = __ RegisterLocation(first_arg_reg); Node* callable = __ LoadRegister(callable_reg);
Node* args_count = __ BytecodeOperandCount(1); Node* receiver_reg = __ BytecodeOperandReg(1);
Node* receiver_arg = __ RegisterLocation(receiver_reg);
Node* receiver_args_count = __ BytecodeOperandCount(2);
Node* receiver_count = __ Int32Constant(1);
Node* args_count = __ Int32Sub(receiver_args_count, receiver_count);
Node* context = __ GetContext(); Node* context = __ GetContext();
// Call into Runtime function CallWithSpread which does everything. // Call into Runtime function CallWithSpread which does everything.
Node* runtime_function = __ Int32Constant(Runtime::kCallWithSpread);
Node* result = Node* result =
__ CallRuntimeN(runtime_function, context, first_arg, args_count); __ CallJSWithSpread(callable, context, receiver_arg, args_count);
__ SetAccumulator(result); __ SetAccumulator(result);
__ Dispatch(); __ Dispatch();
} }
......
...@@ -459,48 +459,5 @@ RUNTIME_FUNCTION(Runtime_GetSuperConstructor) { ...@@ -459,48 +459,5 @@ RUNTIME_FUNCTION(Runtime_GetSuperConstructor) {
return prototype; return prototype;
} }
RUNTIME_FUNCTION(Runtime_CallWithSpread) {
HandleScope scope(isolate);
DCHECK_LE(3, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, callable, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 1);
int function_argc = args.length() - 2;
CONVERT_ARG_HANDLE_CHECKED(Object, spread, args.length() - 1);
// Iterate over the spread if we need to.
if (spread->IterationHasObservableEffects()) {
Handle<JSFunction> spread_iterable_function = isolate->spread_iterable();
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, spread,
Execution::Call(isolate, spread_iterable_function,
isolate->factory()->undefined_value(), 1, &spread));
}
uint32_t spread_length;
Handle<JSArray> spread_array = Handle<JSArray>::cast(spread);
CHECK(spread_array->length()->ToArrayIndex(&spread_length));
int result_length = function_argc - 1 + spread_length;
ScopedVector<Handle<Object>> function_args(result_length);
// Append each of the individual args to the result.
for (int i = 0; i < function_argc - 1; i++) {
function_args[i] = args.at<Object>(2 + i);
}
// Append element of the spread to the result.
ElementsAccessor* accessor = spread_array->GetElementsAccessor();
for (uint32_t i = 0; i < spread_length; i++) {
DCHECK(accessor->HasElement(spread_array, i));
Handle<Object> element = accessor->Get(spread_array, i);
function_args[function_argc - 1 + i] = element;
}
// Call the function.
RETURN_RESULT_OR_FAILURE(
isolate, Execution::Call(isolate, callable, receiver, result_length,
function_args.start()));
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -92,8 +92,7 @@ namespace internal { ...@@ -92,8 +92,7 @@ namespace internal {
F(StoreToSuper_Sloppy, 4, 1) \ F(StoreToSuper_Sloppy, 4, 1) \
F(StoreKeyedToSuper_Strict, 4, 1) \ F(StoreKeyedToSuper_Strict, 4, 1) \
F(StoreKeyedToSuper_Sloppy, 4, 1) \ F(StoreKeyedToSuper_Sloppy, 4, 1) \
F(GetSuperConstructor, 1, 1) \ F(GetSuperConstructor, 1, 1)
F(CallWithSpread, -1, 1)
#define FOR_EACH_INTRINSIC_COLLECTIONS(F) \ #define FOR_EACH_INTRINSIC_COLLECTIONS(F) \
F(StringGetRawHashField, 1, 1) \ F(StringGetRawHashField, 1, 1) \
......
...@@ -11,7 +11,7 @@ snippet: " ...@@ -11,7 +11,7 @@ snippet: "
" "
frame size: 3 frame size: 3
parameter count: 1 parameter count: 1
bytecode array length: 23 bytecode array length: 24
bytecodes: [ bytecodes: [
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
/* 34 S> */ B(LdaGlobal), U8(0), U8(4), /* 34 S> */ B(LdaGlobal), U8(0), U8(4),
...@@ -20,7 +20,7 @@ bytecodes: [ ...@@ -20,7 +20,7 @@ bytecodes: [
B(Star), R(0), B(Star), R(0),
B(CreateArrayLiteral), U8(2), U8(0), U8(9), B(CreateArrayLiteral), U8(2), U8(0), U8(9),
B(Star), R(2), B(Star), R(2),
/* 39 E> */ B(CallWithSpread), R(0), U8(3), /* 39 E> */ B(CallWithSpread), R(0), R(1), U8(2),
B(LdaUndefined), B(LdaUndefined),
/* 58 S> */ B(Return), /* 58 S> */ B(Return),
] ]
...@@ -38,7 +38,7 @@ snippet: " ...@@ -38,7 +38,7 @@ snippet: "
" "
frame size: 4 frame size: 4
parameter count: 1 parameter count: 1
bytecode array length: 26 bytecode array length: 27
bytecodes: [ bytecodes: [
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
/* 34 S> */ B(LdaGlobal), U8(0), U8(4), /* 34 S> */ B(LdaGlobal), U8(0), U8(4),
...@@ -49,7 +49,7 @@ bytecodes: [ ...@@ -49,7 +49,7 @@ bytecodes: [
B(Star), R(2), B(Star), R(2),
B(CreateArrayLiteral), U8(2), U8(0), U8(9), B(CreateArrayLiteral), U8(2), U8(0), U8(9),
B(Star), R(3), B(Star), R(3),
/* 39 E> */ B(CallWithSpread), R(0), U8(4), /* 39 E> */ B(CallWithSpread), R(0), R(1), U8(3),
B(LdaUndefined), B(LdaUndefined),
/* 61 S> */ B(Return), /* 61 S> */ B(Return),
] ]
......
...@@ -139,7 +139,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { ...@@ -139,7 +139,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, reg_list, pair) .CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, reg_list, pair)
.CallJSRuntime(Context::SPREAD_ITERABLE_INDEX, reg_list) .CallJSRuntime(Context::SPREAD_ITERABLE_INDEX, reg_list)
.NewWithSpread(reg, reg_list) .NewWithSpread(reg, reg_list)
.CallWithSpread(reg_list); .CallWithSpread(reg, reg_list);
// Emit binary operator invocations. // Emit binary operator invocations.
builder.BinaryOperation(Token::Value::ADD, reg, 1) builder.BinaryOperation(Token::Value::ADD, reg, 1)
......
...@@ -692,8 +692,8 @@ TARGET_TEST_F(InterpreterAssemblerTest, CallJS) { ...@@ -692,8 +692,8 @@ TARGET_TEST_F(InterpreterAssemblerTest, CallJS) {
TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
InterpreterAssemblerTestState state(this, bytecode); InterpreterAssemblerTestState state(this, bytecode);
InterpreterAssemblerForTest m(&state, bytecode); InterpreterAssemblerForTest m(&state, bytecode);
Callable builtin = Callable builtin = CodeFactory::InterpreterPushArgsAndCall(
CodeFactory::InterpreterPushArgsAndCall(isolate(), tail_call_mode); isolate(), tail_call_mode, InterpreterPushArgsMode::kOther);
Node* function = m.IntPtrConstant(0); Node* function = m.IntPtrConstant(0);
Node* first_arg = m.IntPtrConstant(1); Node* first_arg = m.IntPtrConstant(1);
Node* arg_count = m.Int32Constant(2); Node* arg_count = m.Int32Constant(2);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment