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