| Index: src/interpreter/bytecode-generator.cc
|
| diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc
|
| index 1200cacd0707baeb4b9dbaf7ffbb079fc94479ad..45acc9991273a5c3234ff8f60e33281009257188 100644
|
| --- a/src/interpreter/bytecode-generator.cc
|
| +++ b/src/interpreter/bytecode-generator.cc
|
| @@ -2486,24 +2486,68 @@ 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);
|
| + ZoneList<Expression*>* args = expr->arguments();
|
| + RegisterList args_regs =
|
| + register_allocator()->NewRegisterList(args->length());
|
| +
|
| + bool has_spread = false;
|
| + for (int i = 0; i < args->length(); i++) {
|
| + if (args->at(i)->IsSpread()) has_spread = true;
|
| + }
|
| +
|
| + if (has_spread) {
|
| + // Pre-allocate regs for ReflectConstruct so we can use them.
|
| + RegisterList reflect_construct_args =
|
| + register_allocator()->NewRegisterList(4);
|
| +
|
| + // Deal with the spread arg
|
| + if (args->length() == 1) {
|
| + Register spread_array = VisitForRegisterValue(
|
| + args->at(args->length() - 1)->AsSpread()->expression());
|
| + Runtime::FunctionId function_id = Runtime::kSpreadIterablePrepare;
|
| + builder()->CallRuntime(function_id, spread_array);
|
| + } else {
|
| + RegisterList spread_prepare_args =
|
| + register_allocator()->NewRegisterList(args->length());
|
| + // visit args at 0 --> length -2 inclusive
|
| + for (int i = 0; i < args->length() - 1; i++) {
|
| + VisitForRegisterValue(args->at(i), spread_prepare_args[i]);
|
| + }
|
| + // visit the spread
|
| + VisitForRegisterValue(
|
| + args->at(args->length() - 1)->AsSpread()->expression(),
|
| + spread_prepare_args[args->length() - 1]);
|
|
|
| - // The new target is loaded into the accumulator from the
|
| - // {new.target} variable.
|
| - VisitForAccumulatorValue(super->new_target_var());
|
| + Runtime::FunctionId function_id = Runtime::kSpreadIterablePrepareVarArgs;
|
| + builder()->CallRuntime(function_id, spread_prepare_args);
|
| + }
|
|
|
| - // 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);
|
| + builder()->StoreAccumulatorInRegister(reflect_construct_args[2]);
|
| +
|
| + // Do ReflectConstruct
|
| + Register receiver = reflect_construct_args[0];
|
| + builder()->LoadUndefined().StoreAccumulatorInRegister(receiver);
|
| + builder()->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 {
|
| + 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) {
|
|
|