Revert of [Ignition/turbo] Add a CallWithSpread bytecode. (patchset #10 id:170001 of https://codereview.chromium.org/2629363002/ )
Reason for revert:
Causes a few bugs caught by clusterfuzz.
Original issue's description:
> [Ignition/turbo] Add a CallWithSpread bytecode.
>
> Also, emit a NewWithSpread bytecode for CallNew AST nodes where possible, rather than desugaring in the parser.
>
> BUG=v8:5511
>
> Review-Url: https://codereview.chromium.org/2629363002
> Cr-Commit-Position: refs/heads/master@{#42455}
> Committed: 4bae43471d
TBR=bmeurer@chromium.org,rmcilroy@chromium.org,verwaest@chromium.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=v8:5511
Review-Url: https://codereview.chromium.org/2642843002
Cr-Commit-Position: refs/heads/master@{#42470}
This commit is contained in:
parent
51740cc16a
commit
75b861210f
@ -409,8 +409,8 @@ void AstNumberingVisitor::VisitCompareOperation(CompareOperation* node) {
|
||||
|
||||
void AstNumberingVisitor::VisitSpread(Spread* node) {
|
||||
IncrementNodeCount();
|
||||
// We can only get here from spread calls currently.
|
||||
DisableFullCodegenAndCrankshaft(kSpreadCall);
|
||||
// We can only get here from super calls currently.
|
||||
DisableFullCodegenAndCrankshaft(kSuperReference);
|
||||
node->set_base_id(ReserveIdRange(Spread::num_ids()));
|
||||
Visit(node->expression());
|
||||
}
|
||||
|
@ -1900,10 +1900,6 @@ class Call final : public Expression {
|
||||
}
|
||||
void MarkTail() { bit_field_ = IsTailField::update(bit_field_, true); }
|
||||
|
||||
bool only_last_arg_is_spread() {
|
||||
return !arguments_->is_empty() && arguments_->last()->IsSpread();
|
||||
}
|
||||
|
||||
enum CallType {
|
||||
GLOBAL_CALL,
|
||||
WITH_CALL,
|
||||
@ -2003,10 +1999,6 @@ class CallNew final : public Expression {
|
||||
set_is_monomorphic(true);
|
||||
}
|
||||
|
||||
bool only_last_arg_is_spread() {
|
||||
return !arguments_->is_empty() && arguments_->last()->IsSpread();
|
||||
}
|
||||
|
||||
private:
|
||||
friend class AstNodeFactory;
|
||||
|
||||
|
@ -185,7 +185,6 @@ namespace internal {
|
||||
"Sloppy function expects JSReceiver as receiver.") \
|
||||
V(kSmiAdditionOverflow, "Smi addition overflow") \
|
||||
V(kSmiSubtractionOverflow, "Smi subtraction overflow") \
|
||||
V(kSpreadCall, "Call with spread argument") \
|
||||
V(kStackAccessBelowStackPointer, "Stack access below stack pointer") \
|
||||
V(kStackFrameTypesMustMatch, "Stack frame types must match") \
|
||||
V(kSuperReference, "Super reference") \
|
||||
|
@ -1353,16 +1353,6 @@ Node* BytecodeGraphBuilder::ProcessCallNewWithSpreadArguments(
|
||||
return value;
|
||||
}
|
||||
|
||||
void BytecodeGraphBuilder::VisitCallWithSpread() {
|
||||
PrepareEagerCheckpoint();
|
||||
interpreter::Register first_arg = bytecode_iterator().GetRegisterOperand(0);
|
||||
size_t arg_count = bytecode_iterator().GetRegisterCountOperand(1);
|
||||
const Operator* call =
|
||||
javascript()->CallRuntime(Runtime::kCallWithSpread, arg_count);
|
||||
Node* value = ProcessCallRuntimeArguments(call, first_arg, arg_count);
|
||||
environment()->BindAccumulator(value, Environment::kAttachFrameState);
|
||||
}
|
||||
|
||||
void BytecodeGraphBuilder::VisitNewWithSpread() {
|
||||
PrepareEagerCheckpoint();
|
||||
interpreter::Register callee_reg = bytecode_iterator().GetRegisterOperand(0);
|
||||
|
@ -891,11 +891,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable,
|
||||
return *this;
|
||||
}
|
||||
|
||||
BytecodeArrayBuilder& BytecodeArrayBuilder::CallWithSpread(RegisterList args) {
|
||||
OutputCallWithSpread(args, args.register_count());
|
||||
return *this;
|
||||
}
|
||||
|
||||
BytecodeArrayBuilder& BytecodeArrayBuilder::New(Register constructor,
|
||||
RegisterList args,
|
||||
int feedback_slot_id) {
|
||||
|
@ -213,11 +213,6 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final
|
||||
Call::CallType call_type,
|
||||
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]|
|
||||
// onwards. The final argument must be a spread.
|
||||
BytecodeArrayBuilder& CallWithSpread(RegisterList args);
|
||||
|
||||
// Call the new operator. The accumulator holds the |new_target|.
|
||||
// The |constructor| is in a register and arguments are in |args|.
|
||||
BytecodeArrayBuilder& New(Register constructor, RegisterList args,
|
||||
|
@ -2445,27 +2445,12 @@ void BytecodeGenerator::VisitCall(Call* expr) {
|
||||
return VisitCallSuper(expr);
|
||||
}
|
||||
|
||||
Register callee = register_allocator()->NewRegister();
|
||||
// Grow the args list as we visit receiver / arguments to avoid allocating all
|
||||
// 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();
|
||||
}
|
||||
|
||||
// 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
|
||||
// specifies the call type (e.g., property, spread, tailcall, etc.).
|
||||
RegisterList args = register_allocator()->NewGrowableRegisterList();
|
||||
|
||||
// Prepare the callee and the receiver to the function call. This depends on
|
||||
// the semantics of the underlying call type.
|
||||
@ -2474,7 +2459,7 @@ void BytecodeGenerator::VisitCall(Call* expr) {
|
||||
case Call::KEYED_PROPERTY_CALL: {
|
||||
Property* property = callee_expr->AsProperty();
|
||||
VisitAndPushIntoRegisterList(property->obj(), &args);
|
||||
VisitPropertyLoadForRegister(args.last_register(), property, callee);
|
||||
VisitPropertyLoadForRegister(args[0], property, callee);
|
||||
break;
|
||||
}
|
||||
case Call::GLOBAL_CALL: {
|
||||
@ -2535,11 +2520,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.
|
||||
@ -2569,17 +2550,9 @@ void BytecodeGenerator::VisitCall(Call* expr) {
|
||||
|
||||
builder()->SetExpressionPosition(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);
|
||||
} else {
|
||||
int const feedback_slot_index = feedback_index(expr->CallFeedbackICSlot());
|
||||
builder()->Call(callee, args, feedback_slot_index, call_type,
|
||||
expr->tail_call_mode());
|
||||
}
|
||||
int const feedback_slot_index = feedback_index(expr->CallFeedbackICSlot());
|
||||
builder()->Call(callee, args, feedback_slot_index, call_type,
|
||||
expr->tail_call_mode());
|
||||
}
|
||||
|
||||
void BytecodeGenerator::VisitCallSuper(Call* expr) {
|
||||
@ -2601,7 +2574,7 @@ void BytecodeGenerator::VisitCallSuper(Call* expr) {
|
||||
|
||||
// When a super call contains a spread, a CallSuper AST node is only created
|
||||
// if there is exactly one spread, and it is the last argument.
|
||||
if (expr->only_last_arg_is_spread()) {
|
||||
if (!args->is_empty() && args->last()->IsSpread()) {
|
||||
// TODO(petermarshall): Collect type on the feedback slot.
|
||||
builder()->NewWithSpread(constructor, args_regs);
|
||||
} else {
|
||||
@ -2622,18 +2595,12 @@ void BytecodeGenerator::VisitCallNew(CallNew* expr) {
|
||||
RegisterList args = register_allocator()->NewGrowableRegisterList();
|
||||
VisitArguments(expr->arguments(), &args);
|
||||
|
||||
builder()->SetExpressionPosition(expr);
|
||||
// The accumulator holds new target which is the same as the
|
||||
// constructor for CallNew.
|
||||
builder()->SetExpressionPosition(expr);
|
||||
builder()->LoadAccumulatorWithRegister(constructor);
|
||||
|
||||
if (expr->only_last_arg_is_spread()) {
|
||||
// TODO(petermarshall): Collect type on the feedback slot.
|
||||
builder()->NewWithSpread(constructor, args);
|
||||
} else {
|
||||
builder()->New(constructor, args,
|
||||
feedback_index(expr->CallNewFeedbackSlot()));
|
||||
}
|
||||
builder()
|
||||
->LoadAccumulatorWithRegister(constructor)
|
||||
.New(constructor, args, feedback_index(expr->CallNewFeedbackSlot()));
|
||||
}
|
||||
|
||||
void BytecodeGenerator::VisitCallRuntime(CallRuntime* expr) {
|
||||
|
@ -151,8 +151,6 @@ 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(TailCall, AccumulatorUse::kWrite, OperandType::kReg, \
|
||||
OperandType::kRegList, OperandType::kRegCount, OperandType::kIdx) \
|
||||
V(CallRuntime, AccumulatorUse::kWrite, OperandType::kRuntimeId, \
|
||||
|
@ -2176,27 +2176,7 @@ void Interpreter::DoCallJSRuntime(InterpreterAssembler* assembler) {
|
||||
__ Dispatch();
|
||||
}
|
||||
|
||||
// CallWithSpread <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
|
||||
// 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* 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);
|
||||
__ SetAccumulator(result);
|
||||
__ Dispatch();
|
||||
}
|
||||
|
||||
// NewWithSpread <first_arg> <arg_count>
|
||||
// NewWithSpread <constructor> <first_arg> <arg_count>
|
||||
//
|
||||
// Call the constructor in |constructor| with the first argument in register
|
||||
// |first_arg| and |arg_count| arguments in subsequent registers. The final
|
||||
|
@ -2597,7 +2597,6 @@ typename ParserBase<Impl>::ExpressionListT ParserBase<Impl>::ParseArguments(
|
||||
bool done = (peek() == Token::RPAREN);
|
||||
bool was_unspread = false;
|
||||
int unspread_sequences_count = 0;
|
||||
int spread_count = 0;
|
||||
while (!done) {
|
||||
int start_pos = peek_position();
|
||||
bool is_spread = Check(Token::ELLIPSIS);
|
||||
@ -2621,7 +2620,6 @@ typename ParserBase<Impl>::ExpressionListT ParserBase<Impl>::ParseArguments(
|
||||
// are not prefixed with a spread '...' operator.
|
||||
if (is_spread) {
|
||||
was_unspread = false;
|
||||
spread_count++;
|
||||
} else if (!was_unspread) {
|
||||
was_unspread = true;
|
||||
unspread_sequences_count++;
|
||||
@ -2657,11 +2655,7 @@ typename ParserBase<Impl>::ExpressionListT ParserBase<Impl>::ParseArguments(
|
||||
// Unspread parameter sequences are translated into array literals in the
|
||||
// parser. Ensure that the number of materialized literals matches between
|
||||
// the parser and preparser
|
||||
if (was_unspread || spread_count > 1) {
|
||||
// There was more than one spread, or the spread was not the final
|
||||
// argument, so the parser will materialize literals.
|
||||
impl()->MaterializeUnspreadArgumentsLiterals(unspread_sequences_count);
|
||||
}
|
||||
impl()->MaterializeUnspreadArgumentsLiterals(unspread_sequences_count);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3203,7 +3197,7 @@ ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) {
|
||||
|
||||
bool is_super_call = result->IsSuperCallReference();
|
||||
if (spread_pos.IsValid()) {
|
||||
result = impl()->SpreadCall(result, args, pos, is_possibly_eval);
|
||||
result = impl()->SpreadCall(result, args, pos);
|
||||
} else {
|
||||
result = factory()->NewCall(result, args, pos, is_possibly_eval);
|
||||
}
|
||||
|
@ -3682,85 +3682,90 @@ uint32_t Parser::ComputeTemplateLiteralHash(const TemplateLiteral* lit) {
|
||||
return running_hash;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool OnlyLastArgIsSpread(ZoneList<Expression*>* args) {
|
||||
for (int i = 0; i < args->length() - 1; i++) {
|
||||
if (args->at(i)->IsSpread()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return args->at(args->length() - 1)->IsSpread();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ZoneList<Expression*>* Parser::PrepareSpreadArguments(
|
||||
ZoneList<Expression*>* list) {
|
||||
// Here we only deal with multiple arguments where the spread is not at the
|
||||
// end, or there are multiple spreads.
|
||||
DCHECK_GT(list->length(), 1);
|
||||
DCHECK(!OnlyLastArgIsSpread(list));
|
||||
|
||||
ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(1, zone());
|
||||
// Spread-call with multiple arguments produces array literals for each
|
||||
// sequences of unspread arguments, and converts each spread iterable to
|
||||
// an Internal array. Finally, all of these produced arrays are flattened
|
||||
// into a single InternalArray, containing the arguments for the call.
|
||||
//
|
||||
// EG: Apply(Func, Flatten([unspread0, unspread1], Spread(spread0),
|
||||
// Spread(spread1), [unspread2, unspread3]))
|
||||
int i = 0;
|
||||
int n = list->length();
|
||||
while (i < n) {
|
||||
if (!list->at(i)->IsSpread()) {
|
||||
ZoneList<Expression*>* unspread =
|
||||
new (zone()) ZoneList<Expression*>(1, zone());
|
||||
|
||||
// Push array of unspread parameters
|
||||
while (i < n && !list->at(i)->IsSpread()) {
|
||||
unspread->Add(list->at(i++), zone());
|
||||
}
|
||||
int literal_index = function_state_->NextMaterializedLiteralIndex();
|
||||
args->Add(factory()->NewArrayLiteral(unspread, literal_index,
|
||||
kNoSourcePosition),
|
||||
zone());
|
||||
|
||||
if (i == n) break;
|
||||
}
|
||||
|
||||
// Push eagerly spread argument
|
||||
if (list->length() == 1) {
|
||||
// Spread-call with single spread argument produces an InternalArray
|
||||
// containing the values from the array.
|
||||
//
|
||||
// Function is called or constructed with the produced array of arguments
|
||||
//
|
||||
// EG: Apply(Func, Spread(spread0))
|
||||
ZoneList<Expression*>* spread_list =
|
||||
new (zone()) ZoneList<Expression*>(1, zone());
|
||||
spread_list->Add(list->at(i++)->AsSpread()->expression(), zone());
|
||||
args->Add(factory()->NewCallRuntime(Context::SPREAD_ITERABLE_INDEX,
|
||||
new (zone()) ZoneList<Expression*>(0, zone());
|
||||
spread_list->Add(list->at(0)->AsSpread()->expression(), zone());
|
||||
args->Add(factory()->NewCallRuntime(Runtime::kSpreadIterablePrepare,
|
||||
spread_list, kNoSourcePosition),
|
||||
zone());
|
||||
}
|
||||
return args;
|
||||
} else {
|
||||
// Spread-call with multiple arguments produces array literals for each
|
||||
// sequences of unspread arguments, and converts each spread iterable to
|
||||
// an Internal array. Finally, all of these produced arrays are flattened
|
||||
// into a single InternalArray, containing the arguments for the call.
|
||||
//
|
||||
// EG: Apply(Func, Flatten([unspread0, unspread1], Spread(spread0),
|
||||
// Spread(spread1), [unspread2, unspread3]))
|
||||
int i = 0;
|
||||
int n = list->length();
|
||||
while (i < n) {
|
||||
if (!list->at(i)->IsSpread()) {
|
||||
ZoneList<Expression*>* unspread =
|
||||
new (zone()) ZoneList<Expression*>(1, zone());
|
||||
|
||||
list = new (zone()) ZoneList<Expression*>(1, zone());
|
||||
list->Add(factory()->NewCallRuntime(Context::SPREAD_ARGUMENTS_INDEX, args,
|
||||
kNoSourcePosition),
|
||||
zone());
|
||||
return list;
|
||||
// Push array of unspread parameters
|
||||
while (i < n && !list->at(i)->IsSpread()) {
|
||||
unspread->Add(list->at(i++), zone());
|
||||
}
|
||||
int literal_index = function_state_->NextMaterializedLiteralIndex();
|
||||
args->Add(factory()->NewArrayLiteral(unspread, literal_index,
|
||||
kNoSourcePosition),
|
||||
zone());
|
||||
|
||||
if (i == n) break;
|
||||
}
|
||||
|
||||
// Push eagerly spread argument
|
||||
ZoneList<Expression*>* spread_list =
|
||||
new (zone()) ZoneList<Expression*>(1, zone());
|
||||
spread_list->Add(list->at(i++)->AsSpread()->expression(), zone());
|
||||
args->Add(factory()->NewCallRuntime(Context::SPREAD_ITERABLE_INDEX,
|
||||
spread_list, kNoSourcePosition),
|
||||
zone());
|
||||
}
|
||||
|
||||
list = new (zone()) ZoneList<Expression*>(1, zone());
|
||||
list->Add(factory()->NewCallRuntime(Context::SPREAD_ARGUMENTS_INDEX, args,
|
||||
kNoSourcePosition),
|
||||
zone());
|
||||
return list;
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
Expression* Parser::SpreadCall(Expression* function,
|
||||
ZoneList<Expression*>* args, int pos,
|
||||
Call::PossiblyEval is_possibly_eval) {
|
||||
// Handle these cases in BytecodeGenerator.
|
||||
if (OnlyLastArgIsSpread(args)) {
|
||||
if (function->IsSuperCallReference()) {
|
||||
function = NewSuperCallReference(pos);
|
||||
}
|
||||
return factory()->NewCall(function, args, pos);
|
||||
}
|
||||
|
||||
ZoneList<Expression*>* args, int pos) {
|
||||
if (function->IsSuperCallReference()) {
|
||||
// Super calls
|
||||
// $super_constructor = %_GetSuperConstructor(<this-function>)
|
||||
// %reflect_construct($super_constructor, args, new.target)
|
||||
|
||||
bool only_last_arg_is_spread = false;
|
||||
for (int i = 0; i < args->length(); i++) {
|
||||
if (args->at(i)->IsSpread()) {
|
||||
if (i == args->length() - 1) {
|
||||
only_last_arg_is_spread = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (only_last_arg_is_spread) {
|
||||
// Handle in BytecodeGenerator.
|
||||
Expression* super_call_ref = NewSuperCallReference(pos);
|
||||
return factory()->NewCall(super_call_ref, args, pos);
|
||||
}
|
||||
args = PrepareSpreadArguments(args);
|
||||
ZoneList<Expression*>* tmp = new (zone()) ZoneList<Expression*>(1, zone());
|
||||
tmp->Add(function->AsSuperCallReference()->this_function_var(), zone());
|
||||
@ -3802,10 +3807,6 @@ Expression* Parser::SpreadCall(Expression* function,
|
||||
|
||||
Expression* Parser::SpreadCallNew(Expression* function,
|
||||
ZoneList<Expression*>* args, int pos) {
|
||||
if (OnlyLastArgIsSpread(args)) {
|
||||
// Handle in BytecodeGenerator.
|
||||
return factory()->NewCallNew(function, args, pos);
|
||||
}
|
||||
args = PrepareSpreadArguments(args);
|
||||
args->InsertAt(0, function, zone());
|
||||
|
||||
|
@ -591,7 +591,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
|
||||
|
||||
ZoneList<Expression*>* PrepareSpreadArguments(ZoneList<Expression*>* list);
|
||||
Expression* SpreadCall(Expression* function, ZoneList<Expression*>* args,
|
||||
int pos, Call::PossiblyEval is_possibly_eval);
|
||||
int pos);
|
||||
Expression* SpreadCallNew(Expression* function, ZoneList<Expression*>* args,
|
||||
int pos);
|
||||
Expression* RewriteSuperCall(Expression* call_expression);
|
||||
|
@ -988,8 +988,7 @@ class PreParser : public ParserBase<PreParser> {
|
||||
|
||||
V8_INLINE PreParserExpression SpreadCall(PreParserExpression function,
|
||||
PreParserExpressionList args,
|
||||
int pos,
|
||||
Call::PossiblyEval possibly_eval);
|
||||
int pos);
|
||||
V8_INLINE PreParserExpression SpreadCallNew(PreParserExpression function,
|
||||
PreParserExpressionList args,
|
||||
int pos);
|
||||
@ -1613,9 +1612,9 @@ class PreParser : public ParserBase<PreParser> {
|
||||
};
|
||||
|
||||
PreParserExpression PreParser::SpreadCall(PreParserExpression function,
|
||||
PreParserExpressionList args, int pos,
|
||||
Call::PossiblyEval possibly_eval) {
|
||||
return factory()->NewCall(function, args, pos, possibly_eval);
|
||||
PreParserExpressionList args,
|
||||
int pos) {
|
||||
return factory()->NewCall(function, args, pos);
|
||||
}
|
||||
|
||||
PreParserExpression PreParser::SpreadCallNew(PreParserExpression function,
|
||||
|
@ -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
|
||||
|
@ -91,8 +91,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) \
|
||||
|
@ -1,107 +0,0 @@
|
||||
#
|
||||
# Autogenerated by generate-bytecode-expectations.
|
||||
#
|
||||
|
||||
---
|
||||
wrap: yes
|
||||
|
||||
---
|
||||
snippet: "
|
||||
Math.max(...[1, 2, 3]);
|
||||
"
|
||||
frame size: 3
|
||||
parameter count: 1
|
||||
bytecode array length: 23
|
||||
bytecodes: [
|
||||
/* 30 E> */ B(StackCheck),
|
||||
/* 34 S> */ B(LdaGlobal), U8(0), U8(4),
|
||||
B(Star), R(1),
|
||||
/* 38 E> */ B(LdaNamedProperty), R(1), U8(1), U8(6),
|
||||
B(Star), R(0),
|
||||
B(CreateArrayLiteral), U8(2), U8(0), U8(9),
|
||||
B(Star), R(2),
|
||||
/* 39 E> */ B(CallWithSpread), R(0), U8(3),
|
||||
B(LdaUndefined),
|
||||
/* 58 S> */ B(Return),
|
||||
]
|
||||
constant pool: [
|
||||
ONE_BYTE_INTERNALIZED_STRING_TYPE ["Math"],
|
||||
ONE_BYTE_INTERNALIZED_STRING_TYPE ["max"],
|
||||
CONSTANT_ELEMENTS_PAIR_TYPE,
|
||||
]
|
||||
handlers: [
|
||||
]
|
||||
|
||||
---
|
||||
snippet: "
|
||||
Math.max(0, ...[1, 2, 3]);
|
||||
"
|
||||
frame size: 4
|
||||
parameter count: 1
|
||||
bytecode array length: 26
|
||||
bytecodes: [
|
||||
/* 30 E> */ B(StackCheck),
|
||||
/* 34 S> */ B(LdaGlobal), U8(0), U8(4),
|
||||
B(Star), R(1),
|
||||
/* 38 E> */ B(LdaNamedProperty), R(1), U8(1), U8(6),
|
||||
B(Star), R(0),
|
||||
B(LdaZero),
|
||||
B(Star), R(2),
|
||||
B(CreateArrayLiteral), U8(2), U8(0), U8(9),
|
||||
B(Star), R(3),
|
||||
/* 39 E> */ B(CallWithSpread), R(0), U8(4),
|
||||
B(LdaUndefined),
|
||||
/* 61 S> */ B(Return),
|
||||
]
|
||||
constant pool: [
|
||||
ONE_BYTE_INTERNALIZED_STRING_TYPE ["Math"],
|
||||
ONE_BYTE_INTERNALIZED_STRING_TYPE ["max"],
|
||||
CONSTANT_ELEMENTS_PAIR_TYPE,
|
||||
]
|
||||
handlers: [
|
||||
]
|
||||
|
||||
---
|
||||
snippet: "
|
||||
Math.max(0, ...[1, 2, 3], 4);
|
||||
"
|
||||
frame size: 8
|
||||
parameter count: 1
|
||||
bytecode array length: 60
|
||||
bytecodes: [
|
||||
/* 30 E> */ B(StackCheck),
|
||||
/* 34 S> */ B(LdaUndefined),
|
||||
B(Star), R(1),
|
||||
/* 34 E> */ B(LdaGlobal), U8(0), U8(2),
|
||||
B(Star), R(0),
|
||||
B(LdaNamedProperty), R(0), U8(1), U8(4),
|
||||
B(Star), R(2),
|
||||
B(LdaUndefined),
|
||||
B(Star), R(4),
|
||||
B(CreateArrayLiteral), U8(2), U8(1), U8(9),
|
||||
B(Star), R(5),
|
||||
B(LdaUndefined),
|
||||
B(Star), R(6),
|
||||
B(CreateArrayLiteral), U8(3), U8(0), U8(9),
|
||||
B(Star), R(7),
|
||||
B(CallJSRuntime), U8(%spread_iterable), R(6), U8(2),
|
||||
B(Star), R(6),
|
||||
B(CreateArrayLiteral), U8(4), U8(2), U8(9),
|
||||
B(Star), R(7),
|
||||
B(CallJSRuntime), U8(%spread_arguments), R(4), U8(4),
|
||||
B(Star), R(4),
|
||||
B(Mov), R(0), R(3),
|
||||
B(CallJSRuntime), U8(%reflect_apply), R(1), U8(4),
|
||||
B(LdaUndefined),
|
||||
/* 64 S> */ B(Return),
|
||||
]
|
||||
constant pool: [
|
||||
ONE_BYTE_INTERNALIZED_STRING_TYPE ["Math"],
|
||||
ONE_BYTE_INTERNALIZED_STRING_TYPE ["max"],
|
||||
CONSTANT_ELEMENTS_PAIR_TYPE,
|
||||
CONSTANT_ELEMENTS_PAIR_TYPE,
|
||||
CONSTANT_ELEMENTS_PAIR_TYPE,
|
||||
]
|
||||
handlers: [
|
||||
]
|
||||
|
@ -1,157 +0,0 @@
|
||||
#
|
||||
# Autogenerated by generate-bytecode-expectations.
|
||||
#
|
||||
|
||||
---
|
||||
wrap: yes
|
||||
|
||||
---
|
||||
snippet: "
|
||||
class A { constructor(...args) { this.args = args; } }
|
||||
new A(...[1, 2, 3]);
|
||||
"
|
||||
frame size: 8
|
||||
parameter count: 1
|
||||
bytecode array length: 64
|
||||
bytecodes: [
|
||||
B(LdaTheHole),
|
||||
B(Star), R(2),
|
||||
/* 30 E> */ B(StackCheck),
|
||||
B(LdaTheHole),
|
||||
B(Star), R(0),
|
||||
/* 34 S> */ B(CreateClosure), U8(0), U8(2), U8(2),
|
||||
B(Star), R(3),
|
||||
B(LdaTheHole),
|
||||
B(Star), R(4),
|
||||
B(LdaSmi), U8(34),
|
||||
B(Star), R(6),
|
||||
B(LdaSmi), U8(88),
|
||||
B(Star), R(7),
|
||||
B(Mov), R(3), R(5),
|
||||
B(CallRuntime), U16(Runtime::kDefineClass), R(4), U8(4),
|
||||
B(Star), R(4),
|
||||
B(CallRuntime), U16(Runtime::kInstallClassNameAccessor), R(3), U8(1),
|
||||
B(CallRuntime), U16(Runtime::kToFastProperties), R(3), U8(1),
|
||||
B(Star), R(0),
|
||||
B(Star), R(1),
|
||||
B(Star), R(2),
|
||||
/* 89 S> */ B(CreateArrayLiteral), U8(1), U8(0), U8(9),
|
||||
B(Star), R(4),
|
||||
B(Ldar), R(2),
|
||||
/* 89 E> */ B(NewWithSpread), R(2), R(4), U8(1),
|
||||
B(LdaUndefined),
|
||||
/* 110 S> */ B(Return),
|
||||
]
|
||||
constant pool: [
|
||||
SHARED_FUNCTION_INFO_TYPE,
|
||||
CONSTANT_ELEMENTS_PAIR_TYPE,
|
||||
]
|
||||
handlers: [
|
||||
]
|
||||
|
||||
---
|
||||
snippet: "
|
||||
class A { constructor(...args) { this.args = args; } }
|
||||
new A(0, ...[1, 2, 3]);
|
||||
"
|
||||
frame size: 8
|
||||
parameter count: 1
|
||||
bytecode array length: 67
|
||||
bytecodes: [
|
||||
B(LdaTheHole),
|
||||
B(Star), R(2),
|
||||
/* 30 E> */ B(StackCheck),
|
||||
B(LdaTheHole),
|
||||
B(Star), R(0),
|
||||
/* 34 S> */ B(CreateClosure), U8(0), U8(2), U8(2),
|
||||
B(Star), R(3),
|
||||
B(LdaTheHole),
|
||||
B(Star), R(4),
|
||||
B(LdaSmi), U8(34),
|
||||
B(Star), R(6),
|
||||
B(LdaSmi), U8(88),
|
||||
B(Star), R(7),
|
||||
B(Mov), R(3), R(5),
|
||||
B(CallRuntime), U16(Runtime::kDefineClass), R(4), U8(4),
|
||||
B(Star), R(4),
|
||||
B(CallRuntime), U16(Runtime::kInstallClassNameAccessor), R(3), U8(1),
|
||||
B(CallRuntime), U16(Runtime::kToFastProperties), R(3), U8(1),
|
||||
B(Star), R(0),
|
||||
B(Star), R(1),
|
||||
B(Star), R(2),
|
||||
/* 89 S> */ B(LdaZero),
|
||||
B(Star), R(4),
|
||||
B(CreateArrayLiteral), U8(1), U8(0), U8(9),
|
||||
B(Star), R(5),
|
||||
B(Ldar), R(2),
|
||||
/* 89 E> */ B(NewWithSpread), R(2), R(4), U8(2),
|
||||
B(LdaUndefined),
|
||||
/* 113 S> */ B(Return),
|
||||
]
|
||||
constant pool: [
|
||||
SHARED_FUNCTION_INFO_TYPE,
|
||||
CONSTANT_ELEMENTS_PAIR_TYPE,
|
||||
]
|
||||
handlers: [
|
||||
]
|
||||
|
||||
---
|
||||
snippet: "
|
||||
class A { constructor(...args) { this.args = args; } }
|
||||
new A(0, ...[1, 2, 3], 4);
|
||||
"
|
||||
frame size: 9
|
||||
parameter count: 1
|
||||
bytecode array length: 98
|
||||
bytecodes: [
|
||||
B(LdaTheHole),
|
||||
B(Star), R(2),
|
||||
/* 30 E> */ B(StackCheck),
|
||||
B(LdaTheHole),
|
||||
B(Star), R(0),
|
||||
/* 34 S> */ B(CreateClosure), U8(0), U8(2), U8(2),
|
||||
B(Star), R(3),
|
||||
B(LdaTheHole),
|
||||
B(Star), R(4),
|
||||
B(LdaSmi), U8(34),
|
||||
B(Star), R(6),
|
||||
B(LdaSmi), U8(88),
|
||||
B(Star), R(7),
|
||||
B(Mov), R(3), R(5),
|
||||
B(CallRuntime), U16(Runtime::kDefineClass), R(4), U8(4),
|
||||
B(Star), R(4),
|
||||
B(CallRuntime), U16(Runtime::kInstallClassNameAccessor), R(3), U8(1),
|
||||
B(CallRuntime), U16(Runtime::kToFastProperties), R(3), U8(1),
|
||||
B(Star), R(0),
|
||||
B(Star), R(1),
|
||||
B(Star), R(2),
|
||||
/* 89 S> */ B(LdaUndefined),
|
||||
B(Star), R(3),
|
||||
B(LdaUndefined),
|
||||
B(Star), R(5),
|
||||
/* 93 E> */ B(CreateArrayLiteral), U8(1), U8(1), U8(9),
|
||||
B(Star), R(6),
|
||||
B(LdaUndefined),
|
||||
B(Star), R(7),
|
||||
B(CreateArrayLiteral), U8(2), U8(0), U8(9),
|
||||
B(Star), R(8),
|
||||
B(CallJSRuntime), U8(%spread_iterable), R(7), U8(2),
|
||||
B(Star), R(7),
|
||||
B(CreateArrayLiteral), U8(3), U8(2), U8(9),
|
||||
B(Star), R(8),
|
||||
B(CallJSRuntime), U8(%spread_arguments), R(5), U8(4),
|
||||
B(Star), R(5),
|
||||
B(Mov), R(1), R(4),
|
||||
B(CallJSRuntime), U8(%reflect_construct), R(3), U8(3),
|
||||
B(LdaUndefined),
|
||||
/* 116 S> */ B(Return),
|
||||
]
|
||||
constant pool: [
|
||||
SHARED_FUNCTION_INFO_TYPE,
|
||||
CONSTANT_ELEMENTS_PAIR_TYPE,
|
||||
CONSTANT_ELEMENTS_PAIR_TYPE,
|
||||
CONSTANT_ELEMENTS_PAIR_TYPE,
|
||||
]
|
||||
handlers: [
|
||||
]
|
||||
|
@ -2343,34 +2343,6 @@ TEST(SuperCallAndSpread) {
|
||||
LoadGolden("SuperCallAndSpread.golden")));
|
||||
}
|
||||
|
||||
TEST(CallAndSpread) {
|
||||
InitializedIgnitionHandleScope scope;
|
||||
BytecodeExpectationsPrinter printer(CcTest::isolate());
|
||||
const char* snippets[] = {"Math.max(...[1, 2, 3]);\n",
|
||||
"Math.max(0, ...[1, 2, 3]);\n",
|
||||
"Math.max(0, ...[1, 2, 3], 4);\n"};
|
||||
|
||||
CHECK(CompareTexts(BuildActual(printer, snippets),
|
||||
LoadGolden("CallAndSpread.golden")));
|
||||
}
|
||||
|
||||
TEST(NewAndSpread) {
|
||||
InitializedIgnitionHandleScope scope;
|
||||
BytecodeExpectationsPrinter printer(CcTest::isolate());
|
||||
const char* snippets[] = {
|
||||
"class A { constructor(...args) { this.args = args; } }\n"
|
||||
"new A(...[1, 2, 3]);\n",
|
||||
|
||||
"class A { constructor(...args) { this.args = args; } }\n"
|
||||
"new A(0, ...[1, 2, 3]);\n",
|
||||
|
||||
"class A { constructor(...args) { this.args = args; } }\n"
|
||||
"new A(0, ...[1, 2, 3], 4);\n"};
|
||||
|
||||
CHECK(CompareTexts(BuildActual(printer, snippets),
|
||||
LoadGolden("NewAndSpread.golden")));
|
||||
}
|
||||
|
||||
} // namespace interpreter
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -138,8 +138,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
|
||||
.CallRuntime(Runtime::kIsArray, reg)
|
||||
.CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, reg_list, pair)
|
||||
.CallJSRuntime(Context::SPREAD_ITERABLE_INDEX, reg_list)
|
||||
.NewWithSpread(reg, reg_list)
|
||||
.CallWithSpread(reg_list);
|
||||
.NewWithSpread(reg, reg_list);
|
||||
|
||||
// Emit binary operator invocations.
|
||||
builder.BinaryOperation(Token::Value::ADD, reg, 1)
|
||||
|
Loading…
Reference in New Issue
Block a user