Index: src/rewriter.cc |
diff --git a/src/rewriter.cc b/src/rewriter.cc |
index 11af2bd26246d6fb44ee3fa5cd734f87071dff29..086a5a86f37ecb6cd8fb533eaac6ff913f9041f2 100644 |
--- a/src/rewriter.cc |
+++ b/src/rewriter.cc |
@@ -13,12 +13,13 @@ namespace internal { |
class Processor: public AstVisitor { |
public: |
- Processor(Isolate* isolate, Variable* result, |
+ Processor(Isolate* isolate, Scope* scope, Variable* result, |
AstValueFactory* ast_value_factory) |
: result_(result), |
result_assigned_(false), |
replacement_(nullptr), |
is_set_(false), |
+ scope_(scope), |
factory_(ast_value_factory) { |
InitializeAstVisitor(isolate, ast_value_factory->zone()); |
} |
@@ -28,6 +29,7 @@ class Processor: public AstVisitor { |
void Process(ZoneList<Statement*>* statements); |
bool result_assigned() const { return result_assigned_; } |
+ Scope* scope() { return scope_; } |
AstNodeFactory* factory() { return &factory_; } |
private: |
@@ -49,8 +51,10 @@ class Processor: public AstVisitor { |
// was hoping for. |
bool is_set_; |
+ Scope* scope_; |
AstNodeFactory factory_; |
+ // Returns ".result = value" |
Expression* SetResult(Expression* value) { |
result_assigned_ = true; |
VariableProxy* result_proxy = factory()->NewVariableProxy(result_); |
@@ -167,9 +171,31 @@ void Processor::VisitTryCatchStatement(TryCatchStatement* node) { |
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()); |
- Visit(node->try_block()); // Exception will not be caught. |
+ { // 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. |
+ Variable* backup = 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, RelocInfo::kNoPosition); |
+ Expression* restore = factory()->NewAssignment( |
+ Token::ASSIGN, result_proxy, backup_proxy, RelocInfo::kNoPosition); |
+ node->finally_block()->statements()->InsertAt( |
+ 0, factory()->NewExpressionStatement(save, RelocInfo::kNoPosition), |
+ zone()); |
+ node->finally_block()->statements()->Add( |
+ factory()->NewExpressionStatement(restore, RelocInfo::kNoPosition), |
+ zone()); |
+ } |
+ is_set_ = set_after; |
+ Visit(node->try_block()); |
node->set_try_block(replacement_->AsBlock()); |
replacement_ = node; |
} |
@@ -260,7 +286,8 @@ bool Rewriter::Rewrite(ParseInfo* info) { |
scope->NewTemporary(info->ast_value_factory()->dot_result_string()); |
// The name string must be internalized at this point. |
DCHECK(!result->name().is_null()); |
- Processor processor(info->isolate(), result, info->ast_value_factory()); |
+ Processor processor(info->isolate(), scope, result, |
+ info->ast_value_factory()); |
processor.Process(body); |
if (processor.HasStackOverflow()) return false; |