Index: runtime/vm/flow_graph_builder.cc |
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc |
index 2f96f6199d3a63a8063ab8cee2b69d4b86a42ef7..43ffdd34f286d556e939df88a9bbc8fb0067f19e 100644 |
--- a/runtime/vm/flow_graph_builder.cc |
+++ b/runtime/vm/flow_graph_builder.cc |
@@ -3244,45 +3244,52 @@ void EffectGraphVisitor::VisitCatchClauseNode(CatchClauseNode* node) { |
void EffectGraphVisitor::VisitTryCatchNode(TryCatchNode* node) { |
InlineBailout("EffectGraphVisitor::VisitTryCatchNode (exception)"); |
- intptr_t old_try_index = owner()->try_index(); |
Kevin Millikin (Google)
2013/06/26 14:27:04
The name 'try_index' isn't quite right. There can
|
- intptr_t try_index = owner()->AllocateTryIndex(); |
- owner()->set_try_index(try_index); |
+ intptr_t original_handler_index = owner()->try_index(); |
+ intptr_t try_handler_index = owner()->AllocateTryIndex(); |
+ owner()->set_try_index(try_handler_index); |
// Preserve CTX into local variable '%saved_context'. |
BuildStoreContext(node->context_var()); |
- EffectGraphVisitor for_try_block(owner(), temp_index()); |
- node->try_block()->Visit(&for_try_block); |
+ EffectGraphVisitor for_try(owner(), temp_index()); |
+ node->try_block()->Visit(&for_try); |
- if (for_try_block.is_open()) { |
+ if (for_try.is_open()) { |
JoinEntryInstr* after_try = |
- new JoinEntryInstr(owner()->AllocateBlockId(), old_try_index); |
- for_try_block.Goto(after_try); |
- for_try_block.exit_ = after_try; |
+ new JoinEntryInstr(owner()->AllocateBlockId(), original_handler_index); |
+ for_try.Goto(after_try); |
+ for_try.exit_ = after_try; |
} |
JoinEntryInstr* try_entry = |
- new JoinEntryInstr(owner()->AllocateBlockId(), try_index); |
+ new JoinEntryInstr(owner()->AllocateBlockId(), try_handler_index); |
Goto(try_entry); |
- AppendFragment(try_entry, for_try_block); |
- exit_ = for_try_block.exit_; |
+ AppendFragment(try_entry, for_try); |
+ exit_ = for_try.exit_; |
// We are done generating code for the try block. |
- owner()->set_try_index(old_try_index); |
+ owner()->set_try_index(original_handler_index); |
CatchClauseNode* catch_block = node->catch_block(); |
+ SequenceNode* finally_block = node->finally_block(); |
if (catch_block != NULL) { |
- EffectGraphVisitor for_catch_block(owner(), temp_index()); |
- catch_block->Visit(&for_catch_block); |
+ // If there is a finally block, it is the handler for code in the catch |
+ // block. |
+ intptr_t catch_handler_index = (finally_block == NULL) |
+ ? original_handler_index |
+ : owner()->AllocateTryIndex(); |
+ owner()->set_try_index(catch_handler_index); |
+ EffectGraphVisitor for_catch(owner(), temp_index()); |
+ catch_block->Visit(&for_catch); |
CatchBlockEntryInstr* catch_entry = |
new CatchBlockEntryInstr(owner()->AllocateBlockId(), |
- old_try_index, |
+ catch_handler_index, |
catch_block->handler_types(), |
- try_index); |
+ try_handler_index); |
owner()->AddCatchEntry(catch_entry); |
- ASSERT(!for_catch_block.is_open()); |
- AppendFragment(catch_entry, for_catch_block); |
+ ASSERT(!for_catch.is_open()); |
+ AppendFragment(catch_entry, for_catch); |
if (node->end_catch_label() != NULL) { |
JoinEntryInstr* join = node->end_catch_label()->join_for_continue(); |
if (join != NULL) { |
@@ -3290,6 +3297,41 @@ void EffectGraphVisitor::VisitTryCatchNode(TryCatchNode* node) { |
exit_ = join; |
} |
} |
+ |
+ if (finally_block != NULL) { |
+ // Create a handler for the code in the catch block, containing the |
+ // code in the finally block. |
+ owner()->set_try_index(original_handler_index); |
+ EffectGraphVisitor for_finally(owner(), temp_index()); |
+ for_finally.AddInstruction( |
+ new CatchEntryInstr(catch_block->exception_var(), |
+ catch_block->stacktrace_var())); |
+ for_finally.BuildLoadContext(catch_block->context_var()); |
+ |
+ finally_block->Visit(&for_finally); |
+ if (for_finally.is_open()) { |
+ // Rethrow the exception. Manually build the graph for rethrow. |
+ Value* exception = for_finally.Bind( |
+ for_finally.BuildLoadLocal(catch_block->exception_var())); |
+ for_finally.PushArgument(exception); |
+ Value* stacktrace = for_finally.Bind( |
+ for_finally.BuildLoadLocal(catch_block->stacktrace_var())); |
+ for_finally.PushArgument(stacktrace); |
+ for_finally.AddInstruction(new ReThrowInstr(catch_block->token_pos())); |
+ for_finally.CloseFragment(); |
+ } |
+ ASSERT(!for_finally.is_open()); |
+ |
+ const Array& types = Array::ZoneHandle(Array::New(1, Heap::kOld)); |
+ types.SetAt(0, Type::Handle(Type::DynamicType())); |
+ CatchBlockEntryInstr* finally_entry = |
+ new CatchBlockEntryInstr(owner()->AllocateBlockId(), |
+ original_handler_index, |
+ types, |
+ catch_handler_index); |
+ owner()->AddCatchEntry(finally_entry); |
+ AppendFragment(finally_entry, for_finally); |
+ } |
} |
// Generate code for the finally block if one exists. |