OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 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/interpreter/bytecode-generator.h" | 5 #include "src/interpreter/bytecode-generator.h" |
6 | 6 |
7 #include "src/ast/scopes.h" | 7 #include "src/ast/scopes.h" |
8 #include "src/compiler.h" | 8 #include "src/compiler.h" |
9 #include "src/interpreter/control-flow-builders.h" | 9 #include "src/interpreter/control-flow-builders.h" |
10 #include "src/objects.h" | 10 #include "src/objects.h" |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
97 ControlScope* outer() const { return outer_; } | 97 ControlScope* outer() const { return outer_; } |
98 | 98 |
99 private: | 99 private: |
100 BytecodeGenerator* generator_; | 100 BytecodeGenerator* generator_; |
101 ControlScope* outer_; | 101 ControlScope* outer_; |
102 | 102 |
103 DISALLOW_COPY_AND_ASSIGN(ControlScope); | 103 DISALLOW_COPY_AND_ASSIGN(ControlScope); |
104 }; | 104 }; |
105 | 105 |
106 | 106 |
| 107 // Scoped class for enabling break inside blocks and switch blocks. |
| 108 class BytecodeGenerator::ControlScopeForBreakable final |
| 109 : public BytecodeGenerator::ControlScope { |
| 110 public: |
| 111 ControlScopeForBreakable(BytecodeGenerator* generator, |
| 112 BreakableStatement* statement, |
| 113 BreakableControlFlowBuilder* control_builder) |
| 114 : ControlScope(generator), |
| 115 statement_(statement), |
| 116 control_builder_(control_builder) {} |
| 117 |
| 118 protected: |
| 119 virtual bool Execute(Command command, Statement* statement) { |
| 120 if (statement != statement_) return false; |
| 121 switch (command) { |
| 122 case CMD_BREAK: |
| 123 control_builder_->Break(); |
| 124 return true; |
| 125 case CMD_CONTINUE: |
| 126 break; |
| 127 } |
| 128 return false; |
| 129 } |
| 130 |
| 131 private: |
| 132 Statement* statement_; |
| 133 BreakableControlFlowBuilder* control_builder_; |
| 134 }; |
| 135 |
| 136 |
107 // Scoped class for enabling 'break' and 'continue' in iteration | 137 // Scoped class for enabling 'break' and 'continue' in iteration |
108 // constructs, e.g. do...while, while..., for... | 138 // constructs, e.g. do...while, while..., for... |
109 class BytecodeGenerator::ControlScopeForIteration | 139 class BytecodeGenerator::ControlScopeForIteration final |
110 : public BytecodeGenerator::ControlScope { | 140 : public BytecodeGenerator::ControlScope { |
111 public: | 141 public: |
112 ControlScopeForIteration(BytecodeGenerator* generator, | 142 ControlScopeForIteration(BytecodeGenerator* generator, |
113 IterationStatement* statement, | 143 IterationStatement* statement, |
114 LoopBuilder* loop_builder) | 144 LoopBuilder* loop_builder) |
115 : ControlScope(generator), | 145 : ControlScope(generator), |
116 statement_(statement), | 146 statement_(statement), |
117 loop_builder_(loop_builder) {} | 147 loop_builder_(loop_builder) {} |
118 | 148 |
119 protected: | 149 protected: |
120 virtual bool Execute(Command command, Statement* statement) { | 150 virtual bool Execute(Command command, Statement* statement) { |
121 if (statement != statement_) return false; | 151 if (statement != statement_) return false; |
122 switch (command) { | 152 switch (command) { |
123 case CMD_BREAK: | 153 case CMD_BREAK: |
124 loop_builder_->Break(); | 154 loop_builder_->Break(); |
125 return true; | 155 return true; |
126 case CMD_CONTINUE: | 156 case CMD_CONTINUE: |
127 loop_builder_->Continue(); | 157 loop_builder_->Continue(); |
128 return true; | 158 return true; |
129 } | 159 } |
130 return false; | 160 return false; |
131 } | 161 } |
132 | 162 |
133 private: | 163 private: |
134 Statement* statement_; | 164 Statement* statement_; |
135 LoopBuilder* loop_builder_; | 165 LoopBuilder* loop_builder_; |
136 }; | 166 }; |
137 | 167 |
138 | 168 |
139 // Scoped class for enabling 'break' in switch statements. | |
140 class BytecodeGenerator::ControlScopeForSwitch | |
141 : public BytecodeGenerator::ControlScope { | |
142 public: | |
143 ControlScopeForSwitch(BytecodeGenerator* generator, | |
144 SwitchStatement* statement, | |
145 SwitchBuilder* switch_builder) | |
146 : ControlScope(generator), | |
147 statement_(statement), | |
148 switch_builder_(switch_builder) {} | |
149 | |
150 protected: | |
151 virtual bool Execute(Command command, Statement* statement) { | |
152 if (statement != statement_) return false; | |
153 switch (command) { | |
154 case CMD_BREAK: | |
155 switch_builder_->Break(); | |
156 return true; | |
157 case CMD_CONTINUE: | |
158 break; | |
159 } | |
160 return false; | |
161 } | |
162 | |
163 private: | |
164 Statement* statement_; | |
165 SwitchBuilder* switch_builder_; | |
166 }; | |
167 | |
168 | |
169 void BytecodeGenerator::ControlScope::PerformCommand(Command command, | 169 void BytecodeGenerator::ControlScope::PerformCommand(Command command, |
170 Statement* statement) { | 170 Statement* statement) { |
171 ControlScope* current = this; | 171 ControlScope* current = this; |
172 do { | 172 do { |
173 if (current->Execute(command, statement)) return; | 173 if (current->Execute(command, statement)) return; |
174 current = current->outer(); | 174 current = current->outer(); |
175 } while (current != nullptr); | 175 } while (current != nullptr); |
176 UNREACHABLE(); | 176 UNREACHABLE(); |
177 } | 177 } |
178 | 178 |
(...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
477 | 477 |
478 // Visit declarations within the function scope. | 478 // Visit declarations within the function scope. |
479 VisitDeclarations(scope()->declarations()); | 479 VisitDeclarations(scope()->declarations()); |
480 | 480 |
481 // Visit statements in the function body. | 481 // Visit statements in the function body. |
482 VisitStatements(info()->literal()->body()); | 482 VisitStatements(info()->literal()->body()); |
483 } | 483 } |
484 | 484 |
485 | 485 |
486 void BytecodeGenerator::VisitBlock(Block* stmt) { | 486 void BytecodeGenerator::VisitBlock(Block* stmt) { |
| 487 BlockBuilder block_builder(this->builder()); |
| 488 ControlScopeForBreakable execution_control(this, stmt, &block_builder); |
| 489 |
487 if (stmt->scope() == NULL) { | 490 if (stmt->scope() == NULL) { |
488 // Visit statements in the same scope, no declarations. | 491 // Visit statements in the same scope, no declarations. |
489 VisitStatements(stmt->statements()); | 492 VisitStatements(stmt->statements()); |
490 } else { | 493 } else { |
491 // Visit declarations and statements in a block scope. | 494 // Visit declarations and statements in a block scope. |
492 if (stmt->scope()->NeedsContext()) { | 495 if (stmt->scope()->NeedsContext()) { |
493 VisitNewLocalBlockContext(stmt->scope()); | 496 VisitNewLocalBlockContext(stmt->scope()); |
494 ContextScope scope(this, stmt->scope()); | 497 ContextScope scope(this, stmt->scope()); |
495 VisitDeclarations(stmt->scope()->declarations()); | 498 VisitDeclarations(stmt->scope()->declarations()); |
496 VisitStatements(stmt->statements()); | 499 VisitStatements(stmt->statements()); |
497 } else { | 500 } else { |
498 VisitDeclarations(stmt->scope()->declarations()); | 501 VisitDeclarations(stmt->scope()->declarations()); |
499 VisitStatements(stmt->statements()); | 502 VisitStatements(stmt->statements()); |
500 } | 503 } |
501 } | 504 } |
| 505 if (stmt->labels() != nullptr) block_builder.EndBlock(); |
502 } | 506 } |
503 | 507 |
504 | 508 |
505 void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) { | 509 void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) { |
506 Variable* variable = decl->proxy()->var(); | 510 Variable* variable = decl->proxy()->var(); |
507 VariableMode mode = decl->mode(); | 511 VariableMode mode = decl->mode(); |
508 // Const and let variables are initialized with the hole so that we can | 512 // Const and let variables are initialized with the hole so that we can |
509 // check that they are only assigned once. | 513 // check that they are only assigned once. |
510 bool hole_init = mode == CONST || mode == CONST_LEGACY || mode == LET; | 514 bool hole_init = mode == CONST || mode == CONST_LEGACY || mode == LET; |
511 switch (variable->location()) { | 515 switch (variable->location()) { |
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
678 | 682 |
679 | 683 |
680 void BytecodeGenerator::VisitWithStatement(WithStatement* stmt) { | 684 void BytecodeGenerator::VisitWithStatement(WithStatement* stmt) { |
681 UNIMPLEMENTED(); | 685 UNIMPLEMENTED(); |
682 } | 686 } |
683 | 687 |
684 | 688 |
685 void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { | 689 void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { |
686 ZoneList<CaseClause*>* clauses = stmt->cases(); | 690 ZoneList<CaseClause*>* clauses = stmt->cases(); |
687 SwitchBuilder switch_builder(builder(), clauses->length()); | 691 SwitchBuilder switch_builder(builder(), clauses->length()); |
688 ControlScopeForSwitch scope(this, stmt, &switch_builder); | 692 ControlScopeForBreakable scope(this, stmt, &switch_builder); |
689 int default_index = -1; | 693 int default_index = -1; |
690 | 694 |
691 // Keep the switch value in a register until a case matches. | 695 // Keep the switch value in a register until a case matches. |
692 Register tag = VisitForRegisterValue(stmt->tag()); | 696 Register tag = VisitForRegisterValue(stmt->tag()); |
693 | 697 |
694 // Iterate over all cases and create nodes for label comparison. | 698 // Iterate over all cases and create nodes for label comparison. |
695 BytecodeLabel done_label; | 699 BytecodeLabel done_label; |
696 for (int i = 0; i < clauses->length(); i++) { | 700 for (int i = 0; i < clauses->length(); i++) { |
697 CaseClause* clause = clauses->at(i); | 701 CaseClause* clause = clauses->at(i); |
698 | 702 |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
746 } else if (stmt->cond()->ToBooleanIsTrue()) { | 750 } else if (stmt->cond()->ToBooleanIsTrue()) { |
747 loop_builder.Condition(); | 751 loop_builder.Condition(); |
748 Visit(stmt->body()); | 752 Visit(stmt->body()); |
749 loop_builder.JumpToHeader(); | 753 loop_builder.JumpToHeader(); |
750 } else { | 754 } else { |
751 Visit(stmt->body()); | 755 Visit(stmt->body()); |
752 loop_builder.Condition(); | 756 loop_builder.Condition(); |
753 VisitForAccumulatorValue(stmt->cond()); | 757 VisitForAccumulatorValue(stmt->cond()); |
754 loop_builder.JumpToHeaderIfTrue(); | 758 loop_builder.JumpToHeaderIfTrue(); |
755 } | 759 } |
756 loop_builder.LoopEnd(); | 760 loop_builder.EndLoop(); |
757 } | 761 } |
758 | 762 |
759 | 763 |
760 void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) { | 764 void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) { |
761 if (stmt->cond()->ToBooleanIsFalse()) { | 765 if (stmt->cond()->ToBooleanIsFalse()) { |
762 // If the condition is false there is no need to generate the loop. | 766 // If the condition is false there is no need to generate the loop. |
763 return; | 767 return; |
764 } | 768 } |
765 | 769 |
766 LoopBuilder loop_builder(builder()); | 770 LoopBuilder loop_builder(builder()); |
767 ControlScopeForIteration execution_control(this, stmt, &loop_builder); | 771 ControlScopeForIteration execution_control(this, stmt, &loop_builder); |
768 loop_builder.LoopHeader(); | 772 loop_builder.LoopHeader(); |
769 loop_builder.Condition(); | 773 loop_builder.Condition(); |
770 if (!stmt->cond()->ToBooleanIsTrue()) { | 774 if (!stmt->cond()->ToBooleanIsTrue()) { |
771 VisitForAccumulatorValue(stmt->cond()); | 775 VisitForAccumulatorValue(stmt->cond()); |
772 loop_builder.BreakIfFalse(); | 776 loop_builder.BreakIfFalse(); |
773 } | 777 } |
774 Visit(stmt->body()); | 778 Visit(stmt->body()); |
775 loop_builder.JumpToHeader(); | 779 loop_builder.JumpToHeader(); |
776 loop_builder.LoopEnd(); | 780 loop_builder.EndLoop(); |
777 } | 781 } |
778 | 782 |
779 | 783 |
780 void BytecodeGenerator::VisitForStatement(ForStatement* stmt) { | 784 void BytecodeGenerator::VisitForStatement(ForStatement* stmt) { |
781 if (stmt->init() != nullptr) { | 785 if (stmt->init() != nullptr) { |
782 Visit(stmt->init()); | 786 Visit(stmt->init()); |
783 } | 787 } |
784 if (stmt->cond() && stmt->cond()->ToBooleanIsFalse()) { | 788 if (stmt->cond() && stmt->cond()->ToBooleanIsFalse()) { |
785 // If the condition is known to be false there is no need to generate | 789 // If the condition is known to be false there is no need to generate |
786 // body, next or condition blocks. Init block should be generated. | 790 // body, next or condition blocks. Init block should be generated. |
787 return; | 791 return; |
788 } | 792 } |
789 | 793 |
790 LoopBuilder loop_builder(builder()); | 794 LoopBuilder loop_builder(builder()); |
791 ControlScopeForIteration execution_control(this, stmt, &loop_builder); | 795 ControlScopeForIteration execution_control(this, stmt, &loop_builder); |
792 | 796 |
793 loop_builder.LoopHeader(); | 797 loop_builder.LoopHeader(); |
794 loop_builder.Condition(); | 798 loop_builder.Condition(); |
795 if (stmt->cond() && !stmt->cond()->ToBooleanIsTrue()) { | 799 if (stmt->cond() && !stmt->cond()->ToBooleanIsTrue()) { |
796 VisitForAccumulatorValue(stmt->cond()); | 800 VisitForAccumulatorValue(stmt->cond()); |
797 loop_builder.BreakIfFalse(); | 801 loop_builder.BreakIfFalse(); |
798 } | 802 } |
799 Visit(stmt->body()); | 803 Visit(stmt->body()); |
800 if (stmt->next() != nullptr) { | 804 if (stmt->next() != nullptr) { |
801 loop_builder.Next(); | 805 loop_builder.Next(); |
802 Visit(stmt->next()); | 806 Visit(stmt->next()); |
803 } | 807 } |
804 loop_builder.JumpToHeader(); | 808 loop_builder.JumpToHeader(); |
805 loop_builder.LoopEnd(); | 809 loop_builder.EndLoop(); |
806 } | 810 } |
807 | 811 |
808 | 812 |
809 void BytecodeGenerator::VisitForInAssignment(Expression* expr, | 813 void BytecodeGenerator::VisitForInAssignment(Expression* expr, |
810 FeedbackVectorSlot slot) { | 814 FeedbackVectorSlot slot) { |
811 DCHECK(expr->IsValidReferenceExpression()); | 815 DCHECK(expr->IsValidReferenceExpression()); |
812 | 816 |
813 // Evaluate assignment starting with the value to be stored in the | 817 // Evaluate assignment starting with the value to be stored in the |
814 // accumulator. | 818 // accumulator. |
815 Property* property = expr->AsProperty(); | 819 Property* property = expr->AsProperty(); |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
887 loop_builder.ContinueIfUndefined(); | 891 loop_builder.ContinueIfUndefined(); |
888 | 892 |
889 VisitForInAssignment(stmt->each(), stmt->EachFeedbackSlot()); | 893 VisitForInAssignment(stmt->each(), stmt->EachFeedbackSlot()); |
890 Visit(stmt->body()); | 894 Visit(stmt->body()); |
891 | 895 |
892 // TODO(oth): replace CountOperation here with ForInStep. | 896 // TODO(oth): replace CountOperation here with ForInStep. |
893 loop_builder.Next(); | 897 loop_builder.Next(); |
894 builder()->LoadAccumulatorWithRegister(index).CountOperation( | 898 builder()->LoadAccumulatorWithRegister(index).CountOperation( |
895 Token::Value::ADD, language_mode_strength()); | 899 Token::Value::ADD, language_mode_strength()); |
896 loop_builder.JumpToHeader(); | 900 loop_builder.JumpToHeader(); |
897 loop_builder.LoopEnd(); | 901 loop_builder.EndLoop(); |
898 } | 902 } |
899 | 903 |
900 | 904 |
901 void BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) { | 905 void BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) { |
902 UNIMPLEMENTED(); | 906 UNIMPLEMENTED(); |
903 } | 907 } |
904 | 908 |
905 | 909 |
906 void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { | 910 void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { |
907 if (FLAG_ignition_fake_try_catch) { | 911 if (FLAG_ignition_fake_try_catch) { |
(...skipping 1290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2198 } | 2202 } |
2199 | 2203 |
2200 | 2204 |
2201 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { | 2205 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { |
2202 return info()->feedback_vector()->GetIndex(slot); | 2206 return info()->feedback_vector()->GetIndex(slot); |
2203 } | 2207 } |
2204 | 2208 |
2205 } // namespace interpreter | 2209 } // namespace interpreter |
2206 } // namespace internal | 2210 } // namespace internal |
2207 } // namespace v8 | 2211 } // namespace v8 |
OLD | NEW |