pattern-rewriter.cc 28.8 KB
Newer Older
1 2 3 4
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
#include "src/ast/ast.h"
6
#include "src/messages.h"
7
#include "src/objects-inl.h"
8
#include "src/parsing/expression-scope-reparenter.h"
9
#include "src/parsing/parser.h"
10 11 12 13 14

namespace v8 {

namespace internal {

15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
class PatternRewriter final : public AstVisitor<PatternRewriter> {
 public:
  // Limit the allowed number of local variables in a function. The hard limit
  // is that offsets computed by FullCodeGenerator::StackOperand and similar
  // functions are ints, and they should not overflow. In addition, accessing
  // local variables creates user-controlled constants in the generated code,
  // and we don't want too much user-controlled memory inside the code (this was
  // the reason why this limit was introduced in the first place; see
  // https://codereview.chromium.org/7003030/ ).
  static const int kMaxNumFunctionLocals = 4194303;  // 2^22-1

  typedef Parser::DeclarationDescriptor DeclarationDescriptor;

  static void DeclareAndInitializeVariables(
      Parser* parser, Block* block,
      const DeclarationDescriptor* declaration_descriptor,
      const Parser::DeclarationParsingResult::Declaration* declaration,
      ZoneList<const AstRawString*>* names, bool* ok);

  static void RewriteDestructuringAssignment(Parser* parser,
                                             RewritableExpression* to_rewrite,
                                             Scope* scope);

 private:
39 40 41 42 43 44 45 46 47 48 49 50 51
  enum PatternContext { BINDING, ASSIGNMENT, ASSIGNMENT_ELEMENT };

  class AssignmentElementScope {
   public:
    explicit AssignmentElementScope(PatternRewriter* rewriter)
        : rewriter_(rewriter), context_(rewriter->context()) {
      if (context_ == ASSIGNMENT) rewriter->context_ = ASSIGNMENT_ELEMENT;
    }
    ~AssignmentElementScope() { rewriter_->context_ = context_; }

   private:
    PatternRewriter* const rewriter_;
    const PatternContext context_;
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
  };

  PatternRewriter(Scope* scope, Parser* parser, PatternContext context)
      : scope_(scope),
        parser_(parser),
        context_(context),
        initializer_position_(kNoSourcePosition),
        value_beg_position_(kNoSourcePosition),
        block_(nullptr),
        descriptor_(nullptr),
        names_(nullptr),
        current_value_(nullptr),
        recursion_level_(0),
        ok_(nullptr) {}

#define DECLARE_VISIT(type) void Visit##type(v8::internal::type* node);
  // Visiting functions for AST nodes make this an AstVisitor.
  AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT

  PatternContext context() const { return context_; }

  void RecurseIntoSubpattern(AstNode* pattern, Expression* value) {
    Expression* old_value = current_value_;
    current_value_ = value;
    recursion_level_++;
    Visit(pattern);
    recursion_level_--;
    current_value_ = old_value;
  }

  void VisitObjectLiteral(ObjectLiteral* node, Variable** temp_var);
  void VisitArrayLiteral(ArrayLiteral* node, Variable** temp_var);

86
  bool IsBindingContext() const { return context_ == BINDING; }
87
  bool IsAssignmentContext() const {
88
    return context_ == ASSIGNMENT || context_ == ASSIGNMENT_ELEMENT;
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
  }
  bool IsSubPattern() const { return recursion_level_ > 1; }

  bool DeclaresParameterContainingSloppyEval() const;
  void RewriteParameterScopes(Expression* expr);

  Variable* CreateTempVar(Expression* value = nullptr);

  AstNodeFactory* factory() const { return parser_->factory(); }
  AstValueFactory* ast_value_factory() const {
    return parser_->ast_value_factory();
  }
  Zone* zone() const { return parser_->zone(); }
  Scope* scope() const { return scope_; }

  Scope* const scope_;
  Parser* const parser_;
  PatternContext context_;
  int initializer_position_;
  int value_beg_position_;
  Block* block_;
  const DeclarationDescriptor* descriptor_;
  ZoneList<const AstRawString*>* names_;
  Expression* current_value_;
  int recursion_level_;
  bool* ok_;

  DEFINE_AST_VISITOR_MEMBERS_WITHOUT_STACKOVERFLOW()
};

void Parser::DeclareAndInitializeVariables(
    Block* block, const DeclarationDescriptor* declaration_descriptor,
121 122
    const DeclarationParsingResult::Declaration* declaration,
    ZoneList<const AstRawString*>* names, bool* ok) {
123 124 125 126
  PatternRewriter::DeclareAndInitializeVariables(
      this, block, declaration_descriptor, declaration, names, ok);
}

127 128
void Parser::RewriteDestructuringAssignment(RewritableExpression* to_rewrite) {
  PatternRewriter::RewriteDestructuringAssignment(this, to_rewrite, scope());
129 130 131 132 133
}

Expression* Parser::RewriteDestructuringAssignment(Assignment* assignment) {
  DCHECK_NOT_NULL(assignment);
  DCHECK_EQ(Token::ASSIGN, assignment->op());
134
  auto to_rewrite = factory()->NewRewritableExpression(assignment, scope());
135
  RewriteDestructuringAssignment(to_rewrite);
136 137
  return to_rewrite->expression();
}
138

139 140 141 142 143
void PatternRewriter::DeclareAndInitializeVariables(
    Parser* parser, Block* block,
    const DeclarationDescriptor* declaration_descriptor,
    const Parser::DeclarationParsingResult::Declaration* declaration,
    ZoneList<const AstRawString*>* names, bool* ok) {
144 145
  DCHECK(block->ignore_completion_value());

146
  PatternRewriter rewriter(declaration_descriptor->scope, parser, BINDING);
147
  rewriter.initializer_position_ = declaration->initializer_position;
148
  rewriter.value_beg_position_ = declaration->value_beg_position;
149 150 151 152
  rewriter.block_ = block;
  rewriter.descriptor_ = declaration_descriptor;
  rewriter.names_ = names;
  rewriter.ok_ = ok;
153

154 155
  rewriter.RecurseIntoSubpattern(declaration->pattern,
                                 declaration->initializer);
156 157
}

158
void PatternRewriter::RewriteDestructuringAssignment(
159
    Parser* parser, RewritableExpression* to_rewrite, Scope* scope) {
160
  DCHECK(!scope->HasBeenRemoved());
161 162
  DCHECK(!to_rewrite->is_rewritten());

163 164
  PatternRewriter rewriter(scope, parser, ASSIGNMENT);
  rewriter.RecurseIntoSubpattern(to_rewrite, nullptr);
165 166
}

167
void PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
168
  Expression* value = current_value_;
169 170 171 172 173 174

  if (IsAssignmentContext()) {
    // In an assignment context, simply perform the assignment
    Assignment* assignment = factory()->NewAssignment(
        Token::ASSIGN, pattern, value, pattern->position());
    block_->statements()->Add(
175
        factory()->NewExpressionStatement(assignment, pattern->position()),
176 177 178 179
        zone());
    return;
  }

180 181 182 183
  DCHECK_NOT_NULL(block_);
  DCHECK_NOT_NULL(descriptor_);
  DCHECK_NOT_NULL(ok_);

184
  descriptor_->scope->RemoveUnresolved(pattern);
185 186 187 188 189 190 191 192 193 194

  // Declare variable.
  // Note that we *always* must treat the initial value via a separate init
  // assignment for variables and constants because the value must be assigned
  // when the variable is encountered in the source. But the variable/constant
  // is declared (and set to 'undefined') upon entering the function within
  // which the variable or constant is declared. Only function variables have
  // an initial value in the declaration (because they are initialized upon
  // entering the function).
  const AstRawString* name = pattern->raw_name();
195 196
  VariableProxy* proxy =
      factory()->NewVariableProxy(name, NORMAL_VARIABLE, pattern->position());
197 198 199 200 201 202 203 204 205 206
  Declaration* declaration;
  if (descriptor_->mode == VAR && !descriptor_->scope->is_declaration_scope()) {
    DCHECK(descriptor_->scope->is_block_scope() ||
           descriptor_->scope->is_with_scope());
    declaration = factory()->NewNestedVariableDeclaration(
        proxy, descriptor_->scope, descriptor_->declaration_pos);
  } else {
    declaration =
        factory()->NewVariableDeclaration(proxy, descriptor_->declaration_pos);
  }
207 208 209 210 211 212 213 214 215

  // When an extra declaration scope needs to be inserted to account for
  // a sloppy eval in a default parameter or function body, the parameter
  // needs to be declared in the function's scope, not in the varblock
  // scope which will be used for the initializer expression.
  Scope* outer_function_scope = nullptr;
  if (DeclaresParameterContainingSloppyEval()) {
    outer_function_scope = descriptor_->scope->outer_scope();
  }
216 217 218
  Variable* var = parser_->Declare(
      declaration, descriptor_->declaration_kind, descriptor_->mode,
      Variable::DefaultInitializationFlag(descriptor_->mode), ok_,
219
      outer_function_scope);
220 221
  if (!*ok_) return;
  DCHECK_NOT_NULL(var);
222
  DCHECK(proxy->is_resolved());
223
  DCHECK_NE(initializer_position_, kNoSourcePosition);
224
  var->set_initializer_position(initializer_position_);
225

226 227 228 229 230 231
  Scope* declaration_scope =
      outer_function_scope != nullptr
          ? outer_function_scope
          : (IsLexicalVariableMode(descriptor_->mode)
                 ? descriptor_->scope
                 : descriptor_->scope->GetDeclarationScope());
232
  if (declaration_scope->num_var() > kMaxNumFunctionLocals) {
233
    parser_->ReportMessage(MessageTemplate::kTooManyVariables);
234 235 236
    *ok_ = false;
    return;
  }
237 238
  if (names_) {
    names_->Add(name, zone());
239 240
  }

241 242 243
  // If there's no initializer, we're done.
  if (value == nullptr) return;

244
  Scope* var_init_scope = descriptor_->scope;
245 246
  Parser::MarkLoopVariableAsAssigned(var_init_scope, proxy->var(),
                                     descriptor_->declaration_kind);
247

248
  // A declaration of the form:
249 250 251 252 253 254 255
  //
  //    var v = x;
  //
  // is syntactic sugar for:
  //
  //    var v; v = x;
  //
256 257 258 259 260
  // In particular, we need to re-lookup 'v' as it may be a different
  // 'v' than the 'v' in the declaration (e.g., if we are inside a
  // 'with' statement or 'catch' block). Global var declarations
  // also need special treatment.

261 262 263 264 265
  // For 'let' and 'const' declared variables the initialization always
  // assigns to the declared variable.
  // But for var declarations we need to do a new lookup.
  if (descriptor_->mode == VAR) {
    proxy = var_init_scope->NewUnresolved(factory(), name);
266
  } else {
267 268 269 270 271 272 273
    DCHECK_NOT_NULL(proxy);
    DCHECK_NOT_NULL(proxy->var());
  }
  // Add break location for destructured sub-pattern.
  int pos = value_beg_position_;
  if (pos == kNoSourcePosition) {
    pos = IsSubPattern() ? pattern->position() : value->position();
274
  }
275 276 277 278
  Assignment* assignment =
      factory()->NewAssignment(Token::INIT, proxy, value, pos);
  block_->statements()->Add(factory()->NewExpressionStatement(assignment, pos),
                            zone());
279 280
}

281
Variable* PatternRewriter::CreateTempVar(Expression* value) {
282
  auto temp = scope()->NewTemporary(ast_value_factory()->empty_string());
283 284 285
  if (value != nullptr) {
    auto assignment = factory()->NewAssignment(
        Token::ASSIGN, factory()->NewVariableProxy(temp), value,
yangguo's avatar
yangguo committed
286
        kNoSourcePosition);
287

neis's avatar
neis committed
288
    block_->statements()->Add(
yangguo's avatar
yangguo committed
289
        factory()->NewExpressionStatement(assignment, kNoSourcePosition),
290 291
        zone());
  }
292 293 294
  return temp;
}

295
void PatternRewriter::VisitRewritableExpression(RewritableExpression* node) {
296 297 298 299 300 301 302 303
  if (!node->expression()->IsAssignment()) {
    // RewritableExpressions are also used for desugaring Spread, which is
    // orthogonal to PatternRewriter; just visit the underlying expression.
    DCHECK_EQ(AstNode::kArrayLiteral, node->expression()->node_type());
    return Visit(node->expression());
  } else if (context() != ASSIGNMENT) {
    // This is not a destructuring assignment. Mark the node as rewritten to
    // prevent redundant rewriting and visit the underlying expression.
304 305
    DCHECK(!node->is_rewritten());
    node->set_rewritten();
306
    return Visit(node->expression());
307
  }
308

309 310
  DCHECK(!node->is_rewritten());
  DCHECK_EQ(ASSIGNMENT, context());
311 312 313 314 315 316
  Assignment* assign = node->expression()->AsAssignment();
  DCHECK_NOT_NULL(assign);
  DCHECK_EQ(Token::ASSIGN, assign->op());

  int pos = assign->position();
  Block* old_block = block_;
317
  block_ = factory()->NewBlock(8, true);
318 319 320
  Variable* temp = nullptr;
  Expression* pattern = assign->target();
  Expression* old_value = current_value_;
321
  current_value_ = assign->value();
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
  if (pattern->IsObjectLiteral()) {
    VisitObjectLiteral(pattern->AsObjectLiteral(), &temp);
  } else {
    DCHECK(pattern->IsArrayLiteral());
    VisitArrayLiteral(pattern->AsArrayLiteral(), &temp);
  }
  DCHECK_NOT_NULL(temp);
  current_value_ = old_value;
  Expression* expr = factory()->NewDoExpression(block_, temp, pos);
  node->Rewrite(expr);
  block_ = old_block;
  if (block_) {
    block_->statements()->Add(factory()->NewExpressionStatement(expr, pos),
                              zone());
  }
}

339
bool PatternRewriter::DeclaresParameterContainingSloppyEval() const {
340 341 342 343
  // Need to check for a binding context to make sure we have a descriptor.
  if (IsBindingContext() &&
      // Only relevant for parameters.
      descriptor_->declaration_kind == DeclarationDescriptor::PARAMETER &&
344 345 346 347
      // And only when scope is a block scope;
      // without eval, it is a function scope.
      scope()->is_block_scope()) {
    DCHECK(scope()->is_declaration_scope());
348
    DCHECK(scope()->AsDeclarationScope()->calls_sloppy_eval());
349 350 351 352 353 354 355
    DCHECK(scope()->outer_scope()->is_function_scope());
    return true;
  }

  return false;
}

356 357 358 359
// When an extra declaration scope needs to be inserted to account for
// a sloppy eval in a default parameter or function body, the expressions
// needs to be in that new inner scope which was added after initial
// parsing.
360
void PatternRewriter::RewriteParameterScopes(Expression* expr) {
361
  if (DeclaresParameterContainingSloppyEval()) {
362
    ReparentExpressionScope(parser_->stack_limit(), expr, scope());
363
  }
364
}
365

366 367
void PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern,
                                         Variable** temp_var) {
368 369
  auto temp = *temp_var = CreateTempVar(current_value_);

370 371 372 373 374 375 376 377 378 379 380
  ZoneList<Expression*>* rest_runtime_callargs = nullptr;
  if (pattern->has_rest_property()) {
    // non_rest_properties_count = pattern->properties()->length - 1;
    // args_length = 1 + non_rest_properties_count because we need to
    // pass temp as well to the runtime function.
    int args_length = pattern->properties()->length();
    rest_runtime_callargs =
        new (zone()) ZoneList<Expression*>(args_length, zone());
    rest_runtime_callargs->Add(factory()->NewVariableProxy(temp), zone());
  }

381 382
  block_->statements()->Add(parser_->BuildAssertIsCoercible(temp, pattern),
                            zone());
383

384
  for (ObjectLiteralProperty* property : *pattern->properties()) {
385 386 387 388 389
    Expression* value;

    if (property->kind() == ObjectLiteralProperty::Kind::SPREAD) {
      // var { y, [x++]: a, ...c } = temp
      //     becomes
390 391 392
      // var y = temp.y;
      // var temp1 = %ToName(x++);
      // var a = temp[temp1];
393
      // var c;
394
      // c = %CopyDataPropertiesWithExcludedProperties(temp, "y", temp1);
395 396 397 398 399 400 401 402 403 404 405 406 407
      value = factory()->NewCallRuntime(
          Runtime::kCopyDataPropertiesWithExcludedProperties,
          rest_runtime_callargs, kNoSourcePosition);
    } else {
      Expression* key = property->key();

      if (!key->IsLiteral()) {
        // Computed property names contain expressions which might require
        // scope rewriting.
        RewriteParameterScopes(key);
      }

      if (pattern->has_rest_property()) {
408 409 410 411 412 413 414 415 416 417 418 419 420
        Expression* excluded_property = key;

        if (property->is_computed_name()) {
          DCHECK(!key->IsPropertyName() || !key->IsNumberLiteral());
          auto args = new (zone()) ZoneList<Expression*>(1, zone());
          args->Add(key, zone());
          auto to_name_key = CreateTempVar(factory()->NewCallRuntime(
              Runtime::kToName, args, kNoSourcePosition));
          key = factory()->NewVariableProxy(to_name_key);
          excluded_property = factory()->NewVariableProxy(to_name_key);
        } else {
          DCHECK(key->IsPropertyName() || key->IsNumberLiteral());
        }
421

422
        DCHECK_NOT_NULL(rest_runtime_callargs);
423
        rest_runtime_callargs->Add(excluded_property, zone());
424
      }
425

426 427 428
      value = factory()->NewProperty(factory()->NewVariableProxy(temp), key,
                                     kNoSourcePosition);
    }
429

430
    AssignmentElementScope element_scope(this);
431
    RecurseIntoSubpattern(property->value(), value);
432 433 434
  }
}

435
void PatternRewriter::VisitObjectLiteral(ObjectLiteral* node) {
436 437 438 439
  Variable* temp_var = nullptr;
  VisitObjectLiteral(node, &temp_var);
}

440 441
void PatternRewriter::VisitArrayLiteral(ArrayLiteral* node,
                                        Variable** temp_var) {
442
  DCHECK(block_->ignore_completion_value());
443

444
  auto temp = *temp_var = CreateTempVar(current_value_);
445
  auto iterator = CreateTempVar(factory()->NewGetIterator(
446
      factory()->NewVariableProxy(temp), current_value_, IteratorType::kNormal,
447
      current_value_->position()));
448 449 450 451 452
  auto next = CreateTempVar(factory()->NewProperty(
      factory()->NewVariableProxy(iterator),
      factory()->NewStringLiteral(ast_value_factory()->next_string(),
                                  kNoSourcePosition),
      kNoSourcePosition));
yangguo's avatar
yangguo committed
453 454
  auto done =
      CreateTempVar(factory()->NewBooleanLiteral(false, kNoSourcePosition));
455 456
  auto result = CreateTempVar();
  auto v = CreateTempVar();
457
  auto completion = CreateTempVar();
yangguo's avatar
yangguo committed
458
  auto nopos = kNoSourcePosition;
459 460 461 462 463 464 465

  // For the purpose of iterator finalization, we temporarily set block_ to a
  // new block.  In the main body of this function, we write to block_ (both
  // explicitly and implicitly via recursion).  At the end of the function, we
  // wrap this new block in a try-finally statement, restore block_ to its
  // original value, and add the try-finally statement to block_.
  auto target = block_;
466
  block_ = factory()->NewBlock(8, true);
467 468

  Spread* spread = nullptr;
469
  for (Expression* value : *node->values()) {
470 471 472 473 474
    if (value->IsSpread()) {
      spread = value->AsSpread();
      break;
    }

475
    // if (!done) {
476
    //   done = true;  // If .next, .done or .value throws, don't close.
477
    //   result = IteratorNext(iterator);
478 479 480 481 482 483
    //   if (result.done) {
    //     v = undefined;
    //   } else {
    //     v = result.value;
    //     done = false;
    //   }
484
    // }
485
    Statement* if_not_done;
486
    {
487 488 489
      auto result_done = factory()->NewProperty(
          factory()->NewVariableProxy(result),
          factory()->NewStringLiteral(ast_value_factory()->done_string(),
yangguo's avatar
yangguo committed
490 491
                                      kNoSourcePosition),
          kNoSourcePosition);
492 493 494

      auto assign_undefined = factory()->NewAssignment(
          Token::ASSIGN, factory()->NewVariableProxy(v),
yangguo's avatar
yangguo committed
495
          factory()->NewUndefinedLiteral(kNoSourcePosition), kNoSourcePosition);
496 497 498 499 500 501

      auto assign_value = factory()->NewAssignment(
          Token::ASSIGN, factory()->NewVariableProxy(v),
          factory()->NewProperty(
              factory()->NewVariableProxy(result),
              factory()->NewStringLiteral(ast_value_factory()->value_string(),
yangguo's avatar
yangguo committed
502 503 504
                                          kNoSourcePosition),
              kNoSourcePosition),
          kNoSourcePosition);
505 506 507

      auto unset_done = factory()->NewAssignment(
          Token::ASSIGN, factory()->NewVariableProxy(done),
yangguo's avatar
yangguo committed
508 509
          factory()->NewBooleanLiteral(false, kNoSourcePosition),
          kNoSourcePosition);
510

511
      auto inner_else = factory()->NewBlock(2, true);
512 513 514 515 516 517 518 519 520 521
      inner_else->statements()->Add(
          factory()->NewExpressionStatement(assign_value, nopos), zone());
      inner_else->statements()->Add(
          factory()->NewExpressionStatement(unset_done, nopos), zone());

      auto inner_if = factory()->NewIfStatement(
          result_done,
          factory()->NewExpressionStatement(assign_undefined, nopos),
          inner_else, nopos);

522
      auto next_block = factory()->NewBlock(3, true);
523 524 525 526 527 528 529 530 531 532
      next_block->statements()->Add(
          factory()->NewExpressionStatement(
              factory()->NewAssignment(
                  Token::ASSIGN, factory()->NewVariableProxy(done),
                  factory()->NewBooleanLiteral(true, nopos), nopos),
              nopos),
          zone());
      next_block->statements()->Add(
          factory()->NewExpressionStatement(
              parser_->BuildIteratorNextResult(
533 534
                  factory()->NewVariableProxy(iterator),
                  factory()->NewVariableProxy(next), result,
535
                  IteratorType::kNormal, kNoSourcePosition),
yangguo's avatar
yangguo committed
536
              kNoSourcePosition),
537
          zone());
538
      next_block->statements()->Add(inner_if, zone());
539

540
      if_not_done = factory()->NewIfStatement(
yangguo's avatar
yangguo committed
541 542 543 544
          factory()->NewUnaryOperation(
              Token::NOT, factory()->NewVariableProxy(done), kNoSourcePosition),
          next_block, factory()->NewEmptyStatement(kNoSourcePosition),
          kNoSourcePosition);
545
    }
546
    block_->statements()->Add(if_not_done, zone());
547

548
    if (!value->IsTheHoleLiteral()) {
549
      {
550 551 552 553
        // completion = kAbruptCompletion;
        Expression* proxy = factory()->NewVariableProxy(completion);
        Expression* assignment = factory()->NewAssignment(
            Token::ASSIGN, proxy,
554
            factory()->NewSmiLiteral(Parser::kAbruptCompletion, nopos), nopos);
555 556 557 558
        block_->statements()->Add(
            factory()->NewExpressionStatement(assignment, nopos), zone());
      }

559 560 561 562
      {
        AssignmentElementScope element_scope(this);
        RecurseIntoSubpattern(value, factory()->NewVariableProxy(v));
      }
563

564
      {
565 566 567 568
        // completion = kNormalCompletion;
        Expression* proxy = factory()->NewVariableProxy(completion);
        Expression* assignment = factory()->NewAssignment(
            Token::ASSIGN, proxy,
569
            factory()->NewSmiLiteral(Parser::kNormalCompletion, nopos), nopos);
570 571 572
        block_->statements()->Add(
            factory()->NewExpressionStatement(assignment, nopos), zone());
      }
573 574
    }
  }
575 576

  if (spread != nullptr) {
577 578 579 580
    // A spread can only occur as the last component.  It is not handled by
    // RecurseIntoSubpattern above.

    // let array = [];
581
    // let index = 0;
582
    // while (!done) {
583
    //   done = true;  // If .next, .done or .value throws, don't close.
584
    //   result = IteratorNext(iterator);
585
    //   if (!result.done) {
586
    //     StoreInArrayLiteral(array, index, result.value);
587
    //     done = false;
588
    //   }
589
    //   index++;
590 591 592 593 594 595
    // }

    // let array = [];
    Variable* array;
    {
      auto empty_exprs = new (zone()) ZoneList<Expression*>(0, zone());
596 597
      array = CreateTempVar(
          factory()->NewArrayLiteral(empty_exprs, kNoSourcePosition));
598 599
    }

600 601 602 603
    // let index = 0;
    Variable* index =
        CreateTempVar(factory()->NewSmiLiteral(0, kNoSourcePosition));

604
    // done = true;
605 606 607 608 609 610
    Statement* set_done = factory()->NewExpressionStatement(
        factory()->NewAssignment(
            Token::ASSIGN, factory()->NewVariableProxy(done),
            factory()->NewBooleanLiteral(true, nopos), nopos),
        nopos);

611 612 613
    // result = IteratorNext(iterator);
    Statement* get_next = factory()->NewExpressionStatement(
        parser_->BuildIteratorNextResult(factory()->NewVariableProxy(iterator),
614
                                         factory()->NewVariableProxy(next),
615
                                         result, IteratorType::kNormal, nopos),
616 617
        nopos);

618 619
    // StoreInArrayLiteral(array, index, result.value);
    Statement* store;
620
    {
621 622 623 624 625 626 627 628 629
      auto value = factory()->NewProperty(
          factory()->NewVariableProxy(result),
          factory()->NewStringLiteral(ast_value_factory()->value_string(),
                                      nopos),
          nopos);
      store = factory()->NewExpressionStatement(
          factory()->NewStoreInArrayLiteral(factory()->NewVariableProxy(array),
                                            factory()->NewVariableProxy(index),
                                            value, nopos),
630 631
          nopos);
    }
632

633 634 635 636 637 638 639
    // done = false;
    Statement* unset_done = factory()->NewExpressionStatement(
        factory()->NewAssignment(
            Token::ASSIGN, factory()->NewVariableProxy(done),
            factory()->NewBooleanLiteral(false, nopos), nopos),
        nopos);

640 641
    // if (!result.done) { #store; #unset_done }
    Statement* maybe_store_and_unset_done;
642 643 644 645 646 647
    {
      Expression* result_done =
          factory()->NewProperty(factory()->NewVariableProxy(result),
                                 factory()->NewStringLiteral(
                                     ast_value_factory()->done_string(), nopos),
                                 nopos);
648

649
      Block* then = factory()->NewBlock(2, true);
650
      then->statements()->Add(store, zone());
651 652
      then->statements()->Add(unset_done, zone());

653
      maybe_store_and_unset_done = factory()->NewIfStatement(
654 655
          factory()->NewUnaryOperation(Token::NOT, result_done, nopos), then,
          factory()->NewEmptyStatement(nopos), nopos);
656
    }
657

658 659 660 661 662 663 664 665 666
    // index++;
    Statement* increment_index;
    {
      increment_index = factory()->NewExpressionStatement(
          factory()->NewCountOperation(
              Token::INC, false, factory()->NewVariableProxy(index), nopos),
          nopos);
    }

667
    // while (!done) {
668
    //   #set_done;
669
    //   #get_next;
670 671
    //   #maybe_store_and_unset_done;
    //   #increment_index;
672 673 674 675 676
    // }
    WhileStatement* loop = factory()->NewWhileStatement(nullptr, nopos);
    {
      Expression* condition = factory()->NewUnaryOperation(
          Token::NOT, factory()->NewVariableProxy(done), nopos);
677
      Block* body = factory()->NewBlock(4, true);
678
      body->statements()->Add(set_done, zone());
679
      body->statements()->Add(get_next, zone());
680 681
      body->statements()->Add(maybe_store_and_unset_done, zone());
      body->statements()->Add(increment_index, zone());
682 683
      loop->Initialize(condition, body);
    }
684

685
    block_->statements()->Add(loop, zone());
686 687 688
    RecurseIntoSubpattern(spread->expression(),
                          factory()->NewVariableProxy(array));
  }
689

690 691
  Expression* closing_condition = factory()->NewUnaryOperation(
      Token::NOT, factory()->NewVariableProxy(done), nopos);
692

693 694
  parser_->FinalizeIteratorUse(completion, closing_condition, iterator, block_,
                               target, IteratorType::kNormal);
695
  block_ = target;
696 697
}

698
void PatternRewriter::VisitArrayLiteral(ArrayLiteral* node) {
699 700 701 702
  Variable* temp_var = nullptr;
  VisitArrayLiteral(node, &temp_var);
}

703
void PatternRewriter::VisitAssignment(Assignment* node) {
704 705 706 707
  // let {<pattern> = <init>} = <value>
  //   becomes
  // temp = <value>;
  // <pattern> = temp === undefined ? <init> : temp;
708 709
  DCHECK_EQ(Token::ASSIGN, node->op());

710 711 712 713
  // Rewriting of Assignment nodes for destructuring assignment
  // is handled in VisitRewritableExpression().
  DCHECK_NE(ASSIGNMENT, context());

714 715
  auto initializer = node->value();
  auto value = initializer;
716
  auto temp = CreateTempVar(current_value_);
717

718 719 720 721 722 723
  Expression* is_undefined = factory()->NewCompareOperation(
      Token::EQ_STRICT, factory()->NewVariableProxy(temp),
      factory()->NewUndefinedLiteral(kNoSourcePosition), kNoSourcePosition);
  value = factory()->NewConditional(is_undefined, initializer,
                                    factory()->NewVariableProxy(temp),
                                    kNoSourcePosition);
724

725 726
  // Initializer may have been parsed in the wrong scope.
  RewriteParameterScopes(initializer);
727

728
  RecurseIntoSubpattern(node->target(), value);
729 730 731 732 733
}


// =============== AssignmentPattern only ==================

734
void PatternRewriter::VisitProperty(v8::internal::Property* node) {
735 736 737 738 739 740 741
  DCHECK(IsAssignmentContext());
  auto value = current_value_;

  Assignment* assignment =
      factory()->NewAssignment(Token::ASSIGN, node, value, node->position());

  block_->statements()->Add(
yangguo's avatar
yangguo committed
742
      factory()->NewExpressionStatement(assignment, kNoSourcePosition), zone());
743 744 745 746 747
}


// =============== UNREACHABLE =============================

748 749
#define NOT_A_PATTERN(Node) \
  void PatternRewriter::Visit##Node(v8::internal::Node*) { UNREACHABLE(); }
750 751

NOT_A_PATTERN(BinaryOperation)
752
NOT_A_PATTERN(NaryOperation)
753 754 755 756 757 758 759
NOT_A_PATTERN(Block)
NOT_A_PATTERN(BreakStatement)
NOT_A_PATTERN(Call)
NOT_A_PATTERN(CallNew)
NOT_A_PATTERN(CallRuntime)
NOT_A_PATTERN(ClassLiteral)
NOT_A_PATTERN(CompareOperation)
760
NOT_A_PATTERN(CompoundAssignment)
761 762 763 764
NOT_A_PATTERN(Conditional)
NOT_A_PATTERN(ContinueStatement)
NOT_A_PATTERN(CountOperation)
NOT_A_PATTERN(DebuggerStatement)
765
NOT_A_PATTERN(DoExpression)
766 767
NOT_A_PATTERN(DoWhileStatement)
NOT_A_PATTERN(EmptyStatement)
768
NOT_A_PATTERN(EmptyParentheses)
769 770 771 772 773 774
NOT_A_PATTERN(ExpressionStatement)
NOT_A_PATTERN(ForInStatement)
NOT_A_PATTERN(ForOfStatement)
NOT_A_PATTERN(ForStatement)
NOT_A_PATTERN(FunctionDeclaration)
NOT_A_PATTERN(FunctionLiteral)
775
NOT_A_PATTERN(GetIterator)
776
NOT_A_PATTERN(GetTemplateObject)
777
NOT_A_PATTERN(IfStatement)
778
NOT_A_PATTERN(ImportCallExpression)
779 780 781
NOT_A_PATTERN(Literal)
NOT_A_PATTERN(NativeFunctionLiteral)
NOT_A_PATTERN(RegExpLiteral)
782
NOT_A_PATTERN(ResolvedProperty)
783
NOT_A_PATTERN(ReturnStatement)
784 785
NOT_A_PATTERN(SloppyBlockFunctionStatement)
NOT_A_PATTERN(Spread)
786
NOT_A_PATTERN(StoreInArrayLiteral)
787 788
NOT_A_PATTERN(SuperPropertyReference)
NOT_A_PATTERN(SuperCallReference)
789
NOT_A_PATTERN(SwitchStatement)
790
NOT_A_PATTERN(TemplateLiteral)
791 792 793 794 795 796 797 798
NOT_A_PATTERN(ThisFunction)
NOT_A_PATTERN(Throw)
NOT_A_PATTERN(TryCatchStatement)
NOT_A_PATTERN(TryFinallyStatement)
NOT_A_PATTERN(UnaryOperation)
NOT_A_PATTERN(VariableDeclaration)
NOT_A_PATTERN(WhileStatement)
NOT_A_PATTERN(WithStatement)
799
NOT_A_PATTERN(Yield)
800
NOT_A_PATTERN(YieldStar)
801
NOT_A_PATTERN(Await)
802
NOT_A_PATTERN(InitializeClassFieldsStatement)
803 804

#undef NOT_A_PATTERN
805 806
}  // namespace internal
}  // namespace v8