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
|