OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/parsing/rewriter.h" | 5 #include "src/parsing/rewriter.h" |
6 | 6 |
7 #include "src/ast/ast.h" | 7 #include "src/ast/ast.h" |
8 #include "src/ast/scopes.h" | 8 #include "src/ast/scopes.h" |
9 #include "src/parsing/parse-info.h" | 9 #include "src/parsing/parse-info.h" |
10 #include "src/parsing/parser.h" | 10 #include "src/parsing/parser.h" |
11 | 11 |
12 namespace v8 { | 12 namespace v8 { |
13 namespace internal { | 13 namespace internal { |
14 | 14 |
15 class Processor final : public AstVisitor<Processor> { | 15 class Processor final : public AstVisitor<Processor> { |
16 public: | 16 public: |
17 Processor(Isolate* isolate, DeclarationScope* closure_scope, Variable* result, | 17 Processor(Isolate* isolate, DeclarationScope* closure_scope, Variable* result, |
18 AstValueFactory* ast_value_factory) | 18 AstValueFactory* ast_value_factory) |
19 : result_(result), | 19 : result_(result), |
20 result_assigned_(false), | 20 result_assigned_(false), |
21 replacement_(nullptr), | 21 replacement_(nullptr), |
22 is_set_(false), | 22 is_set_(false), |
| 23 breakable_(false), |
23 zone_(ast_value_factory->zone()), | 24 zone_(ast_value_factory->zone()), |
24 closure_scope_(closure_scope), | 25 closure_scope_(closure_scope), |
25 factory_(ast_value_factory) { | 26 factory_(ast_value_factory) { |
26 DCHECK_EQ(closure_scope, closure_scope->GetClosureScope()); | 27 DCHECK_EQ(closure_scope, closure_scope->GetClosureScope()); |
27 InitializeAstVisitor(isolate); | 28 InitializeAstVisitor(isolate); |
28 } | 29 } |
29 | 30 |
30 Processor(Parser* parser, DeclarationScope* closure_scope, Variable* result, | 31 Processor(Parser* parser, DeclarationScope* closure_scope, Variable* result, |
31 AstValueFactory* ast_value_factory) | 32 AstValueFactory* ast_value_factory) |
32 : result_(result), | 33 : result_(result), |
33 result_assigned_(false), | 34 result_assigned_(false), |
34 replacement_(nullptr), | 35 replacement_(nullptr), |
35 is_set_(false), | 36 is_set_(false), |
| 37 breakable_(false), |
36 zone_(ast_value_factory->zone()), | 38 zone_(ast_value_factory->zone()), |
37 closure_scope_(closure_scope), | 39 closure_scope_(closure_scope), |
38 factory_(ast_value_factory) { | 40 factory_(ast_value_factory) { |
39 DCHECK_EQ(closure_scope, closure_scope->GetClosureScope()); | 41 DCHECK_EQ(closure_scope, closure_scope->GetClosureScope()); |
40 InitializeAstVisitor(parser->stack_limit()); | 42 InitializeAstVisitor(parser->stack_limit()); |
41 } | 43 } |
42 | 44 |
43 void Process(ZoneList<Statement*>* statements); | 45 void Process(ZoneList<Statement*>* statements); |
44 bool result_assigned() const { return result_assigned_; } | 46 bool result_assigned() const { return result_assigned_; } |
45 | 47 |
(...skipping 24 matching lines...) Expand all Loading... |
70 // When visiting a node, we "return" a replacement for that node in | 72 // When visiting a node, we "return" a replacement for that node in |
71 // [replacement_]. In many cases this will just be the original node. | 73 // [replacement_]. In many cases this will just be the original node. |
72 Statement* replacement_; | 74 Statement* replacement_; |
73 | 75 |
74 // To avoid storing to .result all the time, we eliminate some of | 76 // To avoid storing to .result all the time, we eliminate some of |
75 // the stores by keeping track of whether or not we're sure .result | 77 // the stores by keeping track of whether or not we're sure .result |
76 // will be overwritten anyway. This is a bit more tricky than what I | 78 // will be overwritten anyway. This is a bit more tricky than what I |
77 // was hoping for. | 79 // was hoping for. |
78 bool is_set_; | 80 bool is_set_; |
79 | 81 |
| 82 bool breakable_; |
| 83 |
| 84 class BreakableScope final { |
| 85 public: |
| 86 explicit BreakableScope(Processor* processor, bool breakable = true) |
| 87 : processor_(processor), previous_(processor->breakable_) { |
| 88 processor->breakable_ = processor->breakable_ || breakable; |
| 89 } |
| 90 |
| 91 ~BreakableScope() { processor_->breakable_ = previous_; } |
| 92 |
| 93 private: |
| 94 Processor* processor_; |
| 95 bool previous_; |
| 96 }; |
| 97 |
80 Zone* zone_; | 98 Zone* zone_; |
81 DeclarationScope* closure_scope_; | 99 DeclarationScope* closure_scope_; |
82 AstNodeFactory factory_; | 100 AstNodeFactory factory_; |
83 | 101 |
84 // Node visitors. | 102 // Node visitors. |
85 #define DEF_VISIT(type) void Visit##type(type* node); | 103 #define DEF_VISIT(type) void Visit##type(type* node); |
86 AST_NODE_LIST(DEF_VISIT) | 104 AST_NODE_LIST(DEF_VISIT) |
87 #undef DEF_VISIT | 105 #undef DEF_VISIT |
88 | 106 |
89 void VisitIterationStatement(IterationStatement* stmt); | 107 void VisitIterationStatement(IterationStatement* stmt); |
90 | 108 |
91 DEFINE_AST_VISITOR_SUBCLASS_MEMBERS(); | 109 DEFINE_AST_VISITOR_SUBCLASS_MEMBERS(); |
92 }; | 110 }; |
93 | 111 |
94 | 112 |
95 Statement* Processor::AssignUndefinedBefore(Statement* s) { | 113 Statement* Processor::AssignUndefinedBefore(Statement* s) { |
96 Expression* result_proxy = factory()->NewVariableProxy(result_); | 114 Expression* result_proxy = factory()->NewVariableProxy(result_); |
97 Expression* undef = factory()->NewUndefinedLiteral(kNoSourcePosition); | 115 Expression* undef = factory()->NewUndefinedLiteral(kNoSourcePosition); |
98 Expression* assignment = factory()->NewAssignment(Token::ASSIGN, result_proxy, | 116 Expression* assignment = factory()->NewAssignment(Token::ASSIGN, result_proxy, |
99 undef, kNoSourcePosition); | 117 undef, kNoSourcePosition); |
100 Block* b = factory()->NewBlock(NULL, 2, false, kNoSourcePosition); | 118 Block* b = factory()->NewBlock(NULL, 2, false, kNoSourcePosition); |
101 b->statements()->Add( | 119 b->statements()->Add( |
102 factory()->NewExpressionStatement(assignment, kNoSourcePosition), zone()); | 120 factory()->NewExpressionStatement(assignment, kNoSourcePosition), zone()); |
103 b->statements()->Add(s, zone()); | 121 b->statements()->Add(s, zone()); |
104 return b; | 122 return b; |
105 } | 123 } |
106 | 124 |
107 | 125 |
108 void Processor::Process(ZoneList<Statement*>* statements) { | 126 void Processor::Process(ZoneList<Statement*>* statements) { |
109 for (int i = statements->length() - 1; i >= 0; --i) { | 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) { |
110 Visit(statements->at(i)); | 134 Visit(statements->at(i)); |
111 statements->Set(i, replacement_); | 135 statements->Set(i, replacement_); |
112 } | 136 } |
113 } | 137 } |
114 | 138 |
115 | 139 |
116 void Processor::VisitBlock(Block* node) { | 140 void Processor::VisitBlock(Block* node) { |
117 // An initializer block is the rewritten form of a variable declaration | 141 // An initializer block is the rewritten form of a variable declaration |
118 // with initialization expressions. The initializer block contains the | 142 // with initialization expressions. The initializer block contains the |
119 // list of assignments corresponding to the initialization expressions. | 143 // list of assignments corresponding to the initialization expressions. |
120 // While unclear from the spec (ECMA-262, 3rd., 12.2), the value of | 144 // While unclear from the spec (ECMA-262, 3rd., 12.2), the value of |
121 // a variable declaration with initialization expression is 'undefined' | 145 // a variable declaration with initialization expression is 'undefined' |
122 // with some JS VMs: For instance, using smjs, print(eval('var x = 7')) | 146 // 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 | 147 // returns 'undefined'. To obtain the same behavior with v8, we need |
124 // to prevent rewriting in that case. | 148 // to prevent rewriting in that case. |
125 if (!node->ignore_completion_value()) Process(node->statements()); | 149 if (!node->ignore_completion_value()) { |
| 150 BreakableScope scope(this, node->labels() != nullptr); |
| 151 Process(node->statements()); |
| 152 } |
126 replacement_ = node; | 153 replacement_ = node; |
127 } | 154 } |
128 | 155 |
129 | 156 |
130 void Processor::VisitExpressionStatement(ExpressionStatement* node) { | 157 void Processor::VisitExpressionStatement(ExpressionStatement* node) { |
131 // Rewrite : <x>; -> .result = <x>; | 158 // Rewrite : <x>; -> .result = <x>; |
132 if (!is_set_) { | 159 if (!is_set_) { |
133 node->set_expression(SetResult(node->expression())); | 160 node->set_expression(SetResult(node->expression())); |
134 is_set_ = true; | 161 is_set_ = true; |
135 } | 162 } |
(...skipping 14 matching lines...) Expand all Loading... |
150 replacement_ = node; | 177 replacement_ = node; |
151 | 178 |
152 if (!is_set_) { | 179 if (!is_set_) { |
153 is_set_ = true; | 180 is_set_ = true; |
154 replacement_ = AssignUndefinedBefore(node); | 181 replacement_ = AssignUndefinedBefore(node); |
155 } | 182 } |
156 } | 183 } |
157 | 184 |
158 | 185 |
159 void Processor::VisitIterationStatement(IterationStatement* node) { | 186 void Processor::VisitIterationStatement(IterationStatement* node) { |
| 187 BreakableScope scope(this); |
160 // Rewrite the body. | 188 // Rewrite the body. |
161 bool set_after = is_set_; | 189 bool set_after = is_set_; |
162 is_set_ = false; // We are in a loop, so we can't rely on [set_after]. | 190 is_set_ = false; // We are in a loop, so we can't rely on [set_after]. |
163 Visit(node->body()); | 191 Visit(node->body()); |
164 node->set_body(replacement_); | 192 node->set_body(replacement_); |
165 is_set_ = is_set_ && set_after; | 193 is_set_ = is_set_ && set_after; |
166 replacement_ = node; | 194 replacement_ = node; |
167 | 195 |
168 if (!is_set_) { | 196 if (!is_set_) { |
169 is_set_ = true; | 197 is_set_ = true; |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
246 replacement_ = node; | 274 replacement_ = node; |
247 | 275 |
248 if (!is_set_) { | 276 if (!is_set_) { |
249 is_set_ = true; | 277 is_set_ = true; |
250 replacement_ = AssignUndefinedBefore(node); | 278 replacement_ = AssignUndefinedBefore(node); |
251 } | 279 } |
252 } | 280 } |
253 | 281 |
254 | 282 |
255 void Processor::VisitSwitchStatement(SwitchStatement* node) { | 283 void Processor::VisitSwitchStatement(SwitchStatement* node) { |
| 284 BreakableScope scope(this); |
256 // Rewrite statements in all case clauses (in reverse order). | 285 // Rewrite statements in all case clauses (in reverse order). |
257 ZoneList<CaseClause*>* clauses = node->cases(); | 286 ZoneList<CaseClause*>* clauses = node->cases(); |
258 bool set_after = is_set_; | 287 bool set_after = is_set_; |
259 for (int i = clauses->length() - 1; i >= 0; --i) { | 288 for (int i = clauses->length() - 1; i >= 0; --i) { |
260 CaseClause* clause = clauses->at(i); | 289 CaseClause* clause = clauses->at(i); |
261 Process(clause->statements()); | 290 Process(clause->statements()); |
262 } | 291 } |
263 is_set_ = is_set_ && set_after; | 292 is_set_ = is_set_ && set_after; |
264 replacement_ = node; | 293 replacement_ = node; |
265 | 294 |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
391 processor.SetResult(undef), expr->position()); | 420 processor.SetResult(undef), expr->position()); |
392 body->Add(completion, factory->zone()); | 421 body->Add(completion, factory->zone()); |
393 } | 422 } |
394 } | 423 } |
395 return true; | 424 return true; |
396 } | 425 } |
397 | 426 |
398 | 427 |
399 } // namespace internal | 428 } // namespace internal |
400 } // namespace v8 | 429 } // namespace v8 |
OLD | NEW |