Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1019)

Unified Diff: src/parsing/rewriter.cc

Issue 2427253003: Simplify and fix the rewriter (Closed)
Patch Set: Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | test/mjsunit/es6/completion.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/parsing/rewriter.cc
diff --git a/src/parsing/rewriter.cc b/src/parsing/rewriter.cc
index b1b81caebd0981a659bc5ddc4d4787acbbd51b38..9246d1eb10a21bf7792af143781a4e8690c004f5 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) {
+ 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.
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;
}
@@ -312,14 +307,13 @@ void Processor::VisitBreakStatement(BreakStatement* node) {
void Processor::VisitWithStatement(WithStatement* node) {
+ bool set_after = is_set_;
+
Visit(node->statement());
node->set_statement(replacement_);
- replacement_ = node;
- if (!is_set_) {
- is_set_ = true;
- replacement_ = AssignUndefinedBefore(node);
- }
+ 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
+ is_set_ = true;
}
« no previous file with comments | « no previous file | test/mjsunit/es6/completion.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698