Index: src/interpreter/bytecode-generator.cc |
diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc |
index d611cafd3a3b8bc18281cef25cdff6cd3242fd4b..5565e01f547fc2db137c61a1c82d8594b4cdef41 100644 |
--- a/src/interpreter/bytecode-generator.cc |
+++ b/src/interpreter/bytecode-generator.cc |
@@ -2488,24 +2488,49 @@ void BytecodeGenerator::VisitCallSuper(Call* expr) { |
Register constructor = this_function; // Re-use dead this_function register. |
builder()->StoreAccumulatorInRegister(constructor); |
- RegisterList args = |
- register_allocator()->NewRegisterList(expr->arguments()->length()); |
- VisitArguments(expr->arguments(), args); |
- |
- // The new target is loaded into the accumulator from the |
- // {new.target} variable. |
- VisitForAccumulatorValue(super->new_target_var()); |
- |
- // Call construct. |
- builder()->SetExpressionPosition(expr); |
- // TODO(turbofan): For now we do gather feedback on super constructor |
- // calls, utilizing the existing machinery to inline the actual call |
- // target and the JSCreate for the implicit receiver allocation. This |
- // is not an ideal solution for super constructor calls, but it gets |
- // the job done for now. In the long run we might want to revisit this |
- // and come up with a better way. |
- int const feedback_slot_index = feedback_index(expr->CallFeedbackICSlot()); |
- builder()->New(constructor, args, feedback_slot_index); |
+ ZoneList<Expression*>* args = expr->arguments(); |
+ |
+ // 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 (!args->is_empty() && args->last()->IsSpread()) { |
+ // Prepare the spread arguments. |
+ RegisterList spread_prepare_args = |
+ register_allocator()->NewRegisterList(args->length()); |
+ VisitArguments(args, spread_prepare_args); |
+ |
+ builder()->CallRuntime(Runtime::kSpreadIterablePrepareVarargs, |
+ spread_prepare_args); |
+ |
+ // Call ReflectConstruct to do the actual super constructor call. |
+ RegisterList reflect_construct_args = |
+ register_allocator()->NewRegisterList(4); |
+ builder() |
+ ->StoreAccumulatorInRegister(reflect_construct_args[2]) |
+ .LoadUndefined() |
+ .StoreAccumulatorInRegister(reflect_construct_args[0]) |
+ .MoveRegister(constructor, reflect_construct_args[1]); |
+ VisitForRegisterValue(super->new_target_var(), reflect_construct_args[3]); |
+ builder()->CallJSRuntime(Context::REFLECT_CONSTRUCT_INDEX, |
+ reflect_construct_args); |
+ } else { |
+ RegisterList args_regs = |
+ register_allocator()->NewRegisterList(args->length()); |
+ VisitArguments(args, args_regs); |
+ // The new target is loaded into the accumulator from the |
+ // {new.target} variable. |
+ VisitForAccumulatorValue(super->new_target_var()); |
+ |
+ // Call construct. |
+ builder()->SetExpressionPosition(expr); |
+ // TODO(turbofan): For now we do gather feedback on super constructor |
+ // calls, utilizing the existing machinery to inline the actual call |
+ // target and the JSCreate for the implicit receiver allocation. This |
+ // is not an ideal solution for super constructor calls, but it gets |
+ // the job done for now. In the long run we might want to revisit this |
+ // and come up with a better way. |
+ int const feedback_slot_index = feedback_index(expr->CallFeedbackICSlot()); |
+ builder()->New(constructor, args_regs, feedback_slot_index); |
+ } |
} |
void BytecodeGenerator::VisitCallNew(CallNew* expr) { |
@@ -2813,7 +2838,7 @@ void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) { |
builder()->BinaryOperation(expr->op(), lhs, feedback_index(slot)); |
} |
-void BytecodeGenerator::VisitSpread(Spread* expr) { UNREACHABLE(); } |
+void BytecodeGenerator::VisitSpread(Spread* expr) { Visit(expr->expression()); } |
void BytecodeGenerator::VisitEmptyParentheses(EmptyParentheses* expr) { |
UNREACHABLE(); |