OLD | NEW |
---|---|
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 4123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4134 void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { | 4134 void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { |
4135 ASSERT(!HasStackOverflow()); | 4135 ASSERT(!HasStackOverflow()); |
4136 ASSERT(current_block() != NULL); | 4136 ASSERT(current_block() != NULL); |
4137 ASSERT(current_block()->HasPredecessor()); | 4137 ASSERT(current_block()->HasPredecessor()); |
4138 | 4138 |
4139 // We only optimize switch statements with smi-literal smi comparisons, | 4139 // We only optimize switch statements with smi-literal smi comparisons, |
4140 // with a bounded number of clauses. | 4140 // with a bounded number of clauses. |
4141 const int kCaseClauseLimit = 128; | 4141 const int kCaseClauseLimit = 128; |
4142 ZoneList<CaseClause*>* clauses = stmt->cases(); | 4142 ZoneList<CaseClause*>* clauses = stmt->cases(); |
4143 int clause_count = clauses->length(); | 4143 int clause_count = clauses->length(); |
4144 ZoneList<HBasicBlock*> body_blocks(clause_count, zone()); | |
4144 if (clause_count > kCaseClauseLimit) { | 4145 if (clause_count > kCaseClauseLimit) { |
4145 return Bailout(kSwitchStatementTooManyClauses); | 4146 return Bailout(kSwitchStatementTooManyClauses); |
4146 } | 4147 } |
4147 | 4148 |
4148 ASSERT(stmt->switch_type() != SwitchStatement::UNKNOWN_SWITCH); | 4149 ASSERT(stmt->switch_type() != SwitchStatement::UNKNOWN_SWITCH); |
4149 if (stmt->switch_type() == SwitchStatement::GENERIC_SWITCH) { | |
4150 return Bailout(kSwitchStatementMixedOrNonLiteralSwitchLabels); | |
4151 } | |
4152 | 4150 |
4153 CHECK_ALIVE(VisitForValue(stmt->tag())); | 4151 CHECK_ALIVE(VisitForValue(stmt->tag())); |
4154 Add<HSimulate>(stmt->EntryId()); | 4152 Add<HSimulate>(stmt->EntryId()); |
4155 HValue* tag_value = Pop(); | 4153 HValue* tag_value = Top(); |
4156 HBasicBlock* first_test_block = current_block(); | |
4157 | 4154 |
4158 HUnaryControlInstruction* string_check = NULL; | 4155 HUnaryControlInstruction* string_check = NULL; |
4159 HBasicBlock* not_string_block = NULL; | 4156 HBasicBlock* not_string_block = NULL; |
4160 | 4157 |
4161 // Test switch's tag value if all clauses are string literals | 4158 // Test switch's tag value if all clauses are string literals |
4162 if (stmt->switch_type() == SwitchStatement::STRING_SWITCH) { | 4159 if (stmt->switch_type() == SwitchStatement::STRING_SWITCH) { |
4163 first_test_block = graph()->CreateBasicBlock(); | 4160 HBasicBlock* first_test_block = graph()->CreateBasicBlock(); |
4164 not_string_block = graph()->CreateBasicBlock(); | 4161 not_string_block = graph()->CreateBasicBlock(); |
4165 string_check = New<HIsStringAndBranch>( | 4162 string_check = New<HIsStringAndBranch>( |
4166 tag_value, first_test_block, not_string_block); | 4163 tag_value, first_test_block, not_string_block); |
4167 FinishCurrentBlock(string_check); | 4164 FinishCurrentBlock(string_check); |
4168 | 4165 |
4166 set_current_block(not_string_block); | |
4167 Drop(1); // tag_value | |
4168 | |
4169 set_current_block(first_test_block); | 4169 set_current_block(first_test_block); |
4170 } | 4170 } |
4171 | 4171 |
4172 // 1. Build all the tests, with dangling true branches | 4172 // 1. Build all the tests, with dangling true branches |
4173 BailoutId default_id = BailoutId::None(); | 4173 BailoutId default_id = BailoutId::None(); |
4174 for (int i = 0; i < clause_count; ++i) { | 4174 for (int i = 0; i < clause_count; ++i) { |
titzer
2013/12/10 14:27:09
It seems like this loop can be rewritten to go ove
| |
4175 CaseClause* clause = clauses->at(i); | 4175 CaseClause* clause = clauses->at(i); |
4176 if (clause->is_default()) { | 4176 if (clause->is_default()) { |
4177 default_id = clause->EntryId(); | 4177 body_blocks.Add(NULL, zone()); |
4178 if (default_id.IsNone()) default_id = clause->EntryId(); | |
4178 continue; | 4179 continue; |
4179 } | 4180 } |
4180 | 4181 |
4181 // Generate a compare and branch. | 4182 // Generate a compare and branch. |
4182 CHECK_ALIVE(VisitForValue(clause->label())); | 4183 CHECK_ALIVE(VisitForValue(clause->label())); |
4183 HValue* label_value = Pop(); | 4184 HValue* label_value = Pop(); |
4184 | 4185 |
4185 HBasicBlock* next_test_block = graph()->CreateBasicBlock(); | |
4186 HBasicBlock* body_block = graph()->CreateBasicBlock(); | |
4187 | |
4188 HControlInstruction* compare; | 4186 HControlInstruction* compare; |
4189 | 4187 |
4190 if (stmt->switch_type() == SwitchStatement::SMI_SWITCH) { | 4188 if (stmt->switch_type() == SwitchStatement::SMI_SWITCH) { |
4191 if (!clause->compare_type()->Is(Type::Smi())) { | 4189 if (!clause->compare_type()->Is(Type::Smi())) { |
4192 Add<HDeoptimize>("Non-smi switch type", Deoptimizer::SOFT); | 4190 Add<HDeoptimize>("Non-smi switch type", Deoptimizer::SOFT); |
4193 } | 4191 } |
4194 | 4192 |
4195 HCompareNumericAndBranch* compare_ = | 4193 HCompareNumericAndBranch* compare_ = |
4196 New<HCompareNumericAndBranch>(tag_value, | 4194 New<HCompareNumericAndBranch>(tag_value, |
4197 label_value, | 4195 label_value, |
4198 Token::EQ_STRICT); | 4196 Token::EQ_STRICT); |
4199 compare_->set_observed_input_representation( | 4197 compare_->set_observed_input_representation( |
4200 Representation::Smi(), Representation::Smi()); | 4198 Representation::Smi(), Representation::Smi()); |
4201 compare = compare_; | 4199 compare = compare_; |
4202 } else { | 4200 } else if (stmt->switch_type() == SwitchStatement::STRING_SWITCH) { |
4203 compare = New<HStringCompareAndBranch>(tag_value, | 4201 compare = New<HStringCompareAndBranch>(tag_value, |
4204 label_value, | 4202 label_value, |
4205 Token::EQ_STRICT); | 4203 Token::EQ_STRICT); |
4204 } else { | |
4205 HValue* test = Add<HCompareGeneric>(tag_value, | |
4206 label_value, | |
4207 Token::EQ_STRICT); | |
4208 if (test->HasObservableSideEffects()) { | |
4209 Push(test); | |
4210 Add<HSimulate>(clause->id(), REMOVABLE_SIMULATE); | |
4211 Drop(1); | |
4212 } | |
4213 compare = New<HBranch>(test); | |
4206 } | 4214 } |
4207 | 4215 |
4216 HBasicBlock* next_test_block = graph()->CreateBasicBlock(); | |
4217 HBasicBlock* body_block = graph()->CreateBasicBlock(); | |
4218 body_blocks.Add(body_block, zone()); | |
4208 compare->SetSuccessorAt(0, body_block); | 4219 compare->SetSuccessorAt(0, body_block); |
4209 compare->SetSuccessorAt(1, next_test_block); | 4220 compare->SetSuccessorAt(1, next_test_block); |
4210 FinishCurrentBlock(compare); | 4221 FinishCurrentBlock(compare); |
4211 | 4222 |
4223 set_current_block(body_block); | |
4224 Drop(1); // tag_value | |
4225 | |
4212 set_current_block(next_test_block); | 4226 set_current_block(next_test_block); |
4213 } | 4227 } |
4214 | 4228 |
4215 // Save the current block to use for the default or to join with the | 4229 // Save the current block to use for the default or to join with the |
4216 // exit. | 4230 // exit. |
4217 HBasicBlock* last_block = current_block(); | 4231 HBasicBlock* last_block = current_block(); |
4232 Drop(1); // tag_value | |
4218 | 4233 |
4219 if (not_string_block != NULL) { | 4234 if (not_string_block != NULL) { |
4220 BailoutId join_id = !default_id.IsNone() ? default_id : stmt->ExitId(); | 4235 BailoutId join_id = !default_id.IsNone() ? default_id : stmt->ExitId(); |
4221 last_block = CreateJoin(last_block, not_string_block, join_id); | 4236 last_block = CreateJoin(last_block, not_string_block, join_id); |
4222 } | 4237 } |
4223 | 4238 |
4224 // 2. Loop over the clauses and the linked list of tests in lockstep, | 4239 // 2. Loop over the clauses and the linked list of tests in lockstep, |
4225 // translating the clause bodies. | 4240 // translating the clause bodies. |
4226 HBasicBlock* curr_test_block = first_test_block; | |
4227 HBasicBlock* fall_through_block = NULL; | 4241 HBasicBlock* fall_through_block = NULL; |
4228 | 4242 |
4229 BreakAndContinueInfo break_info(stmt); | 4243 BreakAndContinueInfo break_info(stmt); |
4230 { BreakAndContinueScope push(&break_info, this); | 4244 { BreakAndContinueScope push(&break_info, this); |
4231 for (int i = 0; i < clause_count; ++i) { | 4245 for (int i = 0; i < clause_count; ++i) { |
4232 CaseClause* clause = clauses->at(i); | 4246 CaseClause* clause = clauses->at(i); |
4233 | 4247 |
4234 // Identify the block where normal (non-fall-through) control flow | 4248 // Identify the block where normal (non-fall-through) control flow |
4235 // goes to. | 4249 // goes to. |
4236 HBasicBlock* normal_block = NULL; | 4250 HBasicBlock* normal_block = NULL; |
4237 if (clause->is_default()) { | 4251 if (clause->is_default()) { |
4238 if (last_block != NULL) { | 4252 if (last_block == NULL) continue; |
4239 normal_block = last_block; | 4253 normal_block = last_block; |
4240 last_block = NULL; // Cleared to indicate we've handled it. | 4254 last_block = NULL; // Cleared to indicate we've handled it. |
4241 } | |
4242 } else { | 4255 } else { |
4243 // If the current test block is deoptimizing due to an unhandled clause | 4256 normal_block = body_blocks[i]; |
4244 // of the switch, the test instruction is in the next block since the | |
4245 // deopt must end the current block. | |
4246 if (curr_test_block->IsDeoptimizing()) { | |
4247 ASSERT(curr_test_block->end()->SecondSuccessor() == NULL); | |
4248 curr_test_block = curr_test_block->end()->FirstSuccessor(); | |
4249 } | |
4250 normal_block = curr_test_block->end()->FirstSuccessor(); | |
4251 curr_test_block = curr_test_block->end()->SecondSuccessor(); | |
4252 } | 4257 } |
4253 | 4258 |
4254 // Identify a block to emit the body into. | 4259 if (fall_through_block == NULL) { |
4255 if (normal_block == NULL) { | |
4256 if (fall_through_block == NULL) { | |
4257 // (a) Unreachable. | |
4258 if (clause->is_default()) { | |
4259 continue; // Might still be reachable clause bodies. | |
4260 } else { | |
4261 break; | |
4262 } | |
4263 } else { | |
4264 // (b) Reachable only as fall through. | |
4265 set_current_block(fall_through_block); | |
4266 } | |
4267 } else if (fall_through_block == NULL) { | |
4268 // (c) Reachable only normally. | |
4269 set_current_block(normal_block); | 4260 set_current_block(normal_block); |
4270 } else { | 4261 } else { |
4271 // (d) Reachable both ways. | |
4272 HBasicBlock* join = CreateJoin(fall_through_block, | 4262 HBasicBlock* join = CreateJoin(fall_through_block, |
4273 normal_block, | 4263 normal_block, |
4274 clause->EntryId()); | 4264 clause->EntryId()); |
4275 set_current_block(join); | 4265 set_current_block(join); |
4276 } | 4266 } |
4277 | 4267 |
4278 CHECK_BAILOUT(VisitStatements(clause->statements())); | 4268 CHECK_BAILOUT(VisitStatements(clause->statements())); |
4279 fall_through_block = current_block(); | 4269 fall_through_block = current_block(); |
4280 } | 4270 } |
4281 } | 4271 } |
(...skipping 6529 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
10811 if (ShouldProduceTraceOutput()) { | 10801 if (ShouldProduceTraceOutput()) { |
10812 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 10802 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
10813 } | 10803 } |
10814 | 10804 |
10815 #ifdef DEBUG | 10805 #ifdef DEBUG |
10816 graph_->Verify(false); // No full verify. | 10806 graph_->Verify(false); // No full verify. |
10817 #endif | 10807 #endif |
10818 } | 10808 } |
10819 | 10809 |
10820 } } // namespace v8::internal | 10810 } } // namespace v8::internal |
OLD | NEW |