Index: src/rewriter.cc |
diff --git a/src/rewriter.cc b/src/rewriter.cc |
index 89b3e45a4b5660b8edaef244bba24fd0a3152c5d..d88e1199f82a697bed4f622ab6620970756ec881 100644 |
--- a/src/rewriter.cc |
+++ b/src/rewriter.cc |
@@ -16,7 +16,9 @@ |
Processor(Isolate* isolate, Variable* result, |
AstValueFactory* ast_value_factory) |
: result_(result), |
+ result_assigned_(false), |
is_set_(false), |
+ in_try_(false), |
factory_(ast_value_factory) { |
InitializeAstVisitor(isolate, ast_value_factory->zone()); |
} |
@@ -24,21 +26,30 @@ |
virtual ~Processor() { } |
void Process(ZoneList<Statement*>* statements); |
+ bool result_assigned() const { return result_assigned_; } |
AstNodeFactory* factory() { return &factory_; } |
private: |
Variable* result_; |
+ |
+ // We are not tracking result usage via the result_'s use |
+ // counts (we leave the accurate computation to the |
+ // usage analyzer). Instead we simple remember if |
+ // there was ever an assignment to result_. |
+ bool result_assigned_; |
// To avoid storing to .result all the time, we eliminate some of |
// the stores by keeping track of whether or not we're sure .result |
// will be overwritten anyway. This is a bit more tricky than what I |
- // was hoping for. |
+ // was hoping for |
bool is_set_; |
+ bool in_try_; |
AstNodeFactory factory_; |
Expression* SetResult(Expression* value) { |
+ result_assigned_ = true; |
VariableProxy* result_proxy = factory()->NewVariableProxy(result_); |
return factory()->NewAssignment( |
Token::ASSIGN, result_proxy, value, RelocInfo::kNoPosition); |
@@ -77,30 +88,29 @@ |
void Processor::VisitExpressionStatement(ExpressionStatement* node) { |
// Rewrite : <x>; -> .result = <x>; |
- if (!is_set_) { |
+ if (!is_set_ && !node->expression()->IsThrow()) { |
node->set_expression(SetResult(node->expression())); |
- is_set_ = true; |
+ if (!in_try_) is_set_ = true; |
} |
} |
void Processor::VisitIfStatement(IfStatement* node) { |
- // Rewrite both branches. |
- bool set_after = is_set_; |
+ // Rewrite both then and else parts (reversed). |
+ bool save = is_set_; |
+ Visit(node->else_statement()); |
+ bool set_after_then = is_set_; |
+ is_set_ = save; |
Visit(node->then_statement()); |
- bool set_in_then = is_set_; |
- is_set_ = set_after; |
- Visit(node->else_statement()); |
- is_set_ = is_set_ && set_in_then; |
+ is_set_ = is_set_ && set_after_then; |
} |
void Processor::VisitIterationStatement(IterationStatement* node) { |
// Rewrite the body. |
- bool set_after = is_set_; |
- is_set_ = false; // We are in a loop, so we can't rely on [set_after]. |
+ bool set_after_loop = is_set_; |
Visit(node->body()); |
- is_set_ = is_set_ && set_after; |
+ is_set_ = is_set_ && set_after_loop; |
} |
@@ -130,32 +140,36 @@ |
void Processor::VisitTryCatchStatement(TryCatchStatement* node) { |
- // Rewrite both try and catch block. |
- bool set_after = is_set_; |
+ // Rewrite both try and catch blocks (reversed order). |
+ bool set_after_catch = is_set_; |
+ Visit(node->catch_block()); |
+ is_set_ = is_set_ && set_after_catch; |
+ bool save = in_try_; |
+ in_try_ = true; |
Visit(node->try_block()); |
- bool set_in_try = is_set_; |
- is_set_ = set_after; |
- Visit(node->catch_block()); |
- is_set_ = is_set_ && set_in_try; |
+ in_try_ = save; |
} |
void Processor::VisitTryFinallyStatement(TryFinallyStatement* node) { |
- // Rewrite both try and finally block (in reverse order). |
+ // Rewrite both try and finally block (reversed order). |
Visit(node->finally_block()); |
+ bool save = in_try_; |
+ in_try_ = true; |
Visit(node->try_block()); |
+ in_try_ = save; |
} |
void Processor::VisitSwitchStatement(SwitchStatement* node) { |
- // Rewrite statements in all case clauses (in reverse order). |
+ // Rewrite statements in all case clauses in reversed order. |
ZoneList<CaseClause*>* clauses = node->cases(); |
- bool set_after = is_set_; |
+ bool set_after_switch = 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; |
+ is_set_ = is_set_ && set_after_switch; |
} |
@@ -170,7 +184,9 @@ |
void Processor::VisitWithStatement(WithStatement* node) { |
+ bool set_after_body = is_set_; |
Visit(node->statement()); |
+ is_set_ = is_set_ && set_after_body; |
} |
@@ -180,25 +196,20 @@ |
} |
-void Processor::VisitReturnStatement(ReturnStatement* node) { is_set_ = true; } |
- |
- |
// Do nothing: |
+void Processor::VisitVariableDeclaration(VariableDeclaration* node) {} |
+void Processor::VisitFunctionDeclaration(FunctionDeclaration* node) {} |
+void Processor::VisitImportDeclaration(ImportDeclaration* node) {} |
+void Processor::VisitExportDeclaration(ExportDeclaration* node) {} |
void Processor::VisitEmptyStatement(EmptyStatement* node) {} |
+void Processor::VisitReturnStatement(ReturnStatement* node) {} |
void Processor::VisitDebuggerStatement(DebuggerStatement* node) {} |
-// Expressions are never visited. |
+// Expressions are never visited yet. |
#define DEF_VISIT(type) \ |
void Processor::Visit##type(type* expr) { UNREACHABLE(); } |
EXPRESSION_NODE_LIST(DEF_VISIT) |
-#undef DEF_VISIT |
- |
- |
-// Declarations are never visited. |
-#define DEF_VISIT(type) \ |
- void Processor::Visit##type(type* expr) { UNREACHABLE(); } |
-DECLARATION_NODE_LIST(DEF_VISIT) |
#undef DEF_VISIT |
@@ -221,19 +232,21 @@ |
processor.Process(body); |
if (processor.HasStackOverflow()) return false; |
- DCHECK(function->end_position() != RelocInfo::kNoPosition); |
- // Set the position of the assignment statement one character past the |
- // source code, such that it definitely is not in the source code range |
- // of an immediate inner scope. For example in |
- // eval('with ({x:1}) x = 1'); |
- // the end position of the function generated for executing the eval code |
- // coincides with the end of the with scope which is the position of '1'. |
- int pos = function->end_position(); |
- VariableProxy* result_proxy = |
- processor.factory()->NewVariableProxy(result, pos); |
- Statement* result_statement = |
- processor.factory()->NewReturnStatement(result_proxy, pos); |
- body->Add(result_statement, info->zone()); |
+ if (processor.result_assigned()) { |
+ DCHECK(function->end_position() != RelocInfo::kNoPosition); |
+ // Set the position of the assignment statement one character past the |
+ // source code, such that it definitely is not in the source code range |
+ // of an immediate inner scope. For example in |
+ // eval('with ({x:1}) x = 1'); |
+ // the end position of the function generated for executing the eval code |
+ // coincides with the end of the with scope which is the position of '1'. |
+ int pos = function->end_position(); |
+ VariableProxy* result_proxy = |
+ processor.factory()->NewVariableProxy(result, pos); |
+ Statement* result_statement = |
+ processor.factory()->NewReturnStatement(result_proxy, pos); |
+ body->Add(result_statement, info->zone()); |
+ } |
} |
return true; |