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

Side by Side Diff: runtime/vm/flow_graph_builder.cc

Issue 1154823003: Adjust context level when required before executing inlined finally clauses. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 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 unified diff | Download patch
« no previous file with comments | « runtime/vm/flow_graph_builder.h ('k') | tests/language/regress_23537_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_builder.h ('k') | tests/language/regress_23537_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698