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