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" |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
160 node->set_expression(SetResult(node->expression())); | 160 node->set_expression(SetResult(node->expression())); |
161 is_set_ = true; | 161 is_set_ = true; |
162 } | 162 } |
163 replacement_ = node; | 163 replacement_ = node; |
164 } | 164 } |
165 | 165 |
166 | 166 |
167 void Processor::VisitIfStatement(IfStatement* node) { | 167 void Processor::VisitIfStatement(IfStatement* node) { |
168 // Rewrite both branches. | 168 // Rewrite both branches. |
169 bool set_after = is_set_; | 169 bool set_after = is_set_; |
| 170 |
170 Visit(node->then_statement()); | 171 Visit(node->then_statement()); |
171 node->set_then_statement(replacement_); | 172 node->set_then_statement(replacement_); |
172 bool set_in_then = is_set_; | 173 bool set_in_then = is_set_; |
| 174 |
173 is_set_ = set_after; | 175 is_set_ = set_after; |
174 Visit(node->else_statement()); | 176 Visit(node->else_statement()); |
175 node->set_else_statement(replacement_); | 177 node->set_else_statement(replacement_); |
176 is_set_ = is_set_ && set_in_then; | |
177 replacement_ = node; | |
178 | 178 |
179 if (!is_set_) { | 179 replacement_ = set_in_then && is_set_ ? node : AssignUndefinedBefore(node); |
180 is_set_ = true; | 180 is_set_ = true; |
181 replacement_ = AssignUndefinedBefore(node); | |
182 } | |
183 } | 181 } |
184 | 182 |
185 | 183 |
186 void Processor::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_); |
187 BreakableScope scope(this); | 190 BreakableScope scope(this); |
188 // Rewrite the body. | 191 |
189 bool set_after = is_set_; | |
190 is_set_ = false; // We are in a loop, so we can't rely on [set_after]. | |
191 Visit(node->body()); | 192 Visit(node->body()); |
192 node->set_body(replacement_); | 193 node->set_body(replacement_); |
193 is_set_ = is_set_ && set_after; | |
194 replacement_ = node; | |
195 | 194 |
196 if (!is_set_) { | 195 replacement_ = AssignUndefinedBefore(node); |
197 is_set_ = true; | 196 is_set_ = true; |
198 replacement_ = AssignUndefinedBefore(node); | |
199 } | |
200 } | 197 } |
201 | 198 |
202 | 199 |
203 void Processor::VisitDoWhileStatement(DoWhileStatement* node) { | 200 void Processor::VisitDoWhileStatement(DoWhileStatement* node) { |
204 VisitIterationStatement(node); | 201 VisitIterationStatement(node); |
205 } | 202 } |
206 | 203 |
207 | 204 |
208 void Processor::VisitWhileStatement(WhileStatement* node) { | 205 void Processor::VisitWhileStatement(WhileStatement* node) { |
209 VisitIterationStatement(node); | 206 VisitIterationStatement(node); |
(...skipping 11 matching lines...) Expand all Loading... |
221 | 218 |
222 | 219 |
223 void Processor::VisitForOfStatement(ForOfStatement* node) { | 220 void Processor::VisitForOfStatement(ForOfStatement* node) { |
224 VisitIterationStatement(node); | 221 VisitIterationStatement(node); |
225 } | 222 } |
226 | 223 |
227 | 224 |
228 void Processor::VisitTryCatchStatement(TryCatchStatement* node) { | 225 void Processor::VisitTryCatchStatement(TryCatchStatement* node) { |
229 // Rewrite both try and catch block. | 226 // Rewrite both try and catch block. |
230 bool set_after = is_set_; | 227 bool set_after = is_set_; |
| 228 |
231 Visit(node->try_block()); | 229 Visit(node->try_block()); |
232 node->set_try_block(static_cast<Block*>(replacement_)); | 230 node->set_try_block(static_cast<Block*>(replacement_)); |
233 bool set_in_try = is_set_; | 231 bool set_in_try = is_set_; |
| 232 |
234 is_set_ = set_after; | 233 is_set_ = set_after; |
235 Visit(node->catch_block()); | 234 Visit(node->catch_block()); |
236 node->set_catch_block(static_cast<Block*>(replacement_)); | 235 node->set_catch_block(static_cast<Block*>(replacement_)); |
237 is_set_ = is_set_ && set_in_try; | |
238 replacement_ = node; | |
239 | 236 |
240 if (!is_set_) { | 237 replacement_ = is_set_ && set_in_try ? node : AssignUndefinedBefore(node); |
241 is_set_ = true; | 238 is_set_ = true; |
242 replacement_ = AssignUndefinedBefore(node); | |
243 } | |
244 } | 239 } |
245 | 240 |
246 | 241 |
247 void Processor::VisitTryFinallyStatement(TryFinallyStatement* node) { | 242 void Processor::VisitTryFinallyStatement(TryFinallyStatement* node) { |
248 // Rewrite both try and finally block (in reverse order). | 243 // Only rewrite finally if it could contain 'break' or 'continue'. Always |
249 bool set_after = is_set_; | 244 // rewrite try. |
250 is_set_ = true; // Don't normally need to assign in finally block. | 245 if (breakable_) { |
251 Visit(node->finally_block()); | 246 bool set_after = is_set_; |
252 node->set_finally_block(replacement_->AsBlock()); | 247 // Only set result before a 'break' or 'continue'. |
253 { // Save .result value at the beginning of the finally block and restore it | 248 is_set_ = true; |
254 // at the end again: ".backup = .result; ...; .result = .backup" | 249 Visit(node->finally_block()); |
255 // This is necessary because the finally block does not normally contribute | 250 node->set_finally_block(replacement_->AsBlock()); |
256 // to the completion value. | 251 // Save .result value at the beginning of the finally block and restore it |
257 CHECK_NOT_NULL(closure_scope()); | 252 // at the end again: ".backup = .result; ...; .result = .backup" |
258 Variable* backup = closure_scope()->NewTemporary( | 253 // This is necessary because the finally block does not normally contribute |
259 factory()->ast_value_factory()->dot_result_string()); | 254 // to the completion value. |
260 Expression* backup_proxy = factory()->NewVariableProxy(backup); | 255 CHECK_NOT_NULL(closure_scope()); |
261 Expression* result_proxy = factory()->NewVariableProxy(result_); | 256 Variable* backup = closure_scope()->NewTemporary( |
262 Expression* save = factory()->NewAssignment( | 257 factory()->ast_value_factory()->dot_result_string()); |
263 Token::ASSIGN, backup_proxy, result_proxy, kNoSourcePosition); | 258 Expression* backup_proxy = factory()->NewVariableProxy(backup); |
264 Expression* restore = factory()->NewAssignment( | 259 Expression* result_proxy = factory()->NewVariableProxy(result_); |
265 Token::ASSIGN, result_proxy, backup_proxy, kNoSourcePosition); | 260 Expression* save = factory()->NewAssignment( |
266 node->finally_block()->statements()->InsertAt( | 261 Token::ASSIGN, backup_proxy, result_proxy, kNoSourcePosition); |
267 0, factory()->NewExpressionStatement(save, kNoSourcePosition), zone()); | 262 Expression* restore = factory()->NewAssignment( |
268 node->finally_block()->statements()->Add( | 263 Token::ASSIGN, result_proxy, backup_proxy, kNoSourcePosition); |
269 factory()->NewExpressionStatement(restore, kNoSourcePosition), zone()); | 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; |
270 } | 269 } |
271 is_set_ = set_after; | |
272 Visit(node->try_block()); | 270 Visit(node->try_block()); |
273 node->set_try_block(replacement_->AsBlock()); | 271 node->set_try_block(replacement_->AsBlock()); |
274 replacement_ = node; | |
275 | 272 |
276 if (!is_set_) { | 273 replacement_ = is_set_ ? node : AssignUndefinedBefore(node); |
277 is_set_ = true; | 274 is_set_ = true; |
278 replacement_ = AssignUndefinedBefore(node); | |
279 } | |
280 } | 275 } |
281 | 276 |
282 | 277 |
283 void Processor::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); | 284 BreakableScope scope(this); |
285 // Rewrite statements in all case clauses (in reverse order). | 285 // Rewrite statements in all case clauses. |
286 ZoneList<CaseClause*>* clauses = node->cases(); | 286 ZoneList<CaseClause*>* clauses = node->cases(); |
287 bool set_after = is_set_; | |
288 for (int i = clauses->length() - 1; i >= 0; --i) { | 287 for (int i = clauses->length() - 1; i >= 0; --i) { |
289 CaseClause* clause = clauses->at(i); | 288 CaseClause* clause = clauses->at(i); |
290 Process(clause->statements()); | 289 Process(clause->statements()); |
291 } | 290 } |
292 is_set_ = is_set_ && set_after; | |
293 replacement_ = node; | |
294 | 291 |
295 if (!is_set_) { | 292 replacement_ = AssignUndefinedBefore(node); |
296 is_set_ = true; | 293 is_set_ = true; |
297 replacement_ = AssignUndefinedBefore(node); | |
298 } | |
299 } | 294 } |
300 | 295 |
301 | 296 |
302 void Processor::VisitContinueStatement(ContinueStatement* node) { | 297 void Processor::VisitContinueStatement(ContinueStatement* node) { |
303 is_set_ = false; | 298 is_set_ = false; |
304 replacement_ = node; | 299 replacement_ = node; |
305 } | 300 } |
306 | 301 |
307 | 302 |
308 void Processor::VisitBreakStatement(BreakStatement* node) { | 303 void Processor::VisitBreakStatement(BreakStatement* node) { |
309 is_set_ = false; | 304 is_set_ = false; |
310 replacement_ = node; | 305 replacement_ = node; |
311 } | 306 } |
312 | 307 |
313 | 308 |
314 void Processor::VisitWithStatement(WithStatement* node) { | 309 void Processor::VisitWithStatement(WithStatement* node) { |
315 Visit(node->statement()); | 310 Visit(node->statement()); |
316 node->set_statement(replacement_); | 311 node->set_statement(replacement_); |
317 replacement_ = node; | |
318 | 312 |
319 if (!is_set_) { | 313 replacement_ = is_set_ ? node : AssignUndefinedBefore(node); |
320 is_set_ = true; | 314 is_set_ = true; |
321 replacement_ = AssignUndefinedBefore(node); | |
322 } | |
323 } | 315 } |
324 | 316 |
325 | 317 |
326 void Processor::VisitSloppyBlockFunctionStatement( | 318 void Processor::VisitSloppyBlockFunctionStatement( |
327 SloppyBlockFunctionStatement* node) { | 319 SloppyBlockFunctionStatement* node) { |
328 Visit(node->statement()); | 320 Visit(node->statement()); |
329 node->set_statement(replacement_); | 321 node->set_statement(replacement_); |
330 replacement_ = node; | 322 replacement_ = node; |
331 } | 323 } |
332 | 324 |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
420 processor.SetResult(undef), expr->position()); | 412 processor.SetResult(undef), expr->position()); |
421 body->Add(completion, factory->zone()); | 413 body->Add(completion, factory->zone()); |
422 } | 414 } |
423 } | 415 } |
424 return true; | 416 return true; |
425 } | 417 } |
426 | 418 |
427 | 419 |
428 } // namespace internal | 420 } // namespace internal |
429 } // namespace v8 | 421 } // namespace v8 |
OLD | NEW |