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