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/linkage.h" | 10 #include "src/compiler/linkage.h" |
11 #include "src/compiler/machine-operator.h" | 11 #include "src/compiler/machine-operator.h" |
12 #include "src/compiler/node-matchers.h" | 12 #include "src/compiler/node-matchers.h" |
13 #include "src/compiler/node-properties.h" | 13 #include "src/compiler/node-properties.h" |
14 #include "src/compiler/operator-properties.h" | 14 #include "src/compiler/operator-properties.h" |
15 #include "src/full-codegen.h" | 15 #include "src/full-codegen.h" |
16 #include "src/parser.h" | 16 #include "src/parser.h" |
17 #include "src/scopes.h" | 17 #include "src/scopes.h" |
18 | 18 |
19 namespace v8 { | 19 namespace v8 { |
20 namespace internal { | 20 namespace internal { |
21 namespace compiler { | 21 namespace compiler { |
22 | 22 |
23 | 23 |
| 24 // Scoped class tracking control statements entered by the visitor. There are |
| 25 // different types of statements participating in this stack to properly track |
| 26 // local as well as non-local control flow: |
| 27 // - IterationStatement : Allows proper 'break' and 'continue' behavior. |
| 28 // - BreakableStatement : Allows 'break' from block and switch statements. |
| 29 // - TryCatchStatement : Intercepts 'throw' and implicit exceptional edges. |
| 30 // - TryFinallyStatement: Intercepts 'break', 'continue', 'throw' and 'return'. |
| 31 class AstGraphBuilder::ControlScope BASE_EMBEDDED { |
| 32 public: |
| 33 ControlScope(AstGraphBuilder* builder, int stack_delta) |
| 34 : builder_(builder), |
| 35 next_(builder->execution_control()), |
| 36 stack_delta_(stack_delta) { |
| 37 builder_->set_execution_control(this); // Push. |
| 38 } |
| 39 |
| 40 virtual ~ControlScope() { |
| 41 builder_->set_execution_control(next_); // Pop. |
| 42 } |
| 43 |
| 44 // Either 'break' or 'continue' to the target statement. |
| 45 void BreakTo(BreakableStatement* target); |
| 46 void ContinueTo(BreakableStatement* target); |
| 47 |
| 48 // Either 'return' or 'throw' the given value. |
| 49 void ReturnValue(Node* return_value); |
| 50 void ThrowValue(Node* exception_value); |
| 51 |
| 52 class DeferredCommands; |
| 53 |
| 54 protected: |
| 55 enum Command { CMD_BREAK, CMD_CONTINUE, CMD_RETURN, CMD_THROW }; |
| 56 |
| 57 // Performs one of the above commands on this stack of control scopes. This |
| 58 // walks through the stack giving each scope a chance to execute or defer the |
| 59 // given command by overriding the {Execute} method appropriately. Note that |
| 60 // this also drops extra operands from the environment for each skipped scope. |
| 61 void PerformCommand(Command cmd, Statement* target, Node* value); |
| 62 |
| 63 // Interface to execute a given command in this scope. Returning {true} here |
| 64 // indicates successful execution whereas {false} requests to skip scope. |
| 65 virtual bool Execute(Command cmd, Statement* target, Node* value) { |
| 66 // For function-level control. |
| 67 switch (cmd) { |
| 68 case CMD_THROW: |
| 69 builder()->BuildThrow(value); |
| 70 return true; |
| 71 case CMD_RETURN: |
| 72 builder()->BuildReturn(value); |
| 73 return true; |
| 74 case CMD_BREAK: |
| 75 case CMD_CONTINUE: |
| 76 break; |
| 77 } |
| 78 return false; |
| 79 } |
| 80 |
| 81 Environment* environment() { return builder_->environment(); } |
| 82 AstGraphBuilder* builder() const { return builder_; } |
| 83 int stack_delta() const { return stack_delta_; } |
| 84 |
| 85 private: |
| 86 AstGraphBuilder* builder_; |
| 87 ControlScope* next_; |
| 88 int stack_delta_; |
| 89 }; |
| 90 |
| 91 |
| 92 // Helper class for a try-finally control scope. It can record intercepted |
| 93 // control-flow commands that cause entry into a finally-block, and re-apply |
| 94 // them after again leaving that block. Special tokens are used to identify |
| 95 // paths going through the finally-block to dispatch after leaving the block. |
| 96 class AstGraphBuilder::ControlScope::DeferredCommands : public ZoneObject { |
| 97 public: |
| 98 explicit DeferredCommands(AstGraphBuilder* owner) |
| 99 : owner_(owner), deferred_(owner->zone()) {} |
| 100 |
| 101 // One recorded control-flow command. |
| 102 struct Entry { |
| 103 Command command; // The command type being applied on this path. |
| 104 Statement* statement; // The target statement for the command or {NULL}. |
| 105 Node* value; // The passed value node for the command or {NULL}. |
| 106 Node* token; // A token identifying this particular path. |
| 107 }; |
| 108 |
| 109 // Records a control-flow command while entering the finally-block. This also |
| 110 // generates a new dispatch token that identifies one particular path. |
| 111 Node* RecordCommand(Command cmd, Statement* stmt, Node* value) { |
| 112 Node* token = NewPathTokenForDeferredCommand(); |
| 113 deferred_.push_back({cmd, stmt, value, token}); |
| 114 return token; |
| 115 } |
| 116 |
| 117 // Returns the dispatch token to be used to identify the implicit fall-through |
| 118 // path at the end of a try-block into the corresponding finally-block. |
| 119 Node* GetFallThroughToken() { return NewPathTokenForImplicitFallThrough(); } |
| 120 |
| 121 // Applies all recorded control-flow commands after the finally-block again. |
| 122 // This generates a dynamic dispatch on the token from the entry point. |
| 123 void ApplyDeferredCommands(Node* token) { |
| 124 SwitchBuilder dispatch(owner_, static_cast<int>(deferred_.size())); |
| 125 dispatch.BeginSwitch(); |
| 126 for (size_t i = 0; i < deferred_.size(); ++i) { |
| 127 Node* condition = NewPathDispatchCondition(token, deferred_[i].token); |
| 128 dispatch.BeginLabel(static_cast<int>(i), condition); |
| 129 dispatch.EndLabel(); |
| 130 } |
| 131 for (size_t i = 0; i < deferred_.size(); ++i) { |
| 132 dispatch.BeginCase(static_cast<int>(i)); |
| 133 owner_->execution_control()->PerformCommand( |
| 134 deferred_[i].command, deferred_[i].statement, deferred_[i].value); |
| 135 dispatch.EndCase(); |
| 136 } |
| 137 dispatch.EndSwitch(); |
| 138 } |
| 139 |
| 140 protected: |
| 141 Node* NewPathTokenForDeferredCommand() { |
| 142 return owner_->jsgraph()->Constant(static_cast<int>(deferred_.size())); |
| 143 } |
| 144 Node* NewPathTokenForImplicitFallThrough() { |
| 145 return owner_->jsgraph()->Constant(-1); |
| 146 } |
| 147 Node* NewPathDispatchCondition(Node* t1, Node* t2) { |
| 148 // TODO(mstarzinger): This should be machine()->WordEqual(), but our Phi |
| 149 // nodes all have kRepTagged|kTypeAny, which causes representation mismatch. |
| 150 return owner_->NewNode(owner_->javascript()->StrictEqual(), t1, t2); |
| 151 } |
| 152 |
| 153 private: |
| 154 AstGraphBuilder* owner_; |
| 155 ZoneVector<Entry> deferred_; |
| 156 }; |
| 157 |
| 158 |
| 159 // Control scope implementation for a BreakableStatement. |
| 160 class AstGraphBuilder::ControlScopeForBreakable : public ControlScope { |
| 161 public: |
| 162 ControlScopeForBreakable(AstGraphBuilder* owner, BreakableStatement* target, |
| 163 ControlBuilder* control) |
| 164 : ControlScope(owner, 0), target_(target), control_(control) {} |
| 165 |
| 166 protected: |
| 167 virtual bool Execute(Command cmd, Statement* target, Node* value) OVERRIDE { |
| 168 if (target != target_) return false; // We are not the command target. |
| 169 switch (cmd) { |
| 170 case CMD_BREAK: |
| 171 control_->Break(); |
| 172 return true; |
| 173 case CMD_CONTINUE: |
| 174 case CMD_THROW: |
| 175 case CMD_RETURN: |
| 176 break; |
| 177 } |
| 178 return false; |
| 179 } |
| 180 |
| 181 private: |
| 182 BreakableStatement* target_; |
| 183 ControlBuilder* control_; |
| 184 }; |
| 185 |
| 186 |
| 187 // Control scope implementation for an IterationStatement. |
| 188 class AstGraphBuilder::ControlScopeForIteration : public ControlScope { |
| 189 public: |
| 190 ControlScopeForIteration(AstGraphBuilder* owner, IterationStatement* target, |
| 191 LoopBuilder* control, int stack_delta) |
| 192 : ControlScope(owner, stack_delta), target_(target), control_(control) {} |
| 193 |
| 194 protected: |
| 195 virtual bool Execute(Command cmd, Statement* target, Node* value) OVERRIDE { |
| 196 if (target != target_) return false; // We are not the command target. |
| 197 switch (cmd) { |
| 198 case CMD_BREAK: |
| 199 control_->Break(); |
| 200 return true; |
| 201 case CMD_CONTINUE: |
| 202 control_->Continue(); |
| 203 return true; |
| 204 case CMD_THROW: |
| 205 case CMD_RETURN: |
| 206 break; |
| 207 } |
| 208 return false; |
| 209 } |
| 210 |
| 211 private: |
| 212 BreakableStatement* target_; |
| 213 LoopBuilder* control_; |
| 214 }; |
| 215 |
| 216 |
| 217 // Control scope implementation for a TryCatchStatement. |
| 218 class AstGraphBuilder::ControlScopeForCatch : public ControlScope { |
| 219 public: |
| 220 ControlScopeForCatch(AstGraphBuilder* owner, TryCatchBuilder* control) |
| 221 : ControlScope(owner, 0), control_(control) {} |
| 222 |
| 223 protected: |
| 224 virtual bool Execute(Command cmd, Statement* target, Node* value) OVERRIDE { |
| 225 switch (cmd) { |
| 226 case CMD_THROW: |
| 227 control_->Throw(value); |
| 228 return true; |
| 229 case CMD_BREAK: |
| 230 case CMD_CONTINUE: |
| 231 case CMD_RETURN: |
| 232 break; |
| 233 } |
| 234 return false; |
| 235 } |
| 236 |
| 237 private: |
| 238 TryCatchBuilder* control_; |
| 239 }; |
| 240 |
| 241 |
| 242 // Control scope implementation for a TryFinallyStatement. |
| 243 class AstGraphBuilder::ControlScopeForFinally : public ControlScope { |
| 244 public: |
| 245 ControlScopeForFinally(AstGraphBuilder* owner, DeferredCommands* commands, |
| 246 TryFinallyBuilder* control) |
| 247 : ControlScope(owner, 0), commands_(commands), control_(control) {} |
| 248 |
| 249 protected: |
| 250 virtual bool Execute(Command cmd, Statement* target, Node* value) OVERRIDE { |
| 251 Node* token = commands_->RecordCommand(cmd, target, value); |
| 252 control_->LeaveTry(token); |
| 253 return true; |
| 254 } |
| 255 |
| 256 private: |
| 257 DeferredCommands* commands_; |
| 258 TryFinallyBuilder* control_; |
| 259 }; |
| 260 |
| 261 |
24 AstGraphBuilder::AstGraphBuilder(Zone* local_zone, CompilationInfo* info, | 262 AstGraphBuilder::AstGraphBuilder(Zone* local_zone, CompilationInfo* info, |
25 JSGraph* jsgraph, LoopAssignmentAnalysis* loop) | 263 JSGraph* jsgraph, LoopAssignmentAnalysis* loop) |
26 : local_zone_(local_zone), | 264 : local_zone_(local_zone), |
27 info_(info), | 265 info_(info), |
28 jsgraph_(jsgraph), | 266 jsgraph_(jsgraph), |
29 environment_(nullptr), | 267 environment_(nullptr), |
30 ast_context_(nullptr), | 268 ast_context_(nullptr), |
31 globals_(0, local_zone), | 269 globals_(0, local_zone), |
32 breakable_(nullptr), | 270 execution_control_(nullptr), |
33 execution_context_(nullptr), | 271 execution_context_(nullptr), |
34 input_buffer_size_(0), | 272 input_buffer_size_(0), |
35 input_buffer_(nullptr), | 273 input_buffer_(nullptr), |
36 current_context_(nullptr), | 274 current_context_(nullptr), |
37 exit_control_(nullptr), | 275 exit_control_(nullptr), |
38 loop_assignment_analysis_(loop) { | 276 loop_assignment_analysis_(loop) { |
39 InitializeAstVisitor(info->isolate(), local_zone); | 277 InitializeAstVisitor(info->isolate(), local_zone); |
40 } | 278 } |
41 | 279 |
42 | 280 |
(...skipping 20 matching lines...) Expand all Loading... |
63 | 301 |
64 | 302 |
65 bool AstGraphBuilder::CreateGraph() { | 303 bool AstGraphBuilder::CreateGraph() { |
66 Scope* scope = info()->scope(); | 304 Scope* scope = info()->scope(); |
67 DCHECK(graph() != NULL); | 305 DCHECK(graph() != NULL); |
68 | 306 |
69 // Set up the basic structure of the graph. | 307 // Set up the basic structure of the graph. |
70 int parameter_count = info()->num_parameters(); | 308 int parameter_count = info()->num_parameters(); |
71 graph()->SetStart(graph()->NewNode(common()->Start(parameter_count))); | 309 graph()->SetStart(graph()->NewNode(common()->Start(parameter_count))); |
72 | 310 |
73 Node* start = graph()->start(); | 311 // Initialize control scope. |
| 312 ControlScope control(this, 0); |
| 313 |
74 // Initialize the top-level environment. | 314 // Initialize the top-level environment. |
75 Environment env(this, scope, start); | 315 Environment env(this, scope, graph()->start()); |
76 set_environment(&env); | 316 set_environment(&env); |
77 | 317 |
78 if (info()->is_osr()) { | 318 if (info()->is_osr()) { |
79 // Use OSR normal entry as the start of the top-level environment. | 319 // Use OSR normal entry as the start of the top-level environment. |
80 // It will be replaced with {Dead} after typing and optimizations. | 320 // It will be replaced with {Dead} after typing and optimizations. |
81 NewNode(common()->OsrNormalEntry()); | 321 NewNode(common()->OsrNormalEntry()); |
82 } | 322 } |
83 | 323 |
84 // Initialize the incoming context. | 324 // Initialize the incoming context. |
85 Node* outer_context = GetFunctionContext(); | 325 Node* outer_context = GetFunctionContext(); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
123 if (HasStackOverflow()) return false; | 363 if (HasStackOverflow()) return false; |
124 | 364 |
125 // Emit tracing call if requested to do so. | 365 // Emit tracing call if requested to do so. |
126 if (FLAG_trace) { | 366 if (FLAG_trace) { |
127 // TODO(mstarzinger): Only traces implicit return. | 367 // TODO(mstarzinger): Only traces implicit return. |
128 Node* return_value = jsgraph()->UndefinedConstant(); | 368 Node* return_value = jsgraph()->UndefinedConstant(); |
129 NewNode(javascript()->CallRuntime(Runtime::kTraceExit, 1), return_value); | 369 NewNode(javascript()->CallRuntime(Runtime::kTraceExit, 1), return_value); |
130 } | 370 } |
131 | 371 |
132 // Return 'undefined' in case we can fall off the end. | 372 // Return 'undefined' in case we can fall off the end. |
133 Node* control = NewNode(common()->Return(), jsgraph()->UndefinedConstant()); | 373 BuildReturn(jsgraph()->UndefinedConstant()); |
134 UpdateControlDependencyToLeaveFunction(control); | |
135 | 374 |
136 // Finish the basic structure of the graph. | 375 // Finish the basic structure of the graph. |
137 environment()->UpdateControlDependency(exit_control()); | 376 environment()->UpdateControlDependency(exit_control()); |
138 graph()->SetEnd(NewNode(common()->End())); | 377 graph()->SetEnd(NewNode(common()->End())); |
139 | 378 |
140 return true; | 379 return true; |
141 } | 380 } |
142 | 381 |
143 | 382 |
144 // Left-hand side can only be a property, a global or a variable slot. | 383 // Left-hand side can only be a property, a global or a variable slot. |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
295 Node* AstGraphBuilder::AstValueContext::ConsumeValue() { | 534 Node* AstGraphBuilder::AstValueContext::ConsumeValue() { |
296 return environment()->Pop(); | 535 return environment()->Pop(); |
297 } | 536 } |
298 | 537 |
299 | 538 |
300 Node* AstGraphBuilder::AstTestContext::ConsumeValue() { | 539 Node* AstGraphBuilder::AstTestContext::ConsumeValue() { |
301 return environment()->Pop(); | 540 return environment()->Pop(); |
302 } | 541 } |
303 | 542 |
304 | 543 |
305 AstGraphBuilder::BreakableScope* AstGraphBuilder::BreakableScope::FindBreakable( | 544 void AstGraphBuilder::ControlScope::PerformCommand(Command command, |
306 BreakableStatement* target) { | 545 Statement* target, |
307 BreakableScope* current = this; | 546 Node* value) { |
308 while (current != NULL && current->target_ != target) { | 547 Environment* env = environment()->CopyAsUnreachable(); |
309 owner_->environment()->Drop(current->drop_extra_); | 548 ControlScope* current = this; |
| 549 while (current != NULL) { |
| 550 if (current->Execute(command, target, value)) break; |
| 551 environment()->Drop(current->stack_delta()); |
310 current = current->next_; | 552 current = current->next_; |
311 } | 553 } |
312 DCHECK(current != NULL); // Always found (unless stack is malformed). | 554 // TODO(mstarzinger): Unconditionally kill environment once throw is control. |
313 return current; | 555 if (command != CMD_THROW) builder()->set_environment(env); |
| 556 DCHECK(current != NULL); // Always handled (unless stack is malformed). |
314 } | 557 } |
315 | 558 |
316 | 559 |
317 void AstGraphBuilder::BreakableScope::BreakTarget(BreakableStatement* stmt) { | 560 void AstGraphBuilder::ControlScope::BreakTo(BreakableStatement* stmt) { |
318 FindBreakable(stmt)->control_->Break(); | 561 PerformCommand(CMD_BREAK, stmt, nullptr); |
319 } | 562 } |
320 | 563 |
321 | 564 |
322 void AstGraphBuilder::BreakableScope::ContinueTarget(BreakableStatement* stmt) { | 565 void AstGraphBuilder::ControlScope::ContinueTo(BreakableStatement* stmt) { |
323 FindBreakable(stmt)->control_->Continue(); | 566 PerformCommand(CMD_CONTINUE, stmt, nullptr); |
324 } | 567 } |
325 | 568 |
326 | 569 |
| 570 void AstGraphBuilder::ControlScope::ReturnValue(Node* return_value) { |
| 571 PerformCommand(CMD_RETURN, nullptr, return_value); |
| 572 } |
| 573 |
| 574 |
| 575 void AstGraphBuilder::ControlScope::ThrowValue(Node* exception_value) { |
| 576 PerformCommand(CMD_THROW, nullptr, exception_value); |
| 577 } |
| 578 |
| 579 |
327 void AstGraphBuilder::VisitForValueOrNull(Expression* expr) { | 580 void AstGraphBuilder::VisitForValueOrNull(Expression* expr) { |
328 if (expr == NULL) { | 581 if (expr == NULL) { |
329 return environment()->Push(jsgraph()->NullConstant()); | 582 return environment()->Push(jsgraph()->NullConstant()); |
330 } | 583 } |
331 VisitForValue(expr); | 584 VisitForValue(expr); |
332 } | 585 } |
333 | 586 |
334 | 587 |
335 void AstGraphBuilder::VisitForValueOrTheHole(Expression* expr) { | 588 void AstGraphBuilder::VisitForValueOrTheHole(Expression* expr) { |
336 if (expr == NULL) { | 589 if (expr == NULL) { |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
476 | 729 |
477 | 730 |
478 void AstGraphBuilder::VisitModulePath(ModulePath* modl) { UNREACHABLE(); } | 731 void AstGraphBuilder::VisitModulePath(ModulePath* modl) { UNREACHABLE(); } |
479 | 732 |
480 | 733 |
481 void AstGraphBuilder::VisitModuleUrl(ModuleUrl* modl) { UNREACHABLE(); } | 734 void AstGraphBuilder::VisitModuleUrl(ModuleUrl* modl) { UNREACHABLE(); } |
482 | 735 |
483 | 736 |
484 void AstGraphBuilder::VisitBlock(Block* stmt) { | 737 void AstGraphBuilder::VisitBlock(Block* stmt) { |
485 BlockBuilder block(this); | 738 BlockBuilder block(this); |
486 BreakableScope scope(this, stmt, &block, 0); | 739 ControlScopeForBreakable scope(this, stmt, &block); |
487 if (stmt->labels() != NULL) block.BeginBlock(); | 740 if (stmt->labels() != NULL) block.BeginBlock(); |
488 if (stmt->scope() == NULL) { | 741 if (stmt->scope() == NULL) { |
489 // Visit statements in the same scope, no declarations. | 742 // Visit statements in the same scope, no declarations. |
490 VisitStatements(stmt->statements()); | 743 VisitStatements(stmt->statements()); |
491 } else { | 744 } else { |
492 // Visit declarations and statements in a block scope. | 745 // Visit declarations and statements in a block scope. |
493 Node* context = BuildLocalBlockContext(stmt->scope()); | 746 Node* context = BuildLocalBlockContext(stmt->scope()); |
494 ContextScope scope(this, stmt->scope(), context); | 747 ContextScope scope(this, stmt->scope(), context); |
495 VisitDeclarations(stmt->scope()->declarations()); | 748 VisitDeclarations(stmt->scope()->declarations()); |
496 VisitStatements(stmt->statements()); | 749 VisitStatements(stmt->statements()); |
(...skipping 24 matching lines...) Expand all Loading... |
521 compare_if.If(condition); | 774 compare_if.If(condition); |
522 compare_if.Then(); | 775 compare_if.Then(); |
523 Visit(stmt->then_statement()); | 776 Visit(stmt->then_statement()); |
524 compare_if.Else(); | 777 compare_if.Else(); |
525 Visit(stmt->else_statement()); | 778 Visit(stmt->else_statement()); |
526 compare_if.End(); | 779 compare_if.End(); |
527 } | 780 } |
528 | 781 |
529 | 782 |
530 void AstGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) { | 783 void AstGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) { |
531 Environment* env = environment()->CopyAsUnreachable(); | 784 execution_control()->ContinueTo(stmt->target()); |
532 breakable()->ContinueTarget(stmt->target()); | |
533 set_environment(env); | |
534 } | 785 } |
535 | 786 |
536 | 787 |
537 void AstGraphBuilder::VisitBreakStatement(BreakStatement* stmt) { | 788 void AstGraphBuilder::VisitBreakStatement(BreakStatement* stmt) { |
538 Environment* env = environment()->CopyAsUnreachable(); | 789 execution_control()->BreakTo(stmt->target()); |
539 breakable()->BreakTarget(stmt->target()); | |
540 set_environment(env); | |
541 } | 790 } |
542 | 791 |
543 | 792 |
544 void AstGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { | 793 void AstGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { |
545 VisitForValue(stmt->expression()); | 794 VisitForValue(stmt->expression()); |
546 Node* result = environment()->Pop(); | 795 Node* result = environment()->Pop(); |
547 Node* control = NewNode(common()->Return(), result); | 796 execution_control()->ReturnValue(result); |
548 UpdateControlDependencyToLeaveFunction(control); | |
549 } | 797 } |
550 | 798 |
551 | 799 |
552 void AstGraphBuilder::VisitWithStatement(WithStatement* stmt) { | 800 void AstGraphBuilder::VisitWithStatement(WithStatement* stmt) { |
553 VisitForValue(stmt->expression()); | 801 VisitForValue(stmt->expression()); |
554 Node* value = environment()->Pop(); | 802 Node* value = environment()->Pop(); |
555 const Operator* op = javascript()->CreateWithContext(); | 803 const Operator* op = javascript()->CreateWithContext(); |
556 Node* context = NewNode(op, value, GetFunctionClosure()); | 804 Node* context = NewNode(op, value, GetFunctionClosure()); |
557 PrepareFrameState(context, stmt->EntryId()); | 805 PrepareFrameState(context, stmt->EntryId()); |
558 ContextScope scope(this, stmt->scope(), context); | 806 ContextScope scope(this, stmt->scope(), context); |
559 Visit(stmt->statement()); | 807 Visit(stmt->statement()); |
560 } | 808 } |
561 | 809 |
562 | 810 |
563 void AstGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { | 811 void AstGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { |
564 ZoneList<CaseClause*>* clauses = stmt->cases(); | 812 ZoneList<CaseClause*>* clauses = stmt->cases(); |
565 SwitchBuilder compare_switch(this, clauses->length()); | 813 SwitchBuilder compare_switch(this, clauses->length()); |
566 BreakableScope scope(this, stmt, &compare_switch, 0); | 814 ControlScopeForBreakable scope(this, stmt, &compare_switch); |
567 compare_switch.BeginSwitch(); | 815 compare_switch.BeginSwitch(); |
568 int default_index = -1; | 816 int default_index = -1; |
569 | 817 |
570 // Keep the switch value on the stack until a case matches. | 818 // Keep the switch value on the stack until a case matches. |
571 VisitForValue(stmt->tag()); | 819 VisitForValue(stmt->tag()); |
572 Node* tag = environment()->Top(); | 820 Node* tag = environment()->Top(); |
573 | 821 |
574 // Iterate over all cases and create nodes for label comparison. | 822 // Iterate over all cases and create nodes for label comparison. |
575 for (int i = 0; i < clauses->length(); i++) { | 823 for (int i = 0; i < clauses->length(); i++) { |
576 CaseClause* clause = clauses->at(i); | 824 CaseClause* clause = clauses->at(i); |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
809 Node* condition = environment()->Pop(); | 1057 Node* condition = environment()->Pop(); |
810 for_loop.BreakWhen(condition); | 1058 for_loop.BreakWhen(condition); |
811 VisitForEffect(stmt->assign_each()); | 1059 VisitForEffect(stmt->assign_each()); |
812 VisitIterationBody(stmt, &for_loop, 0); | 1060 VisitIterationBody(stmt, &for_loop, 0); |
813 for_loop.EndBody(); | 1061 for_loop.EndBody(); |
814 for_loop.EndLoop(); | 1062 for_loop.EndLoop(); |
815 } | 1063 } |
816 | 1064 |
817 | 1065 |
818 void AstGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) { | 1066 void AstGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) { |
819 // TODO(turbofan): Implement try-catch here. | 1067 TryCatchBuilder try_control(this); |
820 SetStackOverflow(); | 1068 |
| 1069 // Evaluate the try-block inside a control scope. This simulates a handler |
| 1070 // that is intercepting 'throw' control commands. |
| 1071 try_control.BeginTry(); |
| 1072 { |
| 1073 ControlScopeForCatch scope(this, &try_control); |
| 1074 Visit(stmt->try_block()); |
| 1075 } |
| 1076 try_control.EndTry(); |
| 1077 |
| 1078 // Create a catch scope that binds the exception. |
| 1079 Node* exception = try_control.GetExceptionNode(); |
| 1080 if (exception == NULL) exception = jsgraph()->NullConstant(); |
| 1081 Unique<String> name = MakeUnique(stmt->variable()->name()); |
| 1082 const Operator* op = javascript()->CreateCatchContext(name); |
| 1083 Node* context = NewNode(op, exception, GetFunctionClosure()); |
| 1084 PrepareFrameState(context, BailoutId::None()); |
| 1085 ContextScope scope(this, stmt->scope(), context); |
| 1086 DCHECK(stmt->scope()->declarations()->is_empty()); |
| 1087 |
| 1088 // Evaluate the catch-block. |
| 1089 Visit(stmt->catch_block()); |
| 1090 try_control.EndCatch(); |
| 1091 |
| 1092 // TODO(mstarzinger): Remove bailout once everything works. |
| 1093 if (!FLAG_turbo_exceptions) SetStackOverflow(); |
821 } | 1094 } |
822 | 1095 |
823 | 1096 |
824 void AstGraphBuilder::VisitTryFinallyStatement(TryFinallyStatement* stmt) { | 1097 void AstGraphBuilder::VisitTryFinallyStatement(TryFinallyStatement* stmt) { |
825 // TODO(turbofan): Implement try-catch here. | 1098 TryFinallyBuilder try_control(this); |
826 SetStackOverflow(); | 1099 |
| 1100 // We keep a record of all paths that enter the finally-block to be able to |
| 1101 // dispatch to the correct continuation point after the statements in the |
| 1102 // finally-block have been evaluated. |
| 1103 // |
| 1104 // The try-finally construct can enter the finally-block in three ways: |
| 1105 // 1. By exiting the try-block normally, falling through at the end. |
| 1106 // 2. By exiting the try-block with a function-local control flow transfer |
| 1107 // (i.e. through break/continue/return statements). |
| 1108 // 3. By exiting the try-block with a thrown exception. |
| 1109 ControlScope::DeferredCommands* commands = |
| 1110 new (zone()) ControlScope::DeferredCommands(this); |
| 1111 |
| 1112 // Evaluate the try-block inside a control scope. This simulates a handler |
| 1113 // that is intercepting all control commands. |
| 1114 try_control.BeginTry(); |
| 1115 { |
| 1116 ControlScopeForFinally scope(this, commands, &try_control); |
| 1117 Visit(stmt->try_block()); |
| 1118 } |
| 1119 try_control.EndTry(commands->GetFallThroughToken()); |
| 1120 |
| 1121 // Evaluate the finally-block. |
| 1122 Visit(stmt->finally_block()); |
| 1123 try_control.EndFinally(); |
| 1124 |
| 1125 // Dynamic dispatch after the finally-block. |
| 1126 Node* token = try_control.GetDispatchTokenNode(); |
| 1127 commands->ApplyDeferredCommands(token); |
| 1128 |
| 1129 // TODO(mstarzinger): Remove bailout once everything works. |
| 1130 if (!FLAG_turbo_exceptions) SetStackOverflow(); |
827 } | 1131 } |
828 | 1132 |
829 | 1133 |
830 void AstGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) { | 1134 void AstGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) { |
831 // TODO(turbofan): Do we really need a separate reloc-info for this? | 1135 // TODO(turbofan): Do we really need a separate reloc-info for this? |
832 Node* node = NewNode(javascript()->CallRuntime(Runtime::kDebugBreak, 0)); | 1136 Node* node = NewNode(javascript()->CallRuntime(Runtime::kDebugBreak, 0)); |
833 PrepareFrameState(node, stmt->DebugBreakId()); | 1137 PrepareFrameState(node, stmt->DebugBreakId()); |
834 } | 1138 } |
835 | 1139 |
836 | 1140 |
(...skipping 543 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1380 void AstGraphBuilder::VisitYield(Yield* expr) { | 1684 void AstGraphBuilder::VisitYield(Yield* expr) { |
1381 // TODO(turbofan): Implement yield here. | 1685 // TODO(turbofan): Implement yield here. |
1382 SetStackOverflow(); | 1686 SetStackOverflow(); |
1383 ast_context()->ProduceValue(jsgraph()->UndefinedConstant()); | 1687 ast_context()->ProduceValue(jsgraph()->UndefinedConstant()); |
1384 } | 1688 } |
1385 | 1689 |
1386 | 1690 |
1387 void AstGraphBuilder::VisitThrow(Throw* expr) { | 1691 void AstGraphBuilder::VisitThrow(Throw* expr) { |
1388 VisitForValue(expr->exception()); | 1692 VisitForValue(expr->exception()); |
1389 Node* exception = environment()->Pop(); | 1693 Node* exception = environment()->Pop(); |
1390 const Operator* op = javascript()->CallRuntime(Runtime::kThrow, 1); | 1694 if (FLAG_turbo_exceptions) { |
1391 Node* value = NewNode(op, exception); | 1695 execution_control()->ThrowValue(exception); |
1392 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine()); | 1696 ast_context()->ProduceValue(exception); |
1393 ast_context()->ProduceValue(value); | 1697 } else { |
| 1698 // TODO(mstarzinger): Temporary workaround for bailout-id for debugger. |
| 1699 const Operator* op = javascript()->CallRuntime(Runtime::kThrow, 1); |
| 1700 Node* value = NewNode(op, exception); |
| 1701 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine()); |
| 1702 ast_context()->ProduceValue(value); |
| 1703 } |
1394 } | 1704 } |
1395 | 1705 |
1396 | 1706 |
1397 void AstGraphBuilder::VisitProperty(Property* expr) { | 1707 void AstGraphBuilder::VisitProperty(Property* expr) { |
1398 Node* value; | 1708 Node* value; |
1399 VectorSlotPair pair = CreateVectorSlotPair(expr->PropertyFeedbackSlot()); | 1709 VectorSlotPair pair = CreateVectorSlotPair(expr->PropertyFeedbackSlot()); |
1400 if (expr->key()->IsPropertyName()) { | 1710 if (expr->key()->IsPropertyName()) { |
1401 VisitForValue(expr->obj()); | 1711 VisitForValue(expr->obj()); |
1402 Node* object = environment()->Pop(); | 1712 Node* object = environment()->Pop(); |
1403 Unique<Name> name = MakeUnique(expr->key()->AsLiteral()->AsPropertyName()); | 1713 Unique<Name> name = MakeUnique(expr->key()->AsLiteral()->AsPropertyName()); |
(...skipping 421 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1825 } | 2135 } |
1826 | 2136 |
1827 | 2137 |
1828 void AstGraphBuilder::VisitIfNotNull(Statement* stmt) { | 2138 void AstGraphBuilder::VisitIfNotNull(Statement* stmt) { |
1829 if (stmt == NULL) return; | 2139 if (stmt == NULL) return; |
1830 Visit(stmt); | 2140 Visit(stmt); |
1831 } | 2141 } |
1832 | 2142 |
1833 | 2143 |
1834 void AstGraphBuilder::VisitIterationBody(IterationStatement* stmt, | 2144 void AstGraphBuilder::VisitIterationBody(IterationStatement* stmt, |
1835 LoopBuilder* loop, int drop_extra) { | 2145 LoopBuilder* loop, int stack_delta) { |
1836 BreakableScope scope(this, stmt, loop, drop_extra); | 2146 ControlScopeForIteration scope(this, stmt, loop, stack_delta); |
1837 Visit(stmt->body()); | 2147 Visit(stmt->body()); |
1838 } | 2148 } |
1839 | 2149 |
1840 | 2150 |
1841 void AstGraphBuilder::VisitDelete(UnaryOperation* expr) { | 2151 void AstGraphBuilder::VisitDelete(UnaryOperation* expr) { |
1842 Node* value; | 2152 Node* value; |
1843 if (expr->expression()->IsVariableProxy()) { | 2153 if (expr->expression()->IsVariableProxy()) { |
1844 // Delete of an unqualified identifier is only allowed in classic mode but | 2154 // Delete of an unqualified identifier is only allowed in classic mode but |
1845 // deleting "this" is allowed in all language modes. | 2155 // deleting "this" is allowed in all language modes. |
1846 Variable* variable = expr->expression()->AsVariableProxy()->var(); | 2156 Variable* variable = expr->expression()->AsVariableProxy()->var(); |
(...skipping 506 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2353 Node* AstGraphBuilder::BuildThrowConstAssignError(BailoutId bailout_id) { | 2663 Node* AstGraphBuilder::BuildThrowConstAssignError(BailoutId bailout_id) { |
2354 // TODO(mstarzinger): Should be unified with the VisitThrow implementation. | 2664 // TODO(mstarzinger): Should be unified with the VisitThrow implementation. |
2355 const Operator* op = | 2665 const Operator* op = |
2356 javascript()->CallRuntime(Runtime::kThrowConstAssignError, 0); | 2666 javascript()->CallRuntime(Runtime::kThrowConstAssignError, 0); |
2357 Node* call = NewNode(op); | 2667 Node* call = NewNode(op); |
2358 PrepareFrameState(call, bailout_id); | 2668 PrepareFrameState(call, bailout_id); |
2359 return call; | 2669 return call; |
2360 } | 2670 } |
2361 | 2671 |
2362 | 2672 |
| 2673 Node* AstGraphBuilder::BuildReturn(Node* return_value) { |
| 2674 Node* control = NewNode(common()->Return(), return_value); |
| 2675 UpdateControlDependencyToLeaveFunction(control); |
| 2676 return control; |
| 2677 } |
| 2678 |
| 2679 |
| 2680 Node* AstGraphBuilder::BuildThrow(Node* exception_value) { |
| 2681 const Operator* op = javascript()->CallRuntime(Runtime::kThrow, 1); |
| 2682 Node* control = NewNode(op, exception_value); |
| 2683 // TODO(mstarzinger): Thread through the correct bailout id to this point. |
| 2684 // PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine()); |
| 2685 PrepareFrameState(control, BailoutId::None()); |
| 2686 return control; |
| 2687 } |
| 2688 |
| 2689 |
2363 Node* AstGraphBuilder::BuildBinaryOp(Node* left, Node* right, Token::Value op) { | 2690 Node* AstGraphBuilder::BuildBinaryOp(Node* left, Node* right, Token::Value op) { |
2364 const Operator* js_op; | 2691 const Operator* js_op; |
2365 switch (op) { | 2692 switch (op) { |
2366 case Token::BIT_OR: | 2693 case Token::BIT_OR: |
2367 js_op = javascript()->BitwiseOr(); | 2694 js_op = javascript()->BitwiseOr(); |
2368 break; | 2695 break; |
2369 case Token::BIT_AND: | 2696 case Token::BIT_AND: |
2370 js_op = javascript()->BitwiseAnd(); | 2697 js_op = javascript()->BitwiseAnd(); |
2371 break; | 2698 break; |
2372 case Token::BIT_XOR: | 2699 case Token::BIT_XOR: |
(...skipping 309 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2682 Node* dead_node = graph()->NewNode(common()->Dead()); | 3009 Node* dead_node = graph()->NewNode(common()->Dead()); |
2683 dead_control_.set(dead_node); | 3010 dead_control_.set(dead_node); |
2684 return dead_node; | 3011 return dead_node; |
2685 } | 3012 } |
2686 return dead_control_.get(); | 3013 return dead_control_.get(); |
2687 } | 3014 } |
2688 | 3015 |
2689 } // namespace compiler | 3016 } // namespace compiler |
2690 } // namespace internal | 3017 } // namespace internal |
2691 } // namespace v8 | 3018 } // namespace v8 |
OLD | NEW |