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 @@
namespace v8 {
namespace internal {
Handle<Code> Builtins::InterpreterPushArgsAndCall(TailCallMode tail_call_mode,
CallableType function_type) {
switch (tail_call_mode) {
case TailCallMode::kDisallow:
if (function_type == CallableType::kJSFunction) {
Handle<Code> Builtins::InterpreterPushArgsAndCall(
TailCallMode tail_call_mode, InterpreterPushArgsMode mode) {
switch (mode) {
case InterpreterPushArgsMode::kJSFunction:
if (tail_call_mode == TailCallMode::kDisallow) {
return InterpreterPushArgsAndCallFunction();
} else {
return InterpreterPushArgsAndCall();
}
case TailCallMode::kAllow:
if (function_type == CallableType::kJSFunction) {
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 {
return InterpreterPushArgsAndTailCall();
}
......@@ -29,35 +32,41 @@ Handle<Code> Builtins::InterpreterPushArgsAndCall(TailCallMode tail_call_mode,
}
void Builtins::Generate_InterpreterPushArgsAndCall(MacroAssembler* masm) {
return Generate_InterpreterPushArgsAndCallImpl(masm, TailCallMode::kDisallow,
CallableType::kAny);
return Generate_InterpreterPushArgsAndCallImpl(
masm, TailCallMode::kDisallow, InterpreterPushArgsMode::kOther);
}
void Builtins::Generate_InterpreterPushArgsAndCallFunction(
MacroAssembler* masm) {
return Generate_InterpreterPushArgsAndCallImpl(masm, TailCallMode::kDisallow,
CallableType::kJSFunction);
return Generate_InterpreterPushArgsAndCallImpl(
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) {
return Generate_InterpreterPushArgsAndCallImpl(masm, TailCallMode::kAllow,
CallableType::kAny);
return Generate_InterpreterPushArgsAndCallImpl(
masm, TailCallMode::kAllow, InterpreterPushArgsMode::kOther);
}
void Builtins::Generate_InterpreterPushArgsAndTailCallFunction(
MacroAssembler* masm) {
return Generate_InterpreterPushArgsAndCallImpl(masm, TailCallMode::kAllow,
CallableType::kJSFunction);
return Generate_InterpreterPushArgsAndCallImpl(
masm, TailCallMode::kAllow, InterpreterPushArgsMode::kJSFunction);
}
Handle<Code> Builtins::InterpreterPushArgsAndConstruct(
PushArgsConstructMode mode) {
InterpreterPushArgsMode mode) {
switch (mode) {
case PushArgsConstructMode::kJSFunction:
case InterpreterPushArgsMode::kJSFunction:
return InterpreterPushArgsAndConstructFunction();
case PushArgsConstructMode::kWithFinalSpread:
case InterpreterPushArgsMode::kWithFinalSpread:
return InterpreterPushArgsAndConstructWithFinalSpread();
case PushArgsConstructMode::kOther:
case InterpreterPushArgsMode::kOther:
return InterpreterPushArgsAndConstruct();
}
UNREACHABLE();
......@@ -66,19 +75,19 @@ Handle<Code> Builtins::InterpreterPushArgsAndConstruct(
void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
return Generate_InterpreterPushArgsAndConstructImpl(
masm, PushArgsConstructMode::kOther);
masm, InterpreterPushArgsMode::kOther);
}
void Builtins::Generate_InterpreterPushArgsAndConstructWithFinalSpread(
MacroAssembler* masm) {
return Generate_InterpreterPushArgsAndConstructImpl(
masm, PushArgsConstructMode::kWithFinalSpread);
masm, InterpreterPushArgsMode::kWithFinalSpread);
}
void Builtins::Generate_InterpreterPushArgsAndConstructFunction(
MacroAssembler* masm) {
return Generate_InterpreterPushArgsAndConstructImpl(
masm, PushArgsConstructMode::kJSFunction);
masm, InterpreterPushArgsMode::kJSFunction);
}
} // namespace internal
......
......@@ -74,6 +74,7 @@ namespace internal {
ASM(TailCall_ReceiverIsNullOrUndefined) \
ASM(TailCall_ReceiverIsNotNullOrUndefined) \
ASM(TailCall_ReceiverIsAny) \
ASM(CallWithSpread) \
\
/* Construct */ \
/* ES6 section 9.2.2 [[Construct]] ( argumentsList, newTarget) */ \
......@@ -139,6 +140,7 @@ namespace internal {
ASM(InterpreterEntryTrampoline) \
ASM(InterpreterPushArgsAndCall) \
ASM(InterpreterPushArgsAndCallFunction) \
ASM(InterpreterPushArgsAndCallWithFinalSpread) \
ASM(InterpreterPushArgsAndTailCall) \
ASM(InterpreterPushArgsAndTailCallFunction) \
ASM(InterpreterPushArgsAndConstruct) \
......@@ -805,7 +807,7 @@ namespace internal {
// Forward declarations.
class ObjectVisitor;
enum class PushArgsConstructMode : unsigned;
enum class InterpreterPushArgsMode : unsigned;
namespace compiler {
class CodeAssemblerState;
}
......@@ -847,10 +849,9 @@ class Builtins {
Handle<Code> NonPrimitiveToPrimitive(
ToPrimitiveHint hint = ToPrimitiveHint::kDefault);
Handle<Code> OrdinaryToPrimitive(OrdinaryToPrimitiveHint hint);
Handle<Code> InterpreterPushArgsAndCall(
TailCallMode tail_call_mode,
CallableType function_type = CallableType::kAny);
Handle<Code> InterpreterPushArgsAndConstruct(PushArgsConstructMode mode);
Handle<Code> InterpreterPushArgsAndCall(TailCallMode tail_call_mode,
InterpreterPushArgsMode mode);
Handle<Code> InterpreterPushArgsAndConstruct(InterpreterPushArgsMode mode);
Handle<Code> NewFunctionContext(ScopeType scope_type);
Handle<Code> NewCloneShallowArray(AllocationSiteMode allocation_mode);
Handle<Code> NewCloneShallowObject(int length);
......@@ -905,10 +906,10 @@ class Builtins {
static void Generate_InterpreterPushArgsAndCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode,
CallableType function_type);
InterpreterPushArgsMode mode);
static void Generate_InterpreterPushArgsAndConstructImpl(
MacroAssembler* masm, PushArgsConstructMode mode);
MacroAssembler* masm, InterpreterPushArgsMode mode);
enum class MathMaxMinKind { kMax, kMin };
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,
// static
void Builtins::Generate_InterpreterPushArgsAndCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode,
CallableType function_type) {
InterpreterPushArgsMode mode) {
// ----------- S t a t e -------------
// -- r3 : the number of arguments (not including the receiver)
// -- r5 : the address of the first argument to be pushed. Subsequent
......@@ -1180,12 +1180,12 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
Generate_InterpreterPushArgs(masm, r6, r5, r6, r7, &stack_overflow);
// Call the target.
if (function_type == CallableType::kJSFunction) {
if (mode == InterpreterPushArgsMode::kJSFunction) {
__ Jump(masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny,
tail_call_mode),
RelocInfo::CODE_TARGET);
} else {
DCHECK_EQ(function_type, CallableType::kAny);
DCHECK_EQ(mode, InterpreterPushArgsMode::kOther);
__ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
tail_call_mode),
RelocInfo::CODE_TARGET);
......@@ -1201,7 +1201,7 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
// static
void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
MacroAssembler* masm, PushArgsConstructMode mode) {
MacroAssembler* masm, InterpreterPushArgsMode mode) {
// ----------- S t a t e -------------
// -- r3 : argument count (not including receiver)
// -- r6 : new target
......@@ -1224,7 +1224,7 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
__ bind(&skip);
__ AssertUndefinedOrAllocationSite(r5, r8);
if (mode == PushArgsConstructMode::kJSFunction) {
if (mode == InterpreterPushArgsMode::kJSFunction) {
__ AssertFunction(r4);
// Tail call to the function-specific construct stub (still in the caller
......@@ -1234,12 +1234,12 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
// Jump to the construct function.
__ addi(ip, r7, Operand(Code::kHeaderSize - kHeapObjectTag));
__ Jump(ip);
} else if (mode == PushArgsConstructMode::kWithFinalSpread) {
} else if (mode == InterpreterPushArgsMode::kWithFinalSpread) {
// Call the constructor with r3, r4, and r6 unmodified.
__ Jump(masm->isolate()->builtins()->ConstructWithSpread(),
RelocInfo::CODE_TARGET);
} else {
DCHECK_EQ(PushArgsConstructMode::kOther, mode);
DCHECK_EQ(InterpreterPushArgsMode::kOther, mode);
// Call the constructor with r3, r4, and r6 unmodified.
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
}
......
......@@ -1170,7 +1170,7 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm,
// static
void Builtins::Generate_InterpreterPushArgsAndCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode,
CallableType function_type) {
InterpreterPushArgsMode mode) {
// ----------- S t a t e -------------
// -- r2 : the number of arguments (not including the receiver)
// -- r4 : the address of the first argument to be pushed. Subsequent
......@@ -1187,12 +1187,12 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
Generate_InterpreterPushArgs(masm, r5, r4, r5, r6, &stack_overflow);
// Call the target.
if (function_type == CallableType::kJSFunction) {
if (mode == InterpreterPushArgsMode::kJSFunction) {
__ Jump(masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny,
tail_call_mode),
RelocInfo::CODE_TARGET);
} else {
DCHECK_EQ(function_type, CallableType::kAny);
DCHECK_EQ(mode, InterpreterPushArgsMode::kOther);
__ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
tail_call_mode),
RelocInfo::CODE_TARGET);
......@@ -1208,7 +1208,7 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
// static
void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
MacroAssembler* masm, PushArgsConstructMode mode) {
MacroAssembler* masm, InterpreterPushArgsMode mode) {
// ----------- S t a t e -------------
// -- r2 : argument count (not including receiver)
// -- r5 : new target
......@@ -1230,7 +1230,7 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
__ bind(&skip);
__ AssertUndefinedOrAllocationSite(r4, r7);
if (mode == PushArgsConstructMode::kJSFunction) {
if (mode == InterpreterPushArgsMode::kJSFunction) {
__ AssertFunction(r3);
// Tail call to the function-specific construct stub (still in the caller
......@@ -1240,12 +1240,12 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
// Jump to the construct function.
__ AddP(ip, r6, Operand(Code::kHeaderSize - kHeapObjectTag));
__ Jump(ip);
} else if (mode == PushArgsConstructMode::kWithFinalSpread) {
} else if (mode == InterpreterPushArgsMode::kWithFinalSpread) {
// Call the constructor with r2, r3, and r5 unmodified.
__ Jump(masm->isolate()->builtins()->ConstructWithSpread(),
RelocInfo::CODE_TARGET);
} else {
DCHECK_EQ(PushArgsConstructMode::kOther, mode);
DCHECK_EQ(InterpreterPushArgsMode::kOther, mode);
// Call the constructor with r2, r3, and r5 unmodified.
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
}
......
This diff is collapsed.
......@@ -694,7 +694,7 @@ static void Generate_InterpreterPushArgs(MacroAssembler* masm,
// static
void Builtins::Generate_InterpreterPushArgsAndCallImpl(
MacroAssembler* masm, TailCallMode tail_call_mode,
CallableType function_type) {
InterpreterPushArgsMode mode) {
// ----------- S t a t e -------------
// -- eax : the number of arguments (not including the receiver)
// -- ebx : the address of the first argument to be pushed. Subsequent
......@@ -726,12 +726,12 @@ void Builtins::Generate_InterpreterPushArgsAndCallImpl(
// Call the target.
__ Push(edx); // Re-push return address.
if (function_type == CallableType::kJSFunction) {
if (mode == InterpreterPushArgsMode::kJSFunction) {
__ Jump(masm->isolate()->builtins()->CallFunction(ConvertReceiverMode::kAny,
tail_call_mode),
RelocInfo::CODE_TARGET);
} else {
DCHECK_EQ(function_type, CallableType::kAny);
DCHECK_EQ(mode, InterpreterPushArgsMode::kOther);
__ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny,
tail_call_mode),
RelocInfo::CODE_TARGET);
......@@ -844,7 +844,7 @@ void Generate_InterpreterPushArgsAndReturnAddress(
// static
void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
MacroAssembler* masm, PushArgsConstructMode mode) {
MacroAssembler* masm, InterpreterPushArgsMode mode) {
// ----------- S t a t e -------------
// -- eax : the number of arguments (not including the receiver)
// -- edx : the new target
......@@ -870,7 +870,7 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
__ Pop(edi);
__ AssertUndefinedOrAllocationSite(ebx);
if (mode == PushArgsConstructMode::kJSFunction) {
if (mode == InterpreterPushArgsMode::kJSFunction) {
// Tail call to the function-specific construct stub (still in the caller
// context at this point).
__ AssertFunction(edi);
......@@ -879,12 +879,12 @@ void Builtins::Generate_InterpreterPushArgsAndConstructImpl(
__ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kConstructStubOffset));
__ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
__ jmp(ecx);
} else if (mode == PushArgsConstructMode::kWithFinalSpread) {
} else if (mode == InterpreterPushArgsMode::kWithFinalSpread) {
// Call the constructor with unmodified eax, edi, edx values.
__ Jump(masm->isolate()->builtins()->ConstructWithSpread(),
RelocInfo::CODE_TARGET);
} else {
DCHECK_EQ(PushArgsConstructMode::kOther, mode);
DCHECK_EQ(InterpreterPushArgsMode::kOther, mode);
// Call the constructor with unmodified eax, edi, edx values.
__ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
}
......
......@@ -373,6 +373,12 @@ Callable CodeFactory::Call(Isolate* isolate, ConvertReceiverMode mode,
CallTrampolineDescriptor(isolate));
}
// static
Callable CodeFactory::CallWithSpread(Isolate* isolate) {
return Callable(isolate->builtins()->CallWithSpread(),
CallTrampolineDescriptor(isolate));
}
// static
Callable CodeFactory::CallFunction(Isolate* isolate, ConvertReceiverMode mode) {
return Callable(isolate->builtins()->CallFunction(mode),
......@@ -400,15 +406,15 @@ Callable CodeFactory::ConstructFunction(Isolate* isolate) {
// static
Callable CodeFactory::InterpreterPushArgsAndCall(Isolate* isolate,
TailCallMode tail_call_mode,
CallableType function_type) {
return Callable(isolate->builtins()->InterpreterPushArgsAndCall(
tail_call_mode, function_type),
InterpreterPushArgsAndCallDescriptor(isolate));
InterpreterPushArgsMode mode) {
return Callable(
isolate->builtins()->InterpreterPushArgsAndCall(tail_call_mode, mode),
InterpreterPushArgsAndCallDescriptor(isolate));
}
// static
Callable CodeFactory::InterpreterPushArgsAndConstruct(
Isolate* isolate, PushArgsConstructMode mode) {
Isolate* isolate, InterpreterPushArgsMode mode) {
return Callable(isolate->builtins()->InterpreterPushArgsAndConstruct(mode),
InterpreterPushArgsAndConstructDescriptor(isolate));
}
......
......@@ -165,6 +165,7 @@ class V8_EXPORT_PRIVATE CodeFactory final {
static Callable Call(Isolate* isolate,
ConvertReceiverMode mode = ConvertReceiverMode::kAny,
TailCallMode tail_call_mode = TailCallMode::kDisallow);
static Callable CallWithSpread(Isolate* isolate);
static Callable CallFunction(
Isolate* isolate, ConvertReceiverMode mode = ConvertReceiverMode::kAny);
static Callable Construct(Isolate* isolate);
......@@ -174,11 +175,11 @@ class V8_EXPORT_PRIVATE CodeFactory final {
static Callable HasProperty(Isolate* isolate);
static Callable ForInFilter(Isolate* isolate);
static Callable InterpreterPushArgsAndCall(
Isolate* isolate, TailCallMode tail_call_mode,
CallableType function_type = CallableType::kAny);
static Callable InterpreterPushArgsAndCall(Isolate* isolate,
TailCallMode tail_call_mode,
InterpreterPushArgsMode mode);
static Callable InterpreterPushArgsAndConstruct(Isolate* isolate,
PushArgsConstructMode mode);
InterpreterPushArgsMode mode);
static Callable InterpreterPushArgsAndConstructArray(Isolate* isolate);
static Callable InterpreterCEntry(Isolate* isolate, int result_size = 1);
static Callable InterpreterOnStackReplacement(Isolate* isolate);
......
......@@ -1275,11 +1275,14 @@ void BytecodeGraphBuilder::VisitCall() {
void BytecodeGraphBuilder::VisitCallWithSpread() {
PrepareEagerCheckpoint();
interpreter::Register first_arg = bytecode_iterator().GetRegisterOperand(0);
size_t arg_count = bytecode_iterator().GetRegisterCountOperand(1);
const Operator* op =
javascript()->CallFunctionWithSpread(static_cast<int>(arg_count));
Node* value = ProcessCallRuntimeArguments(op, first_arg, arg_count);
Node* callee =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
interpreter::Register receiver = bytecode_iterator().GetRegisterOperand(1);
size_t arg_count = bytecode_iterator().GetRegisterCountOperand(2);
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);
}
......
......@@ -551,8 +551,16 @@ void JSGenericLowering::LowerJSCallFunction(Node* node) {
void JSGenericLowering::LowerJSCallFunctionWithSpread(Node* node) {
CallFunctionWithSpreadParameters const& p =
CallFunctionWithSpreadParametersOf(node->op());
ReplaceWithRuntimeCall(node, Runtime::kCallWithSpread,
static_cast<int>(p.arity()));
int const arg_count = static_cast<int>(p.arity() - 2);
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) {
......
......@@ -1200,38 +1200,24 @@ inline bool IsConstructable(FunctionKind kind, LanguageMode mode) {
return true;
}
enum class CallableType : unsigned { kJSFunction, kAny };
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 {
enum class InterpreterPushArgsMode : unsigned {
kJSFunction,
kWithFinalSpread,
kOther
};
inline size_t hash_value(PushArgsConstructMode mode) {
inline size_t hash_value(InterpreterPushArgsMode 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) {
case PushArgsConstructMode::kJSFunction:
case InterpreterPushArgsMode::kJSFunction:
return os << "JSFunction";
case PushArgsConstructMode::kWithFinalSpread:
case InterpreterPushArgsMode::kWithFinalSpread:
return os << "WithFinalSpread";
case PushArgsConstructMode::kOther:
case InterpreterPushArgsMode::kOther:
return os << "Other";
}
UNREACHABLE();
......
......@@ -891,8 +891,9 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable,
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::CallWithSpread(RegisterList args) {
OutputCallWithSpread(args, args.register_count());
BytecodeArrayBuilder& BytecodeArrayBuilder::CallWithSpread(Register callable,
RegisterList args) {
OutputCallWithSpread(callable, args, args.register_count());
return *this;
}
......
......@@ -214,9 +214,9 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final
TailCallMode tail_call_mode = TailCallMode::kDisallow);
// 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.
BytecodeArrayBuilder& CallWithSpread(RegisterList args);
BytecodeArrayBuilder& CallWithSpread(Register callable, RegisterList args);
// Call the new operator. The accumulator holds the |new_target|.
// The |constructor| is in a register and arguments are in |args|.
......
......@@ -2466,19 +2466,8 @@ void BytecodeGenerator::VisitCall(Call* expr) {
// the registers up-front. Otherwise these registers are unavailable during
// receiver / argument visiting and we can end up with memory leaks due to
// registers keeping objects alive.
RegisterList args;
Register callee;
// 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();
}
Register callee = register_allocator()->NewRegister();
RegisterList args = register_allocator()->NewGrowableRegisterList();
// 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
......@@ -2552,11 +2541,7 @@ void BytecodeGenerator::VisitCall(Call* expr) {
// Evaluate all arguments to the function call and store in sequential args
// registers.
VisitArguments(expr->arguments(), &args);
// TODO(petermarshall): Check this for spread calls as well when
// CallWithSpread is done.
if (!expr->only_last_arg_is_spread()) {
CHECK_EQ(expr->arguments()->length() + 1, args.register_count());
}
CHECK_EQ(expr->arguments()->length() + 1, args.register_count());
// Resolve callee for a potential direct eval call. This block will mutate the
// callee value.
......@@ -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
// exactly one spread, and it is the last argument.
if (expr->only_last_arg_is_spread()) {
CHECK_EQ(expr->arguments()->length() + 2, args.register_count());
DCHECK_EQ(TailCallMode::kDisallow, expr->tail_call_mode());
builder()->CallWithSpread(args);
builder()->CallWithSpread(callee, args);
} else {
int const feedback_slot_index = feedback_index(expr->CallFeedbackICSlot());
builder()->Call(callee, args, feedback_slot_index, call_type,
......
......@@ -151,8 +151,8 @@ namespace interpreter {
OperandType::kRegCount, OperandType::kIdx) \
V(CallProperty, AccumulatorUse::kWrite, OperandType::kReg, \
OperandType::kRegList, OperandType::kRegCount, OperandType::kIdx) \
V(CallWithSpread, AccumulatorUse::kWrite, OperandType::kRegList, \
OperandType::kRegCount) \
V(CallWithSpread, AccumulatorUse::kWrite, OperandType::kReg, \
OperandType::kRegList, OperandType::kRegCount) \
V(TailCall, AccumulatorUse::kWrite, OperandType::kReg, \
OperandType::kRegList, OperandType::kRegCount, OperandType::kIdx) \
V(CallRuntime, AccumulatorUse::kWrite, OperandType::kRuntimeId, \
......
......@@ -543,7 +543,7 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context,
// Call using call function builtin.
Callable callable = CodeFactory::InterpreterPushArgsAndCall(
isolate(), tail_call_mode, CallableType::kJSFunction);
isolate(), tail_call_mode, InterpreterPushArgsMode::kJSFunction);
Node* code_target = HeapConstant(callable.code());
Node* ret_value = CallStub(callable.descriptor(), code_target, context,
arg_count, first_arg, function);
......@@ -659,7 +659,7 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context,
// Call using call builtin.
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* ret_value = CallStub(callable_call.descriptor(), code_target_call,
context, arg_count, first_arg, function);
......@@ -675,7 +675,18 @@ Node* InterpreterAssembler::CallJS(Node* function, Node* context,
Node* first_arg, Node* arg_count,
TailCallMode tail_call_mode) {
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());
return CallStub(callable.descriptor(), code_target, context, arg_count,
......@@ -718,7 +729,7 @@ Node* InterpreterAssembler::CallConstruct(Node* constructor, Node* context,
Comment("call using callConstructFunction");
IncrementCallCount(type_feedback_vector, slot_id);
Callable callable_function = CodeFactory::InterpreterPushArgsAndConstruct(
isolate(), PushArgsConstructMode::kJSFunction);
isolate(), InterpreterPushArgsMode::kJSFunction);
return_value.Bind(CallStub(callable_function.descriptor(),
HeapConstant(callable_function.code()), context,
arg_count, new_target, constructor,
......@@ -821,7 +832,7 @@ Node* InterpreterAssembler::CallConstruct(Node* constructor, Node* context,
{
Comment("call using callConstruct builtin");
Callable callable = CodeFactory::InterpreterPushArgsAndConstruct(
isolate(), PushArgsConstructMode::kOther);
isolate(), InterpreterPushArgsMode::kOther);
Node* code_target = HeapConstant(callable.code());
return_value.Bind(CallStub(callable.descriptor(), code_target, context,
arg_count, new_target, constructor,
......@@ -841,7 +852,7 @@ Node* InterpreterAssembler::CallConstructWithSpread(Node* constructor,
Variable return_value(this, MachineRepresentation::kTagged);
Comment("call using ConstructWithSpread");
Callable callable = CodeFactory::InterpreterPushArgsAndConstruct(
isolate(), PushArgsConstructMode::kWithFinalSpread);
isolate(), InterpreterPushArgsMode::kWithFinalSpread);
Node* code_target = HeapConstant(callable.code());
return_value.Bind(CallStub(callable.descriptor(), code_target, context,
arg_count, new_target, constructor,
......
......@@ -129,6 +129,14 @@ class V8_EXPORT_PRIVATE InterpreterAssembler : public CodeStubAssembler {
compiler::Node* first_arg, compiler::Node* arg_count,
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
// including receiver) and the first argument located at
// |first_arg|. The |new_target| is the same as the
......
......@@ -2176,22 +2176,25 @@ void Interpreter::DoCallJSRuntime(InterpreterAssembler* assembler) {
__ Dispatch();
}
// CallWithSpread <first_arg> <arg_count>
// CallWithSpread <callable> <first_arg> <arg_count>
//
// Call a JSfunction or Callable in |first_arg| with the receiver in
// |first_arg + 1| and |arg_count - 2| arguments in subsequent registers. The
// Call a JSfunction or Callable in |callable| with the receiver in
// |first_arg| and |arg_count - 1| arguments in subsequent registers. The
// final argument is always a spread.
//
void Interpreter::DoCallWithSpread(InterpreterAssembler* assembler) {
Node* first_arg_reg = __ BytecodeOperandReg(0);
Node* first_arg = __ RegisterLocation(first_arg_reg);
Node* args_count = __ BytecodeOperandCount(1);
Node* callable_reg = __ BytecodeOperandReg(0);
Node* callable = __ LoadRegister(callable_reg);
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();
// Call into Runtime function CallWithSpread which does everything.
Node* runtime_function = __ Int32Constant(Runtime::kCallWithSpread);
Node* result =
__ CallRuntimeN(runtime_function, context, first_arg, args_count);
__ CallJSWithSpread(callable, context, receiver_arg, args_count);
__ SetAccumulator(result);
__ Dispatch();
}
......
......@@ -459,48 +459,5 @@ RUNTIME_FUNCTION(Runtime_GetSuperConstructor) {
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 v8
......@@ -92,8 +92,7 @@ namespace internal {
F(StoreToSuper_Sloppy, 4, 1) \
F(StoreKeyedToSuper_Strict, 4, 1) \
F(StoreKeyedToSuper_Sloppy, 4, 1) \
F(GetSuperConstructor, 1, 1) \
F(CallWithSpread, -1, 1)
F(GetSuperConstructor, 1, 1)
#define FOR_EACH_INTRINSIC_COLLECTIONS(F) \
F(StringGetRawHashField, 1, 1) \
......
......@@ -11,7 +11,7 @@ snippet: "
"
frame size: 3
parameter count: 1
bytecode array length: 23
bytecode array length: 24
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 34 S> */ B(LdaGlobal), U8(0), U8(4),
......@@ -20,7 +20,7 @@ bytecodes: [
B(Star), R(0),
B(CreateArrayLiteral), U8(2), U8(0), U8(9),
B(Star), R(2),
/* 39 E> */ B(CallWithSpread), R(0), U8(3),
/* 39 E> */ B(CallWithSpread), R(0), R(1), U8(2),
B(LdaUndefined),
/* 58 S> */ B(Return),
]
......@@ -38,7 +38,7 @@ snippet: "
"
frame size: 4
parameter count: 1
bytecode array length: 26
bytecode array length: 27
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 34 S> */ B(LdaGlobal), U8(0), U8(4),
......@@ -49,7 +49,7 @@ bytecodes: [
B(Star), R(2),
B(CreateArrayLiteral), U8(2), U8(0), U8(9),
B(Star), R(3),
/* 39 E> */ B(CallWithSpread), R(0), U8(4),
/* 39 E> */ B(CallWithSpread), R(0), R(1), U8(3),
B(LdaUndefined),
/* 61 S> */ B(Return),
]
......
......@@ -139,7 +139,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, reg_list, pair)
.CallJSRuntime(Context::SPREAD_ITERABLE_INDEX, reg_list)
.NewWithSpread(reg, reg_list)
.CallWithSpread(reg_list);
.CallWithSpread(reg, reg_list);
// Emit binary operator invocations.
builder.BinaryOperation(Token::Value::ADD, reg, 1)
......
......@@ -692,8 +692,8 @@ TARGET_TEST_F(InterpreterAssemblerTest, CallJS) {
TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
InterpreterAssemblerTestState state(this, bytecode);
InterpreterAssemblerForTest m(&state, bytecode);
Callable builtin =
CodeFactory::InterpreterPushArgsAndCall(isolate(), tail_call_mode);
Callable builtin = CodeFactory::InterpreterPushArgsAndCall(
isolate(), tail_call_mode, InterpreterPushArgsMode::kOther);
Node* function = m.IntPtrConstant(0);
Node* first_arg = m.IntPtrConstant(1);
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