Chromium Code Reviews| 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_; | 287 for (int i = 0; i < clauses->length(); ++i) { |
|
neis
2016/10/21 12:15:25
I think changing the order here is wrong. Consider
Toon Verwaest
2016/10/21 14:15:01
Good point, I'll add the test.
| |
| 288 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) { |
| 310 bool set_after = is_set_; | |
| 311 | |
| 315 Visit(node->statement()); | 312 Visit(node->statement()); |
| 316 node->set_statement(replacement_); | 313 node->set_statement(replacement_); |
| 317 replacement_ = node; | |
| 318 | 314 |
| 319 if (!is_set_) { | 315 replacement_ = set_after ? node : AssignUndefinedBefore(node); |
|
neis
2016/10/21 12:15:25
Why did you change this to look at the old value o
Toon Verwaest
2016/10/21 14:13:08
Because is set has no meaning. That's just whether
neis
2016/10/21 16:06:13
If is_set_ is true, we shouldn't need to assign un
| |
| 320 is_set_ = true; | 316 is_set_ = true; |
| 321 replacement_ = AssignUndefinedBefore(node); | |
| 322 } | |
| 323 } | 317 } |
| 324 | 318 |
| 325 | 319 |
| 326 void Processor::VisitSloppyBlockFunctionStatement( | 320 void Processor::VisitSloppyBlockFunctionStatement( |
| 327 SloppyBlockFunctionStatement* node) { | 321 SloppyBlockFunctionStatement* node) { |
| 328 Visit(node->statement()); | 322 Visit(node->statement()); |
| 329 node->set_statement(replacement_); | 323 node->set_statement(replacement_); |
| 330 replacement_ = node; | 324 replacement_ = node; |
| 331 } | 325 } |
| 332 | 326 |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 420 processor.SetResult(undef), expr->position()); | 414 processor.SetResult(undef), expr->position()); |
| 421 body->Add(completion, factory->zone()); | 415 body->Add(completion, factory->zone()); |
| 422 } | 416 } |
| 423 } | 417 } |
| 424 return true; | 418 return true; |
| 425 } | 419 } |
| 426 | 420 |
| 427 | 421 |
| 428 } // namespace internal | 422 } // namespace internal |
| 429 } // namespace v8 | 423 } // namespace v8 |
| OLD | NEW |