LCOV - code coverage report
Current view: top level - src/parsing - pattern-rewriter.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 248 301 82.4 %
Date: 2017-10-20 Functions: 16 64 25.0 %

          Line data    Source code
       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             :       ZoneList<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:
      43      209328 :     explicit AssignmentElementScope(PatternRewriter* rewriter)
      44             :         : rewriter_(rewriter), context_(rewriter->context()) {
      45      209328 :       if (context_ == ASSIGNMENT) rewriter->context_ = ASSIGNMENT_ELEMENT;
      46             :     }
      47      209328 :     ~AssignmentElementScope() { rewriter_->context_ = context_; }
      48             : 
      49             :    private:
      50             :     PatternRewriter* const rewriter_;
      51             :     const PatternContext context_;
      52             :   };
      53             : 
      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     9255900 :         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.
      69             :   AST_NODE_LIST(DECLARE_VISIT)
      70             : #undef DECLARE_VISIT
      71             : 
      72             :   PatternContext context() const { return context_; }
      73             : 
      74             :   void RecurseIntoSubpattern(AstNode* pattern, Expression* value) {
      75      279648 :     Expression* old_value = current_value_;
      76     9457762 :     current_value_ = value;
      77     9535548 :     recursion_level_++;
      78     9535548 :     Visit(pattern);
      79      279648 :     recursion_level_--;
      80      279648 :     current_value_ = old_value;
      81             :   }
      82             : 
      83             :   void VisitObjectLiteral(ObjectLiteral* node, Variable** temp_var);
      84             :   void VisitArrayLiteral(ArrayLiteral* node, Variable** temp_var);
      85             : 
      86             :   bool IsBindingContext() const { return context_ == BINDING; }
      87             :   bool IsAssignmentContext() const {
      88     9269631 :     return context_ == ASSIGNMENT || context_ == ASSIGNMENT_ELEMENT;
      89             :   }
      90             :   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             : 
      97             :   AstNodeFactory* factory() const { return parser_->factory(); }
      98             :   AstValueFactory* ast_value_factory() const {
      99      747807 :     return parser_->ast_value_factory();
     100             :   }
     101     8907815 :   Zone* zone() const { return parser_->zone(); }
     102             :   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             :   ZoneList<const AstRawString*>* names_;
     112             :   Expression* current_value_;
     113             :   int recursion_level_;
     114             :   bool* ok_;
     115             : 
     116    19099586 :   DEFINE_AST_VISITOR_MEMBERS_WITHOUT_STACKOVERFLOW()
     117             : };
     118             : 
     119     9178114 : void Parser::DeclareAndInitializeVariables(
     120             :     Block* block, const DeclarationDescriptor* declaration_descriptor,
     121             :     const DeclarationParsingResult::Declaration* declaration,
     122             :     ZoneList<const AstRawString*>* names, bool* ok) {
     123             :   PatternRewriter::DeclareAndInitializeVariables(
     124     9178114 :       this, block, declaration_descriptor, declaration, names, ok);
     125     9178116 : }
     126             : 
     127       60912 : void Parser::RewriteDestructuringAssignment(RewritableExpression* to_rewrite) {
     128       77786 :   PatternRewriter::RewriteDestructuringAssignment(this, to_rewrite, scope());
     129       60912 : }
     130             : 
     131       16874 : Expression* Parser::RewriteDestructuringAssignment(Assignment* assignment) {
     132             :   DCHECK_NOT_NULL(assignment);
     133             :   DCHECK_EQ(Token::ASSIGN, assignment->op());
     134       33748 :   auto to_rewrite = factory()->NewRewritableExpression(assignment);
     135             :   RewriteDestructuringAssignment(to_rewrite);
     136       16874 :   return to_rewrite->expression();
     137             : }
     138             : 
     139     9178114 : void PatternRewriter::DeclareAndInitializeVariables(
     140             :     Parser* parser, Block* block,
     141             :     const DeclarationDescriptor* declaration_descriptor,
     142             :     const Parser::DeclarationParsingResult::Declaration* declaration,
     143             :     ZoneList<const AstRawString*>* names, bool* ok) {
     144             :   DCHECK(block->ignore_completion_value());
     145             : 
     146     9178114 :   PatternRewriter rewriter(declaration_descriptor->scope, parser, BINDING);
     147     9178114 :   rewriter.initializer_position_ = declaration->initializer_position;
     148     9178114 :   rewriter.value_beg_position_ = declaration->value_beg_position;
     149     9178114 :   rewriter.block_ = block;
     150     9178114 :   rewriter.descriptor_ = declaration_descriptor;
     151     9178114 :   rewriter.names_ = names;
     152     9178114 :   rewriter.ok_ = ok;
     153             : 
     154             :   rewriter.RecurseIntoSubpattern(declaration->pattern,
     155     9178114 :                                  declaration->initializer);
     156     9178116 : }
     157             : 
     158       77786 : 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       77786 : }
     166             : 
     167    58967743 : void PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
     168     9269631 :   Expression* value = current_value_;
     169             : 
     170     9269631 :   if (IsAssignmentContext()) {
     171             :     // In an assignment context, simply perform the assignment
     172             :     Assignment* assignment = factory()->NewAssignment(
     173     9441778 :         Token::ASSIGN, pattern, value, pattern->position());
     174             :     block_->statements()->Add(
     175       60584 :         factory()->NewExpressionStatement(assignment, pattern->position()),
     176       60584 :         zone());
     177     1909649 :     return;
     178             :   }
     179             : 
     180             :   DCHECK_NOT_NULL(block_);
     181             :   DCHECK_NOT_NULL(descriptor_);
     182             :   DCHECK_NOT_NULL(ok_);
     183             : 
     184     9210459 :   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     9209048 :   const AstRawString* name = pattern->raw_name();
     195     7420568 :   VariableProxy* proxy =
     196     9209048 :       factory()->NewVariableProxy(name, NORMAL_VARIABLE, pattern->position());
     197             :   Declaration* declaration;
     198    17499448 :   if (descriptor_->mode == VAR && !descriptor_->scope->is_declaration_scope()) {
     199             :     DCHECK(descriptor_->scope->is_block_scope() ||
     200             :            descriptor_->scope->is_with_scope());
     201             :     declaration = factory()->NewNestedVariableDeclaration(
     202     1594470 :         proxy, descriptor_->scope, descriptor_->declaration_pos);
     203             :   } else {
     204             :     declaration =
     205    16823626 :         factory()->NewVariableDeclaration(proxy, descriptor_->declaration_pos);
     206             :   }
     207             : 
     208             :   // When an extra declaration scope needs to be inserted to account for
     209             :   // a sloppy eval in a default parameter or function body, the parameter
     210             :   // needs to be declared in the function's scope, not in the varblock
     211             :   // scope which will be used for the initializer expression.
     212             :   Scope* outer_function_scope = nullptr;
     213     9209048 :   if (DeclaresParameterContainingSloppyEval()) {
     214        1412 :     outer_function_scope = descriptor_->scope->outer_scope();
     215             :   }
     216             :   Variable* var = parser_->Declare(
     217             :       declaration, descriptor_->declaration_kind, descriptor_->mode,
     218     9209048 :       Variable::DefaultInitializationFlag(descriptor_->mode), ok_,
     219    18418096 :       outer_function_scope);
     220     9209049 :   if (!*ok_) return;
     221             :   DCHECK_NOT_NULL(var);
     222             :   DCHECK(proxy->is_resolved());
     223             :   DCHECK_NE(initializer_position_, kNoSourcePosition);
     224     9162555 :   var->set_initializer_position(initializer_position_);
     225             : 
     226             :   Scope* declaration_scope =
     227             :       outer_function_scope != nullptr
     228             :           ? outer_function_scope
     229     9161143 :           : (IsLexicalVariableMode(descriptor_->mode)
     230             :                  ? descriptor_->scope
     231    18323698 :                  : descriptor_->scope->GetDeclarationScope());
     232     9162555 :   if (declaration_scope->num_var() > kMaxNumFunctionLocals) {
     233           0 :     parser_->ReportMessage(MessageTemplate::kTooManyVariables);
     234           0 :     *ok_ = false;
     235           0 :     return;
     236             :   }
     237     9162555 :   if (names_) {
     238      168230 :     names_->Add(name, zone());
     239             :   }
     240             : 
     241             :   // If there's no initializer, we're done.
     242     9162555 :   if (value == nullptr) return;
     243             : 
     244     7420568 :   Scope* var_init_scope = descriptor_->scope;
     245             :   Parser::MarkLoopVariableAsAssigned(var_init_scope, proxy->var(),
     246     7420568 :                                      descriptor_->declaration_kind);
     247             : 
     248             :   // A declaration of the form:
     249             :   //
     250             :   //    var v = x;
     251             :   //
     252             :   // is syntactic sugar for:
     253             :   //
     254             :   //    var v; v = x;
     255             :   //
     256             :   // In particular, we need to re-lookup 'v' as it may be a different
     257             :   // 'v' than the 'v' in the declaration (e.g., if we are inside a
     258             :   // 'with' statement or 'catch' block). Global var declarations
     259             :   // also need special treatment.
     260             : 
     261             :   // For 'let' and 'const' declared variables the initialization always
     262             :   // assigns to the declared variable.
     263             :   // But for var declarations we need to do a new lookup.
     264     7420568 :   if (descriptor_->mode == VAR) {
     265     6540591 :     proxy = var_init_scope->NewUnresolved(factory(), name);
     266             :   } else {
     267             :     DCHECK_NOT_NULL(proxy);
     268             :     DCHECK_NOT_NULL(proxy->var());
     269             :   }
     270             :   // Add break location for destructured sub-pattern.
     271     7420568 :   int pos = value_beg_position_;
     272     7420568 :   if (pos == kNoSourcePosition) {
     273      627544 :     pos = IsSubPattern() ? pattern->position() : value->position();
     274             :   }
     275             :   Assignment* assignment =
     276     7420568 :       factory()->NewAssignment(Token::INIT, proxy, value, pos);
     277     7420567 :   block_->statements()->Add(factory()->NewExpressionStatement(assignment, pos),
     278     7420567 :                             zone());
     279             : }
     280             : 
     281     2234165 : Variable* PatternRewriter::CreateTempVar(Expression* value) {
     282     1128674 :   auto temp = scope()->NewTemporary(ast_value_factory()->empty_string());
     283      564337 :   if (value != nullptr) {
     284             :     auto assignment = factory()->NewAssignment(
     285      368497 :         Token::ASSIGN, factory()->NewVariableProxy(temp), value,
     286      368497 :         kNoSourcePosition);
     287             : 
     288             :     block_->statements()->Add(
     289      368497 :         factory()->NewExpressionStatement(assignment, kNoSourcePosition),
     290      368497 :         zone());
     291             :   }
     292      564337 :   return temp;
     293             : }
     294             : 
     295      428924 : void PatternRewriter::VisitRewritableExpression(RewritableExpression* node) {
     296       92031 :   if (!node->expression()->IsAssignment()) {
     297             :     // RewritableExpressions are also used for desugaring Spread, which is
     298             :     // orthogonal to PatternRewriter; just visit the underlying expression.
     299             :     DCHECK_EQ(AstNode::kArrayLiteral, node->expression()->node_type());
     300       16986 :     return Visit(node->expression());
     301       89290 :   } else if (context() != ASSIGNMENT) {
     302             :     // This is not a destructuring assignment. Mark the node as rewritten to
     303             :     // prevent redundant rewriting and visit the underlying expression.
     304             :     DCHECK(!node->is_rewritten());
     305             :     node->set_rewritten();
     306       11504 :     return Visit(node->expression());
     307             :   }
     308             : 
     309             :   DCHECK(!node->is_rewritten());
     310             :   DCHECK_EQ(ASSIGNMENT, context());
     311      233358 :   Assignment* assign = node->expression()->AsAssignment();
     312             :   DCHECK_NOT_NULL(assign);
     313             :   DCHECK_EQ(Token::ASSIGN, assign->op());
     314             : 
     315       77786 :   int pos = assign->position();
     316       77786 :   Block* old_block = block_;
     317       77786 :   block_ = factory()->NewBlock(8, true);
     318       77786 :   Variable* temp = nullptr;
     319             :   Expression* pattern = assign->target();
     320       77786 :   Expression* old_value = current_value_;
     321       77786 :   current_value_ = assign->value();
     322       77786 :   if (pattern->IsObjectLiteral()) {
     323       89760 :     VisitObjectLiteral(pattern->AsObjectLiteral(), &temp);
     324             :   } else {
     325             :     DCHECK(pattern->IsArrayLiteral());
     326       65812 :     VisitArrayLiteral(pattern->AsArrayLiteral(), &temp);
     327             :   }
     328             :   DCHECK_NOT_NULL(temp);
     329       77786 :   current_value_ = old_value;
     330      155572 :   Expression* expr = factory()->NewDoExpression(block_, temp, pos);
     331             :   node->Rewrite(expr);
     332       77786 :   block_ = old_block;
     333       77786 :   if (block_) {
     334           0 :     block_->statements()->Add(factory()->NewExpressionStatement(expr, pos),
     335           0 :                               zone());
     336             :   }
     337             : }
     338             : 
     339     9341869 : bool PatternRewriter::DeclaresParameterContainingSloppyEval() const {
     340             :   // Need to check for a binding context to make sure we have a descriptor.
     341    18512462 :   if (IsBindingContext() &&
     342             :       // Only relevant for parameters.
     343     9341869 :       descriptor_->declaration_kind == DeclarationDescriptor::PARAMETER &&
     344             :       // And only when scope is a block scope;
     345             :       // without eval, it is a function scope.
     346       60965 :       scope()->is_block_scope()) {
     347             :     DCHECK(scope()->is_declaration_scope());
     348             :     DCHECK(scope()->AsDeclarationScope()->calls_sloppy_eval());
     349             :     DCHECK(scope()->outer_scope()->is_function_scope());
     350             :     return true;
     351             :   }
     352             : 
     353           0 :   return false;
     354             : }
     355             : 
     356             : // When an extra declaration scope needs to be inserted to account for
     357             : // a sloppy eval in a default parameter or function body, the expressions
     358             : // needs to be in that new inner scope which was added after initial
     359             : // parsing.
     360       72234 : void PatternRewriter::RewriteParameterScopes(Expression* expr) {
     361       71856 :   if (DeclaresParameterContainingSloppyEval()) {
     362         378 :     ReparentExpressionScope(parser_->stack_limit(), expr, scope());
     363             :   }
     364       71856 : }
     365             : 
     366      433219 : void PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern,
     367      364053 :                                          Variable** temp_var) {
     368      102057 :   auto temp = *temp_var = CreateTempVar(current_value_);
     369             : 
     370             :   ZoneList<Expression*>* rest_runtime_callargs = nullptr;
     371      102057 :   if (pattern->has_rest_property()) {
     372             :     // non_rest_properties_count = pattern->properties()->length - 1;
     373             :     // args_length = 1 + non_rest_properties_count because we need to
     374             :     // pass temp as well to the runtime function.
     375        3515 :     int args_length = pattern->properties()->length();
     376             :     rest_runtime_callargs =
     377        3515 :         new (zone()) ZoneList<Expression*>(args_length, zone());
     378        7030 :     rest_runtime_callargs->Add(factory()->NewVariableProxy(temp), zone());
     379             :   }
     380             : 
     381      102057 :   block_->statements()->Add(parser_->BuildAssertIsCoercible(temp, pattern),
     382      102057 :                             zone());
     383             : 
     384      331162 :   for (ObjectLiteralProperty* property : *pattern->properties()) {
     385             :     Expression* value;
     386             : 
     387      127048 :     if (property->kind() == ObjectLiteralProperty::Kind::SPREAD) {
     388             :       // var { y, [x++]: a, ...c } = temp
     389             :       //     becomes
     390             :       // var y = temp.y;
     391             :       // var temp1 = %ToName(x++);
     392             :       // var a = temp[temp1];
     393             :       // var c;
     394             :       // c = %CopyDataPropertiesWithExcludedProperties(temp, "y", temp1);
     395             :       value = factory()->NewCallRuntime(
     396             :           Runtime::kCopyDataPropertiesWithExcludedProperties,
     397        3515 :           rest_runtime_callargs, kNoSourcePosition);
     398             :     } else {
     399      253566 :       Expression* key = property->key();
     400             : 
     401      123533 :       if (!key->IsLiteral()) {
     402             :         // Computed property names contain expressions which might require
     403             :         // scope rewriting.
     404        8351 :         RewriteParameterScopes(key);
     405             :       }
     406             : 
     407      123533 :       if (pattern->has_rest_property()) {
     408        2985 :         Expression* excluded_property = key;
     409             : 
     410        2985 :         if (property->is_computed_name()) {
     411             :           DCHECK(!key->IsPropertyName() || !key->IsNumberLiteral());
     412         280 :           auto args = new (zone()) ZoneList<Expression*>(1, zone());
     413         280 :           args->Add(key, zone());
     414             :           auto to_name_key = CreateTempVar(factory()->NewCallRuntime(
     415         280 :               Runtime::kToName, args, kNoSourcePosition));
     416         560 :           key = factory()->NewVariableProxy(to_name_key);
     417         560 :           excluded_property = factory()->NewVariableProxy(to_name_key);
     418             :         } else {
     419             :           DCHECK(key->IsPropertyName() || key->IsNumberLiteral());
     420             :         }
     421             : 
     422             :         DCHECK_NOT_NULL(rest_runtime_callargs);
     423        2985 :         rest_runtime_callargs->Add(excluded_property, zone());
     424             :       }
     425             : 
     426      123533 :       value = factory()->NewProperty(factory()->NewVariableProxy(temp), key,
     427      247066 :                                      kNoSourcePosition);
     428             :     }
     429             : 
     430             :     AssignmentElementScope element_scope(this);
     431             :     RecurseIntoSubpattern(property->value(), value);
     432             :   }
     433      102057 : }
     434             : 
     435       57177 : void PatternRewriter::VisitObjectLiteral(ObjectLiteral* node) {
     436       57177 :   Variable* temp_var = nullptr;
     437       57177 :   VisitObjectLiteral(node, &temp_var);
     438       57177 : }
     439             : 
     440      130560 : void PatternRewriter::VisitArrayLiteral(ArrayLiteral* node,
     441     4101795 :                                         Variable** temp_var) {
     442             :   DCHECK(block_->ignore_completion_value());
     443             : 
     444       65280 :   auto temp = *temp_var = CreateTempVar(current_value_);
     445             :   auto iterator = CreateTempVar(factory()->NewGetIterator(
     446       65280 :       factory()->NewVariableProxy(temp), current_value_, IteratorType::kNormal,
     447      195840 :       current_value_->position()));
     448             :   auto done =
     449       65280 :       CreateTempVar(factory()->NewBooleanLiteral(false, kNoSourcePosition));
     450       65280 :   auto result = CreateTempVar();
     451       65280 :   auto v = CreateTempVar();
     452       65280 :   auto completion = CreateTempVar();
     453             :   auto nopos = kNoSourcePosition;
     454             : 
     455             :   // For the purpose of iterator finalization, we temporarily set block_ to a
     456             :   // new block.  In the main body of this function, we write to block_ (both
     457             :   // explicitly and implicitly via recursion).  At the end of the function, we
     458             :   // wrap this new block in a try-finally statement, restore block_ to its
     459             :   // original value, and add the try-finally statement to block_.
     460       65280 :   auto target = block_;
     461       65280 :   block_ = factory()->NewBlock(8, true);
     462             : 
     463        6815 :   Spread* spread = nullptr;
     464      215480 :   for (Expression* value : *node->values()) {
     465       91735 :     if (value->IsSpread()) {
     466        6815 :       spread = value->AsSpread();
     467        6815 :       break;
     468             :     }
     469             : 
     470             :     // if (!done) {
     471             :     //   done = true;  // If .next, .done or .value throws, don't close.
     472             :     //   result = IteratorNext(iterator);
     473             :     //   if (result.done) {
     474             :     //     v = undefined;
     475             :     //   } else {
     476             :     //     v = result.value;
     477             :     //     done = false;
     478             :     //   }
     479             :     // }
     480             :     Statement* if_not_done;
     481             :     {
     482             :       auto result_done = factory()->NewProperty(
     483       84920 :           factory()->NewVariableProxy(result),
     484             :           factory()->NewStringLiteral(ast_value_factory()->done_string(),
     485      169840 :                                       kNoSourcePosition),
     486       84920 :           kNoSourcePosition);
     487             : 
     488             :       auto assign_undefined = factory()->NewAssignment(
     489       84920 :           Token::ASSIGN, factory()->NewVariableProxy(v),
     490      169840 :           factory()->NewUndefinedLiteral(kNoSourcePosition), kNoSourcePosition);
     491             : 
     492             :       auto assign_value = factory()->NewAssignment(
     493       84920 :           Token::ASSIGN, factory()->NewVariableProxy(v),
     494             :           factory()->NewProperty(
     495       84920 :               factory()->NewVariableProxy(result),
     496             :               factory()->NewStringLiteral(ast_value_factory()->value_string(),
     497      169840 :                                           kNoSourcePosition),
     498       84920 :               kNoSourcePosition),
     499       84920 :           kNoSourcePosition);
     500             : 
     501             :       auto unset_done = factory()->NewAssignment(
     502       84920 :           Token::ASSIGN, factory()->NewVariableProxy(done),
     503       84920 :           factory()->NewBooleanLiteral(false, kNoSourcePosition),
     504       84920 :           kNoSourcePosition);
     505             : 
     506       84920 :       auto inner_else = factory()->NewBlock(2, true);
     507             :       inner_else->statements()->Add(
     508      169840 :           factory()->NewExpressionStatement(assign_value, nopos), zone());
     509             :       inner_else->statements()->Add(
     510      169840 :           factory()->NewExpressionStatement(unset_done, nopos), zone());
     511             : 
     512             :       auto inner_if = factory()->NewIfStatement(
     513             :           result_done,
     514       84920 :           factory()->NewExpressionStatement(assign_undefined, nopos),
     515       84920 :           inner_else, nopos);
     516             : 
     517       84920 :       auto next_block = factory()->NewBlock(3, true);
     518             :       next_block->statements()->Add(
     519             :           factory()->NewExpressionStatement(
     520             :               factory()->NewAssignment(
     521       84920 :                   Token::ASSIGN, factory()->NewVariableProxy(done),
     522      169840 :                   factory()->NewBooleanLiteral(true, nopos), nopos),
     523       84920 :               nopos),
     524       84920 :           zone());
     525             :       next_block->statements()->Add(
     526             :           factory()->NewExpressionStatement(
     527             :               parser_->BuildIteratorNextResult(
     528       84920 :                   factory()->NewVariableProxy(iterator), result,
     529             :                   IteratorType::kNormal, kNoSourcePosition),
     530      169840 :               kNoSourcePosition),
     531       84920 :           zone());
     532       84920 :       next_block->statements()->Add(inner_if, zone());
     533             : 
     534             :       if_not_done = factory()->NewIfStatement(
     535             :           factory()->NewUnaryOperation(
     536      169840 :               Token::NOT, factory()->NewVariableProxy(done), kNoSourcePosition),
     537       84920 :           next_block, factory()->NewEmptyStatement(kNoSourcePosition),
     538      169840 :           kNoSourcePosition);
     539             :     }
     540       84920 :     block_->statements()->Add(if_not_done, zone());
     541             : 
     542       87560 :     if (!(value->IsLiteral() && value->AsLiteral()->raw_value()->IsTheHole())) {
     543             :       {
     544             :         // completion = kAbruptCompletion;
     545       82280 :         Expression* proxy = factory()->NewVariableProxy(completion);
     546             :         Expression* assignment = factory()->NewAssignment(
     547             :             Token::ASSIGN, proxy,
     548      164560 :             factory()->NewSmiLiteral(Parser::kAbruptCompletion, nopos), nopos);
     549             :         block_->statements()->Add(
     550      164560 :             factory()->NewExpressionStatement(assignment, nopos), zone());
     551             :       }
     552             : 
     553             :       {
     554             :         AssignmentElementScope element_scope(this);
     555       82280 :         RecurseIntoSubpattern(value, factory()->NewVariableProxy(v));
     556             :       }
     557             : 
     558             :       {
     559             :         // completion = kNormalCompletion;
     560       82280 :         Expression* proxy = factory()->NewVariableProxy(completion);
     561             :         Expression* assignment = factory()->NewAssignment(
     562             :             Token::ASSIGN, proxy,
     563      164560 :             factory()->NewSmiLiteral(Parser::kNormalCompletion, nopos), nopos);
     564             :         block_->statements()->Add(
     565      164560 :             factory()->NewExpressionStatement(assignment, nopos), zone());
     566             :       }
     567             :     }
     568             :   }
     569             : 
     570       65280 :   if (spread != nullptr) {
     571             :     // A spread can only occur as the last component.  It is not handled by
     572             :     // RecurseIntoSubpattern above.
     573             : 
     574             :     // let array = [];
     575             :     // while (!done) {
     576             :     //   done = true;  // If .next, .done or .value throws, don't close.
     577             :     //   result = IteratorNext(iterator);
     578             :     //   if (!result.done) {
     579             :     //     %AppendElement(array, result.value);
     580             :     //     done = false;
     581             :     //   }
     582             :     // }
     583             : 
     584             :     // let array = [];
     585             :     Variable* array;
     586             :     {
     587        6815 :       auto empty_exprs = new (zone()) ZoneList<Expression*>(0, zone());
     588             :       array = CreateTempVar(
     589       13630 :           factory()->NewArrayLiteral(empty_exprs, kNoSourcePosition));
     590             :     }
     591             : 
     592             :     // done = true;
     593             :     Statement* set_done = factory()->NewExpressionStatement(
     594             :         factory()->NewAssignment(
     595        6815 :             Token::ASSIGN, factory()->NewVariableProxy(done),
     596       13630 :             factory()->NewBooleanLiteral(true, nopos), nopos),
     597       13630 :         nopos);
     598             : 
     599             :     // result = IteratorNext(iterator);
     600             :     Statement* get_next = factory()->NewExpressionStatement(
     601        6815 :         parser_->BuildIteratorNextResult(factory()->NewVariableProxy(iterator),
     602             :                                          result, IteratorType::kNormal, nopos),
     603       20445 :         nopos);
     604             : 
     605             :     // %AppendElement(array, result.value);
     606             :     Statement* append_element;
     607             :     {
     608        6815 :       auto args = new (zone()) ZoneList<Expression*>(2, zone());
     609       13630 :       args->Add(factory()->NewVariableProxy(array), zone());
     610             :       args->Add(factory()->NewProperty(
     611        6815 :                     factory()->NewVariableProxy(result),
     612             :                     factory()->NewStringLiteral(
     613       13630 :                         ast_value_factory()->value_string(), nopos),
     614        6815 :                     nopos),
     615        6815 :                 zone());
     616             :       append_element = factory()->NewExpressionStatement(
     617        6815 :           factory()->NewCallRuntime(Runtime::kAppendElement, args, nopos),
     618       13630 :           nopos);
     619             :     }
     620             : 
     621             :     // done = false;
     622             :     Statement* unset_done = factory()->NewExpressionStatement(
     623             :         factory()->NewAssignment(
     624        6815 :             Token::ASSIGN, factory()->NewVariableProxy(done),
     625       13630 :             factory()->NewBooleanLiteral(false, nopos), nopos),
     626       13630 :         nopos);
     627             : 
     628             :     // if (!result.done) { #append_element; #unset_done }
     629             :     Statement* maybe_append_and_unset_done;
     630             :     {
     631             :       Expression* result_done =
     632        6815 :           factory()->NewProperty(factory()->NewVariableProxy(result),
     633             :                                  factory()->NewStringLiteral(
     634       13630 :                                      ast_value_factory()->done_string(), nopos),
     635        6815 :                                  nopos);
     636             : 
     637        6815 :       Block* then = factory()->NewBlock(2, true);
     638        6815 :       then->statements()->Add(append_element, zone());
     639        6815 :       then->statements()->Add(unset_done, zone());
     640             : 
     641             :       maybe_append_and_unset_done = factory()->NewIfStatement(
     642        6815 :           factory()->NewUnaryOperation(Token::NOT, result_done, nopos), then,
     643       20445 :           factory()->NewEmptyStatement(nopos), nopos);
     644             :     }
     645             : 
     646             :     // while (!done) {
     647             :     //   #set_done;
     648             :     //   #get_next;
     649             :     //   #maybe_append_and_unset_done;
     650             :     // }
     651        6815 :     WhileStatement* loop = factory()->NewWhileStatement(nullptr, nopos);
     652             :     {
     653             :       Expression* condition = factory()->NewUnaryOperation(
     654       13630 :           Token::NOT, factory()->NewVariableProxy(done), nopos);
     655        6815 :       Block* body = factory()->NewBlock(3, true);
     656        6815 :       body->statements()->Add(set_done, zone());
     657        6815 :       body->statements()->Add(get_next, zone());
     658        6815 :       body->statements()->Add(maybe_append_and_unset_done, zone());
     659             :       loop->Initialize(condition, body);
     660             :     }
     661             : 
     662        6815 :     block_->statements()->Add(loop, zone());
     663             :     RecurseIntoSubpattern(spread->expression(),
     664        6815 :                           factory()->NewVariableProxy(array));
     665             :   }
     666             : 
     667             :   Expression* closing_condition = factory()->NewUnaryOperation(
     668      130560 :       Token::NOT, factory()->NewVariableProxy(done), nopos);
     669             : 
     670             :   parser_->FinalizeIteratorUse(completion, closing_condition, iterator, block_,
     671       65280 :                                target, IteratorType::kNormal);
     672       65280 :   block_ = target;
     673       65280 : }
     674             : 
     675       32374 : void PatternRewriter::VisitArrayLiteral(ArrayLiteral* node) {
     676       32374 :   Variable* temp_var = nullptr;
     677       32374 :   VisitArrayLiteral(node, &temp_var);
     678       32374 : }
     679             : 
     680      444535 : void PatternRewriter::VisitAssignment(Assignment* node) {
     681             :   // let {<pattern> = <init>} = <value>
     682             :   //   becomes
     683             :   // temp = <value>;
     684             :   // <pattern> = temp === undefined ? <init> : temp;
     685             :   DCHECK_EQ(Token::ASSIGN, node->op());
     686             : 
     687             :   // Rewriting of Assignment nodes for destructuring assignment
     688             :   // is handled in VisitRewritableExpression().
     689             :   DCHECK_NE(ASSIGNMENT, context());
     690             : 
     691             :   auto initializer = node->value();
     692             :   auto value = initializer;
     693       63505 :   auto temp = CreateTempVar(current_value_);
     694             : 
     695             :   Expression* is_undefined = factory()->NewCompareOperation(
     696       63505 :       Token::EQ_STRICT, factory()->NewVariableProxy(temp),
     697      127010 :       factory()->NewUndefinedLiteral(kNoSourcePosition), kNoSourcePosition);
     698             :   value = factory()->NewConditional(is_undefined, initializer,
     699       63505 :                                     factory()->NewVariableProxy(temp),
     700       63505 :                                     kNoSourcePosition);
     701             : 
     702             :   // Initializer may have been parsed in the wrong scope.
     703       63505 :   RewriteParameterScopes(initializer);
     704             : 
     705             :   RecurseIntoSubpattern(node->target(), value);
     706       63505 : }
     707             : 
     708             : 
     709             : // =============== AssignmentPattern only ==================
     710             : 
     711      105225 : void PatternRewriter::VisitProperty(v8::internal::Property* node) {
     712             :   DCHECK(IsAssignmentContext());
     713       35075 :   auto value = current_value_;
     714             : 
     715             :   Assignment* assignment =
     716       70150 :       factory()->NewAssignment(Token::ASSIGN, node, value, node->position());
     717             : 
     718             :   block_->statements()->Add(
     719       70150 :       factory()->NewExpressionStatement(assignment, kNoSourcePosition), zone());
     720       35075 : }
     721             : 
     722             : 
     723             : // =============== UNREACHABLE =============================
     724             : 
     725             : #define NOT_A_PATTERN(Node) \
     726             :   void PatternRewriter::Visit##Node(v8::internal::Node*) { UNREACHABLE(); }
     727             : 
     728           0 : NOT_A_PATTERN(BinaryOperation)
     729           0 : NOT_A_PATTERN(Block)
     730           0 : NOT_A_PATTERN(BreakStatement)
     731           0 : NOT_A_PATTERN(Call)
     732           0 : NOT_A_PATTERN(CallNew)
     733           0 : NOT_A_PATTERN(CallRuntime)
     734           0 : NOT_A_PATTERN(ClassLiteral)
     735           0 : NOT_A_PATTERN(CompareOperation)
     736           0 : NOT_A_PATTERN(CompoundAssignment)
     737           0 : NOT_A_PATTERN(Conditional)
     738           0 : NOT_A_PATTERN(ContinueStatement)
     739           0 : NOT_A_PATTERN(CountOperation)
     740           0 : NOT_A_PATTERN(DebuggerStatement)
     741           0 : NOT_A_PATTERN(DoExpression)
     742           0 : NOT_A_PATTERN(DoWhileStatement)
     743           0 : NOT_A_PATTERN(EmptyStatement)
     744           0 : NOT_A_PATTERN(EmptyParentheses)
     745           0 : NOT_A_PATTERN(ExpressionStatement)
     746           0 : NOT_A_PATTERN(ForInStatement)
     747           0 : NOT_A_PATTERN(ForOfStatement)
     748           0 : NOT_A_PATTERN(ForStatement)
     749           0 : NOT_A_PATTERN(FunctionDeclaration)
     750           0 : NOT_A_PATTERN(FunctionLiteral)
     751           0 : NOT_A_PATTERN(GetIterator)
     752           0 : NOT_A_PATTERN(GetTemplateObject)
     753           0 : NOT_A_PATTERN(IfStatement)
     754           0 : NOT_A_PATTERN(ImportCallExpression)
     755           0 : NOT_A_PATTERN(Literal)
     756           0 : NOT_A_PATTERN(NativeFunctionLiteral)
     757           0 : NOT_A_PATTERN(RegExpLiteral)
     758           0 : NOT_A_PATTERN(ReturnStatement)
     759           0 : NOT_A_PATTERN(SloppyBlockFunctionStatement)
     760           0 : NOT_A_PATTERN(Spread)
     761           0 : NOT_A_PATTERN(SuperPropertyReference)
     762           0 : NOT_A_PATTERN(SuperCallReference)
     763           0 : NOT_A_PATTERN(SwitchStatement)
     764           0 : NOT_A_PATTERN(ThisFunction)
     765           0 : NOT_A_PATTERN(Throw)
     766           0 : NOT_A_PATTERN(TryCatchStatement)
     767           0 : NOT_A_PATTERN(TryFinallyStatement)
     768           0 : NOT_A_PATTERN(UnaryOperation)
     769           0 : NOT_A_PATTERN(VariableDeclaration)
     770           0 : NOT_A_PATTERN(WhileStatement)
     771           0 : NOT_A_PATTERN(WithStatement)
     772           0 : NOT_A_PATTERN(Yield)
     773           0 : NOT_A_PATTERN(YieldStar)
     774           0 : NOT_A_PATTERN(Await)
     775             : 
     776             : #undef NOT_A_PATTERN
     777             : }  // namespace internal
     778             : }  // namespace v8

Generated by: LCOV version 1.10