Index: src/full-codegen/full-codegen.h |
diff --git a/src/full-codegen/full-codegen.h b/src/full-codegen/full-codegen.h |
index e99462c19bf507175e025fa0926e2e6a2fad0837..f44e7784e65e9bda14084077824aa16336a4b1ad 100644 |
--- a/src/full-codegen/full-codegen.h |
+++ b/src/full-codegen/full-codegen.h |
@@ -99,6 +99,7 @@ class FullCodeGenerator: public AstVisitor { |
private: |
class Breakable; |
class Iteration; |
+ class TryFinally; |
class TestContext; |
@@ -115,11 +116,13 @@ class FullCodeGenerator: public AstVisitor { |
codegen_->nesting_stack_ = previous_; |
} |
- virtual Breakable* AsBreakable() { return NULL; } |
- virtual Iteration* AsIteration() { return NULL; } |
+ virtual Breakable* AsBreakable() { return nullptr; } |
+ virtual Iteration* AsIteration() { return nullptr; } |
+ virtual TryFinally* AsTryFinally() { return nullptr; } |
virtual bool IsContinueTarget(Statement* target) { return false; } |
virtual bool IsBreakTarget(Statement* target) { return false; } |
+ virtual bool IsTryFinally() { return false; } |
// Notify the statement that we are exiting it via break, continue, or |
// return and give it a chance to generate cleanup code. Return the |
@@ -217,14 +220,50 @@ class FullCodeGenerator: public AstVisitor { |
} |
}; |
+ class DeferredCommands { |
+ public: |
+ enum Command { kReturn, kThrow, kBreak, kContinue }; |
+ typedef int TokenId; |
+ struct DeferredCommand { |
+ Command command; |
+ TokenId token; |
+ Statement* target; |
+ }; |
+ |
+ DeferredCommands(FullCodeGenerator* codegen, Label* finally_entry) |
+ : codegen_(codegen), |
+ commands_(codegen->zone()), |
+ return_token_(TokenDispenserForFinally::kInvalidToken), |
+ throw_token_(TokenDispenserForFinally::kInvalidToken), |
+ finally_entry_(finally_entry) {} |
+ |
+ void EmitCommands(); |
+ |
+ void RecordBreak(Statement* target); |
+ void RecordContinue(Statement* target); |
+ void RecordReturn(); |
+ void RecordThrow(); |
+ void EmitFallThrough(); |
+ |
+ private: |
+ MacroAssembler* masm() { return codegen_->masm(); } |
+ void EmitJumpToFinally(TokenId token); |
+ |
+ FullCodeGenerator* codegen_; |
+ ZoneVector<DeferredCommand> commands_; |
+ TokenDispenserForFinally dispenser_; |
+ TokenId return_token_; |
+ TokenId throw_token_; |
+ Label* finally_entry_; |
+ }; |
+ |
// The try block of a try/finally statement. |
class TryFinally : public NestedStatement { |
public: |
static const int kElementCount = TryBlockConstant::kElementCount; |
- TryFinally(FullCodeGenerator* codegen, Label* finally_entry) |
- : NestedStatement(codegen), finally_entry_(finally_entry) { |
- } |
+ TryFinally(FullCodeGenerator* codegen, DeferredCommands* commands) |
+ : NestedStatement(codegen), deferred_commands_(commands) {} |
NestedStatement* Exit(int* stack_depth, int* context_length) override; |
NestedStatement* AccumulateDepth(int* stack_depth) override { |
@@ -232,8 +271,13 @@ class FullCodeGenerator: public AstVisitor { |
return previous_; |
} |
+ bool IsTryFinally() override { return true; } |
+ TryFinally* AsTryFinally() override { return this; } |
+ |
+ DeferredCommands* deferred_commands() { return deferred_commands_; } |
+ |
private: |
- Label* finally_entry_; |
+ DeferredCommands* deferred_commands_; |
}; |
// The finally block of a try/finally statement. |
@@ -455,8 +499,9 @@ class FullCodeGenerator: public AstVisitor { |
// Emit code to pop values from the stack associated with nested statements |
// like try/catch, try/finally, etc, running the finallies and unwinding the |
- // handlers as needed. |
- void EmitUnwindBeforeReturn(); |
+ // handlers as needed. Also emits the return sequence if necessary (i.e., |
+ // if the return is not delayed by a finally block). |
+ void EmitUnwindAndReturn(); |
// Platform-specific return sequence |
void EmitReturnSequence(); |
@@ -669,6 +714,9 @@ class FullCodeGenerator: public AstVisitor { |
void ExitFinallyBlock(); |
void ClearPendingMessage(); |
+ void EmitContinue(Statement* target); |
+ void EmitBreak(Statement* target); |
+ |
// Loop nesting counter. |
int loop_depth() { return loop_depth_; } |
void increment_loop_depth() { loop_depth_++; } |