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

Unified Diff: runtime/vm/flow_graph_builder.cc

Issue 17893003: Fix a VM bug in the handling of try/catch/finally. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 6 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 | runtime/vm/parser.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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.
« no previous file with comments | « no previous file | runtime/vm/parser.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698