OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/flow_graph_builder.h" | 5 #include "vm/flow_graph_builder.h" |
6 | 6 |
7 #include "lib/invocation_mirror.h" | 7 #include "lib/invocation_mirror.h" |
8 #include "vm/ast_printer.h" | 8 #include "vm/ast_printer.h" |
9 #include "vm/bit_vector.h" | 9 #include "vm/bit_vector.h" |
10 #include "vm/class_finalizer.h" | 10 #include "vm/class_finalizer.h" |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
106 // Base class for a stack of enclosing statements of interest (e.g., | 106 // Base class for a stack of enclosing statements of interest (e.g., |
107 // blocks (breakable) and loops (continuable)). | 107 // blocks (breakable) and loops (continuable)). |
108 class NestedStatement : public ValueObject { | 108 class NestedStatement : public ValueObject { |
109 public: | 109 public: |
110 FlowGraphBuilder* owner() const { return owner_; } | 110 FlowGraphBuilder* owner() const { return owner_; } |
111 const SourceLabel* label() const { return label_; } | 111 const SourceLabel* label() const { return label_; } |
112 NestedStatement* outer() const { return outer_; } | 112 NestedStatement* outer() const { return outer_; } |
113 JoinEntryInstr* break_target() const { return break_target_; } | 113 JoinEntryInstr* break_target() const { return break_target_; } |
114 | 114 |
115 virtual intptr_t ContextLevel() const; | 115 virtual intptr_t ContextLevel() const; |
| 116 virtual void AdjustContextLevel(intptr_t context_level); |
116 | 117 |
117 virtual JoinEntryInstr* BreakTargetFor(SourceLabel* label); | 118 virtual JoinEntryInstr* BreakTargetFor(SourceLabel* label); |
118 virtual JoinEntryInstr* ContinueTargetFor(SourceLabel* label); | 119 virtual JoinEntryInstr* ContinueTargetFor(SourceLabel* label); |
119 | 120 |
120 protected: | 121 protected: |
121 NestedStatement(FlowGraphBuilder* owner, const SourceLabel* label) | 122 NestedStatement(FlowGraphBuilder* owner, const SourceLabel* label) |
122 : owner_(owner), | 123 : owner_(owner), |
123 label_(label), | 124 label_(label), |
124 outer_(owner->nesting_stack_), | 125 outer_(owner->nesting_stack_), |
125 break_target_(NULL), | 126 break_target_(NULL), |
(...skipping 19 matching lines...) Expand all Loading... |
145 const intptr_t try_index_; | 146 const intptr_t try_index_; |
146 }; | 147 }; |
147 | 148 |
148 | 149 |
149 intptr_t NestedStatement::ContextLevel() const { | 150 intptr_t NestedStatement::ContextLevel() const { |
150 // Context level is determined by the innermost nested statement having one. | 151 // Context level is determined by the innermost nested statement having one. |
151 return (outer() == NULL) ? 0 : outer()->ContextLevel(); | 152 return (outer() == NULL) ? 0 : outer()->ContextLevel(); |
152 } | 153 } |
153 | 154 |
154 | 155 |
| 156 void NestedStatement::AdjustContextLevel(intptr_t context_level) { |
| 157 // There must be a NestedContextAdjustment on the nesting stack. |
| 158 ASSERT(outer() != NULL); |
| 159 outer()->AdjustContextLevel(context_level); |
| 160 } |
| 161 |
| 162 |
155 intptr_t FlowGraphBuilder::context_level() const { | 163 intptr_t FlowGraphBuilder::context_level() const { |
156 return (nesting_stack() == NULL) ? 0 : nesting_stack()->ContextLevel(); | 164 return (nesting_stack() == NULL) ? 0 : nesting_stack()->ContextLevel(); |
157 } | 165 } |
158 | 166 |
159 | 167 |
160 JoinEntryInstr* NestedStatement::BreakTargetFor(SourceLabel* label) { | 168 JoinEntryInstr* NestedStatement::BreakTargetFor(SourceLabel* label) { |
161 if (label != label_) return NULL; | 169 if (label != label_) return NULL; |
162 if (break_target_ == NULL) { | 170 if (break_target_ == NULL) { |
163 break_target_ = | 171 break_target_ = |
164 new(owner()->zone()) JoinEntryInstr(owner()->AllocateBlockId(), | 172 new(owner()->zone()) JoinEntryInstr(owner()->AllocateBlockId(), |
165 owner()->try_index()); | 173 owner()->try_index()); |
166 } | 174 } |
167 return break_target_; | 175 return break_target_; |
168 } | 176 } |
169 | 177 |
170 | 178 |
171 JoinEntryInstr* NestedStatement::ContinueTargetFor(SourceLabel* label) { | 179 JoinEntryInstr* NestedStatement::ContinueTargetFor(SourceLabel* label) { |
172 return NULL; | 180 return NULL; |
173 } | 181 } |
174 | 182 |
175 | 183 |
(...skipping 10 matching lines...) Expand all Loading... |
186 }; | 194 }; |
187 | 195 |
188 | 196 |
189 intptr_t NestedBlock::ContextLevel() const { | 197 intptr_t NestedBlock::ContextLevel() const { |
190 return ((scope_ == NULL) || (scope_->num_context_variables() == 0)) | 198 return ((scope_ == NULL) || (scope_->num_context_variables() == 0)) |
191 ? NestedStatement::ContextLevel() | 199 ? NestedStatement::ContextLevel() |
192 : scope_->context_level(); | 200 : scope_->context_level(); |
193 } | 201 } |
194 | 202 |
195 | 203 |
| 204 // A nested statement reflecting a context level adjustment. |
| 205 class NestedContextAdjustment : public NestedStatement { |
| 206 public: |
| 207 NestedContextAdjustment(FlowGraphBuilder* owner, intptr_t context_level) |
| 208 : NestedStatement(owner, NULL), context_level_(context_level) { } |
| 209 |
| 210 virtual intptr_t ContextLevel() const { return context_level_; } |
| 211 |
| 212 virtual void AdjustContextLevel(intptr_t context_level) { |
| 213 ASSERT(context_level <= context_level_); |
| 214 context_level_ = context_level; |
| 215 } |
| 216 |
| 217 private: |
| 218 intptr_t context_level_; |
| 219 }; |
| 220 |
| 221 |
196 // A nested statement that can be the target of a continue as well as a | 222 // A nested statement that can be the target of a continue as well as a |
197 // break. | 223 // break. |
198 class NestedLoop : public NestedStatement { | 224 class NestedLoop : public NestedStatement { |
199 public: | 225 public: |
200 NestedLoop(FlowGraphBuilder* owner, SourceLabel* label) | 226 NestedLoop(FlowGraphBuilder* owner, SourceLabel* label) |
201 : NestedStatement(owner, label), continue_target_(NULL) { | 227 : NestedStatement(owner, label), continue_target_(NULL) { |
202 owner->IncrementLoopDepth(); | 228 owner->IncrementLoopDepth(); |
203 } | 229 } |
204 | 230 |
205 virtual ~NestedLoop() { | 231 virtual ~NestedLoop() { |
(...skipping 842 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1048 | 1074 |
1049 | 1075 |
1050 // <Statement> ::= Return { value: <Expression> | 1076 // <Statement> ::= Return { value: <Expression> |
1051 // inlined_finally_list: <InlinedFinally>* } | 1077 // inlined_finally_list: <InlinedFinally>* } |
1052 void EffectGraphVisitor::VisitReturnNode(ReturnNode* node) { | 1078 void EffectGraphVisitor::VisitReturnNode(ReturnNode* node) { |
1053 ValueGraphVisitor for_value(owner()); | 1079 ValueGraphVisitor for_value(owner()); |
1054 node->value()->Visit(&for_value); | 1080 node->value()->Visit(&for_value); |
1055 Append(for_value); | 1081 Append(for_value); |
1056 Value* return_value = for_value.value(); | 1082 Value* return_value = for_value.value(); |
1057 | 1083 |
| 1084 NestedContextAdjustment context_adjustment(owner(), owner()->context_level()); |
| 1085 |
1058 if (node->inlined_finally_list_length() > 0) { | 1086 if (node->inlined_finally_list_length() > 0) { |
1059 LocalVariable* temp = owner()->parsed_function().finally_return_temp_var(); | 1087 LocalVariable* temp = owner()->parsed_function().finally_return_temp_var(); |
1060 ASSERT(temp != NULL); | 1088 ASSERT(temp != NULL); |
1061 Do(BuildStoreLocal(*temp, return_value)); | 1089 Do(BuildStoreLocal(*temp, return_value)); |
1062 for (intptr_t i = 0; i < node->inlined_finally_list_length(); i++) { | 1090 for (intptr_t i = 0; i < node->inlined_finally_list_length(); i++) { |
1063 InlineBailout("EffectGraphVisitor::VisitReturnNode (exception)"); | 1091 InlineBailout("EffectGraphVisitor::VisitReturnNode (exception)"); |
1064 EffectGraphVisitor for_effect(owner()); | 1092 EffectGraphVisitor for_effect(owner()); |
1065 node->InlinedFinallyNodeAt(i)->Visit(&for_effect); | 1093 node->InlinedFinallyNodeAt(i)->Visit(&for_effect); |
1066 Append(for_effect); | 1094 Append(for_effect); |
1067 if (!is_open()) { | 1095 if (!is_open()) { |
(...skipping 1220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2288 exit_ = for_test.CreateFalseSuccessor(); | 2316 exit_ = for_test.CreateFalseSuccessor(); |
2289 } else { | 2317 } else { |
2290 for_test.IfFalseGoto(nested_loop.break_target()); | 2318 for_test.IfFalseGoto(nested_loop.break_target()); |
2291 exit_ = nested_loop.break_target(); | 2319 exit_ = nested_loop.break_target(); |
2292 } | 2320 } |
2293 } | 2321 } |
2294 } | 2322 } |
2295 | 2323 |
2296 | 2324 |
2297 void EffectGraphVisitor::VisitJumpNode(JumpNode* node) { | 2325 void EffectGraphVisitor::VisitJumpNode(JumpNode* node) { |
| 2326 NestedContextAdjustment context_adjustment(owner(), owner()->context_level()); |
| 2327 |
2298 for (intptr_t i = 0; i < node->inlined_finally_list_length(); i++) { | 2328 for (intptr_t i = 0; i < node->inlined_finally_list_length(); i++) { |
2299 EffectGraphVisitor for_effect(owner()); | 2329 EffectGraphVisitor for_effect(owner()); |
2300 node->InlinedFinallyNodeAt(i)->Visit(&for_effect); | 2330 node->InlinedFinallyNodeAt(i)->Visit(&for_effect); |
2301 Append(for_effect); | 2331 Append(for_effect); |
2302 if (!is_open()) return; | 2332 if (!is_open()) return; |
2303 } | 2333 } |
2304 | 2334 |
2305 // Unchain the context(s) up to the outer context level of the scope which | 2335 // Unchain the context(s) up to the outer context level of the scope which |
2306 // contains the destination label. | 2336 // contains the destination label. |
2307 SourceLabel* label = node->label(); | 2337 SourceLabel* label = node->label(); |
2308 ASSERT(label->owner() != NULL); | 2338 ASSERT(label->owner() != NULL); |
2309 int target_context_level = 0; | 2339 AdjustContextLevel(label->owner()); |
2310 LocalScope* target_scope = label->owner(); | |
2311 if (target_scope->num_context_variables() > 0) { | |
2312 // The scope of the target label allocates a context, therefore its outer | |
2313 // scope is at a lower context level. | |
2314 target_context_level = target_scope->context_level() - 1; | |
2315 } else { | |
2316 // The scope of the target label does not allocate a context, so its outer | |
2317 // scope is at the same context level. Find it. | |
2318 while ((target_scope != NULL) && | |
2319 (target_scope->num_context_variables() == 0)) { | |
2320 target_scope = target_scope->parent(); | |
2321 } | |
2322 if (target_scope != NULL) { | |
2323 target_context_level = target_scope->context_level(); | |
2324 } | |
2325 } | |
2326 ASSERT(target_context_level >= 0); | |
2327 intptr_t current_context_level = owner()->context_level(); | |
2328 ASSERT(current_context_level >= target_context_level); | |
2329 UnchainContexts(current_context_level - target_context_level); | |
2330 | 2340 |
2331 JoinEntryInstr* jump_target = NULL; | 2341 JoinEntryInstr* jump_target = NULL; |
2332 NestedStatement* current = owner()->nesting_stack(); | 2342 NestedStatement* current = owner()->nesting_stack(); |
2333 while (current != NULL) { | 2343 while (current != NULL) { |
2334 jump_target = (node->kind() == Token::kBREAK) | 2344 jump_target = (node->kind() == Token::kBREAK) |
2335 ? current->BreakTargetFor(node->label()) | 2345 ? current->BreakTargetFor(node->label()) |
2336 : current->ContinueTargetFor(node->label()); | 2346 : current->ContinueTargetFor(node->label()); |
2337 if (jump_target != NULL) break; | 2347 if (jump_target != NULL) break; |
2338 current = current->outer(); | 2348 current = current->outer(); |
2339 } | 2349 } |
(...skipping 1520 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3860 Context::parent_offset(), | 3870 Context::parent_offset(), |
3861 // Not an instance, no type. | 3871 // Not an instance, no type. |
3862 Type::ZoneHandle(Z, Type::null()), | 3872 Type::ZoneHandle(Z, Type::null()), |
3863 Scanner::kNoSourcePos)); | 3873 Scanner::kNoSourcePos)); |
3864 } | 3874 } |
3865 Do(BuildStoreContext(context)); | 3875 Do(BuildStoreContext(context)); |
3866 } | 3876 } |
3867 } | 3877 } |
3868 | 3878 |
3869 | 3879 |
| 3880 void EffectGraphVisitor::AdjustContextLevel(LocalScope* target_scope) { |
| 3881 ASSERT(target_scope != NULL); |
| 3882 intptr_t target_context_level = 0; |
| 3883 if (target_scope->num_context_variables() > 0) { |
| 3884 // The scope of the target label allocates a context, therefore its outer |
| 3885 // scope is at a lower context level. |
| 3886 target_context_level = target_scope->context_level() - 1; |
| 3887 } else { |
| 3888 // The scope of the target label does not allocate a context, so its outer |
| 3889 // scope is at the same context level. Find it. |
| 3890 while ((target_scope != NULL) && |
| 3891 (target_scope->num_context_variables() == 0)) { |
| 3892 target_scope = target_scope->parent(); |
| 3893 } |
| 3894 if (target_scope != NULL) { |
| 3895 target_context_level = target_scope->context_level(); |
| 3896 } |
| 3897 } |
| 3898 ASSERT(target_context_level >= 0); |
| 3899 intptr_t current_context_level = owner()->context_level(); |
| 3900 ASSERT(current_context_level >= target_context_level); |
| 3901 UnchainContexts(current_context_level - target_context_level); |
| 3902 // Record adjusted context level. |
| 3903 owner()->nesting_stack()->AdjustContextLevel(target_context_level); |
| 3904 } |
| 3905 |
| 3906 |
3870 // <Statement> ::= Sequence { scope: LocalScope | 3907 // <Statement> ::= Sequence { scope: LocalScope |
3871 // nodes: <Statement>* | 3908 // nodes: <Statement>* |
3872 // label: SourceLabel } | 3909 // label: SourceLabel } |
3873 void EffectGraphVisitor::VisitSequenceNode(SequenceNode* node) { | 3910 void EffectGraphVisitor::VisitSequenceNode(SequenceNode* node) { |
3874 LocalScope* scope = node->scope(); | 3911 LocalScope* scope = node->scope(); |
3875 const Function& function = owner()->function(); | 3912 const Function& function = owner()->function(); |
3876 const intptr_t num_context_variables = | 3913 const intptr_t num_context_variables = |
3877 (scope != NULL) ? scope->num_context_variables() : 0; | 3914 (scope != NULL) ? scope->num_context_variables() : 0; |
3878 const bool is_top_level_sequence = | 3915 const bool is_top_level_sequence = |
3879 node == owner()->parsed_function().node_sequence(); | 3916 node == owner()->parsed_function().node_sequence(); |
(...skipping 519 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4399 const intptr_t try_index = owner()->try_index(); | 4436 const intptr_t try_index = owner()->try_index(); |
4400 if (try_index >= 0) { | 4437 if (try_index >= 0) { |
4401 // We are about to generate code for an inlined finally block. Exceptions | 4438 // We are about to generate code for an inlined finally block. Exceptions |
4402 // thrown in this block of code should be treated as though they are | 4439 // thrown in this block of code should be treated as though they are |
4403 // thrown not from the current try block but the outer try block if any. | 4440 // thrown not from the current try block but the outer try block if any. |
4404 intptr_t outer_try_index = node->try_index(); | 4441 intptr_t outer_try_index = node->try_index(); |
4405 owner()->set_try_index(outer_try_index); | 4442 owner()->set_try_index(outer_try_index); |
4406 } | 4443 } |
4407 | 4444 |
4408 // Note: do not restore the saved_try_context here since the inlined | 4445 // Note: do not restore the saved_try_context here since the inlined |
4409 // code is running at he context level of the return or jump instruction | 4446 // code is not reached via an exception handler, therefore the context is |
4410 // that follows the inlined code. See issue 22822. | 4447 // always properly set on entry. In other words, the inlined finally clause is |
| 4448 // never the target of a long jump that would find an uninitialized current |
| 4449 // context variable. |
4411 | 4450 |
4412 JoinEntryInstr* finally_entry = | 4451 JoinEntryInstr* finally_entry = |
4413 new(Z) JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index()); | 4452 new(Z) JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index()); |
4414 EffectGraphVisitor for_finally_block(owner()); | 4453 EffectGraphVisitor for_finally_block(owner()); |
| 4454 for_finally_block.AdjustContextLevel(node->finally_block()->scope()); |
4415 node->finally_block()->Visit(&for_finally_block); | 4455 node->finally_block()->Visit(&for_finally_block); |
4416 | 4456 |
4417 if (try_index >= 0) { | 4457 if (try_index >= 0) { |
4418 owner()->set_try_index(try_index); | 4458 owner()->set_try_index(try_index); |
4419 } | 4459 } |
4420 | 4460 |
4421 if (for_finally_block.is_open()) { | 4461 if (for_finally_block.is_open()) { |
4422 JoinEntryInstr* after_finally = | 4462 JoinEntryInstr* after_finally = |
4423 new(Z) JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index()); | 4463 new(Z) JoinEntryInstr(owner()->AllocateBlockId(), owner()->try_index()); |
4424 for_finally_block.Goto(after_finally); | 4464 for_finally_block.Goto(after_finally); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4482 Report::MessageF(Report::kBailout, | 4522 Report::MessageF(Report::kBailout, |
4483 Script::Handle(function.script()), | 4523 Script::Handle(function.script()), |
4484 function.token_pos(), | 4524 function.token_pos(), |
4485 "FlowGraphBuilder Bailout: %s %s", | 4525 "FlowGraphBuilder Bailout: %s %s", |
4486 String::Handle(function.name()).ToCString(), | 4526 String::Handle(function.name()).ToCString(), |
4487 reason); | 4527 reason); |
4488 UNREACHABLE(); | 4528 UNREACHABLE(); |
4489 } | 4529 } |
4490 | 4530 |
4491 } // namespace dart | 4531 } // namespace dart |
OLD | NEW |