Index: runtime/vm/flow_graph_builder.cc |
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc |
index a64a787e455c933d95da840848d461d2980de62c..b8f9eab1457c207cd8cd4662eb80620c8d7bdd3a 100644 |
--- a/runtime/vm/flow_graph_builder.cc |
+++ b/runtime/vm/flow_graph_builder.cc |
@@ -42,6 +42,55 @@ DEFINE_FLAG(bool, trace_type_check_elimination, false, |
DECLARE_FLAG(bool, enable_type_checks); |
+// Base class for a stack of enclosing statements of interest (e.g., |
+// blocks (breakable) and loops (continuable)). |
+class NestedStatement : public ValueObject { |
+ public: |
+ NestedStatement(FlowGraphBuilder* owner, const SourceLabel* label) |
Florian Schneider
2013/11/19 10:37:05
Since only subclasses of NestedStatement exist (Ne
Kevin Millikin (Google)
2013/11/19 11:36:54
OK.
|
+ : owner_(owner), |
+ label_(label), |
+ outer_(owner->nesting_stack_), |
+ break_target_(NULL) { |
+ // Push on the owner's nesting stack. |
+ owner->nesting_stack_ = this; |
+ } |
+ |
+ virtual ~NestedStatement() { |
+ // Pop from the owner's nesting stack. |
+ ASSERT(owner_->nesting_stack_ == this); |
+ owner_->nesting_stack_ = outer_; |
+ } |
+ |
+ FlowGraphBuilder* owner() const { return owner_; } |
+ const SourceLabel* label() const { return label_; } |
+ NestedStatement* outer() const { return outer_; } |
+ JoinEntryInstr* break_target() const { return break_target_; } |
+ |
+ virtual intptr_t ContextLevel() const; |
+ |
+ virtual JoinEntryInstr* BreakTargetFor(SourceLabel* label); |
+ virtual JoinEntryInstr* ContinueTargetFor(SourceLabel* label); |
+ |
+ private: |
+ FlowGraphBuilder* owner_; |
+ const SourceLabel* label_; |
+ NestedStatement* outer_; |
+ |
+ JoinEntryInstr* break_target_; |
+}; |
+ |
+ |
+intptr_t NestedStatement::ContextLevel() const { |
+ // Context level is determined by the innermost nested statement having one. |
+ return (outer() == NULL) ? 0 : outer()->ContextLevel(); |
+} |
+ |
+ |
+intptr_t FlowGraphBuilder::context_level() const { |
+ return (nesting_stack() == NULL) ? 0 : nesting_stack()->ContextLevel(); |
+} |
+ |
+ |
JoinEntryInstr* NestedStatement::BreakTargetFor(SourceLabel* label) { |
if (label != label_) return NULL; |
if (break_target_ == NULL) { |
@@ -57,12 +106,38 @@ JoinEntryInstr* NestedStatement::ContinueTargetFor(SourceLabel* label) { |
} |
+// A nested statement that has its own context level. |
+class NestedBlock : public NestedStatement { |
+ public: |
+ NestedBlock(FlowGraphBuilder* owner, SequenceNode* node) |
+ : NestedStatement(owner, node->label()), scope_(node->scope()) {} |
+ |
+ virtual intptr_t ContextLevel() const; |
+ |
+ private: |
+ LocalScope* scope_; |
+}; |
+ |
+ |
+intptr_t NestedBlock::ContextLevel() const { |
+ return ((scope_ == NULL) || (scope_->num_context_variables() == 0)) |
+ ? NestedStatement::ContextLevel() |
+ : scope_->context_level(); |
+} |
+ |
+ |
// A nested statement that can be the target of a continue as well as a |
// break. |
class NestedLoop : public NestedStatement { |
public: |
NestedLoop(FlowGraphBuilder* owner, SourceLabel* label) |
- : NestedStatement(owner, label), continue_target_(NULL) { } |
+ : NestedStatement(owner, label), continue_target_(NULL) { |
+ owner->IncrementLoopDepth(); |
+ } |
+ |
+ virtual ~NestedLoop() { |
+ owner()->DecrementLoopDepth(); |
+ } |
JoinEntryInstr* continue_target() const { return continue_target_; } |
@@ -143,7 +218,6 @@ FlowGraphBuilder::FlowGraphBuilder(ParsedFunction* parsed_function, |
exit_collector_(exit_collector), |
guarded_fields_(new ZoneGrowableArray<const Field*>()), |
last_used_block_id_(0), // 0 is used for the graph entry. |
- context_level_(0), |
try_index_(CatchClauseNode::kInvalidTryIndex), |
catch_try_index_(CatchClauseNode::kInvalidTryIndex), |
loop_depth_(0), |
@@ -916,9 +990,7 @@ void EffectGraphVisitor::VisitReturnNode(ReturnNode* node) { |
// CTX on entry was saved, but not linked as context parent. |
BuildRestoreContext(*owner()->parsed_function()->saved_entry_context_var()); |
} else { |
- while (current_context_level-- > 0) { |
- UnchainContext(); |
- } |
+ UnchainContexts(current_context_level); |
} |
AddReturnExit(node->token_pos(), return_value); |
@@ -1779,7 +1851,6 @@ void EffectGraphVisitor::VisitCaseNode(CaseNode* node) { |
// g) break-join (optional) |
void EffectGraphVisitor::VisitWhileNode(WhileNode* node) { |
NestedLoop nested_loop(owner(), node->label()); |
- owner()->IncrementLoopDepth(); |
TestGraphVisitor for_test(owner(), node->condition()->token_pos()); |
node->condition()->Visit(&for_test); |
@@ -1800,7 +1871,6 @@ void EffectGraphVisitor::VisitWhileNode(WhileNode* node) { |
Goto(join); |
exit_ = join; |
} |
- owner()->DecrementLoopDepth(); |
} |
@@ -1814,7 +1884,6 @@ void EffectGraphVisitor::VisitWhileNode(WhileNode* node) { |
// g) break-join |
void EffectGraphVisitor::VisitDoWhileNode(DoWhileNode* node) { |
NestedLoop nested_loop(owner(), node->label()); |
- owner()->IncrementLoopDepth(); |
// Traverse the body first in order to generate continue and break labels. |
EffectGraphVisitor for_body(owner()); |
@@ -1854,7 +1923,6 @@ void EffectGraphVisitor::VisitDoWhileNode(DoWhileNode* node) { |
for_test.IfFalseGoto(join); |
exit_ = join; |
} |
- owner()->DecrementLoopDepth(); |
} |
@@ -1877,7 +1945,6 @@ void EffectGraphVisitor::VisitForNode(ForNode* node) { |
ASSERT(is_open()); |
NestedLoop nested_loop(owner(), node->label()); |
- owner()->IncrementLoopDepth(); |
// Compose body to set any jump labels. |
EffectGraphVisitor for_body(owner()); |
node->body()->Visit(&for_body); |
@@ -1923,7 +1990,6 @@ void EffectGraphVisitor::VisitForNode(ForNode* node) { |
exit_ = nested_loop.break_target(); |
} |
} |
- owner()->DecrementLoopDepth(); |
} |
@@ -1959,25 +2025,16 @@ void EffectGraphVisitor::VisitJumpNode(JumpNode* node) { |
ASSERT(target_context_level >= 0); |
intptr_t current_context_level = owner()->context_level(); |
ASSERT(current_context_level >= target_context_level); |
- while (current_context_level-- > target_context_level) { |
- UnchainContext(); |
- } |
+ UnchainContexts(current_context_level - target_context_level); |
JoinEntryInstr* jump_target = NULL; |
- if (node->kind() == Token::kBREAK) { |
- NestedStatement* current = owner()->nesting_stack(); |
- while (current != NULL) { |
- jump_target = current->BreakTargetFor(node->label()); |
- if (jump_target != NULL) break; |
- current = current->outer(); |
- } |
- } else { |
- NestedStatement* current = owner()->nesting_stack(); |
- while (current != NULL) { |
- jump_target = current->ContinueTargetFor(node->label()); |
- if (jump_target != NULL) break; |
- current = current->outer(); |
- } |
+ NestedStatement* current = owner()->nesting_stack(); |
+ while (current != NULL) { |
+ jump_target = (node->kind() == Token::kBREAK) |
+ ? current->BreakTargetFor(node->label()) |
+ : current->ContinueTargetFor(node->label()); |
+ if (jump_target != NULL) break; |
+ current = current->outer(); |
} |
ASSERT(jump_target != NULL); |
Goto(jump_target); |
@@ -3457,13 +3514,17 @@ bool EffectGraphVisitor::MustSaveRestoreContext(SequenceNode* node) const { |
} |
-void EffectGraphVisitor::UnchainContext() { |
- Value* context = Bind(new CurrentContextInstr()); |
- Value* parent = Bind( |
- new LoadFieldInstr(context, |
- Context::parent_offset(), |
- Type::ZoneHandle())); // Not an instance, no type. |
- AddInstruction(new StoreContextInstr(parent)); |
+void EffectGraphVisitor::UnchainContexts(intptr_t n) { |
+ if (n > 0) { |
+ Value* context = Bind(new CurrentContextInstr()); |
+ while (n-- > 0) { |
+ context = Bind( |
+ new LoadFieldInstr(context, |
+ Context::parent_offset(), |
+ Type::ZoneHandle())); // Not an instance, no type. |
+ } |
+ AddInstruction(new StoreContextInstr(context)); |
+ } |
} |
@@ -3474,11 +3535,10 @@ void EffectGraphVisitor::VisitSequenceNode(SequenceNode* node) { |
LocalScope* scope = node->scope(); |
const intptr_t num_context_variables = |
(scope != NULL) ? scope->num_context_variables() : 0; |
- int previous_context_level = owner()->context_level(); |
// The outermost function sequence cannot contain a label. |
ASSERT((node->label() == NULL) || |
(node != owner()->parsed_function()->node_sequence())); |
- NestedStatement nested_block(owner(), node->label()); |
+ NestedBlock nested_block(owner(), node); |
if (num_context_variables > 0) { |
// The loop local scope declares variables that are captured. |
@@ -3510,8 +3570,6 @@ void EffectGraphVisitor::VisitSequenceNode(SequenceNode* node) { |
new StoreContextInstr(Bind(ExitTempLocalScope(tmp_var)))); |
} |
- owner()->set_context_level(scope->context_level()); |
- |
// If this node_sequence is the body of the function being compiled, copy |
// the captured parameters from the frame into the context. |
if (node == owner()->parsed_function()->node_sequence()) { |
@@ -3600,7 +3658,7 @@ void EffectGraphVisitor::VisitSequenceNode(SequenceNode* node) { |
BuildRestoreContext( |
*owner()->parsed_function()->saved_entry_context_var()); |
} else if (num_context_variables > 0) { |
- UnchainContext(); |
+ UnchainContexts(1); |
} |
} |
@@ -3610,8 +3668,6 @@ void EffectGraphVisitor::VisitSequenceNode(SequenceNode* node) { |
if (is_open()) Goto(nested_block.break_target()); |
exit_ = nested_block.break_target(); |
} |
- |
- owner()->set_context_level(previous_context_level); |
} |