OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler/ast-graph-builder.h" | 5 #include "src/compiler/ast-graph-builder.h" |
6 | 6 |
7 #include "src/compiler.h" | 7 #include "src/compiler.h" |
8 #include "src/compiler/ast-loop-assignment-analyzer.h" | 8 #include "src/compiler/ast-loop-assignment-analyzer.h" |
9 #include "src/compiler/control-builders.h" | 9 #include "src/compiler/control-builders.h" |
10 #include "src/compiler/js-type-feedback.h" | 10 #include "src/compiler/js-type-feedback.h" |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
105 | 105 |
106 // Scoped class tracking context objects created by the visitor. Represents | 106 // Scoped class tracking context objects created by the visitor. Represents |
107 // mutations of the context chain within the function body and allows to | 107 // mutations of the context chain within the function body and allows to |
108 // change the current {scope} and {context} during visitation. | 108 // change the current {scope} and {context} during visitation. |
109 class AstGraphBuilder::ContextScope BASE_EMBEDDED { | 109 class AstGraphBuilder::ContextScope BASE_EMBEDDED { |
110 public: | 110 public: |
111 ContextScope(AstGraphBuilder* builder, Scope* scope, Node* context) | 111 ContextScope(AstGraphBuilder* builder, Scope* scope, Node* context) |
112 : builder_(builder), | 112 : builder_(builder), |
113 outer_(builder->execution_context()), | 113 outer_(builder->execution_context()), |
114 scope_(scope), | 114 scope_(scope), |
115 depth_(builder_->environment()->ContextStackDepth()) { | 115 depth_(builder_->environment()->context_chain_length()) { |
116 builder_->environment()->PushContext(context); // Push. | 116 builder_->environment()->PushContext(context); // Push. |
117 builder_->set_execution_context(this); | 117 builder_->set_execution_context(this); |
118 } | 118 } |
119 | 119 |
120 ~ContextScope() { | 120 ~ContextScope() { |
121 builder_->set_execution_context(outer_); // Pop. | 121 builder_->set_execution_context(outer_); // Pop. |
122 builder_->environment()->PopContext(); | 122 builder_->environment()->PopContext(); |
123 CHECK_EQ(depth_, builder_->environment()->ContextStackDepth()); | 123 CHECK_EQ(depth_, builder_->environment()->context_chain_length()); |
124 } | 124 } |
125 | 125 |
126 // Current scope during visitation. | 126 // Current scope during visitation. |
127 Scope* scope() const { return scope_; } | 127 Scope* scope() const { return scope_; } |
128 | 128 |
129 private: | 129 private: |
130 AstGraphBuilder* builder_; | 130 AstGraphBuilder* builder_; |
131 ContextScope* outer_; | 131 ContextScope* outer_; |
132 Scope* scope_; | 132 Scope* scope_; |
133 int depth_; | 133 int depth_; |
134 }; | 134 }; |
135 | 135 |
136 | 136 |
137 // Scoped class tracking control statements entered by the visitor. There are | 137 // Scoped class tracking control statements entered by the visitor. There are |
138 // different types of statements participating in this stack to properly track | 138 // different types of statements participating in this stack to properly track |
139 // local as well as non-local control flow: | 139 // local as well as non-local control flow: |
140 // - IterationStatement : Allows proper 'break' and 'continue' behavior. | 140 // - IterationStatement : Allows proper 'break' and 'continue' behavior. |
141 // - BreakableStatement : Allows 'break' from block and switch statements. | 141 // - BreakableStatement : Allows 'break' from block and switch statements. |
142 // - TryCatchStatement : Intercepts 'throw' and implicit exceptional edges. | 142 // - TryCatchStatement : Intercepts 'throw' and implicit exceptional edges. |
143 // - TryFinallyStatement: Intercepts 'break', 'continue', 'throw' and 'return'. | 143 // - TryFinallyStatement: Intercepts 'break', 'continue', 'throw' and 'return'. |
144 class AstGraphBuilder::ControlScope BASE_EMBEDDED { | 144 class AstGraphBuilder::ControlScope BASE_EMBEDDED { |
145 public: | 145 public: |
146 explicit ControlScope(AstGraphBuilder* builder) | 146 explicit ControlScope(AstGraphBuilder* builder) |
147 : builder_(builder), | 147 : builder_(builder), |
148 outer_(builder->execution_control()), | 148 outer_(builder->execution_control()), |
| 149 context_length_(builder->environment()->context_chain_length()), |
149 stack_height_(builder->environment()->stack_height()) { | 150 stack_height_(builder->environment()->stack_height()) { |
150 builder_->set_execution_control(this); // Push. | 151 builder_->set_execution_control(this); // Push. |
151 } | 152 } |
152 | 153 |
153 virtual ~ControlScope() { | 154 virtual ~ControlScope() { |
154 builder_->set_execution_control(outer_); // Pop. | 155 builder_->set_execution_control(outer_); // Pop. |
155 } | 156 } |
156 | 157 |
157 // Either 'break' or 'continue' to the target statement. | 158 // Either 'break' or 'continue' to the target statement. |
158 void BreakTo(BreakableStatement* target); | 159 void BreakTo(BreakableStatement* target); |
(...skipping 27 matching lines...) Expand all Loading... |
186 return true; | 187 return true; |
187 case CMD_BREAK: | 188 case CMD_BREAK: |
188 case CMD_CONTINUE: | 189 case CMD_CONTINUE: |
189 break; | 190 break; |
190 } | 191 } |
191 return false; | 192 return false; |
192 } | 193 } |
193 | 194 |
194 Environment* environment() { return builder_->environment(); } | 195 Environment* environment() { return builder_->environment(); } |
195 AstGraphBuilder* builder() const { return builder_; } | 196 AstGraphBuilder* builder() const { return builder_; } |
| 197 int context_length() const { return context_length_; } |
196 int stack_height() const { return stack_height_; } | 198 int stack_height() const { return stack_height_; } |
197 | 199 |
198 private: | 200 private: |
199 AstGraphBuilder* builder_; | 201 AstGraphBuilder* builder_; |
200 ControlScope* outer_; | 202 ControlScope* outer_; |
| 203 int context_length_; |
201 int stack_height_; | 204 int stack_height_; |
202 }; | 205 }; |
203 | 206 |
204 | 207 |
205 // Helper class for a try-finally control scope. It can record intercepted | 208 // Helper class for a try-finally control scope. It can record intercepted |
206 // control-flow commands that cause entry into a finally-block, and re-apply | 209 // control-flow commands that cause entry into a finally-block, and re-apply |
207 // them after again leaving that block. Special tokens are used to identify | 210 // them after again leaving that block. Special tokens are used to identify |
208 // paths going through the finally-block to dispatch after leaving the block. | 211 // paths going through the finally-block to dispatch after leaving the block. |
209 class AstGraphBuilder::ControlScope::DeferredCommands : public ZoneObject { | 212 class AstGraphBuilder::ControlScope::DeferredCommands : public ZoneObject { |
210 public: | 213 public: |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
443 DCHECK(graph() != NULL); | 446 DCHECK(graph() != NULL); |
444 | 447 |
445 // Set up the basic structure of the graph. | 448 // Set up the basic structure of the graph. |
446 int parameter_count = info()->num_parameters(); | 449 int parameter_count = info()->num_parameters(); |
447 graph()->SetStart(graph()->NewNode(common()->Start(parameter_count))); | 450 graph()->SetStart(graph()->NewNode(common()->Start(parameter_count))); |
448 | 451 |
449 // Initialize the top-level environment. | 452 // Initialize the top-level environment. |
450 Environment env(this, scope, graph()->start()); | 453 Environment env(this, scope, graph()->start()); |
451 set_environment(&env); | 454 set_environment(&env); |
452 | 455 |
453 // Initialize control scope. | |
454 ControlScope control(this); | |
455 | |
456 if (info()->is_osr()) { | 456 if (info()->is_osr()) { |
457 // Use OSR normal entry as the start of the top-level environment. | 457 // Use OSR normal entry as the start of the top-level environment. |
458 // It will be replaced with {Dead} after typing and optimizations. | 458 // It will be replaced with {Dead} after typing and optimizations. |
459 NewNode(common()->OsrNormalEntry()); | 459 NewNode(common()->OsrNormalEntry()); |
460 } | 460 } |
461 | 461 |
462 // Initialize the incoming context. | 462 // Initialize the incoming context. |
463 CreateFunctionContext(constant_context); | 463 CreateFunctionContext(constant_context); |
464 ContextScope incoming(this, scope, function_context_.get()); | 464 ContextScope incoming(this, scope, function_context_.get()); |
465 | 465 |
| 466 // Initialize control scope. |
| 467 ControlScope control(this); |
| 468 |
466 // Build receiver check for sloppy mode if necessary. | 469 // Build receiver check for sloppy mode if necessary. |
467 // TODO(mstarzinger/verwaest): Should this be moved back into the CallIC? | 470 // TODO(mstarzinger/verwaest): Should this be moved back into the CallIC? |
468 Node* original_receiver = env.Lookup(scope->receiver()); | 471 Node* original_receiver = env.Lookup(scope->receiver()); |
469 Node* patched_receiver = BuildPatchReceiverToGlobalProxy(original_receiver); | 472 Node* patched_receiver = BuildPatchReceiverToGlobalProxy(original_receiver); |
470 env.Bind(scope->receiver(), patched_receiver); | 473 env.Bind(scope->receiver(), patched_receiver); |
471 | 474 |
472 // Build function context only if there are context allocated variables. | 475 // Build function context only if there are context allocated variables. |
473 int heap_slots = info()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; | 476 int heap_slots = info()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; |
474 if (heap_slots > 0) { | 477 if (heap_slots > 0) { |
475 // Push a new inner context scope for the function. | 478 // Push a new inner context scope for the function. |
(...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
806 return environment()->Context(); | 809 return environment()->Context(); |
807 } | 810 } |
808 | 811 |
809 | 812 |
810 void AstGraphBuilder::ControlScope::PerformCommand(Command command, | 813 void AstGraphBuilder::ControlScope::PerformCommand(Command command, |
811 Statement* target, | 814 Statement* target, |
812 Node* value) { | 815 Node* value) { |
813 Environment* env = environment()->CopyAsUnreachable(); | 816 Environment* env = environment()->CopyAsUnreachable(); |
814 ControlScope* current = this; | 817 ControlScope* current = this; |
815 while (current != NULL) { | 818 while (current != NULL) { |
816 environment()->Trim(current->stack_height()); | 819 environment()->TrimStack(current->stack_height()); |
| 820 environment()->TrimContextChain(current->context_length()); |
817 if (current->Execute(command, target, value)) break; | 821 if (current->Execute(command, target, value)) break; |
818 current = current->outer_; | 822 current = current->outer_; |
819 } | 823 } |
820 builder()->set_environment(env); | 824 builder()->set_environment(env); |
821 DCHECK(current != NULL); // Always handled (unless stack is malformed). | 825 DCHECK(current != NULL); // Always handled (unless stack is malformed). |
822 } | 826 } |
823 | 827 |
824 | 828 |
825 void AstGraphBuilder::ControlScope::BreakTo(BreakableStatement* stmt) { | 829 void AstGraphBuilder::ControlScope::BreakTo(BreakableStatement* stmt) { |
826 PerformCommand(CMD_BREAK, stmt, builder()->jsgraph()->TheHoleConstant()); | 830 PerformCommand(CMD_BREAK, stmt, builder()->jsgraph()->TheHoleConstant()); |
(...skipping 2500 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3327 if (exit_control() != NULL) { | 3331 if (exit_control() != NULL) { |
3328 exit = MergeControl(exit_control(), exit); | 3332 exit = MergeControl(exit_control(), exit); |
3329 } | 3333 } |
3330 environment()->MarkAsUnreachable(); | 3334 environment()->MarkAsUnreachable(); |
3331 set_exit_control(exit); | 3335 set_exit_control(exit); |
3332 } | 3336 } |
3333 | 3337 |
3334 | 3338 |
3335 void AstGraphBuilder::Environment::Merge(Environment* other) { | 3339 void AstGraphBuilder::Environment::Merge(Environment* other) { |
3336 DCHECK(values_.size() == other->values_.size()); | 3340 DCHECK(values_.size() == other->values_.size()); |
3337 // TODO(titzer): make context stack heights match. | 3341 DCHECK(contexts_.size() == other->contexts_.size()); |
3338 DCHECK(contexts_.size() <= other->contexts_.size()); | |
3339 | 3342 |
3340 // Nothing to do if the other environment is dead. | 3343 // Nothing to do if the other environment is dead. |
3341 if (other->IsMarkedAsUnreachable()) return; | 3344 if (other->IsMarkedAsUnreachable()) return; |
3342 | 3345 |
3343 // Resurrect a dead environment by copying the contents of the other one and | 3346 // Resurrect a dead environment by copying the contents of the other one and |
3344 // placing a singleton merge as the new control dependency. | 3347 // placing a singleton merge as the new control dependency. |
3345 if (this->IsMarkedAsUnreachable()) { | 3348 if (this->IsMarkedAsUnreachable()) { |
3346 Node* other_control = other->control_dependency_; | 3349 Node* other_control = other->control_dependency_; |
3347 Node* inputs[] = {other_control}; | 3350 Node* inputs[] = {other_control}; |
3348 liveness_block_ = other->liveness_block_; | 3351 liveness_block_ = other->liveness_block_; |
3349 control_dependency_ = | 3352 control_dependency_ = |
3350 graph()->NewNode(common()->Merge(1), arraysize(inputs), inputs, true); | 3353 graph()->NewNode(common()->Merge(1), arraysize(inputs), inputs, true); |
3351 effect_dependency_ = other->effect_dependency_; | 3354 effect_dependency_ = other->effect_dependency_; |
3352 values_ = other->values_; | 3355 values_ = other->values_; |
3353 // TODO(titzer): make context stack heights match. | |
3354 size_t min = std::min(contexts_.size(), other->contexts_.size()); | |
3355 contexts_ = other->contexts_; | 3356 contexts_ = other->contexts_; |
3356 contexts_.resize(min, nullptr); | |
3357 return; | 3357 return; |
3358 } | 3358 } |
3359 | 3359 |
3360 // Record the merge for the local variable liveness calculation. | 3360 // Record the merge for the local variable liveness calculation. |
3361 // Unfortunately, we have to mirror the logic in the MergeControl method: | 3361 // Unfortunately, we have to mirror the logic in the MergeControl method: |
3362 // connect before merge or loop, or create a new merge otherwise. | 3362 // connect before merge or loop, or create a new merge otherwise. |
3363 if (FLAG_analyze_environment_liveness) { | 3363 if (FLAG_analyze_environment_liveness) { |
3364 if (GetControlDependency()->opcode() != IrOpcode::kLoop && | 3364 if (GetControlDependency()->opcode() != IrOpcode::kLoop && |
3365 GetControlDependency()->opcode() != IrOpcode::kMerge) { | 3365 GetControlDependency()->opcode() != IrOpcode::kMerge) { |
3366 liveness_block_ = | 3366 liveness_block_ = |
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3532 // Phi does not exist yet, introduce one. | 3532 // Phi does not exist yet, introduce one. |
3533 value = NewPhi(inputs, value, control); | 3533 value = NewPhi(inputs, value, control); |
3534 value->ReplaceInput(inputs - 1, other); | 3534 value->ReplaceInput(inputs - 1, other); |
3535 } | 3535 } |
3536 return value; | 3536 return value; |
3537 } | 3537 } |
3538 | 3538 |
3539 } // namespace compiler | 3539 } // namespace compiler |
3540 } // namespace internal | 3540 } // namespace internal |
3541 } // namespace v8 | 3541 } // namespace v8 |
OLD | NEW |