LCOV - code coverage report
Current view: top level - src/parsing - pattern-rewriter.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 251 299 83.9 %
Date: 2017-04-26 Functions: 15 60 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/parameter-initializer-rewriter.h"
       9             : #include "src/parsing/parser.h"
      10             : 
      11             : namespace v8 {
      12             : 
      13             : namespace internal {
      14             : 
      15    14330003 : void Parser::PatternRewriter::DeclareAndInitializeVariables(
      16             :     Parser* parser, Block* block,
      17             :     const DeclarationDescriptor* declaration_descriptor,
      18             :     const DeclarationParsingResult::Declaration* declaration,
      19             :     ZoneList<const AstRawString*>* names, bool* ok) {
      20             :   PatternRewriter rewriter;
      21             : 
      22             :   DCHECK(block->ignore_completion_value());
      23             : 
      24    14330003 :   rewriter.scope_ = declaration_descriptor->scope;
      25    14330003 :   rewriter.parser_ = parser;
      26    14330003 :   rewriter.context_ = BINDING;
      27    14330003 :   rewriter.pattern_ = declaration->pattern;
      28    14330003 :   rewriter.initializer_position_ = declaration->initializer_position;
      29    14330003 :   rewriter.block_ = block;
      30    14330003 :   rewriter.descriptor_ = declaration_descriptor;
      31    14330003 :   rewriter.names_ = names;
      32    14330003 :   rewriter.ok_ = ok;
      33    14330003 :   rewriter.recursion_level_ = 0;
      34             : 
      35    14330003 :   rewriter.RecurseIntoSubpattern(rewriter.pattern_, declaration->initializer);
      36    14330005 : }
      37             : 
      38             : 
      39       93661 : void Parser::PatternRewriter::RewriteDestructuringAssignment(
      40             :     Parser* parser, RewritableExpression* to_rewrite, Scope* scope) {
      41             :   DCHECK(!scope->HasBeenRemoved());
      42             :   DCHECK(!to_rewrite->is_rewritten());
      43             : 
      44       93661 :   bool ok = true;
      45             : 
      46             :   PatternRewriter rewriter;
      47       93661 :   rewriter.scope_ = scope;
      48       93661 :   rewriter.parser_ = parser;
      49       93661 :   rewriter.context_ = ASSIGNMENT;
      50       93661 :   rewriter.pattern_ = to_rewrite;
      51       93661 :   rewriter.block_ = nullptr;
      52       93661 :   rewriter.descriptor_ = nullptr;
      53       93661 :   rewriter.names_ = nullptr;
      54       93661 :   rewriter.ok_ = &ok;
      55       93661 :   rewriter.recursion_level_ = 0;
      56             : 
      57             :   rewriter.RecurseIntoSubpattern(rewriter.pattern_, nullptr);
      58             :   DCHECK(ok);
      59       93661 : }
      60             : 
      61             : 
      62       20018 : Expression* Parser::PatternRewriter::RewriteDestructuringAssignment(
      63             :     Parser* parser, Assignment* assignment, Scope* scope) {
      64             :   DCHECK_NOT_NULL(assignment);
      65             :   DCHECK_EQ(Token::ASSIGN, assignment->op());
      66       40036 :   auto to_rewrite = parser->factory()->NewRewritableExpression(assignment);
      67       20018 :   RewriteDestructuringAssignment(parser, to_rewrite, scope);
      68       20018 :   return to_rewrite->expression();
      69             : }
      70             : 
      71             : 
      72             : Parser::PatternRewriter::PatternContext
      73      204641 : Parser::PatternRewriter::SetAssignmentContextIfNeeded(Expression* node) {
      74             :   PatternContext old_context = context();
      75             :   // AssignmentExpressions may occur in the Initializer position of a
      76             :   // SingleNameBinding. Such expressions should not prompt a change in the
      77             :   // pattern's context.
      78      276303 :   if (node->IsAssignment() && node->AsAssignment()->op() == Token::ASSIGN &&
      79             :       !IsInitializerContext()) {
      80             :     set_context(ASSIGNMENT);
      81             :   }
      82      168886 :   return old_context;
      83             : }
      84             : 
      85             : 
      86             : Parser::PatternRewriter::PatternContext
      87      346725 : Parser::PatternRewriter::SetInitializerContextIfNeeded(Expression* node) {
      88             :   // Set appropriate initializer context for BindingElement and
      89             :   // AssignmentElement nodes
      90             :   PatternContext old_context = context();
      91             :   bool is_destructuring_assignment =
      92      360515 :       node->IsRewritableExpression() &&
      93       27580 :       !node->AsRewritableExpression()->is_rewritten();
      94             :   bool is_assignment =
      95      497175 :       node->IsAssignment() && node->AsAssignment()->op() == Token::ASSIGN;
      96      346725 :   if (is_destructuring_assignment || is_assignment) {
      97       75237 :     switch (old_context) {
      98             :       case BINDING:
      99             :         set_context(INITIALIZER);
     100             :         break;
     101             :       case ASSIGNMENT:
     102             :         set_context(ASSIGNMENT_INITIALIZER);
     103             :         break;
     104             :       default:
     105             :         break;
     106             :     }
     107             :   }
     108      346725 :   return old_context;
     109             : }
     110             : 
     111             : 
     112   105850545 : void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
     113    14488564 :   Expression* value = current_value_;
     114             : 
     115    14488564 :   if (IsAssignmentContext()) {
     116             :     // In an assignment context, simply perform the assignment
     117             :     Assignment* assignment = factory()->NewAssignment(
     118    14832809 :         Token::ASSIGN, pattern, value, pattern->position());
     119             :     block_->statements()->Add(
     120       76089 :         factory()->NewExpressionStatement(assignment, pattern->position()),
     121       76089 :         zone());
     122       76089 :     return;
     123             :   }
     124             : 
     125    14413952 :   descriptor_->scope->RemoveUnresolved(pattern);
     126             : 
     127             :   // Declare variable.
     128             :   // Note that we *always* must treat the initial value via a separate init
     129             :   // assignment for variables and constants because the value must be assigned
     130             :   // when the variable is encountered in the source. But the variable/constant
     131             :   // is declared (and set to 'undefined') upon entering the function within
     132             :   // which the variable or constant is declared. Only function variables have
     133             :   // an initial value in the declaration (because they are initialized upon
     134             :   // entering the function).
     135             :   const AstRawString* name = pattern->raw_name();
     136    12097498 :   VariableProxy* proxy =
     137    14412476 :       factory()->NewVariableProxy(name, NORMAL_VARIABLE, pattern->position());
     138             :   Declaration* declaration = factory()->NewVariableDeclaration(
     139    28824950 :       proxy, descriptor_->scope, descriptor_->declaration_pos);
     140             : 
     141             :   // When an extra declaration scope needs to be inserted to account for
     142             :   // a sloppy eval in a default parameter or function body, the parameter
     143             :   // needs to be declared in the function's scope, not in the varblock
     144             :   // scope which will be used for the initializer expression.
     145             :   Scope* outer_function_scope = nullptr;
     146    14412476 :   if (DeclaresParameterContainingSloppyEval()) {
     147        1477 :     outer_function_scope = descriptor_->scope->outer_scope();
     148             :   }
     149             :   Variable* var = parser_->Declare(
     150             :       declaration, descriptor_->declaration_kind, descriptor_->mode,
     151    14412476 :       Variable::DefaultInitializationFlag(descriptor_->mode), ok_,
     152    28824952 :       outer_function_scope);
     153    14412479 :   if (!*ok_) return;
     154             :   DCHECK_NOT_NULL(var);
     155             :   DCHECK(proxy->is_resolved());
     156             :   DCHECK(initializer_position_ != kNoSourcePosition);
     157    14340256 :   var->set_initializer_position(initializer_position_);
     158             : 
     159             :   Scope* declaration_scope =
     160             :       outer_function_scope != nullptr
     161             :           ? outer_function_scope
     162    14338779 :           : (IsLexicalVariableMode(descriptor_->mode)
     163             :                  ? descriptor_->scope
     164    28679035 :                  : descriptor_->scope->GetDeclarationScope());
     165    14340256 :   if (declaration_scope->num_var() > kMaxNumFunctionLocals) {
     166           0 :     parser_->ReportMessage(MessageTemplate::kTooManyVariables);
     167           0 :     *ok_ = false;
     168           0 :     return;
     169             :   }
     170    14340256 :   if (names_) {
     171             :     names_->Add(name, zone());
     172             :   }
     173             : 
     174             :   // If there's no initializer, we're done.
     175    14340256 :   if (value == nullptr) return;
     176             : 
     177    22722670 :   Scope* var_init_scope = descriptor_->scope;
     178             :   MarkLoopVariableAsAssigned(var_init_scope, proxy->var());
     179             : 
     180             :   // A declaration of the form:
     181             :   //
     182             :   //    var v = x;
     183             :   //
     184             :   // is syntactic sugar for:
     185             :   //
     186             :   //    var v; v = x;
     187             :   //
     188             :   // In particular, we need to re-lookup 'v' as it may be a different
     189             :   // 'v' than the 'v' in the declaration (e.g., if we are inside a
     190             :   // 'with' statement or 'catch' block). Global var declarations
     191             :   // also need special treatment.
     192             : 
     193    22722670 :   if (descriptor_->mode == VAR && var_init_scope->is_script_scope()) {
     194             :     // Global variable declarations must be compiled in a specific
     195             :     // way. When the script containing the global variable declaration
     196             :     // is entered, the global variable must be declared, so that if it
     197             :     // doesn't exist (on the global object itself, see ES5 errata) it
     198             :     // gets created with an initial undefined value. This is handled
     199             :     // by the declarations part of the function representing the
     200             :     // top-level global code; see Runtime::DeclareGlobalVariable. If
     201             :     // it already exists (in the object or in a prototype), it is
     202             :     // *not* touched until the variable declaration statement is
     203             :     // executed.
     204             :     //
     205             :     // Executing the variable declaration statement will always
     206             :     // guarantee to give the global object an own property.
     207             :     // This way, global variable declarations can shadow
     208             :     // properties in the prototype chain, but only after the variable
     209             :     // declaration statement has been executed. This is important in
     210             :     // browsers where the global object (window) has lots of
     211             :     // properties defined in prototype objects.
     212             : 
     213             :     ZoneList<Expression*>* arguments =
     214      382053 :         new (zone()) ZoneList<Expression*>(3, zone());
     215             :     arguments->Add(
     216      382053 :         factory()->NewStringLiteral(name, descriptor_->declaration_pos),
     217             :         zone());
     218             :     arguments->Add(factory()->NewNumberLiteral(var_init_scope->language_mode(),
     219      382053 :                                                kNoSourcePosition),
     220             :                    zone());
     221             :     arguments->Add(value, zone());
     222             : 
     223             :     CallRuntime* initialize = factory()->NewCallRuntime(
     224    12287488 :         Runtime::kInitializeVarGlobal, arguments, value->position());
     225             :     block_->statements()->Add(
     226      382053 :         factory()->NewExpressionStatement(initialize, initialize->position()),
     227      382053 :         zone());
     228             :   } else {
     229             :     // For 'let' and 'const' declared variables the initialization always
     230             :     // assigns to the declared variable.
     231             :     // But for var declarations we need to do a new lookup.
     232    11715445 :     if (descriptor_->mode == VAR) {
     233    10243119 :       proxy = var_init_scope->NewUnresolved(factory(), name);
     234             :     } else {
     235             :       DCHECK_NOT_NULL(proxy);
     236             :       DCHECK_NOT_NULL(proxy->var());
     237             :     }
     238             :     // Add break location for destructured sub-pattern.
     239    11715448 :     int pos = IsSubPattern() ? pattern->position() : value->position();
     240             :     Assignment* assignment =
     241    11715448 :         factory()->NewAssignment(Token::INIT, proxy, value, pos);
     242             :     block_->statements()->Add(
     243    23430894 :         factory()->NewExpressionStatement(assignment, pos), zone());
     244             :   }
     245             : }
     246             : 
     247             : 
     248     2879961 : Variable* Parser::PatternRewriter::CreateTempVar(Expression* value) {
     249     1428702 :   auto temp = scope()->NewTemporary(ast_value_factory()->empty_string());
     250      714351 :   if (value != nullptr) {
     251             :     auto assignment = factory()->NewAssignment(
     252      483753 :         Token::ASSIGN, factory()->NewVariableProxy(temp), value,
     253      483753 :         kNoSourcePosition);
     254             : 
     255             :     block_->statements()->Add(
     256      483753 :         factory()->NewExpressionStatement(assignment, kNoSourcePosition),
     257      483753 :         zone());
     258             :   }
     259      714351 :   return temp;
     260             : }
     261             : 
     262             : 
     263      110736 : void Parser::PatternRewriter::VisitRewritableExpression(
     264      841368 :     RewritableExpression* node) {
     265             :   // If this is not a destructuring assignment...
     266      110736 :   if (!IsAssignmentContext()) {
     267             :     // Mark the node as rewritten to prevent redundant rewriting, and
     268             :     // perform BindingPattern rewriting
     269             :     DCHECK(!node->is_rewritten());
     270             :     node->Rewrite(node->expression());
     271        6561 :     return Visit(node->expression());
     272      107472 :   } else if (!node->expression()->IsAssignment()) {
     273          33 :     return Visit(node->expression());
     274             :   }
     275             : 
     276      107439 :   if (node->is_rewritten()) return;
     277             :   DCHECK(IsAssignmentContext());
     278      322317 :   Assignment* assign = node->expression()->AsAssignment();
     279             :   DCHECK_NOT_NULL(assign);
     280             :   DCHECK_EQ(Token::ASSIGN, assign->op());
     281             : 
     282             :   auto initializer = assign->value();
     283             :   auto value = initializer;
     284             : 
     285      107439 :   if (IsInitializerContext()) {
     286             :     // let {<pattern> = <init>} = <value>
     287             :     //   becomes
     288             :     // temp = <value>;
     289             :     // <pattern> = temp === undefined ? <init> : temp;
     290       13778 :     auto temp_var = CreateTempVar(current_value_);
     291             :     Expression* is_undefined = factory()->NewCompareOperation(
     292       13778 :         Token::EQ_STRICT, factory()->NewVariableProxy(temp_var),
     293       27556 :         factory()->NewUndefinedLiteral(kNoSourcePosition), kNoSourcePosition);
     294             :     value = factory()->NewConditional(is_undefined, initializer,
     295       13778 :                                       factory()->NewVariableProxy(temp_var),
     296       13778 :                                       kNoSourcePosition);
     297             :   }
     298             : 
     299      107439 :   PatternContext old_context = SetAssignmentContextIfNeeded(initializer);
     300      107439 :   int pos = assign->position();
     301      107439 :   Block* old_block = block_;
     302      107439 :   block_ = factory()->NewBlock(nullptr, 8, true, pos);
     303      107439 :   Variable* temp = nullptr;
     304             :   Expression* pattern = assign->target();
     305      107439 :   Expression* old_value = current_value_;
     306      107439 :   current_value_ = value;
     307      107439 :   if (pattern->IsObjectLiteral()) {
     308      122384 :     VisitObjectLiteral(pattern->AsObjectLiteral(), &temp);
     309             :   } else {
     310             :     DCHECK(pattern->IsArrayLiteral());
     311       92494 :     VisitArrayLiteral(pattern->AsArrayLiteral(), &temp);
     312             :   }
     313             :   DCHECK_NOT_NULL(temp);
     314      107439 :   current_value_ = old_value;
     315      214878 :   Expression* expr = factory()->NewDoExpression(block_, temp, pos);
     316             :   node->Rewrite(expr);
     317      107439 :   block_ = old_block;
     318      107439 :   if (block_) {
     319       13778 :     block_->statements()->Add(factory()->NewExpressionStatement(expr, pos),
     320       13778 :                               zone());
     321             :   }
     322             :   set_context(old_context);
     323             : }
     324             : 
     325    14590491 : bool Parser::PatternRewriter::DeclaresParameterContainingSloppyEval() const {
     326             :   // Need to check for a binding context to make sure we have a descriptor.
     327    28921931 :   if (IsBindingContext() &&
     328             :       // Only relevant for parameters.
     329    14590491 :       descriptor_->declaration_kind == DeclarationDescriptor::PARAMETER &&
     330             :       // And only when scope is a block scope;
     331             :       // without eval, it is a function scope.
     332      106468 :       scope()->is_block_scope()) {
     333             :     DCHECK(scope()->calls_sloppy_eval());
     334             :     DCHECK(scope()->is_declaration_scope());
     335             :     DCHECK(scope()->outer_scope()->is_function_scope());
     336             :     return true;
     337             :   }
     338             : 
     339           0 :   return false;
     340             : }
     341             : 
     342             : // When an extra declaration scope needs to be inserted to account for
     343             : // a sloppy eval in a default parameter or function body, the expressions
     344             : // needs to be in that new inner scope which was added after initial
     345             : // parsing.
     346       72028 : void Parser::PatternRewriter::RewriteParameterScopes(Expression* expr) {
     347       71547 :   if (DeclaresParameterContainingSloppyEval()) {
     348         481 :     ReparentParameterExpressionScope(parser_->stack_limit(), expr, scope());
     349             :   }
     350       71547 : }
     351             : 
     352      755204 : void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern,
     353      672420 :                                                  Variable** temp_var) {
     354      169272 :   auto temp = *temp_var = CreateTempVar(current_value_);
     355             : 
     356             :   ZoneList<Expression*>* rest_runtime_callargs = nullptr;
     357      169272 :   if (pattern->has_rest_property()) {
     358             :     // non_rest_properties_count = pattern->properties()->length - 1;
     359             :     // args_length = 1 + non_rest_properties_count because we need to
     360             :     // pass temp as well to the runtime function.
     361        3109 :     int args_length = pattern->properties()->length();
     362             :     rest_runtime_callargs =
     363        3109 :         new (zone()) ZoneList<Expression*>(args_length, zone());
     364        3109 :     rest_runtime_callargs->Add(factory()->NewVariableProxy(temp), zone());
     365             :   }
     366             : 
     367      169272 :   block_->statements()->Add(parser_->BuildAssertIsCoercible(temp), zone());
     368             : 
     369      833320 :   for (ObjectLiteralProperty* property : *pattern->properties()) {
     370      742638 :     PatternContext context = SetInitializerContextIfNeeded(property->value());
     371             :     Expression* value;
     372             : 
     373      247388 :     if (property->kind() == ObjectLiteralProperty::Kind::SPREAD) {
     374             :       // var { y, [x++]: a, ...c } = temp
     375             :       //     becomes
     376             :       // var y = temp.y;
     377             :       // var temp1 = %ToName(x++);
     378             :       // var a = temp[temp1];
     379             :       // var c;
     380             :       // c = %CopyDataPropertiesWithExcludedProperties(temp, "y", temp1);
     381             :       value = factory()->NewCallRuntime(
     382             :           Runtime::kCopyDataPropertiesWithExcludedProperties,
     383        3109 :           rest_runtime_callargs, kNoSourcePosition);
     384             :     } else {
     385             :       Expression* key = property->key();
     386             : 
     387      244279 :       if (!key->IsLiteral()) {
     388             :         // Computed property names contain expressions which might require
     389             :         // scope rewriting.
     390       10100 :         RewriteParameterScopes(key);
     391             :       }
     392             : 
     393      244279 :       if (pattern->has_rest_property()) {
     394             :         Expression* excluded_property = key;
     395             : 
     396        3583 :         if (property->is_computed_name()) {
     397             :           DCHECK(!key->IsPropertyName() || !key->IsNumberLiteral());
     398         336 :           auto args = new (zone()) ZoneList<Expression*>(1, zone());
     399             :           args->Add(key, zone());
     400             :           auto to_name_key = CreateTempVar(factory()->NewCallRuntime(
     401         336 :               Runtime::kToName, args, kNoSourcePosition));
     402         336 :           key = factory()->NewVariableProxy(to_name_key);
     403         336 :           excluded_property = factory()->NewVariableProxy(to_name_key);
     404             :         } else {
     405             :           DCHECK(key->IsPropertyName() || key->IsNumberLiteral());
     406             :         }
     407             : 
     408             :         DCHECK(rest_runtime_callargs != nullptr);
     409             :         rest_runtime_callargs->Add(excluded_property, zone());
     410             :       }
     411             : 
     412      244279 :       value = factory()->NewProperty(factory()->NewVariableProxy(temp), key,
     413      244279 :                                      kNoSourcePosition);
     414             :     }
     415             : 
     416             :     RecurseIntoSubpattern(property->value(), value);
     417             :     set_context(context);
     418             :   }
     419      169272 : }
     420             : 
     421             : 
     422      108080 : void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* node) {
     423      108080 :   Variable* temp_var = nullptr;
     424      108080 :   VisitObjectLiteral(node, &temp_var);
     425      108080 : }
     426             : 
     427             : 
     428      153732 : void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node,
     429     4890227 :                                                 Variable** temp_var) {
     430             :   DCHECK(block_->ignore_completion_value());
     431             : 
     432       76866 :   auto temp = *temp_var = CreateTempVar(current_value_);
     433             :   auto iterator = CreateTempVar(
     434       76866 :       factory()->NewGetIterator(factory()->NewVariableProxy(temp),
     435       76866 :                                 IteratorType::kNormal, kNoSourcePosition));
     436             :   auto done =
     437       76866 :       CreateTempVar(factory()->NewBooleanLiteral(false, kNoSourcePosition));
     438       76866 :   auto result = CreateTempVar();
     439       76866 :   auto v = CreateTempVar();
     440       76866 :   auto completion = CreateTempVar();
     441             :   auto nopos = kNoSourcePosition;
     442             : 
     443             :   // For the purpose of iterator finalization, we temporarily set block_ to a
     444             :   // new block.  In the main body of this function, we write to block_ (both
     445             :   // explicitly and implicitly via recursion).  At the end of the function, we
     446             :   // wrap this new block in a try-finally statement, restore block_ to its
     447             :   // original value, and add the try-finally statement to block_.
     448       76866 :   auto target = block_;
     449       76866 :   block_ = factory()->NewBlock(nullptr, 8, true, nopos);
     450             : 
     451        8322 :   Spread* spread = nullptr;
     452      253069 :   for (Expression* value : *node->values()) {
     453      107659 :     if (value->IsSpread()) {
     454        8322 :       spread = value->AsSpread();
     455             :       break;
     456             :     }
     457             : 
     458       99337 :     PatternContext context = SetInitializerContextIfNeeded(value);
     459             : 
     460             :     // if (!done) {
     461             :     //   done = true;  // If .next, .done or .value throws, don't close.
     462             :     //   result = IteratorNext(iterator);
     463             :     //   if (result.done) {
     464             :     //     v = undefined;
     465             :     //   } else {
     466             :     //     v = result.value;
     467             :     //     done = false;
     468             :     //   }
     469             :     // }
     470             :     Statement* if_not_done;
     471             :     {
     472             :       auto result_done = factory()->NewProperty(
     473       99337 :           factory()->NewVariableProxy(result),
     474             :           factory()->NewStringLiteral(ast_value_factory()->done_string(),
     475      198674 :                                       kNoSourcePosition),
     476       99337 :           kNoSourcePosition);
     477             : 
     478             :       auto assign_undefined = factory()->NewAssignment(
     479       99337 :           Token::ASSIGN, factory()->NewVariableProxy(v),
     480      198674 :           factory()->NewUndefinedLiteral(kNoSourcePosition), kNoSourcePosition);
     481             : 
     482             :       auto assign_value = factory()->NewAssignment(
     483       99337 :           Token::ASSIGN, factory()->NewVariableProxy(v),
     484             :           factory()->NewProperty(
     485       99337 :               factory()->NewVariableProxy(result),
     486             :               factory()->NewStringLiteral(ast_value_factory()->value_string(),
     487      198674 :                                           kNoSourcePosition),
     488       99337 :               kNoSourcePosition),
     489       99337 :           kNoSourcePosition);
     490             : 
     491             :       auto unset_done = factory()->NewAssignment(
     492       99337 :           Token::ASSIGN, factory()->NewVariableProxy(done),
     493       99337 :           factory()->NewBooleanLiteral(false, kNoSourcePosition),
     494       99337 :           kNoSourcePosition);
     495             : 
     496             :       auto inner_else =
     497       99337 :           factory()->NewBlock(nullptr, 2, true, kNoSourcePosition);
     498             :       inner_else->statements()->Add(
     499       99337 :           factory()->NewExpressionStatement(assign_value, nopos), zone());
     500             :       inner_else->statements()->Add(
     501       99337 :           factory()->NewExpressionStatement(unset_done, nopos), zone());
     502             : 
     503             :       auto inner_if = factory()->NewIfStatement(
     504             :           result_done,
     505       99337 :           factory()->NewExpressionStatement(assign_undefined, nopos),
     506       99337 :           inner_else, nopos);
     507             : 
     508             :       auto next_block =
     509       99337 :           factory()->NewBlock(nullptr, 3, true, kNoSourcePosition);
     510             :       next_block->statements()->Add(
     511             :           factory()->NewExpressionStatement(
     512             :               factory()->NewAssignment(
     513       99337 :                   Token::ASSIGN, factory()->NewVariableProxy(done),
     514      198674 :                   factory()->NewBooleanLiteral(true, nopos), nopos),
     515       99337 :               nopos),
     516             :           zone());
     517             :       next_block->statements()->Add(
     518             :           factory()->NewExpressionStatement(
     519             :               parser_->BuildIteratorNextResult(
     520       99337 :                   factory()->NewVariableProxy(iterator), result,
     521             :                   IteratorType::kNormal, kNoSourcePosition),
     522      198674 :               kNoSourcePosition),
     523             :           zone());
     524             :       next_block->statements()->Add(inner_if, zone());
     525             : 
     526             :       if_not_done = factory()->NewIfStatement(
     527             :           factory()->NewUnaryOperation(
     528      198674 :               Token::NOT, factory()->NewVariableProxy(done), kNoSourcePosition),
     529       99337 :           next_block, factory()->NewEmptyStatement(kNoSourcePosition),
     530       99337 :           kNoSourcePosition);
     531             :     }
     532       99337 :     block_->statements()->Add(if_not_done, zone());
     533             : 
     534      102511 :     if (!(value->IsLiteral() && value->AsLiteral()->raw_value()->IsTheHole())) {
     535             :       {
     536             :         // completion = kAbruptCompletion;
     537       96163 :         Expression* proxy = factory()->NewVariableProxy(completion);
     538             :         Expression* assignment = factory()->NewAssignment(
     539             :             Token::ASSIGN, proxy,
     540      192326 :             factory()->NewSmiLiteral(kAbruptCompletion, nopos), nopos);
     541             :         block_->statements()->Add(
     542      192326 :             factory()->NewExpressionStatement(assignment, nopos), zone());
     543             :       }
     544             : 
     545       96163 :       RecurseIntoSubpattern(value, factory()->NewVariableProxy(v));
     546             : 
     547             :       {
     548             :         // completion = kNormalCompletion;
     549       96163 :         Expression* proxy = factory()->NewVariableProxy(completion);
     550             :         Expression* assignment = factory()->NewAssignment(
     551             :             Token::ASSIGN, proxy,
     552      192326 :             factory()->NewSmiLiteral(kNormalCompletion, nopos), nopos);
     553             :         block_->statements()->Add(
     554      192326 :             factory()->NewExpressionStatement(assignment, nopos), zone());
     555             :       }
     556             :     }
     557             :     set_context(context);
     558             :   }
     559             : 
     560       76866 :   if (spread != nullptr) {
     561             :     // A spread can only occur as the last component.  It is not handled by
     562             :     // RecurseIntoSubpattern above.
     563             : 
     564             :     // let array = [];
     565             :     // while (!done) {
     566             :     //   done = true;  // If .next, .done or .value throws, don't close.
     567             :     //   result = IteratorNext(iterator);
     568             :     //   if (!result.done) {
     569             :     //     %AppendElement(array, result.value);
     570             :     //     done = false;
     571             :     //   }
     572             :     // }
     573             : 
     574             :     // let array = [];
     575             :     Variable* array;
     576             :     {
     577        8322 :       auto empty_exprs = new (zone()) ZoneList<Expression*>(0, zone());
     578             :       array = CreateTempVar(
     579        8322 :           factory()->NewArrayLiteral(empty_exprs, kNoSourcePosition));
     580             :     }
     581             : 
     582             :     // done = true;
     583             :     Statement* set_done = factory()->NewExpressionStatement(
     584             :         factory()->NewAssignment(
     585        8322 :             Token::ASSIGN, factory()->NewVariableProxy(done),
     586       16644 :             factory()->NewBooleanLiteral(true, nopos), nopos),
     587        8322 :         nopos);
     588             : 
     589             :     // result = IteratorNext(iterator);
     590             :     Statement* get_next = factory()->NewExpressionStatement(
     591        8322 :         parser_->BuildIteratorNextResult(factory()->NewVariableProxy(iterator),
     592             :                                          result, IteratorType::kNormal, nopos),
     593       16644 :         nopos);
     594             : 
     595             :     // %AppendElement(array, result.value);
     596             :     Statement* append_element;
     597             :     {
     598        8322 :       auto args = new (zone()) ZoneList<Expression*>(2, zone());
     599        8322 :       args->Add(factory()->NewVariableProxy(array), zone());
     600             :       args->Add(factory()->NewProperty(
     601        8322 :                     factory()->NewVariableProxy(result),
     602             :                     factory()->NewStringLiteral(
     603       16644 :                         ast_value_factory()->value_string(), nopos),
     604        8322 :                     nopos),
     605             :                 zone());
     606             :       append_element = factory()->NewExpressionStatement(
     607        8322 :           factory()->NewCallRuntime(Runtime::kAppendElement, args, nopos),
     608        8322 :           nopos);
     609             :     }
     610             : 
     611             :     // done = false;
     612             :     Statement* unset_done = factory()->NewExpressionStatement(
     613             :         factory()->NewAssignment(
     614        8322 :             Token::ASSIGN, factory()->NewVariableProxy(done),
     615       16644 :             factory()->NewBooleanLiteral(false, nopos), nopos),
     616        8322 :         nopos);
     617             : 
     618             :     // if (!result.done) { #append_element; #unset_done }
     619             :     Statement* maybe_append_and_unset_done;
     620             :     {
     621             :       Expression* result_done =
     622        8322 :           factory()->NewProperty(factory()->NewVariableProxy(result),
     623             :                                  factory()->NewStringLiteral(
     624       16644 :                                      ast_value_factory()->done_string(), nopos),
     625        8322 :                                  nopos);
     626             : 
     627        8322 :       Block* then = factory()->NewBlock(nullptr, 2, true, nopos);
     628             :       then->statements()->Add(append_element, zone());
     629             :       then->statements()->Add(unset_done, zone());
     630             : 
     631             :       maybe_append_and_unset_done = factory()->NewIfStatement(
     632        8322 :           factory()->NewUnaryOperation(Token::NOT, result_done, nopos), then,
     633       16644 :           factory()->NewEmptyStatement(nopos), nopos);
     634             :     }
     635             : 
     636             :     // while (!done) {
     637             :     //   #set_done;
     638             :     //   #get_next;
     639             :     //   #maybe_append_and_unset_done;
     640             :     // }
     641        8322 :     WhileStatement* loop = factory()->NewWhileStatement(nullptr, nopos);
     642             :     {
     643             :       Expression* condition = factory()->NewUnaryOperation(
     644       16644 :           Token::NOT, factory()->NewVariableProxy(done), nopos);
     645        8322 :       Block* body = factory()->NewBlock(nullptr, 3, true, nopos);
     646             :       body->statements()->Add(set_done, zone());
     647             :       body->statements()->Add(get_next, zone());
     648             :       body->statements()->Add(maybe_append_and_unset_done, zone());
     649             :       loop->Initialize(condition, body);
     650             :     }
     651             : 
     652        8322 :     block_->statements()->Add(loop, zone());
     653             :     RecurseIntoSubpattern(spread->expression(),
     654        8322 :                           factory()->NewVariableProxy(array));
     655             :   }
     656             : 
     657             :   Expression* closing_condition = factory()->NewUnaryOperation(
     658      153732 :       Token::NOT, factory()->NewVariableProxy(done), nopos);
     659             : 
     660             :   parser_->FinalizeIteratorUse(scope(), completion, closing_condition, iterator,
     661      153732 :                                block_, target, IteratorType::kNormal);
     662       76866 :   block_ = target;
     663       76866 : }
     664             : 
     665             : 
     666       30619 : void Parser::PatternRewriter::VisitArrayLiteral(ArrayLiteral* node) {
     667       30619 :   Variable* temp_var = nullptr;
     668       30619 :   VisitArrayLiteral(node, &temp_var);
     669       30619 : }
     670             : 
     671             : 
     672      491576 : void Parser::PatternRewriter::VisitAssignment(Assignment* node) {
     673             :   // let {<pattern> = <init>} = <value>
     674             :   //   becomes
     675             :   // temp = <value>;
     676             :   // <pattern> = temp === undefined ? <init> : temp;
     677             :   DCHECK_EQ(Token::ASSIGN, node->op());
     678             : 
     679             :   auto initializer = node->value();
     680             :   auto value = initializer;
     681       61447 :   auto temp = CreateTempVar(current_value_);
     682             : 
     683       61447 :   if (IsInitializerContext()) {
     684             :     Expression* is_undefined = factory()->NewCompareOperation(
     685       61447 :         Token::EQ_STRICT, factory()->NewVariableProxy(temp),
     686      122894 :         factory()->NewUndefinedLiteral(kNoSourcePosition), kNoSourcePosition);
     687             :     value = factory()->NewConditional(is_undefined, initializer,
     688       61447 :                                       factory()->NewVariableProxy(temp),
     689       61447 :                                       kNoSourcePosition);
     690             :   }
     691             : 
     692             :   // Initializer may have been parsed in the wrong scope.
     693       61447 :   RewriteParameterScopes(initializer);
     694             : 
     695       61447 :   PatternContext old_context = SetAssignmentContextIfNeeded(initializer);
     696             :   RecurseIntoSubpattern(node->target(), value);
     697             :   set_context(old_context);
     698       61447 : }
     699             : 
     700             : 
     701             : // =============== AssignmentPattern only ==================
     702             : 
     703      122502 : void Parser::PatternRewriter::VisitProperty(v8::internal::Property* node) {
     704             :   DCHECK(IsAssignmentContext());
     705       40834 :   auto value = current_value_;
     706             : 
     707             :   Assignment* assignment =
     708       81668 :       factory()->NewAssignment(Token::ASSIGN, node, value, node->position());
     709             : 
     710             :   block_->statements()->Add(
     711       81668 :       factory()->NewExpressionStatement(assignment, kNoSourcePosition), zone());
     712       40834 : }
     713             : 
     714             : 
     715             : // =============== UNREACHABLE =============================
     716             : 
     717             : #define NOT_A_PATTERN(Node)                                        \
     718             :   void Parser::PatternRewriter::Visit##Node(v8::internal::Node*) { \
     719             :     UNREACHABLE();                                                 \
     720             :   }
     721             : 
     722           0 : NOT_A_PATTERN(BinaryOperation)
     723           0 : NOT_A_PATTERN(Block)
     724           0 : NOT_A_PATTERN(BreakStatement)
     725           0 : NOT_A_PATTERN(Call)
     726           0 : NOT_A_PATTERN(CallNew)
     727           0 : NOT_A_PATTERN(CallRuntime)
     728           0 : NOT_A_PATTERN(CaseClause)
     729           0 : NOT_A_PATTERN(ClassLiteral)
     730           0 : NOT_A_PATTERN(CompareOperation)
     731           0 : NOT_A_PATTERN(Conditional)
     732           0 : NOT_A_PATTERN(ContinueStatement)
     733           0 : NOT_A_PATTERN(CountOperation)
     734           0 : NOT_A_PATTERN(DebuggerStatement)
     735           0 : NOT_A_PATTERN(DoExpression)
     736           0 : NOT_A_PATTERN(DoWhileStatement)
     737           0 : NOT_A_PATTERN(EmptyStatement)
     738           0 : NOT_A_PATTERN(EmptyParentheses)
     739           0 : NOT_A_PATTERN(ExpressionStatement)
     740           0 : NOT_A_PATTERN(ForInStatement)
     741           0 : NOT_A_PATTERN(ForOfStatement)
     742           0 : NOT_A_PATTERN(ForStatement)
     743           0 : NOT_A_PATTERN(FunctionDeclaration)
     744           0 : NOT_A_PATTERN(FunctionLiteral)
     745           0 : NOT_A_PATTERN(GetIterator)
     746           0 : NOT_A_PATTERN(IfStatement)
     747           0 : NOT_A_PATTERN(ImportCallExpression)
     748           0 : NOT_A_PATTERN(Literal)
     749           0 : NOT_A_PATTERN(NativeFunctionLiteral)
     750           0 : NOT_A_PATTERN(RegExpLiteral)
     751           0 : NOT_A_PATTERN(ReturnStatement)
     752           0 : NOT_A_PATTERN(SloppyBlockFunctionStatement)
     753           0 : NOT_A_PATTERN(Spread)
     754           0 : NOT_A_PATTERN(SuperPropertyReference)
     755           0 : NOT_A_PATTERN(SuperCallReference)
     756           0 : NOT_A_PATTERN(SwitchStatement)
     757           0 : NOT_A_PATTERN(ThisFunction)
     758           0 : NOT_A_PATTERN(Throw)
     759           0 : NOT_A_PATTERN(TryCatchStatement)
     760           0 : NOT_A_PATTERN(TryFinallyStatement)
     761           0 : NOT_A_PATTERN(UnaryOperation)
     762           0 : NOT_A_PATTERN(VariableDeclaration)
     763           0 : NOT_A_PATTERN(WhileStatement)
     764           0 : NOT_A_PATTERN(WithStatement)
     765           0 : NOT_A_PATTERN(Suspend)
     766             : 
     767             : #undef NOT_A_PATTERN
     768             : }  // namespace internal
     769             : }  // namespace v8

Generated by: LCOV version 1.10