| 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 |