Chromium Code Reviews| 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 | |
| 67 Environment* environment() { return builder_->environment(); } | |
| 68 AstGraphBuilder* builder() const { return builder_; } | |
| 69 int stack_delta() const { return stack_delta_; } | |
| 70 | |
| 71 private: | |
| 72 AstGraphBuilder* builder_; | |
| 73 ControlScope* next_; | |
| 74 int stack_delta_; | |
| 75 }; | |
| 76 | |
| 77 | |
| 78 // Control scope implementation for a BreakableStatement. | |
| 79 class AstGraphBuilder::ControlScopeForBreakable : public ControlScope { | |
| 80 public: | |
| 81 ControlScopeForBreakable(AstGraphBuilder* owner, BreakableStatement* target, | |
| 82 ControlBuilder* control) | |
| 83 : ControlScope(owner, 0), target_(target), control_(control) {} | |
| 84 | |
| 85 protected: | |
| 86 virtual bool Execute(Command cmd, Statement* target, Node* value) OVERRIDE; | |
|
titzer
2015/02/03 09:50:13
Would be nice to have the bodies inline here :-)
Michael Starzinger
2015/02/03 09:59:21
Done. You slight preference is my command. :)
| |
| 87 | |
| 88 private: | |
| 89 BreakableStatement* target_; | |
| 90 ControlBuilder* control_; | |
| 91 }; | |
| 92 | |
| 93 | |
| 94 // Control scope implementation for an IterationStatement. | |
| 95 class AstGraphBuilder::ControlScopeForIteration : public ControlScope { | |
| 96 public: | |
| 97 ControlScopeForIteration(AstGraphBuilder* owner, IterationStatement* target, | |
| 98 LoopBuilder* control, int stack_delta) | |
| 99 : ControlScope(owner, stack_delta), target_(target), control_(control) {} | |
| 100 | |
| 101 protected: | |
| 102 virtual bool Execute(Command cmd, Statement* target, Node* value) OVERRIDE; | |
| 103 | |
| 104 private: | |
| 105 BreakableStatement* target_; | |
| 106 LoopBuilder* control_; | |
| 107 }; | |
| 108 | |
| 109 | |
| 110 // Control scope implementation for a TryCatchStatement. | |
| 111 class AstGraphBuilder::ControlScopeForCatch : public ControlScope { | |
| 112 public: | |
| 113 ControlScopeForCatch(AstGraphBuilder* owner, TryCatchBuilder* control) | |
| 114 : ControlScope(owner, 0), control_(control) {} | |
| 115 | |
| 116 protected: | |
| 117 virtual bool Execute(Command cmd, Statement* target, Node* value) OVERRIDE; | |
| 118 | |
| 119 private: | |
| 120 TryCatchBuilder* control_; | |
| 121 }; | |
| 122 | |
| 123 | |
| 124 // Control scope implementation for a TryFinallyStatement. | |
| 125 class AstGraphBuilder::ControlScopeForFinally : public ControlScope { | |
| 126 public: | |
| 127 ControlScopeForFinally(AstGraphBuilder* owner, DeferredCommands* commands, | |
| 128 TryFinallyBuilder* control) | |
| 129 : ControlScope(owner, 0), commands_(commands), control_(control) {} | |
| 130 | |
| 131 protected: | |
| 132 virtual bool Execute(Command cmd, Statement* target, Node* value) OVERRIDE; | |
| 133 | |
| 134 private: | |
| 135 DeferredCommands* commands_; | |
| 136 TryFinallyBuilder* control_; | |
| 137 }; | |
| 138 | |
| 139 | |
| 24 AstGraphBuilder::AstGraphBuilder(Zone* local_zone, CompilationInfo* info, | 140 AstGraphBuilder::AstGraphBuilder(Zone* local_zone, CompilationInfo* info, |
| 25 JSGraph* jsgraph, LoopAssignmentAnalysis* loop) | 141 JSGraph* jsgraph, LoopAssignmentAnalysis* loop) |
| 26 : local_zone_(local_zone), | 142 : local_zone_(local_zone), |
| 27 info_(info), | 143 info_(info), |
| 28 jsgraph_(jsgraph), | 144 jsgraph_(jsgraph), |
| 29 environment_(nullptr), | 145 environment_(nullptr), |
| 30 ast_context_(nullptr), | 146 ast_context_(nullptr), |
| 31 globals_(0, local_zone), | 147 globals_(0, local_zone), |
| 32 breakable_(nullptr), | 148 execution_control_(nullptr), |
| 33 execution_context_(nullptr), | 149 execution_context_(nullptr), |
| 34 input_buffer_size_(0), | 150 input_buffer_size_(0), |
| 35 input_buffer_(nullptr), | 151 input_buffer_(nullptr), |
| 36 current_context_(nullptr), | 152 current_context_(nullptr), |
| 37 exit_control_(nullptr), | 153 exit_control_(nullptr), |
| 38 loop_assignment_analysis_(loop) { | 154 loop_assignment_analysis_(loop) { |
| 39 InitializeAstVisitor(info->isolate(), local_zone); | 155 InitializeAstVisitor(info->isolate(), local_zone); |
| 40 } | 156 } |
| 41 | 157 |
| 42 | 158 |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 63 | 179 |
| 64 | 180 |
| 65 bool AstGraphBuilder::CreateGraph() { | 181 bool AstGraphBuilder::CreateGraph() { |
| 66 Scope* scope = info()->scope(); | 182 Scope* scope = info()->scope(); |
| 67 DCHECK(graph() != NULL); | 183 DCHECK(graph() != NULL); |
| 68 | 184 |
| 69 // Set up the basic structure of the graph. | 185 // Set up the basic structure of the graph. |
| 70 int parameter_count = info()->num_parameters(); | 186 int parameter_count = info()->num_parameters(); |
| 71 graph()->SetStart(graph()->NewNode(common()->Start(parameter_count))); | 187 graph()->SetStart(graph()->NewNode(common()->Start(parameter_count))); |
| 72 | 188 |
| 73 Node* start = graph()->start(); | 189 // Initialize control scope. |
| 190 ControlScope control(this, 0); | |
| 191 | |
| 74 // Initialize the top-level environment. | 192 // Initialize the top-level environment. |
| 75 Environment env(this, scope, start); | 193 Environment env(this, scope, graph()->start()); |
| 76 set_environment(&env); | 194 set_environment(&env); |
| 77 | 195 |
| 78 if (info()->is_osr()) { | 196 if (info()->is_osr()) { |
| 79 // Use OSR normal entry as the start of the top-level environment. | 197 // Use OSR normal entry as the start of the top-level environment. |
| 80 // It will be replaced with {Dead} after typing and optimizations. | 198 // It will be replaced with {Dead} after typing and optimizations. |
| 81 NewNode(common()->OsrNormalEntry()); | 199 NewNode(common()->OsrNormalEntry()); |
| 82 } | 200 } |
| 83 | 201 |
| 84 // Initialize the incoming context. | 202 // Initialize the incoming context. |
| 85 Node* outer_context = GetFunctionContext(); | 203 Node* outer_context = GetFunctionContext(); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 123 if (HasStackOverflow()) return false; | 241 if (HasStackOverflow()) return false; |
| 124 | 242 |
| 125 // Emit tracing call if requested to do so. | 243 // Emit tracing call if requested to do so. |
| 126 if (FLAG_trace) { | 244 if (FLAG_trace) { |
| 127 // TODO(mstarzinger): Only traces implicit return. | 245 // TODO(mstarzinger): Only traces implicit return. |
| 128 Node* return_value = jsgraph()->UndefinedConstant(); | 246 Node* return_value = jsgraph()->UndefinedConstant(); |
| 129 NewNode(javascript()->CallRuntime(Runtime::kTraceExit, 1), return_value); | 247 NewNode(javascript()->CallRuntime(Runtime::kTraceExit, 1), return_value); |
| 130 } | 248 } |
| 131 | 249 |
| 132 // Return 'undefined' in case we can fall off the end. | 250 // Return 'undefined' in case we can fall off the end. |
| 133 Node* control = NewNode(common()->Return(), jsgraph()->UndefinedConstant()); | 251 BuildReturn(jsgraph()->UndefinedConstant()); |
| 134 UpdateControlDependencyToLeaveFunction(control); | |
| 135 | 252 |
| 136 // Finish the basic structure of the graph. | 253 // Finish the basic structure of the graph. |
| 137 environment()->UpdateControlDependency(exit_control()); | 254 environment()->UpdateControlDependency(exit_control()); |
| 138 graph()->SetEnd(NewNode(common()->End())); | 255 graph()->SetEnd(NewNode(common()->End())); |
| 139 | 256 |
| 140 return true; | 257 return true; |
| 141 } | 258 } |
| 142 | 259 |
| 143 | 260 |
| 144 // Left-hand side can only be a property, a global or a variable slot. | 261 // 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() { | 412 Node* AstGraphBuilder::AstValueContext::ConsumeValue() { |
| 296 return environment()->Pop(); | 413 return environment()->Pop(); |
| 297 } | 414 } |
| 298 | 415 |
| 299 | 416 |
| 300 Node* AstGraphBuilder::AstTestContext::ConsumeValue() { | 417 Node* AstGraphBuilder::AstTestContext::ConsumeValue() { |
| 301 return environment()->Pop(); | 418 return environment()->Pop(); |
| 302 } | 419 } |
| 303 | 420 |
| 304 | 421 |
| 305 AstGraphBuilder::BreakableScope* AstGraphBuilder::BreakableScope::FindBreakable( | 422 // Helper class for a try-finally control scope. It can record intercepted |
| 306 BreakableStatement* target) { | 423 // control-flow commands that cause entry into a finally-block, and re-apply |
| 307 BreakableScope* current = this; | 424 // them after again leaving that block. Special tokens are used to identify |
| 308 while (current != NULL && current->target_ != target) { | 425 // paths going through the finally-block to dispatch after leaving the block. |
| 309 owner_->environment()->Drop(current->drop_extra_); | 426 class AstGraphBuilder::ControlScope::DeferredCommands : public ZoneObject { |
| 310 current = current->next_; | 427 public: |
| 428 explicit DeferredCommands(AstGraphBuilder* owner) | |
| 429 : owner_(owner), deferred_(owner->zone()) {} | |
| 430 | |
| 431 // One recorded control-flow command. | |
| 432 struct Entry { | |
| 433 Command command; // The command type being applied on this path. | |
| 434 Statement* statement; // The target statement for the command or {NULL}. | |
| 435 Node* value; // The passed value node for the command or {NULL}. | |
| 436 Node* token; // A token identifying this particular path. | |
| 437 }; | |
| 438 | |
| 439 // Records a control-flow command while entering the finally-block. This also | |
| 440 // generates a new dispatch token that identifies one particular path. | |
| 441 Node* RecordCommand(Command cmd, Statement* stmt, Node* value) { | |
| 442 Node* token = NewPathTokenForDeferredCommand(); | |
| 443 deferred_.push_back({cmd, stmt, value, token}); | |
| 444 return token; | |
| 311 } | 445 } |
| 312 DCHECK(current != NULL); // Always found (unless stack is malformed). | 446 |
| 313 return current; | 447 // Returns the dispatch token to be used to identify the implicit fall-through |
| 448 // path at the end of a try-block into the corresponding finally-block. | |
| 449 Node* GetFallThroughToken() { return NewPathTokenForImplicitFallThrough(); } | |
| 450 | |
| 451 // Applies all recorded control-flow commands after the finally-block again. | |
| 452 // This generates a dynamic dispatch on the token from the entry point. | |
| 453 void ApplyDeferredCommands(Node* token) { | |
| 454 SwitchBuilder dispatch(owner_, static_cast<int>(deferred_.size())); | |
| 455 dispatch.BeginSwitch(); | |
| 456 for (size_t i = 0; i < deferred_.size(); ++i) { | |
| 457 Node* condition = NewPathDispatchCondition(token, deferred_[i].token); | |
| 458 dispatch.BeginLabel(static_cast<int>(i), condition); | |
| 459 dispatch.EndLabel(); | |
| 460 } | |
| 461 for (size_t i = 0; i < deferred_.size(); ++i) { | |
| 462 dispatch.BeginCase(static_cast<int>(i)); | |
| 463 owner_->execution_control()->PerformCommand( | |
| 464 deferred_[i].command, deferred_[i].statement, deferred_[i].value); | |
| 465 dispatch.EndCase(); | |
| 466 } | |
| 467 dispatch.EndSwitch(); | |
| 468 } | |
| 469 | |
| 470 protected: | |
| 471 Node* NewPathTokenForDeferredCommand() { | |
| 472 return owner_->jsgraph()->Constant(static_cast<int>(deferred_.size())); | |
| 473 } | |
| 474 Node* NewPathTokenForImplicitFallThrough() { | |
| 475 return owner_->jsgraph()->Constant(-1); | |
| 476 } | |
| 477 Node* NewPathDispatchCondition(Node* t1, Node* t2) { | |
| 478 // TODO(mstarzinger): This should be machine()->WordEqual(), but our Phi | |
| 479 // nodes all have kRepTagged|kTypeAny, which causes representation mismatch. | |
| 480 return owner_->NewNode(owner_->javascript()->StrictEqual(), t1, t2); | |
| 481 } | |
| 482 | |
| 483 private: | |
| 484 AstGraphBuilder* owner_; | |
| 485 ZoneVector<Entry> deferred_; | |
| 486 }; | |
| 487 | |
| 488 | |
| 489 bool AstGraphBuilder::ControlScope::Execute(Command command, Statement* target, | |
| 490 Node* value) { | |
| 491 // For function-level control. | |
| 492 switch (command) { | |
| 493 case CMD_THROW: | |
| 494 builder()->BuildThrow(value); | |
| 495 return true; | |
| 496 case CMD_RETURN: | |
| 497 builder()->BuildReturn(value); | |
| 498 return true; | |
| 499 case CMD_BREAK: | |
| 500 case CMD_CONTINUE: | |
| 501 break; | |
| 502 } | |
| 503 return false; | |
| 314 } | 504 } |
| 315 | 505 |
| 316 | 506 |
| 317 void AstGraphBuilder::BreakableScope::BreakTarget(BreakableStatement* stmt) { | 507 bool AstGraphBuilder::ControlScopeForBreakable::Execute(Command command, |
| 318 FindBreakable(stmt)->control_->Break(); | 508 Statement* target, |
| 509 Node* value) { | |
| 510 if (target != target_) return false; // We are not the command target. | |
| 511 switch (command) { | |
| 512 case CMD_BREAK: | |
| 513 control_->Break(); | |
| 514 return true; | |
| 515 case CMD_CONTINUE: | |
| 516 case CMD_THROW: | |
| 517 case CMD_RETURN: | |
| 518 break; | |
| 519 } | |
| 520 return false; | |
| 319 } | 521 } |
| 320 | 522 |
| 321 | 523 |
| 322 void AstGraphBuilder::BreakableScope::ContinueTarget(BreakableStatement* stmt) { | 524 bool AstGraphBuilder::ControlScopeForIteration::Execute(Command command, |
| 323 FindBreakable(stmt)->control_->Continue(); | 525 Statement* target, |
| 526 Node* value) { | |
| 527 if (target != target_) return false; // We are not the command target. | |
| 528 switch (command) { | |
| 529 case CMD_BREAK: | |
| 530 control_->Break(); | |
| 531 return true; | |
| 532 case CMD_CONTINUE: | |
| 533 control_->Continue(); | |
| 534 return true; | |
| 535 case CMD_THROW: | |
| 536 case CMD_RETURN: | |
| 537 break; | |
| 538 } | |
| 539 return false; | |
| 324 } | 540 } |
| 325 | 541 |
| 326 | 542 |
| 543 bool AstGraphBuilder::ControlScopeForCatch::Execute(Command command, | |
| 544 Statement* target, | |
| 545 Node* value) { | |
| 546 switch (command) { | |
| 547 case CMD_THROW: | |
| 548 control_->Throw(value); | |
| 549 return true; | |
| 550 case CMD_BREAK: | |
| 551 case CMD_CONTINUE: | |
| 552 case CMD_RETURN: | |
| 553 break; | |
| 554 } | |
| 555 return false; | |
| 556 } | |
| 557 | |
| 558 | |
| 559 bool AstGraphBuilder::ControlScopeForFinally::Execute(Command cmd, | |
| 560 Statement* target, | |
| 561 Node* value) { | |
| 562 Node* token = commands_->RecordCommand(cmd, target, value); | |
| 563 control_->LeaveTry(token); | |
| 564 return true; | |
| 565 } | |
| 566 | |
| 567 | |
| 568 void AstGraphBuilder::ControlScope::PerformCommand(Command command, | |
| 569 Statement* target, | |
| 570 Node* value) { | |
| 571 Environment* env = environment()->CopyAsUnreachable(); | |
| 572 ControlScope* current = this; | |
| 573 while (current != NULL) { | |
| 574 if (current->Execute(command, target, value)) break; | |
| 575 environment()->Drop(current->stack_delta()); | |
| 576 current = current->next_; | |
| 577 } | |
| 578 // TODO(mstarzinger): Unconditionally kill environment once throw is control. | |
| 579 if (command != CMD_THROW) builder()->set_environment(env); | |
| 580 DCHECK(current != NULL); // Always handled (unless stack is malformed). | |
| 581 } | |
| 582 | |
| 583 | |
| 584 void AstGraphBuilder::ControlScope::BreakTo(BreakableStatement* stmt) { | |
| 585 PerformCommand(CMD_BREAK, stmt, nullptr); | |
| 586 } | |
| 587 | |
| 588 | |
| 589 void AstGraphBuilder::ControlScope::ContinueTo(BreakableStatement* stmt) { | |
| 590 PerformCommand(CMD_CONTINUE, stmt, nullptr); | |
| 591 } | |
| 592 | |
| 593 | |
| 594 void AstGraphBuilder::ControlScope::ReturnValue(Node* return_value) { | |
| 595 PerformCommand(CMD_RETURN, nullptr, return_value); | |
| 596 } | |
| 597 | |
| 598 | |
| 599 void AstGraphBuilder::ControlScope::ThrowValue(Node* exception_value) { | |
| 600 PerformCommand(CMD_THROW, nullptr, exception_value); | |
| 601 } | |
| 602 | |
| 603 | |
| 327 void AstGraphBuilder::VisitForValueOrNull(Expression* expr) { | 604 void AstGraphBuilder::VisitForValueOrNull(Expression* expr) { |
| 328 if (expr == NULL) { | 605 if (expr == NULL) { |
| 329 return environment()->Push(jsgraph()->NullConstant()); | 606 return environment()->Push(jsgraph()->NullConstant()); |
| 330 } | 607 } |
| 331 VisitForValue(expr); | 608 VisitForValue(expr); |
| 332 } | 609 } |
| 333 | 610 |
| 334 | 611 |
| 335 void AstGraphBuilder::VisitForValueOrTheHole(Expression* expr) { | 612 void AstGraphBuilder::VisitForValueOrTheHole(Expression* expr) { |
| 336 if (expr == NULL) { | 613 if (expr == NULL) { |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 476 | 753 |
| 477 | 754 |
| 478 void AstGraphBuilder::VisitModulePath(ModulePath* modl) { UNREACHABLE(); } | 755 void AstGraphBuilder::VisitModulePath(ModulePath* modl) { UNREACHABLE(); } |
| 479 | 756 |
| 480 | 757 |
| 481 void AstGraphBuilder::VisitModuleUrl(ModuleUrl* modl) { UNREACHABLE(); } | 758 void AstGraphBuilder::VisitModuleUrl(ModuleUrl* modl) { UNREACHABLE(); } |
| 482 | 759 |
| 483 | 760 |
| 484 void AstGraphBuilder::VisitBlock(Block* stmt) { | 761 void AstGraphBuilder::VisitBlock(Block* stmt) { |
| 485 BlockBuilder block(this); | 762 BlockBuilder block(this); |
| 486 BreakableScope scope(this, stmt, &block, 0); | 763 ControlScopeForBreakable scope(this, stmt, &block); |
| 487 if (stmt->labels() != NULL) block.BeginBlock(); | 764 if (stmt->labels() != NULL) block.BeginBlock(); |
| 488 if (stmt->scope() == NULL) { | 765 if (stmt->scope() == NULL) { |
| 489 // Visit statements in the same scope, no declarations. | 766 // Visit statements in the same scope, no declarations. |
| 490 VisitStatements(stmt->statements()); | 767 VisitStatements(stmt->statements()); |
| 491 } else { | 768 } else { |
| 492 // Visit declarations and statements in a block scope. | 769 // Visit declarations and statements in a block scope. |
| 493 Node* context = BuildLocalBlockContext(stmt->scope()); | 770 Node* context = BuildLocalBlockContext(stmt->scope()); |
| 494 ContextScope scope(this, stmt->scope(), context); | 771 ContextScope scope(this, stmt->scope(), context); |
| 495 VisitDeclarations(stmt->scope()->declarations()); | 772 VisitDeclarations(stmt->scope()->declarations()); |
| 496 VisitStatements(stmt->statements()); | 773 VisitStatements(stmt->statements()); |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 521 compare_if.If(condition); | 798 compare_if.If(condition); |
| 522 compare_if.Then(); | 799 compare_if.Then(); |
| 523 Visit(stmt->then_statement()); | 800 Visit(stmt->then_statement()); |
| 524 compare_if.Else(); | 801 compare_if.Else(); |
| 525 Visit(stmt->else_statement()); | 802 Visit(stmt->else_statement()); |
| 526 compare_if.End(); | 803 compare_if.End(); |
| 527 } | 804 } |
| 528 | 805 |
| 529 | 806 |
| 530 void AstGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) { | 807 void AstGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) { |
| 531 Environment* env = environment()->CopyAsUnreachable(); | 808 execution_control()->ContinueTo(stmt->target()); |
| 532 breakable()->ContinueTarget(stmt->target()); | |
| 533 set_environment(env); | |
| 534 } | 809 } |
| 535 | 810 |
| 536 | 811 |
| 537 void AstGraphBuilder::VisitBreakStatement(BreakStatement* stmt) { | 812 void AstGraphBuilder::VisitBreakStatement(BreakStatement* stmt) { |
| 538 Environment* env = environment()->CopyAsUnreachable(); | 813 execution_control()->BreakTo(stmt->target()); |
| 539 breakable()->BreakTarget(stmt->target()); | |
| 540 set_environment(env); | |
| 541 } | 814 } |
| 542 | 815 |
| 543 | 816 |
| 544 void AstGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { | 817 void AstGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { |
| 545 VisitForValue(stmt->expression()); | 818 VisitForValue(stmt->expression()); |
| 546 Node* result = environment()->Pop(); | 819 Node* result = environment()->Pop(); |
| 547 Node* control = NewNode(common()->Return(), result); | 820 execution_control()->ReturnValue(result); |
| 548 UpdateControlDependencyToLeaveFunction(control); | |
| 549 } | 821 } |
| 550 | 822 |
| 551 | 823 |
| 552 void AstGraphBuilder::VisitWithStatement(WithStatement* stmt) { | 824 void AstGraphBuilder::VisitWithStatement(WithStatement* stmt) { |
| 553 VisitForValue(stmt->expression()); | 825 VisitForValue(stmt->expression()); |
| 554 Node* value = environment()->Pop(); | 826 Node* value = environment()->Pop(); |
| 555 const Operator* op = javascript()->CreateWithContext(); | 827 const Operator* op = javascript()->CreateWithContext(); |
| 556 Node* context = NewNode(op, value, GetFunctionClosure()); | 828 Node* context = NewNode(op, value, GetFunctionClosure()); |
| 557 PrepareFrameState(context, stmt->EntryId()); | 829 PrepareFrameState(context, stmt->EntryId()); |
| 558 ContextScope scope(this, stmt->scope(), context); | 830 ContextScope scope(this, stmt->scope(), context); |
| 559 Visit(stmt->statement()); | 831 Visit(stmt->statement()); |
| 560 } | 832 } |
| 561 | 833 |
| 562 | 834 |
| 563 void AstGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { | 835 void AstGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { |
| 564 ZoneList<CaseClause*>* clauses = stmt->cases(); | 836 ZoneList<CaseClause*>* clauses = stmt->cases(); |
| 565 SwitchBuilder compare_switch(this, clauses->length()); | 837 SwitchBuilder compare_switch(this, clauses->length()); |
| 566 BreakableScope scope(this, stmt, &compare_switch, 0); | 838 ControlScopeForBreakable scope(this, stmt, &compare_switch); |
| 567 compare_switch.BeginSwitch(); | 839 compare_switch.BeginSwitch(); |
| 568 int default_index = -1; | 840 int default_index = -1; |
| 569 | 841 |
| 570 // Keep the switch value on the stack until a case matches. | 842 // Keep the switch value on the stack until a case matches. |
| 571 VisitForValue(stmt->tag()); | 843 VisitForValue(stmt->tag()); |
| 572 Node* tag = environment()->Top(); | 844 Node* tag = environment()->Top(); |
| 573 | 845 |
| 574 // Iterate over all cases and create nodes for label comparison. | 846 // Iterate over all cases and create nodes for label comparison. |
| 575 for (int i = 0; i < clauses->length(); i++) { | 847 for (int i = 0; i < clauses->length(); i++) { |
| 576 CaseClause* clause = clauses->at(i); | 848 CaseClause* clause = clauses->at(i); |
| (...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 809 Node* condition = environment()->Pop(); | 1081 Node* condition = environment()->Pop(); |
| 810 for_loop.BreakWhen(condition); | 1082 for_loop.BreakWhen(condition); |
| 811 VisitForEffect(stmt->assign_each()); | 1083 VisitForEffect(stmt->assign_each()); |
| 812 VisitIterationBody(stmt, &for_loop, 0); | 1084 VisitIterationBody(stmt, &for_loop, 0); |
| 813 for_loop.EndBody(); | 1085 for_loop.EndBody(); |
| 814 for_loop.EndLoop(); | 1086 for_loop.EndLoop(); |
| 815 } | 1087 } |
| 816 | 1088 |
| 817 | 1089 |
| 818 void AstGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) { | 1090 void AstGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) { |
| 819 // TODO(turbofan): Implement try-catch here. | 1091 TryCatchBuilder try_control(this); |
| 820 SetStackOverflow(); | 1092 |
| 1093 // Evaluate the try-block inside a control scope. This simulates a handler | |
| 1094 // that is intercepting 'throw' control commands. | |
| 1095 try_control.BeginTry(); | |
| 1096 { | |
| 1097 ControlScopeForCatch scope(this, &try_control); | |
| 1098 Visit(stmt->try_block()); | |
| 1099 } | |
| 1100 try_control.EndTry(); | |
| 1101 | |
| 1102 // Create a catch scope that binds the exception. | |
| 1103 Node* exception = try_control.GetExceptionNode(); | |
| 1104 if (exception == NULL) exception = jsgraph()->NullConstant(); | |
| 1105 Unique<String> name = MakeUnique(stmt->variable()->name()); | |
| 1106 const Operator* op = javascript()->CreateCatchContext(name); | |
| 1107 Node* context = NewNode(op, exception, GetFunctionClosure()); | |
| 1108 PrepareFrameState(context, BailoutId::None()); | |
| 1109 ContextScope scope(this, stmt->scope(), context); | |
| 1110 DCHECK(stmt->scope()->declarations()->is_empty()); | |
| 1111 | |
| 1112 // Evaluate the catch-block. | |
| 1113 Visit(stmt->catch_block()); | |
| 1114 try_control.EndCatch(); | |
| 1115 | |
| 1116 // TODO(mstarzinger): Remove bailout once everything works. | |
| 1117 if (!FLAG_turbo_exceptions) SetStackOverflow(); | |
| 821 } | 1118 } |
| 822 | 1119 |
| 823 | 1120 |
| 824 void AstGraphBuilder::VisitTryFinallyStatement(TryFinallyStatement* stmt) { | 1121 void AstGraphBuilder::VisitTryFinallyStatement(TryFinallyStatement* stmt) { |
| 825 // TODO(turbofan): Implement try-catch here. | 1122 TryFinallyBuilder try_control(this); |
| 826 SetStackOverflow(); | 1123 |
| 1124 // We keep a record of all paths that enter the finally-block to be able to | |
| 1125 // dispatch to the correct continuation point after the statements in the | |
| 1126 // finally-block have been evaluated. | |
| 1127 // | |
| 1128 // The try-finally construct can enter the finally-block in three ways: | |
| 1129 // 1. By exiting the try-block normally, falling through at the end. | |
| 1130 // 2. By exiting the try-block with a function-local control flow transfer | |
| 1131 // (i.e. through break/continue/return statements). | |
| 1132 // 3. By exiting the try-block with a thrown exception. | |
| 1133 ControlScope::DeferredCommands* commands = | |
| 1134 new (zone()) ControlScope::DeferredCommands(this); | |
| 1135 | |
| 1136 // Evaluate the try-block inside a control scope. This simulates a handler | |
| 1137 // that is intercepting all control commands. | |
| 1138 try_control.BeginTry(); | |
| 1139 { | |
| 1140 ControlScopeForFinally scope(this, commands, &try_control); | |
| 1141 Visit(stmt->try_block()); | |
| 1142 } | |
| 1143 try_control.EndTry(commands->GetFallThroughToken()); | |
| 1144 | |
| 1145 // Evaluate the finally-block. | |
| 1146 Visit(stmt->finally_block()); | |
| 1147 try_control.EndFinally(); | |
| 1148 | |
| 1149 // Dynamic dispatch after the finally-block. | |
| 1150 Node* token = try_control.GetDispatchTokenNode(); | |
| 1151 commands->ApplyDeferredCommands(token); | |
| 1152 | |
| 1153 // TODO(mstarzinger): Remove bailout once everything works. | |
| 1154 if (!FLAG_turbo_exceptions) SetStackOverflow(); | |
| 827 } | 1155 } |
| 828 | 1156 |
| 829 | 1157 |
| 830 void AstGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) { | 1158 void AstGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) { |
| 831 // TODO(turbofan): Do we really need a separate reloc-info for this? | 1159 // TODO(turbofan): Do we really need a separate reloc-info for this? |
| 832 Node* node = NewNode(javascript()->CallRuntime(Runtime::kDebugBreak, 0)); | 1160 Node* node = NewNode(javascript()->CallRuntime(Runtime::kDebugBreak, 0)); |
| 833 PrepareFrameState(node, stmt->DebugBreakId()); | 1161 PrepareFrameState(node, stmt->DebugBreakId()); |
| 834 } | 1162 } |
| 835 | 1163 |
| 836 | 1164 |
| (...skipping 543 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1380 void AstGraphBuilder::VisitYield(Yield* expr) { | 1708 void AstGraphBuilder::VisitYield(Yield* expr) { |
| 1381 // TODO(turbofan): Implement yield here. | 1709 // TODO(turbofan): Implement yield here. |
| 1382 SetStackOverflow(); | 1710 SetStackOverflow(); |
| 1383 ast_context()->ProduceValue(jsgraph()->UndefinedConstant()); | 1711 ast_context()->ProduceValue(jsgraph()->UndefinedConstant()); |
| 1384 } | 1712 } |
| 1385 | 1713 |
| 1386 | 1714 |
| 1387 void AstGraphBuilder::VisitThrow(Throw* expr) { | 1715 void AstGraphBuilder::VisitThrow(Throw* expr) { |
| 1388 VisitForValue(expr->exception()); | 1716 VisitForValue(expr->exception()); |
| 1389 Node* exception = environment()->Pop(); | 1717 Node* exception = environment()->Pop(); |
| 1390 const Operator* op = javascript()->CallRuntime(Runtime::kThrow, 1); | 1718 if (FLAG_turbo_exceptions) { |
| 1391 Node* value = NewNode(op, exception); | 1719 execution_control()->ThrowValue(exception); |
| 1392 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine()); | 1720 ast_context()->ProduceValue(exception); |
| 1393 ast_context()->ProduceValue(value); | 1721 } else { |
| 1722 // TODO(mstarzinger): Temporary workaround for bailout-id for debugger. | |
| 1723 const Operator* op = javascript()->CallRuntime(Runtime::kThrow, 1); | |
| 1724 Node* value = NewNode(op, exception); | |
| 1725 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine()); | |
| 1726 ast_context()->ProduceValue(value); | |
| 1727 } | |
| 1394 } | 1728 } |
| 1395 | 1729 |
| 1396 | 1730 |
| 1397 void AstGraphBuilder::VisitProperty(Property* expr) { | 1731 void AstGraphBuilder::VisitProperty(Property* expr) { |
| 1398 Node* value; | 1732 Node* value; |
| 1399 VectorSlotPair pair = CreateVectorSlotPair(expr->PropertyFeedbackSlot()); | 1733 VectorSlotPair pair = CreateVectorSlotPair(expr->PropertyFeedbackSlot()); |
| 1400 if (expr->key()->IsPropertyName()) { | 1734 if (expr->key()->IsPropertyName()) { |
| 1401 VisitForValue(expr->obj()); | 1735 VisitForValue(expr->obj()); |
| 1402 Node* object = environment()->Pop(); | 1736 Node* object = environment()->Pop(); |
| 1403 Unique<Name> name = MakeUnique(expr->key()->AsLiteral()->AsPropertyName()); | 1737 Unique<Name> name = MakeUnique(expr->key()->AsLiteral()->AsPropertyName()); |
| (...skipping 421 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1825 } | 2159 } |
| 1826 | 2160 |
| 1827 | 2161 |
| 1828 void AstGraphBuilder::VisitIfNotNull(Statement* stmt) { | 2162 void AstGraphBuilder::VisitIfNotNull(Statement* stmt) { |
| 1829 if (stmt == NULL) return; | 2163 if (stmt == NULL) return; |
| 1830 Visit(stmt); | 2164 Visit(stmt); |
| 1831 } | 2165 } |
| 1832 | 2166 |
| 1833 | 2167 |
| 1834 void AstGraphBuilder::VisitIterationBody(IterationStatement* stmt, | 2168 void AstGraphBuilder::VisitIterationBody(IterationStatement* stmt, |
| 1835 LoopBuilder* loop, int drop_extra) { | 2169 LoopBuilder* loop, int stack_delta) { |
| 1836 BreakableScope scope(this, stmt, loop, drop_extra); | 2170 ControlScopeForIteration scope(this, stmt, loop, stack_delta); |
| 1837 Visit(stmt->body()); | 2171 Visit(stmt->body()); |
| 1838 } | 2172 } |
| 1839 | 2173 |
| 1840 | 2174 |
| 1841 void AstGraphBuilder::VisitDelete(UnaryOperation* expr) { | 2175 void AstGraphBuilder::VisitDelete(UnaryOperation* expr) { |
| 1842 Node* value; | 2176 Node* value; |
| 1843 if (expr->expression()->IsVariableProxy()) { | 2177 if (expr->expression()->IsVariableProxy()) { |
| 1844 // Delete of an unqualified identifier is only allowed in classic mode but | 2178 // Delete of an unqualified identifier is only allowed in classic mode but |
| 1845 // deleting "this" is allowed in all language modes. | 2179 // deleting "this" is allowed in all language modes. |
| 1846 Variable* variable = expr->expression()->AsVariableProxy()->var(); | 2180 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) { | 2687 Node* AstGraphBuilder::BuildThrowConstAssignError(BailoutId bailout_id) { |
| 2354 // TODO(mstarzinger): Should be unified with the VisitThrow implementation. | 2688 // TODO(mstarzinger): Should be unified with the VisitThrow implementation. |
| 2355 const Operator* op = | 2689 const Operator* op = |
| 2356 javascript()->CallRuntime(Runtime::kThrowConstAssignError, 0); | 2690 javascript()->CallRuntime(Runtime::kThrowConstAssignError, 0); |
| 2357 Node* call = NewNode(op); | 2691 Node* call = NewNode(op); |
| 2358 PrepareFrameState(call, bailout_id); | 2692 PrepareFrameState(call, bailout_id); |
| 2359 return call; | 2693 return call; |
| 2360 } | 2694 } |
| 2361 | 2695 |
| 2362 | 2696 |
| 2697 Node* AstGraphBuilder::BuildReturn(Node* return_value) { | |
| 2698 Node* control = NewNode(common()->Return(), return_value); | |
| 2699 UpdateControlDependencyToLeaveFunction(control); | |
| 2700 return control; | |
| 2701 } | |
| 2702 | |
| 2703 | |
| 2704 Node* AstGraphBuilder::BuildThrow(Node* exception_value) { | |
| 2705 const Operator* op = javascript()->CallRuntime(Runtime::kThrow, 1); | |
| 2706 Node* control = NewNode(op, exception_value); | |
| 2707 // TODO(mstarzinger): Thread through the correct bailout id to this point. | |
| 2708 // PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine()); | |
| 2709 PrepareFrameState(control, BailoutId::None()); | |
| 2710 return control; | |
| 2711 } | |
| 2712 | |
| 2713 | |
| 2363 Node* AstGraphBuilder::BuildBinaryOp(Node* left, Node* right, Token::Value op) { | 2714 Node* AstGraphBuilder::BuildBinaryOp(Node* left, Node* right, Token::Value op) { |
| 2364 const Operator* js_op; | 2715 const Operator* js_op; |
| 2365 switch (op) { | 2716 switch (op) { |
| 2366 case Token::BIT_OR: | 2717 case Token::BIT_OR: |
| 2367 js_op = javascript()->BitwiseOr(); | 2718 js_op = javascript()->BitwiseOr(); |
| 2368 break; | 2719 break; |
| 2369 case Token::BIT_AND: | 2720 case Token::BIT_AND: |
| 2370 js_op = javascript()->BitwiseAnd(); | 2721 js_op = javascript()->BitwiseAnd(); |
| 2371 break; | 2722 break; |
| 2372 case Token::BIT_XOR: | 2723 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()); | 3033 Node* dead_node = graph()->NewNode(common()->Dead()); |
| 2683 dead_control_.set(dead_node); | 3034 dead_control_.set(dead_node); |
| 2684 return dead_node; | 3035 return dead_node; |
| 2685 } | 3036 } |
| 2686 return dead_control_.get(); | 3037 return dead_control_.get(); |
| 2687 } | 3038 } |
| 2688 | 3039 |
| 2689 } // namespace compiler | 3040 } // namespace compiler |
| 2690 } // namespace internal | 3041 } // namespace internal |
| 2691 } // namespace v8 | 3042 } // namespace v8 |
| OLD | NEW |