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 for (int i = statements->length() - 1; i >= 0 && (breakable_ || !is_set_); |
adamk
2016/10/20 15:39:06
That's quite a fancy for loop, please add a commen
| |
128 --i) { | |
110 Visit(statements->at(i)); | 129 Visit(statements->at(i)); |
111 statements->Set(i, replacement_); | 130 statements->Set(i, replacement_); |
112 } | 131 } |
113 } | 132 } |
114 | 133 |
115 | 134 |
116 void Processor::VisitBlock(Block* node) { | 135 void Processor::VisitBlock(Block* node) { |
117 // An initializer block is the rewritten form of a variable declaration | 136 // An initializer block is the rewritten form of a variable declaration |
118 // with initialization expressions. The initializer block contains the | 137 // with initialization expressions. The initializer block contains the |
119 // list of assignments corresponding to the initialization expressions. | 138 // list of assignments corresponding to the initialization expressions. |
120 // While unclear from the spec (ECMA-262, 3rd., 12.2), the value of | 139 // While unclear from the spec (ECMA-262, 3rd., 12.2), the value of |
121 // a variable declaration with initialization expression is 'undefined' | 140 // a variable declaration with initialization expression is 'undefined' |
122 // with some JS VMs: For instance, using smjs, print(eval('var x = 7')) | 141 // 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 | 142 // returns 'undefined'. To obtain the same behavior with v8, we need |
124 // to prevent rewriting in that case. | 143 // to prevent rewriting in that case. |
125 if (!node->ignore_completion_value()) Process(node->statements()); | 144 if (!node->ignore_completion_value()) { |
145 BreakableScope scope(this, node->labels() != nullptr); | |
146 Process(node->statements()); | |
147 } | |
126 replacement_ = node; | 148 replacement_ = node; |
127 } | 149 } |
128 | 150 |
129 | 151 |
130 void Processor::VisitExpressionStatement(ExpressionStatement* node) { | 152 void Processor::VisitExpressionStatement(ExpressionStatement* node) { |
131 // Rewrite : <x>; -> .result = <x>; | 153 // Rewrite : <x>; -> .result = <x>; |
132 if (!is_set_) { | 154 if (!is_set_) { |
133 node->set_expression(SetResult(node->expression())); | 155 node->set_expression(SetResult(node->expression())); |
134 is_set_ = true; | 156 is_set_ = true; |
135 } | 157 } |
(...skipping 14 matching lines...) Expand all Loading... | |
150 replacement_ = node; | 172 replacement_ = node; |
151 | 173 |
152 if (!is_set_) { | 174 if (!is_set_) { |
153 is_set_ = true; | 175 is_set_ = true; |
154 replacement_ = AssignUndefinedBefore(node); | 176 replacement_ = AssignUndefinedBefore(node); |
155 } | 177 } |
156 } | 178 } |
157 | 179 |
158 | 180 |
159 void Processor::VisitIterationStatement(IterationStatement* node) { | 181 void Processor::VisitIterationStatement(IterationStatement* node) { |
182 BreakableScope scope(this); | |
160 // Rewrite the body. | 183 // Rewrite the body. |
161 bool set_after = is_set_; | 184 bool set_after = is_set_; |
162 is_set_ = false; // We are in a loop, so we can't rely on [set_after]. | 185 is_set_ = false; // We are in a loop, so we can't rely on [set_after]. |
163 Visit(node->body()); | 186 Visit(node->body()); |
164 node->set_body(replacement_); | 187 node->set_body(replacement_); |
165 is_set_ = is_set_ && set_after; | 188 is_set_ = is_set_ && set_after; |
166 replacement_ = node; | 189 replacement_ = node; |
167 | 190 |
168 if (!is_set_) { | 191 if (!is_set_) { |
169 is_set_ = true; | 192 is_set_ = true; |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
246 replacement_ = node; | 269 replacement_ = node; |
247 | 270 |
248 if (!is_set_) { | 271 if (!is_set_) { |
249 is_set_ = true; | 272 is_set_ = true; |
250 replacement_ = AssignUndefinedBefore(node); | 273 replacement_ = AssignUndefinedBefore(node); |
251 } | 274 } |
252 } | 275 } |
253 | 276 |
254 | 277 |
255 void Processor::VisitSwitchStatement(SwitchStatement* node) { | 278 void Processor::VisitSwitchStatement(SwitchStatement* node) { |
279 BreakableScope scope(this); | |
256 // Rewrite statements in all case clauses (in reverse order). | 280 // Rewrite statements in all case clauses (in reverse order). |
257 ZoneList<CaseClause*>* clauses = node->cases(); | 281 ZoneList<CaseClause*>* clauses = node->cases(); |
258 bool set_after = is_set_; | 282 bool set_after = is_set_; |
259 for (int i = clauses->length() - 1; i >= 0; --i) { | 283 for (int i = clauses->length() - 1; i >= 0; --i) { |
260 CaseClause* clause = clauses->at(i); | 284 CaseClause* clause = clauses->at(i); |
261 Process(clause->statements()); | 285 Process(clause->statements()); |
262 } | 286 } |
263 is_set_ = is_set_ && set_after; | 287 is_set_ = is_set_ && set_after; |
264 replacement_ = node; | 288 replacement_ = node; |
265 | 289 |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
391 processor.SetResult(undef), expr->position()); | 415 processor.SetResult(undef), expr->position()); |
392 body->Add(completion, factory->zone()); | 416 body->Add(completion, factory->zone()); |
393 } | 417 } |
394 } | 418 } |
395 return true; | 419 return true; |
396 } | 420 } |
397 | 421 |
398 | 422 |
399 } // namespace internal | 423 } // namespace internal |
400 } // namespace v8 | 424 } // namespace v8 |
OLD | NEW |