1 // Copyright 2012 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/parsing/rewriter.h"
6 
7 #include "src/ast/ast.h"
8 #include "src/ast/scopes.h"
9 #include "src/parsing/parse-info.h"
10 #include "src/parsing/parser.h"
11 
12 namespace v8 {
13 namespace internal {
14 
15 class Processor final : public AstVisitor<Processor> {
16  public:
Processor(Isolate * isolate,DeclarationScope * closure_scope,Variable * result,AstValueFactory * ast_value_factory)17   Processor(Isolate* isolate, DeclarationScope* closure_scope, Variable* result,
18             AstValueFactory* ast_value_factory)
19       : result_(result),
20         result_assigned_(false),
21         replacement_(nullptr),
22         is_set_(false),
23         breakable_(false),
24         zone_(ast_value_factory->zone()),
25         closure_scope_(closure_scope),
26         factory_(ast_value_factory) {
27     DCHECK_EQ(closure_scope, closure_scope->GetClosureScope());
28     InitializeAstVisitor(isolate);
29   }
30 
Processor(Parser * parser,DeclarationScope * closure_scope,Variable * result,AstValueFactory * ast_value_factory)31   Processor(Parser* parser, DeclarationScope* closure_scope, Variable* result,
32             AstValueFactory* ast_value_factory)
33       : result_(result),
34         result_assigned_(false),
35         replacement_(nullptr),
36         is_set_(false),
37         breakable_(false),
38         zone_(ast_value_factory->zone()),
39         closure_scope_(closure_scope),
40         factory_(ast_value_factory) {
41     DCHECK_EQ(closure_scope, closure_scope->GetClosureScope());
42     InitializeAstVisitor(parser->stack_limit());
43   }
44 
45   void Process(ZoneList<Statement*>* statements);
result_assigned() const46   bool result_assigned() const { return result_assigned_; }
47 
zone()48   Zone* zone() { return zone_; }
closure_scope()49   DeclarationScope* closure_scope() { return closure_scope_; }
factory()50   AstNodeFactory* factory() { return &factory_; }
51 
52   // Returns ".result = value"
SetResult(Expression * value)53   Expression* SetResult(Expression* value) {
54     result_assigned_ = true;
55     VariableProxy* result_proxy = factory()->NewVariableProxy(result_);
56     return factory()->NewAssignment(Token::ASSIGN, result_proxy, value,
57                                     kNoSourcePosition);
58   }
59 
60   // Inserts '.result = undefined' in front of the given statement.
61   Statement* AssignUndefinedBefore(Statement* s);
62 
63  private:
64   Variable* result_;
65 
66   // We are not tracking result usage via the result_'s use
67   // counts (we leave the accurate computation to the
68   // usage analyzer). Instead we simple remember if
69   // there was ever an assignment to result_.
70   bool result_assigned_;
71 
72   // When visiting a node, we "return" a replacement for that node in
73   // [replacement_].  In many cases this will just be the original node.
74   Statement* replacement_;
75 
76   // To avoid storing to .result all the time, we eliminate some of
77   // the stores by keeping track of whether or not we're sure .result
78   // will be overwritten anyway. This is a bit more tricky than what I
79   // was hoping for.
80   bool is_set_;
81 
82   bool breakable_;
83 
84   class BreakableScope final {
85    public:
BreakableScope(Processor * processor,bool breakable=true)86     explicit BreakableScope(Processor* processor, bool breakable = true)
87         : processor_(processor), previous_(processor->breakable_) {
88       processor->breakable_ = processor->breakable_ || breakable;
89     }
90 
~BreakableScope()91     ~BreakableScope() { processor_->breakable_ = previous_; }
92 
93    private:
94     Processor* processor_;
95     bool previous_;
96   };
97 
98   Zone* zone_;
99   DeclarationScope* closure_scope_;
100   AstNodeFactory factory_;
101 
102   // Node visitors.
103 #define DEF_VISIT(type) void Visit##type(type* node);
104   AST_NODE_LIST(DEF_VISIT)
105 #undef DEF_VISIT
106 
107   void VisitIterationStatement(IterationStatement* stmt);
108 
109   DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
110 };
111 
112 
AssignUndefinedBefore(Statement * s)113 Statement* Processor::AssignUndefinedBefore(Statement* s) {
114   Expression* result_proxy = factory()->NewVariableProxy(result_);
115   Expression* undef = factory()->NewUndefinedLiteral(kNoSourcePosition);
116   Expression* assignment = factory()->NewAssignment(Token::ASSIGN, result_proxy,
117                                                     undef, kNoSourcePosition);
118   Block* b = factory()->NewBlock(NULL, 2, false, kNoSourcePosition);
119   b->statements()->Add(
120       factory()->NewExpressionStatement(assignment, kNoSourcePosition), zone());
121   b->statements()->Add(s, zone());
122   return b;
123 }
124 
125 
Process(ZoneList<Statement * > * statements)126 void Processor::Process(ZoneList<Statement*>* statements) {
127   // If we're in a breakable scope (named block, iteration, or switch), we walk
128   // all statements. The last value producing statement before the break needs
129   // to assign to .result. If we're not in a breakable scope, only the last
130   // value producing statement in the block assigns to .result, so we can stop
131   // early.
132   for (int i = statements->length() - 1; i >= 0 && (breakable_ || !is_set_);
133        --i) {
134     Visit(statements->at(i));
135     statements->Set(i, replacement_);
136   }
137 }
138 
139 
VisitBlock(Block * node)140 void Processor::VisitBlock(Block* node) {
141   // An initializer block is the rewritten form of a variable declaration
142   // with initialization expressions. The initializer block contains the
143   // list of assignments corresponding to the initialization expressions.
144   // While unclear from the spec (ECMA-262, 3rd., 12.2), the value of
145   // a variable declaration with initialization expression is 'undefined'
146   // with some JS VMs: For instance, using smjs, print(eval('var x = 7'))
147   // returns 'undefined'. To obtain the same behavior with v8, we need
148   // to prevent rewriting in that case.
149   if (!node->ignore_completion_value()) {
150     BreakableScope scope(this, node->labels() != nullptr);
151     Process(node->statements());
152   }
153   replacement_ = node;
154 }
155 
156 
VisitExpressionStatement(ExpressionStatement * node)157 void Processor::VisitExpressionStatement(ExpressionStatement* node) {
158   // Rewrite : <x>; -> .result = <x>;
159   if (!is_set_) {
160     node->set_expression(SetResult(node->expression()));
161     is_set_ = true;
162   }
163   replacement_ = node;
164 }
165 
166 
VisitIfStatement(IfStatement * node)167 void Processor::VisitIfStatement(IfStatement* node) {
168   // Rewrite both branches.
169   bool set_after = is_set_;
170 
171   Visit(node->then_statement());
172   node->set_then_statement(replacement_);
173   bool set_in_then = is_set_;
174 
175   is_set_ = set_after;
176   Visit(node->else_statement());
177   node->set_else_statement(replacement_);
178 
179   replacement_ = set_in_then && is_set_ ? node : AssignUndefinedBefore(node);
180   is_set_ = true;
181 }
182 
183 
VisitIterationStatement(IterationStatement * node)184 void Processor::VisitIterationStatement(IterationStatement* node) {
185   // The statement may have to produce a value, so always assign undefined
186   // before.
187   // TODO(verwaest): Omit it if we know that there's no break/continue leaving
188   // it early.
189   DCHECK(breakable_ || !is_set_);
190   BreakableScope scope(this);
191 
192   Visit(node->body());
193   node->set_body(replacement_);
194 
195   replacement_ = AssignUndefinedBefore(node);
196   is_set_ = true;
197 }
198 
199 
VisitDoWhileStatement(DoWhileStatement * node)200 void Processor::VisitDoWhileStatement(DoWhileStatement* node) {
201   VisitIterationStatement(node);
202 }
203 
204 
VisitWhileStatement(WhileStatement * node)205 void Processor::VisitWhileStatement(WhileStatement* node) {
206   VisitIterationStatement(node);
207 }
208 
209 
VisitForStatement(ForStatement * node)210 void Processor::VisitForStatement(ForStatement* node) {
211   VisitIterationStatement(node);
212 }
213 
214 
VisitForInStatement(ForInStatement * node)215 void Processor::VisitForInStatement(ForInStatement* node) {
216   VisitIterationStatement(node);
217 }
218 
219 
VisitForOfStatement(ForOfStatement * node)220 void Processor::VisitForOfStatement(ForOfStatement* node) {
221   VisitIterationStatement(node);
222 }
223 
224 
VisitTryCatchStatement(TryCatchStatement * node)225 void Processor::VisitTryCatchStatement(TryCatchStatement* node) {
226   // Rewrite both try and catch block.
227   bool set_after = is_set_;
228 
229   Visit(node->try_block());
230   node->set_try_block(static_cast<Block*>(replacement_));
231   bool set_in_try = is_set_;
232 
233   is_set_ = set_after;
234   Visit(node->catch_block());
235   node->set_catch_block(static_cast<Block*>(replacement_));
236 
237   replacement_ = is_set_ && set_in_try ? node : AssignUndefinedBefore(node);
238   is_set_ = true;
239 }
240 
241 
VisitTryFinallyStatement(TryFinallyStatement * node)242 void Processor::VisitTryFinallyStatement(TryFinallyStatement* node) {
243   // Only rewrite finally if it could contain 'break' or 'continue'. Always
244   // rewrite try.
245   if (breakable_) {
246     bool set_after = is_set_;
247     // Only set result before a 'break' or 'continue'.
248     is_set_ = true;
249     Visit(node->finally_block());
250     node->set_finally_block(replacement_->AsBlock());
251     // Save .result value at the beginning of the finally block and restore it
252     // at the end again: ".backup = .result; ...; .result = .backup"
253     // This is necessary because the finally block does not normally contribute
254     // to the completion value.
255     CHECK_NOT_NULL(closure_scope());
256     Variable* backup = closure_scope()->NewTemporary(
257         factory()->ast_value_factory()->dot_result_string());
258     Expression* backup_proxy = factory()->NewVariableProxy(backup);
259     Expression* result_proxy = factory()->NewVariableProxy(result_);
260     Expression* save = factory()->NewAssignment(
261         Token::ASSIGN, backup_proxy, result_proxy, kNoSourcePosition);
262     Expression* restore = factory()->NewAssignment(
263         Token::ASSIGN, result_proxy, backup_proxy, kNoSourcePosition);
264     node->finally_block()->statements()->InsertAt(
265         0, factory()->NewExpressionStatement(save, kNoSourcePosition), zone());
266     node->finally_block()->statements()->Add(
267         factory()->NewExpressionStatement(restore, kNoSourcePosition), zone());
268     is_set_ = set_after;
269   }
270   Visit(node->try_block());
271   node->set_try_block(replacement_->AsBlock());
272 
273   replacement_ = is_set_ ? node : AssignUndefinedBefore(node);
274   is_set_ = true;
275 }
276 
277 
VisitSwitchStatement(SwitchStatement * node)278 void Processor::VisitSwitchStatement(SwitchStatement* node) {
279   // The statement may have to produce a value, so always assign undefined
280   // before.
281   // TODO(verwaest): Omit it if we know that there's no break/continue leaving
282   // it early.
283   DCHECK(breakable_ || !is_set_);
284   BreakableScope scope(this);
285   // Rewrite statements in all case clauses.
286   ZoneList<CaseClause*>* clauses = node->cases();
287   for (int i = clauses->length() - 1; i >= 0; --i) {
288     CaseClause* clause = clauses->at(i);
289     Process(clause->statements());
290   }
291 
292   replacement_ = AssignUndefinedBefore(node);
293   is_set_ = true;
294 }
295 
296 
VisitContinueStatement(ContinueStatement * node)297 void Processor::VisitContinueStatement(ContinueStatement* node) {
298   is_set_ = false;
299   replacement_ = node;
300 }
301 
302 
VisitBreakStatement(BreakStatement * node)303 void Processor::VisitBreakStatement(BreakStatement* node) {
304   is_set_ = false;
305   replacement_ = node;
306 }
307 
308 
VisitWithStatement(WithStatement * node)309 void Processor::VisitWithStatement(WithStatement* node) {
310   Visit(node->statement());
311   node->set_statement(replacement_);
312 
313   replacement_ = is_set_ ? node : AssignUndefinedBefore(node);
314   is_set_ = true;
315 }
316 
317 
VisitSloppyBlockFunctionStatement(SloppyBlockFunctionStatement * node)318 void Processor::VisitSloppyBlockFunctionStatement(
319     SloppyBlockFunctionStatement* node) {
320   Visit(node->statement());
321   node->set_statement(replacement_);
322   replacement_ = node;
323 }
324 
325 
VisitEmptyStatement(EmptyStatement * node)326 void Processor::VisitEmptyStatement(EmptyStatement* node) {
327   replacement_ = node;
328 }
329 
330 
VisitReturnStatement(ReturnStatement * node)331 void Processor::VisitReturnStatement(ReturnStatement* node) {
332   is_set_ = true;
333   replacement_ = node;
334 }
335 
336 
VisitDebuggerStatement(DebuggerStatement * node)337 void Processor::VisitDebuggerStatement(DebuggerStatement* node) {
338   replacement_ = node;
339 }
340 
341 
342 // Expressions are never visited.
343 #define DEF_VISIT(type)                                         \
344   void Processor::Visit##type(type* expr) { UNREACHABLE(); }
345 EXPRESSION_NODE_LIST(DEF_VISIT)
346 #undef DEF_VISIT
347 
348 
349 // Declarations are never visited.
350 #define DEF_VISIT(type) \
351   void Processor::Visit##type(type* expr) { UNREACHABLE(); }
DECLARATION_NODE_LIST(DEF_VISIT)352 DECLARATION_NODE_LIST(DEF_VISIT)
353 #undef DEF_VISIT
354 
355 
356 // Assumes code has been parsed.  Mutates the AST, so the AST should not
357 // continue to be used in the case of failure.
358 bool Rewriter::Rewrite(ParseInfo* info) {
359   FunctionLiteral* function = info->literal();
360   DCHECK_NOT_NULL(function);
361   Scope* scope = function->scope();
362   DCHECK_NOT_NULL(scope);
363   if (!scope->is_script_scope() && !scope->is_eval_scope()) return true;
364   DeclarationScope* closure_scope = scope->GetClosureScope();
365 
366   ZoneList<Statement*>* body = function->body();
367   if (!body->is_empty()) {
368     Variable* result = closure_scope->NewTemporary(
369         info->ast_value_factory()->dot_result_string());
370     // The name string must be internalized at this point.
371     info->ast_value_factory()->Internalize(info->isolate());
372     DCHECK(!result->name().is_null());
373     Processor processor(info->isolate(), closure_scope, result,
374                         info->ast_value_factory());
375     processor.Process(body);
376     // Internalize any values created during rewriting.
377     info->ast_value_factory()->Internalize(info->isolate());
378     if (processor.HasStackOverflow()) return false;
379 
380     if (processor.result_assigned()) {
381       int pos = kNoSourcePosition;
382       VariableProxy* result_proxy =
383           processor.factory()->NewVariableProxy(result, pos);
384       Statement* result_statement =
385           processor.factory()->NewReturnStatement(result_proxy, pos);
386       body->Add(result_statement, info->zone());
387     }
388   }
389 
390   return true;
391 }
392 
Rewrite(Parser * parser,DeclarationScope * closure_scope,DoExpression * expr,AstValueFactory * factory)393 bool Rewriter::Rewrite(Parser* parser, DeclarationScope* closure_scope,
394                        DoExpression* expr, AstValueFactory* factory) {
395   Block* block = expr->block();
396   DCHECK_EQ(closure_scope, closure_scope->GetClosureScope());
397   DCHECK(block->scope() == nullptr ||
398          block->scope()->GetClosureScope() == closure_scope);
399   ZoneList<Statement*>* body = block->statements();
400   VariableProxy* result = expr->result();
401   Variable* result_var = result->var();
402 
403   if (!body->is_empty()) {
404     Processor processor(parser, closure_scope, result_var, factory);
405     processor.Process(body);
406     if (processor.HasStackOverflow()) return false;
407 
408     if (!processor.result_assigned()) {
409       AstNodeFactory* node_factory = processor.factory();
410       Expression* undef = node_factory->NewUndefinedLiteral(kNoSourcePosition);
411       Statement* completion = node_factory->NewExpressionStatement(
412           processor.SetResult(undef), expr->position());
413       body->Add(completion, factory->zone());
414     }
415   }
416   return true;
417 }
418 
419 
420 }  // namespace internal
421 }  // namespace v8
422