Index: src/interpreter/bytecode-generator.cc |
diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc |
index 8e6c9c53295a530ed45649645f7dc1f0a7953282..3eb010510da19f6ed3571002885791c878bb6f63 100644 |
--- a/src/interpreter/bytecode-generator.cc |
+++ b/src/interpreter/bytecode-generator.cc |
@@ -136,6 +136,36 @@ class BytecodeGenerator::ControlScopeForIteration |
}; |
+// Scoped class for enabling 'break' in switch statements. |
+class BytecodeGenerator::ControlScopeForSwitch |
+ : public BytecodeGenerator::ControlScope { |
+ public: |
+ ControlScopeForSwitch(BytecodeGenerator* generator, |
+ SwitchStatement* statement, |
+ SwitchBuilder* switch_builder) |
+ : ControlScope(generator), |
+ statement_(statement), |
+ switch_builder_(switch_builder) {} |
+ |
+ protected: |
+ virtual bool Execute(Command command, Statement* statement) { |
+ if (statement != statement_) return false; |
+ switch (command) { |
+ case CMD_BREAK: |
+ switch_builder_->Break(); |
+ return true; |
+ case CMD_CONTINUE: |
+ break; |
+ } |
+ return false; |
+ } |
+ |
+ private: |
+ Statement* statement_; |
+ SwitchBuilder* switch_builder_; |
+}; |
+ |
+ |
void BytecodeGenerator::ControlScope::PerformCommand(Command command, |
Statement* statement) { |
ControlScope* current = this; |
@@ -539,11 +569,57 @@ void BytecodeGenerator::VisitWithStatement(WithStatement* stmt) { |
void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { |
- UNIMPLEMENTED(); |
+ ZoneList<CaseClause*>* clauses = stmt->cases(); |
+ SwitchBuilder switch_builder(builder(), clauses->length()); |
+ ControlScopeForSwitch scope(this, stmt, &switch_builder); |
+ int default_index = -1; |
+ |
+ // Keep the switch value in a register until a case matches. |
+ Register tag = VisitForRegisterValue(stmt->tag()); |
+ |
+ // Iterate over all cases and create nodes for label comparison. |
+ BytecodeLabel done_label; |
+ for (int i = 0; i < clauses->length(); i++) { |
+ CaseClause* clause = clauses->at(i); |
+ |
+ // The default is not a test, remember index. |
+ if (clause->is_default()) { |
+ default_index = i; |
+ continue; |
+ } |
+ |
+ // Perform label comparison as if via '===' with tag. |
+ VisitForAccumulatorValue(clause->label()); |
+ builder()->CompareOperation(Token::Value::EQ_STRICT, tag, |
+ language_mode_strength()); |
+ switch_builder.Case(i); |
+ } |
+ |
+ if (default_index >= 0) { |
+ // Emit default jump if there is a default case. |
+ switch_builder.DefaultAt(default_index); |
+ } else { |
+ // Otherwise if we have reached here none of the cases matched, so jump to |
+ // done. |
+ builder()->Jump(&done_label); |
+ } |
+ |
+ // Iterate over all cases and create the case bodies. |
+ for (int i = 0; i < clauses->length(); i++) { |
+ CaseClause* clause = clauses->at(i); |
+ switch_builder.SetCaseTarget(i); |
+ VisitStatements(clause->statements()); |
+ } |
+ builder()->Bind(&done_label); |
+ |
+ switch_builder.SetBreakTarget(done_label); |
} |
-void BytecodeGenerator::VisitCaseClause(CaseClause* clause) { UNIMPLEMENTED(); } |
+void BytecodeGenerator::VisitCaseClause(CaseClause* clause) { |
+ // Handled entirely in VisitSwitchStatement. |
+ UNREACHABLE(); |
+} |
void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { |