• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
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 namespace v8 {
12 
13 namespace internal {
14 
15 class PatternRewriter final : public AstVisitor<PatternRewriter> {
16  public:
17   // Limit the allowed number of local variables in a function. The hard limit
18   // is that offsets computed by FullCodeGenerator::StackOperand and similar
19   // functions are ints, and they should not overflow. In addition, accessing
20   // local variables creates user-controlled constants in the generated code,
21   // and we don't want too much user-controlled memory inside the code (this was
22   // the reason why this limit was introduced in the first place; see
23   // https://codereview.chromium.org/7003030/ ).
24   static const int kMaxNumFunctionLocals = 4194303;  // 2^22-1
25 
26   typedef Parser::DeclarationDescriptor DeclarationDescriptor;
27 
28   static void DeclareAndInitializeVariables(
29       Parser* parser, Block* block,
30       const DeclarationDescriptor* declaration_descriptor,
31       const Parser::DeclarationParsingResult::Declaration* declaration,
32       ZonePtrList<const AstRawString>* names, bool* ok);
33 
34   static void RewriteDestructuringAssignment(Parser* parser,
35                                              RewritableExpression* to_rewrite,
36                                              Scope* scope);
37 
38  private:
39   enum PatternContext { BINDING, ASSIGNMENT, ASSIGNMENT_ELEMENT };
40 
41   class AssignmentElementScope {
42    public:
AssignmentElementScope(PatternRewriter * rewriter)43     explicit AssignmentElementScope(PatternRewriter* rewriter)
44         : rewriter_(rewriter), context_(rewriter->context()) {
45       if (context_ == ASSIGNMENT) rewriter->context_ = ASSIGNMENT_ELEMENT;
46     }
~AssignmentElementScope()47     ~AssignmentElementScope() { rewriter_->context_ = context_; }
48 
49    private:
50     PatternRewriter* const rewriter_;
51     const PatternContext context_;
52   };
53 
PatternRewriter(Scope * scope,Parser * parser,PatternContext context)54   PatternRewriter(Scope* scope, Parser* parser, PatternContext context)
55       : scope_(scope),
56         parser_(parser),
57         context_(context),
58         initializer_position_(kNoSourcePosition),
59         value_beg_position_(kNoSourcePosition),
60         block_(nullptr),
61         descriptor_(nullptr),
62         names_(nullptr),
63         current_value_(nullptr),
64         recursion_level_(0),
65         ok_(nullptr) {}
66 
67 #define DECLARE_VISIT(type) void Visit##type(v8::internal::type* node);
68   // Visiting functions for AST nodes make this an AstVisitor.
AST_NODE_LIST(DECLARE_VISIT)69   AST_NODE_LIST(DECLARE_VISIT)
70 #undef DECLARE_VISIT
71 
72   PatternContext context() const { return context_; }
73 
RecurseIntoSubpattern(AstNode * pattern,Expression * value)74   void RecurseIntoSubpattern(AstNode* pattern, Expression* value) {
75     Expression* old_value = current_value_;
76     current_value_ = value;
77     recursion_level_++;
78     Visit(pattern);
79     recursion_level_--;
80     current_value_ = old_value;
81   }
82 
83   void VisitObjectLiteral(ObjectLiteral* node, Variable** temp_var);
84   void VisitArrayLiteral(ArrayLiteral* node, Variable** temp_var);
85 
IsBindingContext() const86   bool IsBindingContext() const { return context_ == BINDING; }
IsAssignmentContext() const87   bool IsAssignmentContext() const {
88     return context_ == ASSIGNMENT || context_ == ASSIGNMENT_ELEMENT;
89   }
IsSubPattern() const90   bool IsSubPattern() const { return recursion_level_ > 1; }
91 
92   bool DeclaresParameterContainingSloppyEval() const;
93   void RewriteParameterScopes(Expression* expr);
94 
95   Variable* CreateTempVar(Expression* value = nullptr);
96 
factory() const97   AstNodeFactory* factory() const { return parser_->factory(); }
ast_value_factory() const98   AstValueFactory* ast_value_factory() const {
99     return parser_->ast_value_factory();
100   }
zone() const101   Zone* zone() const { return parser_->zone(); }
scope() const102   Scope* scope() const { return scope_; }
103 
104   Scope* const scope_;
105   Parser* const parser_;
106   PatternContext context_;
107   int initializer_position_;
108   int value_beg_position_;
109   Block* block_;
110   const DeclarationDescriptor* descriptor_;
111   ZonePtrList<const AstRawString>* names_;
112   Expression* current_value_;
113   int recursion_level_;
114   bool* ok_;
115 
116   DEFINE_AST_VISITOR_MEMBERS_WITHOUT_STACKOVERFLOW()
117 };
118 
DeclareAndInitializeVariables(Block * block,const DeclarationDescriptor * declaration_descriptor,const DeclarationParsingResult::Declaration * declaration,ZonePtrList<const AstRawString> * names,bool * ok)119 void Parser::DeclareAndInitializeVariables(
120     Block* block, const DeclarationDescriptor* declaration_descriptor,
121     const DeclarationParsingResult::Declaration* declaration,
122     ZonePtrList<const AstRawString>* names, bool* ok) {
123   PatternRewriter::DeclareAndInitializeVariables(
124       this, block, declaration_descriptor, declaration, names, ok);
125 }
126 
RewriteDestructuringAssignment(RewritableExpression * to_rewrite)127 void Parser::RewriteDestructuringAssignment(RewritableExpression* to_rewrite) {
128   PatternRewriter::RewriteDestructuringAssignment(this, to_rewrite, scope());
129 }
130 
RewriteDestructuringAssignment(Assignment * assignment)131 Expression* Parser::RewriteDestructuringAssignment(Assignment* assignment) {
132   DCHECK_NOT_NULL(assignment);
133   DCHECK_EQ(Token::ASSIGN, assignment->op());
134   auto to_rewrite = factory()->NewRewritableExpression(assignment, scope());
135   RewriteDestructuringAssignment(to_rewrite);
136   return to_rewrite->expression();
137 }
138 
DeclareAndInitializeVariables(Parser * parser,Block * block,const DeclarationDescriptor * declaration_descriptor,const Parser::DeclarationParsingResult::Declaration * declaration,ZonePtrList<const AstRawString> * names,bool * ok)139 void PatternRewriter::DeclareAndInitializeVariables(
140     Parser* parser, Block* block,
141     const DeclarationDescriptor* declaration_descriptor,
142     const Parser::DeclarationParsingResult::Declaration* declaration,
143     ZonePtrList<const AstRawString>* names, bool* ok) {
144   DCHECK(block->ignore_completion_value());
145 
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   rewriter.block_ = block;
150   rewriter.descriptor_ = declaration_descriptor;
151   rewriter.names_ = names;
152   rewriter.ok_ = ok;
153 
154   rewriter.RecurseIntoSubpattern(declaration->pattern,
155                                  declaration->initializer);
156 }
157 
RewriteDestructuringAssignment(Parser * parser,RewritableExpression * to_rewrite,Scope * scope)158 void PatternRewriter::RewriteDestructuringAssignment(
159     Parser* parser, RewritableExpression* to_rewrite, Scope* scope) {
160   DCHECK(!scope->HasBeenRemoved());
161   DCHECK(!to_rewrite->is_rewritten());
162 
163   PatternRewriter rewriter(scope, parser, ASSIGNMENT);
164   rewriter.RecurseIntoSubpattern(to_rewrite, nullptr);
165 }
166 
VisitVariableProxy(VariableProxy * pattern)167 void PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
168   Expression* value = current_value_;
169 
170   if (IsAssignmentContext()) {
171     // In an assignment context, simply perform the assignment
172     Assignment* assignment = factory()->NewAssignment(
173         Token::ASSIGN, pattern, value, pattern->position());
174     block_->statements()->Add(
175         factory()->NewExpressionStatement(assignment, pattern->position()),
176         zone());
177     return;
178   }
179 
180   DCHECK_NOT_NULL(block_);
181   DCHECK_NOT_NULL(descriptor_);
182   DCHECK_NOT_NULL(ok_);
183 
184   descriptor_->scope->RemoveUnresolved(pattern);
185 
186   // Declare variable.
187   // Note that we *always* must treat the initial value via a separate init
188   // assignment for variables and constants because the value must be assigned
189   // when the variable is encountered in the source. But the variable/constant
190   // is declared (and set to 'undefined') upon entering the function within
191   // which the variable or constant is declared. Only function variables have
192   // an initial value in the declaration (because they are initialized upon
193   // entering the function).
194   const AstRawString* name = pattern->raw_name();
195   VariableProxy* proxy =
196       factory()->NewVariableProxy(name, NORMAL_VARIABLE, pattern->position());
197   Declaration* declaration;
198   if (descriptor_->mode == VariableMode::kVar &&
199       !descriptor_->scope->is_declaration_scope()) {
200     DCHECK(descriptor_->scope->is_block_scope() ||
201            descriptor_->scope->is_with_scope());
202     declaration = factory()->NewNestedVariableDeclaration(
203         proxy, descriptor_->scope, descriptor_->declaration_pos);
204   } else {
205     declaration =
206         factory()->NewVariableDeclaration(proxy, descriptor_->declaration_pos);
207   }
208 
209   // When an extra declaration scope needs to be inserted to account for
210   // a sloppy eval in a default parameter or function body, the parameter
211   // needs to be declared in the function's scope, not in the varblock
212   // scope which will be used for the initializer expression.
213   Scope* outer_function_scope = nullptr;
214   if (DeclaresParameterContainingSloppyEval()) {
215     outer_function_scope = descriptor_->scope->outer_scope();
216   }
217   Variable* var = parser_->Declare(
218       declaration, descriptor_->declaration_kind, descriptor_->mode,
219       Variable::DefaultInitializationFlag(descriptor_->mode), ok_,
220       outer_function_scope);
221   if (!*ok_) return;
222   DCHECK_NOT_NULL(var);
223   DCHECK(proxy->is_resolved());
224   DCHECK_NE(initializer_position_, kNoSourcePosition);
225   var->set_initializer_position(initializer_position_);
226 
227   Scope* declaration_scope =
228       outer_function_scope != nullptr
229           ? outer_function_scope
230           : (IsLexicalVariableMode(descriptor_->mode)
231                  ? descriptor_->scope
232                  : descriptor_->scope->GetDeclarationScope());
233   if (declaration_scope->num_var() > kMaxNumFunctionLocals) {
234     parser_->ReportMessage(MessageTemplate::kTooManyVariables);
235     *ok_ = false;
236     return;
237   }
238   if (names_) {
239     names_->Add(name, zone());
240   }
241 
242   // If there's no initializer, we're done.
243   if (value == nullptr) return;
244 
245   Scope* var_init_scope = descriptor_->scope;
246   Parser::MarkLoopVariableAsAssigned(var_init_scope, proxy->var(),
247                                      descriptor_->declaration_kind);
248 
249   // A declaration of the form:
250   //
251   //    var v = x;
252   //
253   // is syntactic sugar for:
254   //
255   //    var v; v = x;
256   //
257   // In particular, we need to re-lookup 'v' as it may be a different
258   // 'v' than the 'v' in the declaration (e.g., if we are inside a
259   // 'with' statement or 'catch' block). Global var declarations
260   // also need special treatment.
261 
262   // For 'let' and 'const' declared variables the initialization always
263   // assigns to the declared variable.
264   // But for var declarations we need to do a new lookup.
265   if (descriptor_->mode == VariableMode::kVar) {
266     proxy = var_init_scope->NewUnresolved(factory(), name);
267   } else {
268     DCHECK_NOT_NULL(proxy);
269     DCHECK_NOT_NULL(proxy->var());
270   }
271   // Add break location for destructured sub-pattern.
272   int pos = value_beg_position_;
273   if (pos == kNoSourcePosition) {
274     pos = IsSubPattern() ? pattern->position() : value->position();
275   }
276   Assignment* assignment =
277       factory()->NewAssignment(Token::INIT, proxy, value, pos);
278   block_->statements()->Add(factory()->NewExpressionStatement(assignment, pos),
279                             zone());
280 }
281 
CreateTempVar(Expression * value)282 Variable* PatternRewriter::CreateTempVar(Expression* value) {
283   auto temp = scope()->NewTemporary(ast_value_factory()->empty_string());
284   if (value != nullptr) {
285     auto assignment = factory()->NewAssignment(
286         Token::ASSIGN, factory()->NewVariableProxy(temp), value,
287         kNoSourcePosition);
288 
289     block_->statements()->Add(
290         factory()->NewExpressionStatement(assignment, kNoSourcePosition),
291         zone());
292   }
293   return temp;
294 }
295 
VisitRewritableExpression(RewritableExpression * node)296 void PatternRewriter::VisitRewritableExpression(RewritableExpression* node) {
297   if (!node->expression()->IsAssignment()) {
298     // RewritableExpressions are also used for desugaring Spread, which is
299     // orthogonal to PatternRewriter; just visit the underlying expression.
300     DCHECK_EQ(AstNode::kArrayLiteral, node->expression()->node_type());
301     return Visit(node->expression());
302   } else if (context() != ASSIGNMENT) {
303     // This is not a destructuring assignment. Mark the node as rewritten to
304     // prevent redundant rewriting and visit the underlying expression.
305     DCHECK(!node->is_rewritten());
306     node->set_rewritten();
307     return Visit(node->expression());
308   }
309 
310   DCHECK(!node->is_rewritten());
311   DCHECK_EQ(ASSIGNMENT, context());
312   Assignment* assign = node->expression()->AsAssignment();
313   DCHECK_NOT_NULL(assign);
314   DCHECK_EQ(Token::ASSIGN, assign->op());
315 
316   int pos = assign->position();
317   Block* old_block = block_;
318   block_ = factory()->NewBlock(8, true);
319   Variable* temp = nullptr;
320   Expression* pattern = assign->target();
321   Expression* old_value = current_value_;
322   current_value_ = assign->value();
323   if (pattern->IsObjectLiteral()) {
324     VisitObjectLiteral(pattern->AsObjectLiteral(), &temp);
325   } else {
326     DCHECK(pattern->IsArrayLiteral());
327     VisitArrayLiteral(pattern->AsArrayLiteral(), &temp);
328   }
329   DCHECK_NOT_NULL(temp);
330   current_value_ = old_value;
331   Expression* expr = factory()->NewDoExpression(block_, temp, pos);
332   node->Rewrite(expr);
333   block_ = old_block;
334   if (block_) {
335     block_->statements()->Add(factory()->NewExpressionStatement(expr, pos),
336                               zone());
337   }
338 }
339 
DeclaresParameterContainingSloppyEval() const340 bool PatternRewriter::DeclaresParameterContainingSloppyEval() const {
341   // Need to check for a binding context to make sure we have a descriptor.
342   if (IsBindingContext() &&
343       // Only relevant for parameters.
344       descriptor_->declaration_kind == DeclarationDescriptor::PARAMETER &&
345       // And only when scope is a block scope;
346       // without eval, it is a function scope.
347       scope()->is_block_scope()) {
348     DCHECK(scope()->is_declaration_scope());
349     DCHECK(scope()->AsDeclarationScope()->calls_sloppy_eval());
350     DCHECK(scope()->outer_scope()->is_function_scope());
351     return true;
352   }
353 
354   return false;
355 }
356 
357 // When an extra declaration scope needs to be inserted to account for
358 // a sloppy eval in a default parameter or function body, the expressions
359 // needs to be in that new inner scope which was added after initial
360 // parsing.
RewriteParameterScopes(Expression * expr)361 void PatternRewriter::RewriteParameterScopes(Expression* expr) {
362   if (DeclaresParameterContainingSloppyEval()) {
363     ReparentExpressionScope(parser_->stack_limit(), expr, scope());
364   }
365 }
366 
VisitObjectLiteral(ObjectLiteral * pattern,Variable ** temp_var)367 void PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern,
368                                          Variable** temp_var) {
369   auto temp = *temp_var = CreateTempVar(current_value_);
370 
371   ZonePtrList<Expression>* rest_runtime_callargs = nullptr;
372   if (pattern->has_rest_property()) {
373     // non_rest_properties_count = pattern->properties()->length - 1;
374     // args_length = 1 + non_rest_properties_count because we need to
375     // pass temp as well to the runtime function.
376     int args_length = pattern->properties()->length();
377     rest_runtime_callargs =
378         new (zone()) ZonePtrList<Expression>(args_length, zone());
379     rest_runtime_callargs->Add(factory()->NewVariableProxy(temp), zone());
380   }
381 
382   block_->statements()->Add(parser_->BuildAssertIsCoercible(temp, pattern),
383                             zone());
384 
385   for (ObjectLiteralProperty* property : *pattern->properties()) {
386     Expression* value;
387 
388     if (property->kind() == ObjectLiteralProperty::Kind::SPREAD) {
389       // var { y, [x++]: a, ...c } = temp
390       //     becomes
391       // var y = temp.y;
392       // var temp1 = %ToName(x++);
393       // var a = temp[temp1];
394       // var c;
395       // c = %CopyDataPropertiesWithExcludedProperties(temp, "y", temp1);
396       value = factory()->NewCallRuntime(
397           Runtime::kCopyDataPropertiesWithExcludedProperties,
398           rest_runtime_callargs, kNoSourcePosition);
399     } else {
400       Expression* key = property->key();
401 
402       if (!key->IsLiteral()) {
403         // Computed property names contain expressions which might require
404         // scope rewriting.
405         RewriteParameterScopes(key);
406       }
407 
408       if (pattern->has_rest_property()) {
409         Expression* excluded_property = key;
410 
411         if (property->is_computed_name()) {
412           DCHECK(!key->IsPropertyName() || !key->IsNumberLiteral());
413           auto args = new (zone()) ZonePtrList<Expression>(1, zone());
414           args->Add(key, zone());
415           auto to_name_key = CreateTempVar(factory()->NewCallRuntime(
416               Runtime::kToName, args, kNoSourcePosition));
417           key = factory()->NewVariableProxy(to_name_key);
418           excluded_property = factory()->NewVariableProxy(to_name_key);
419         } else {
420           DCHECK(key->IsPropertyName() || key->IsNumberLiteral());
421         }
422 
423         DCHECK_NOT_NULL(rest_runtime_callargs);
424         rest_runtime_callargs->Add(excluded_property, zone());
425       }
426 
427       value = factory()->NewProperty(factory()->NewVariableProxy(temp), key,
428                                      kNoSourcePosition);
429     }
430 
431     AssignmentElementScope element_scope(this);
432     RecurseIntoSubpattern(property->value(), value);
433   }
434 }
435 
VisitObjectLiteral(ObjectLiteral * node)436 void PatternRewriter::VisitObjectLiteral(ObjectLiteral* node) {
437   Variable* temp_var = nullptr;
438   VisitObjectLiteral(node, &temp_var);
439 }
440 
VisitArrayLiteral(ArrayLiteral * node,Variable ** temp_var)441 void PatternRewriter::VisitArrayLiteral(ArrayLiteral* node,
442                                         Variable** temp_var) {
443   DCHECK(block_->ignore_completion_value());
444 
445   auto temp = *temp_var = CreateTempVar(current_value_);
446   auto iterator = CreateTempVar(factory()->NewGetIterator(
447       factory()->NewVariableProxy(temp), current_value_, IteratorType::kNormal,
448       current_value_->position()));
449   auto next = CreateTempVar(factory()->NewProperty(
450       factory()->NewVariableProxy(iterator),
451       factory()->NewStringLiteral(ast_value_factory()->next_string(),
452                                   kNoSourcePosition),
453       kNoSourcePosition));
454   auto done =
455       CreateTempVar(factory()->NewBooleanLiteral(false, kNoSourcePosition));
456   auto result = CreateTempVar();
457   auto v = CreateTempVar();
458   auto completion = CreateTempVar();
459   auto nopos = kNoSourcePosition;
460 
461   // For the purpose of iterator finalization, we temporarily set block_ to a
462   // new block.  In the main body of this function, we write to block_ (both
463   // explicitly and implicitly via recursion).  At the end of the function, we
464   // wrap this new block in a try-finally statement, restore block_ to its
465   // original value, and add the try-finally statement to block_.
466   auto target = block_;
467   block_ = factory()->NewBlock(8, true);
468 
469   Spread* spread = nullptr;
470   for (Expression* value : *node->values()) {
471     if (value->IsSpread()) {
472       spread = value->AsSpread();
473       break;
474     }
475 
476     // if (!done) {
477     //   done = true;  // If .next, .done or .value throws, don't close.
478     //   result = IteratorNext(iterator);
479     //   if (result.done) {
480     //     v = undefined;
481     //   } else {
482     //     v = result.value;
483     //     done = false;
484     //   }
485     // }
486     Statement* if_not_done;
487     {
488       auto result_done = factory()->NewProperty(
489           factory()->NewVariableProxy(result),
490           factory()->NewStringLiteral(ast_value_factory()->done_string(),
491                                       kNoSourcePosition),
492           kNoSourcePosition);
493 
494       auto assign_undefined = factory()->NewAssignment(
495           Token::ASSIGN, factory()->NewVariableProxy(v),
496           factory()->NewUndefinedLiteral(kNoSourcePosition), kNoSourcePosition);
497 
498       auto assign_value = factory()->NewAssignment(
499           Token::ASSIGN, factory()->NewVariableProxy(v),
500           factory()->NewProperty(
501               factory()->NewVariableProxy(result),
502               factory()->NewStringLiteral(ast_value_factory()->value_string(),
503                                           kNoSourcePosition),
504               kNoSourcePosition),
505           kNoSourcePosition);
506 
507       auto unset_done = factory()->NewAssignment(
508           Token::ASSIGN, factory()->NewVariableProxy(done),
509           factory()->NewBooleanLiteral(false, kNoSourcePosition),
510           kNoSourcePosition);
511 
512       auto inner_else = factory()->NewBlock(2, true);
513       inner_else->statements()->Add(
514           factory()->NewExpressionStatement(assign_value, nopos), zone());
515       inner_else->statements()->Add(
516           factory()->NewExpressionStatement(unset_done, nopos), zone());
517 
518       auto inner_if = factory()->NewIfStatement(
519           result_done,
520           factory()->NewExpressionStatement(assign_undefined, nopos),
521           inner_else, nopos);
522 
523       auto next_block = factory()->NewBlock(3, true);
524       next_block->statements()->Add(
525           factory()->NewExpressionStatement(
526               factory()->NewAssignment(
527                   Token::ASSIGN, factory()->NewVariableProxy(done),
528                   factory()->NewBooleanLiteral(true, nopos), nopos),
529               nopos),
530           zone());
531       next_block->statements()->Add(
532           factory()->NewExpressionStatement(
533               parser_->BuildIteratorNextResult(
534                   factory()->NewVariableProxy(iterator),
535                   factory()->NewVariableProxy(next), result,
536                   IteratorType::kNormal, kNoSourcePosition),
537               kNoSourcePosition),
538           zone());
539       next_block->statements()->Add(inner_if, zone());
540 
541       if_not_done = factory()->NewIfStatement(
542           factory()->NewUnaryOperation(
543               Token::NOT, factory()->NewVariableProxy(done), kNoSourcePosition),
544           next_block, factory()->NewEmptyStatement(kNoSourcePosition),
545           kNoSourcePosition);
546     }
547     block_->statements()->Add(if_not_done, zone());
548 
549     if (!value->IsTheHoleLiteral()) {
550       {
551         // completion = kAbruptCompletion;
552         Expression* proxy = factory()->NewVariableProxy(completion);
553         Expression* assignment = factory()->NewAssignment(
554             Token::ASSIGN, proxy,
555             factory()->NewSmiLiteral(Parser::kAbruptCompletion, nopos), nopos);
556         block_->statements()->Add(
557             factory()->NewExpressionStatement(assignment, nopos), zone());
558       }
559 
560       {
561         AssignmentElementScope element_scope(this);
562         RecurseIntoSubpattern(value, factory()->NewVariableProxy(v));
563       }
564 
565       {
566         // completion = kNormalCompletion;
567         Expression* proxy = factory()->NewVariableProxy(completion);
568         Expression* assignment = factory()->NewAssignment(
569             Token::ASSIGN, proxy,
570             factory()->NewSmiLiteral(Parser::kNormalCompletion, nopos), nopos);
571         block_->statements()->Add(
572             factory()->NewExpressionStatement(assignment, nopos), zone());
573       }
574     }
575   }
576 
577   if (spread != nullptr) {
578     // A spread can only occur as the last component.  It is not handled by
579     // RecurseIntoSubpattern above.
580 
581     // let array = [];
582     // let index = 0;
583     // while (!done) {
584     //   done = true;  // If .next, .done or .value throws, don't close.
585     //   result = IteratorNext(iterator);
586     //   if (!result.done) {
587     //     StoreInArrayLiteral(array, index, result.value);
588     //     done = false;
589     //   }
590     //   index++;
591     // }
592 
593     // let array = [];
594     Variable* array;
595     {
596       auto empty_exprs = new (zone()) ZonePtrList<Expression>(0, zone());
597       array = CreateTempVar(
598           factory()->NewArrayLiteral(empty_exprs, kNoSourcePosition));
599     }
600 
601     // let index = 0;
602     Variable* index =
603         CreateTempVar(factory()->NewSmiLiteral(0, kNoSourcePosition));
604 
605     // done = true;
606     Statement* set_done = factory()->NewExpressionStatement(
607         factory()->NewAssignment(
608             Token::ASSIGN, factory()->NewVariableProxy(done),
609             factory()->NewBooleanLiteral(true, nopos), nopos),
610         nopos);
611 
612     // result = IteratorNext(iterator);
613     Statement* get_next = factory()->NewExpressionStatement(
614         parser_->BuildIteratorNextResult(factory()->NewVariableProxy(iterator),
615                                          factory()->NewVariableProxy(next),
616                                          result, IteratorType::kNormal, nopos),
617         nopos);
618 
619     // StoreInArrayLiteral(array, index, result.value);
620     Statement* store;
621     {
622       auto value = factory()->NewProperty(
623           factory()->NewVariableProxy(result),
624           factory()->NewStringLiteral(ast_value_factory()->value_string(),
625                                       nopos),
626           nopos);
627       store = factory()->NewExpressionStatement(
628           factory()->NewStoreInArrayLiteral(factory()->NewVariableProxy(array),
629                                             factory()->NewVariableProxy(index),
630                                             value, nopos),
631           nopos);
632     }
633 
634     // done = false;
635     Statement* unset_done = factory()->NewExpressionStatement(
636         factory()->NewAssignment(
637             Token::ASSIGN, factory()->NewVariableProxy(done),
638             factory()->NewBooleanLiteral(false, nopos), nopos),
639         nopos);
640 
641     // if (!result.done) { #store; #unset_done }
642     Statement* maybe_store_and_unset_done;
643     {
644       Expression* result_done =
645           factory()->NewProperty(factory()->NewVariableProxy(result),
646                                  factory()->NewStringLiteral(
647                                      ast_value_factory()->done_string(), nopos),
648                                  nopos);
649 
650       Block* then = factory()->NewBlock(2, true);
651       then->statements()->Add(store, zone());
652       then->statements()->Add(unset_done, zone());
653 
654       maybe_store_and_unset_done = factory()->NewIfStatement(
655           factory()->NewUnaryOperation(Token::NOT, result_done, nopos), then,
656           factory()->NewEmptyStatement(nopos), nopos);
657     }
658 
659     // index++;
660     Statement* increment_index;
661     {
662       increment_index = factory()->NewExpressionStatement(
663           factory()->NewCountOperation(
664               Token::INC, false, factory()->NewVariableProxy(index), nopos),
665           nopos);
666     }
667 
668     // while (!done) {
669     //   #set_done;
670     //   #get_next;
671     //   #maybe_store_and_unset_done;
672     //   #increment_index;
673     // }
674     WhileStatement* loop =
675         factory()->NewWhileStatement(nullptr, nullptr, nopos);
676     {
677       Expression* condition = factory()->NewUnaryOperation(
678           Token::NOT, factory()->NewVariableProxy(done), nopos);
679       Block* body = factory()->NewBlock(4, true);
680       body->statements()->Add(set_done, zone());
681       body->statements()->Add(get_next, zone());
682       body->statements()->Add(maybe_store_and_unset_done, zone());
683       body->statements()->Add(increment_index, zone());
684       loop->Initialize(condition, body);
685     }
686 
687     block_->statements()->Add(loop, zone());
688     RecurseIntoSubpattern(spread->expression(),
689                           factory()->NewVariableProxy(array));
690   }
691 
692   Expression* closing_condition = factory()->NewUnaryOperation(
693       Token::NOT, factory()->NewVariableProxy(done), nopos);
694 
695   parser_->FinalizeIteratorUse(completion, closing_condition, iterator, block_,
696                                target, IteratorType::kNormal);
697   block_ = target;
698 }
699 
VisitArrayLiteral(ArrayLiteral * node)700 void PatternRewriter::VisitArrayLiteral(ArrayLiteral* node) {
701   Variable* temp_var = nullptr;
702   VisitArrayLiteral(node, &temp_var);
703 }
704 
VisitAssignment(Assignment * node)705 void PatternRewriter::VisitAssignment(Assignment* node) {
706   // let {<pattern> = <init>} = <value>
707   //   becomes
708   // temp = <value>;
709   // <pattern> = temp === undefined ? <init> : temp;
710   DCHECK_EQ(Token::ASSIGN, node->op());
711 
712   // Rewriting of Assignment nodes for destructuring assignment
713   // is handled in VisitRewritableExpression().
714   DCHECK_NE(ASSIGNMENT, context());
715 
716   auto initializer = node->value();
717   auto value = initializer;
718   auto temp = CreateTempVar(current_value_);
719 
720   Expression* is_undefined = factory()->NewCompareOperation(
721       Token::EQ_STRICT, factory()->NewVariableProxy(temp),
722       factory()->NewUndefinedLiteral(kNoSourcePosition), kNoSourcePosition);
723   value = factory()->NewConditional(is_undefined, initializer,
724                                     factory()->NewVariableProxy(temp),
725                                     kNoSourcePosition);
726 
727   // Initializer may have been parsed in the wrong scope.
728   RewriteParameterScopes(initializer);
729 
730   RecurseIntoSubpattern(node->target(), value);
731 }
732 
733 
734 // =============== AssignmentPattern only ==================
735 
VisitProperty(v8::internal::Property * node)736 void PatternRewriter::VisitProperty(v8::internal::Property* node) {
737   DCHECK(IsAssignmentContext());
738   auto value = current_value_;
739 
740   Assignment* assignment =
741       factory()->NewAssignment(Token::ASSIGN, node, value, node->position());
742 
743   block_->statements()->Add(
744       factory()->NewExpressionStatement(assignment, kNoSourcePosition), zone());
745 }
746 
747 
748 // =============== UNREACHABLE =============================
749 
750 #define NOT_A_PATTERN(Node) \
751   void PatternRewriter::Visit##Node(v8::internal::Node*) { UNREACHABLE(); }
752 
753 NOT_A_PATTERN(BinaryOperation)
754 NOT_A_PATTERN(NaryOperation)
755 NOT_A_PATTERN(Block)
756 NOT_A_PATTERN(BreakStatement)
757 NOT_A_PATTERN(Call)
758 NOT_A_PATTERN(CallNew)
759 NOT_A_PATTERN(CallRuntime)
760 NOT_A_PATTERN(ClassLiteral)
761 NOT_A_PATTERN(CompareOperation)
762 NOT_A_PATTERN(CompoundAssignment)
763 NOT_A_PATTERN(Conditional)
764 NOT_A_PATTERN(ContinueStatement)
765 NOT_A_PATTERN(CountOperation)
766 NOT_A_PATTERN(DebuggerStatement)
767 NOT_A_PATTERN(DoExpression)
768 NOT_A_PATTERN(DoWhileStatement)
769 NOT_A_PATTERN(EmptyStatement)
770 NOT_A_PATTERN(EmptyParentheses)
771 NOT_A_PATTERN(ExpressionStatement)
772 NOT_A_PATTERN(ForInStatement)
773 NOT_A_PATTERN(ForOfStatement)
774 NOT_A_PATTERN(ForStatement)
775 NOT_A_PATTERN(FunctionDeclaration)
776 NOT_A_PATTERN(FunctionLiteral)
777 NOT_A_PATTERN(GetIterator)
778 NOT_A_PATTERN(GetTemplateObject)
779 NOT_A_PATTERN(IfStatement)
780 NOT_A_PATTERN(ImportCallExpression)
781 NOT_A_PATTERN(Literal)
782 NOT_A_PATTERN(NativeFunctionLiteral)
783 NOT_A_PATTERN(RegExpLiteral)
784 NOT_A_PATTERN(ResolvedProperty)
785 NOT_A_PATTERN(ReturnStatement)
786 NOT_A_PATTERN(SloppyBlockFunctionStatement)
787 NOT_A_PATTERN(Spread)
788 NOT_A_PATTERN(StoreInArrayLiteral)
789 NOT_A_PATTERN(SuperPropertyReference)
790 NOT_A_PATTERN(SuperCallReference)
791 NOT_A_PATTERN(SwitchStatement)
792 NOT_A_PATTERN(TemplateLiteral)
793 NOT_A_PATTERN(ThisFunction)
794 NOT_A_PATTERN(Throw)
795 NOT_A_PATTERN(TryCatchStatement)
796 NOT_A_PATTERN(TryFinallyStatement)
797 NOT_A_PATTERN(UnaryOperation)
798 NOT_A_PATTERN(VariableDeclaration)
799 NOT_A_PATTERN(WhileStatement)
800 NOT_A_PATTERN(WithStatement)
801 NOT_A_PATTERN(Yield)
802 NOT_A_PATTERN(YieldStar)
803 NOT_A_PATTERN(Await)
804 NOT_A_PATTERN(InitializeClassFieldsStatement)
805 
806 #undef NOT_A_PATTERN
807 }  // namespace internal
808 }  // namespace v8
809