| Index: src/parsing/rewriter.cc
|
| diff --git a/src/parsing/rewriter.cc b/src/parsing/rewriter.cc
|
| index 19e9e4cd80d05d9cc07138f6c61e91d16a06c8d3..69ac4171c273eef7aa0aa14d1524a1944c04e203 100644
|
| --- a/src/parsing/rewriter.cc
|
| +++ b/src/parsing/rewriter.cc
|
| @@ -167,36 +167,33 @@ void Processor::VisitExpressionStatement(ExpressionStatement* node) {
|
| void Processor::VisitIfStatement(IfStatement* node) {
|
| // Rewrite both branches.
|
| bool set_after = is_set_;
|
| +
|
| Visit(node->then_statement());
|
| node->set_then_statement(replacement_);
|
| bool set_in_then = is_set_;
|
| +
|
| is_set_ = set_after;
|
| Visit(node->else_statement());
|
| node->set_else_statement(replacement_);
|
| - is_set_ = is_set_ && set_in_then;
|
| - replacement_ = node;
|
|
|
| - if (!is_set_) {
|
| - is_set_ = true;
|
| - replacement_ = AssignUndefinedBefore(node);
|
| - }
|
| + replacement_ = set_in_then && is_set_ ? node : AssignUndefinedBefore(node);
|
| + is_set_ = true;
|
| }
|
|
|
|
|
| void Processor::VisitIterationStatement(IterationStatement* node) {
|
| + // The statement may have to produce a value, so always assign undefined
|
| + // before.
|
| + // TODO(verwaest): Omit it if we know that there's no break/continue leaving
|
| + // it early.
|
| + DCHECK(breakable_ || !is_set_);
|
| BreakableScope scope(this);
|
| - // Rewrite the body.
|
| - bool set_after = is_set_;
|
| - is_set_ = false; // We are in a loop, so we can't rely on [set_after].
|
| +
|
| Visit(node->body());
|
| node->set_body(replacement_);
|
| - is_set_ = is_set_ && set_after;
|
| - replacement_ = node;
|
|
|
| - if (!is_set_) {
|
| - is_set_ = true;
|
| - replacement_ = AssignUndefinedBefore(node);
|
| - }
|
| + replacement_ = AssignUndefinedBefore(node);
|
| + is_set_ = true;
|
| }
|
|
|
|
|
| @@ -228,74 +225,72 @@ void Processor::VisitForOfStatement(ForOfStatement* node) {
|
| void Processor::VisitTryCatchStatement(TryCatchStatement* node) {
|
| // Rewrite both try and catch block.
|
| bool set_after = is_set_;
|
| +
|
| Visit(node->try_block());
|
| node->set_try_block(static_cast<Block*>(replacement_));
|
| bool set_in_try = is_set_;
|
| +
|
| is_set_ = set_after;
|
| Visit(node->catch_block());
|
| node->set_catch_block(static_cast<Block*>(replacement_));
|
| - is_set_ = is_set_ && set_in_try;
|
| - replacement_ = node;
|
|
|
| - if (!is_set_) {
|
| - is_set_ = true;
|
| - replacement_ = AssignUndefinedBefore(node);
|
| - }
|
| + replacement_ = is_set_ && set_in_try ? node : AssignUndefinedBefore(node);
|
| + is_set_ = true;
|
| }
|
|
|
|
|
| void Processor::VisitTryFinallyStatement(TryFinallyStatement* node) {
|
| - // Rewrite both try and finally block (in reverse order).
|
| - bool set_after = is_set_;
|
| - is_set_ = true; // Don't normally need to assign in finally block.
|
| - Visit(node->finally_block());
|
| - node->set_finally_block(replacement_->AsBlock());
|
| - { // Save .result value at the beginning of the finally block and restore it
|
| - // at the end again: ".backup = .result; ...; .result = .backup"
|
| - // This is necessary because the finally block does not normally contribute
|
| - // to the completion value.
|
| - CHECK_NOT_NULL(closure_scope());
|
| - Variable* backup = closure_scope()->NewTemporary(
|
| - factory()->ast_value_factory()->dot_result_string());
|
| - Expression* backup_proxy = factory()->NewVariableProxy(backup);
|
| - Expression* result_proxy = factory()->NewVariableProxy(result_);
|
| - Expression* save = factory()->NewAssignment(
|
| - Token::ASSIGN, backup_proxy, result_proxy, kNoSourcePosition);
|
| - Expression* restore = factory()->NewAssignment(
|
| - Token::ASSIGN, result_proxy, backup_proxy, kNoSourcePosition);
|
| - node->finally_block()->statements()->InsertAt(
|
| - 0, factory()->NewExpressionStatement(save, kNoSourcePosition), zone());
|
| - node->finally_block()->statements()->Add(
|
| - factory()->NewExpressionStatement(restore, kNoSourcePosition), zone());
|
| + // Only rewrite finally if it could contain 'break' or 'continue'. Always
|
| + // rewrite try.
|
| + if (breakable_) {
|
| + bool set_after = is_set_;
|
| + // Only set result before a 'break' or 'continue'.
|
| + is_set_ = true;
|
| + Visit(node->finally_block());
|
| + node->set_finally_block(replacement_->AsBlock());
|
| + // Save .result value at the beginning of the finally block and restore it
|
| + // at the end again: ".backup = .result; ...; .result = .backup"
|
| + // This is necessary because the finally block does not normally contribute
|
| + // to the completion value.
|
| + CHECK_NOT_NULL(closure_scope());
|
| + Variable* backup = closure_scope()->NewTemporary(
|
| + factory()->ast_value_factory()->dot_result_string());
|
| + Expression* backup_proxy = factory()->NewVariableProxy(backup);
|
| + Expression* result_proxy = factory()->NewVariableProxy(result_);
|
| + Expression* save = factory()->NewAssignment(
|
| + Token::ASSIGN, backup_proxy, result_proxy, kNoSourcePosition);
|
| + Expression* restore = factory()->NewAssignment(
|
| + Token::ASSIGN, result_proxy, backup_proxy, kNoSourcePosition);
|
| + node->finally_block()->statements()->InsertAt(
|
| + 0, factory()->NewExpressionStatement(save, kNoSourcePosition), zone());
|
| + node->finally_block()->statements()->Add(
|
| + factory()->NewExpressionStatement(restore, kNoSourcePosition), zone());
|
| + is_set_ = set_after;
|
| }
|
| - is_set_ = set_after;
|
| Visit(node->try_block());
|
| node->set_try_block(replacement_->AsBlock());
|
| - replacement_ = node;
|
|
|
| - if (!is_set_) {
|
| - is_set_ = true;
|
| - replacement_ = AssignUndefinedBefore(node);
|
| - }
|
| + replacement_ = is_set_ ? node : AssignUndefinedBefore(node);
|
| + is_set_ = true;
|
| }
|
|
|
|
|
| void Processor::VisitSwitchStatement(SwitchStatement* node) {
|
| + // The statement may have to produce a value, so always assign undefined
|
| + // before.
|
| + // TODO(verwaest): Omit it if we know that there's no break/continue leaving
|
| + // it early.
|
| + DCHECK(breakable_ || !is_set_);
|
| BreakableScope scope(this);
|
| - // Rewrite statements in all case clauses (in reverse order).
|
| + // Rewrite statements in all case clauses.
|
| ZoneList<CaseClause*>* clauses = node->cases();
|
| - bool set_after = is_set_;
|
| for (int i = clauses->length() - 1; i >= 0; --i) {
|
| CaseClause* clause = clauses->at(i);
|
| Process(clause->statements());
|
| }
|
| - is_set_ = is_set_ && set_after;
|
| - replacement_ = node;
|
|
|
| - if (!is_set_) {
|
| - is_set_ = true;
|
| - replacement_ = AssignUndefinedBefore(node);
|
| - }
|
| + replacement_ = AssignUndefinedBefore(node);
|
| + is_set_ = true;
|
| }
|
|
|
|
|
| @@ -314,12 +309,9 @@ void Processor::VisitBreakStatement(BreakStatement* node) {
|
| void Processor::VisitWithStatement(WithStatement* node) {
|
| Visit(node->statement());
|
| node->set_statement(replacement_);
|
| - replacement_ = node;
|
|
|
| - if (!is_set_) {
|
| - is_set_ = true;
|
| - replacement_ = AssignUndefinedBefore(node);
|
| - }
|
| + replacement_ = is_set_ ? node : AssignUndefinedBefore(node);
|
| + is_set_ = true;
|
| }
|
|
|
|
|
|
|