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 4118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4129 ASSERT(current_block()->HasPredecessor()); | 4129 ASSERT(current_block()->HasPredecessor()); |
4130 return Bailout(kWithStatement); | 4130 return Bailout(kWithStatement); |
4131 } | 4131 } |
4132 | 4132 |
4133 | 4133 |
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 a bounded number of clauses. |
4140 // with a bounded number of clauses. | |
4141 const int kCaseClauseLimit = 128; | 4140 const int kCaseClauseLimit = 128; |
4142 ZoneList<CaseClause*>* clauses = stmt->cases(); | 4141 ZoneList<CaseClause*>* clauses = stmt->cases(); |
4143 int clause_count = clauses->length(); | 4142 int clause_count = clauses->length(); |
4144 ZoneList<HBasicBlock*> body_blocks(clause_count, zone()); | 4143 ZoneList<HBasicBlock*> body_blocks(clause_count, zone()); |
4145 if (clause_count > kCaseClauseLimit) { | 4144 if (clause_count > kCaseClauseLimit) { |
4146 return Bailout(kSwitchStatementTooManyClauses); | 4145 return Bailout(kSwitchStatementTooManyClauses); |
4147 } | 4146 } |
4148 | 4147 |
4149 ASSERT(stmt->switch_type() != SwitchStatement::UNKNOWN_SWITCH); | |
4150 | |
4151 CHECK_ALIVE(VisitForValue(stmt->tag())); | 4148 CHECK_ALIVE(VisitForValue(stmt->tag())); |
4152 Add<HSimulate>(stmt->EntryId()); | 4149 Add<HSimulate>(stmt->EntryId()); |
4153 HValue* tag_value = Top(); | 4150 HValue* tag_value = Top(); |
4154 | 4151 Handle<Type> tag_type = stmt->tag()->bounds().lower; |
4155 HUnaryControlInstruction* string_check = NULL; | |
4156 HBasicBlock* not_string_block = NULL; | |
4157 | |
4158 // Test switch's tag value if all clauses are string literals | |
4159 if (stmt->switch_type() == SwitchStatement::STRING_SWITCH) { | |
4160 HBasicBlock* first_test_block = graph()->CreateBasicBlock(); | |
4161 not_string_block = graph()->CreateBasicBlock(); | |
4162 string_check = New<HIsStringAndBranch>( | |
4163 tag_value, first_test_block, not_string_block); | |
4164 FinishCurrentBlock(string_check); | |
4165 | |
4166 set_current_block(not_string_block); | |
4167 Drop(1); // tag_value | |
4168 | |
4169 set_current_block(first_test_block); | |
4170 } | |
4171 | 4152 |
4172 // 1. Build all the tests, with dangling true branches | 4153 // 1. Build all the tests, with dangling true branches |
4173 BailoutId default_id = BailoutId::None(); | 4154 BailoutId default_id = BailoutId::None(); |
4174 for (int i = 0; i < clause_count; ++i) { | 4155 for (int i = 0; i < clause_count; ++i) { |
4175 CaseClause* clause = clauses->at(i); | 4156 CaseClause* clause = clauses->at(i); |
4176 if (clause->is_default()) { | 4157 if (clause->is_default()) { |
4177 body_blocks.Add(NULL, zone()); | 4158 body_blocks.Add(NULL, zone()); |
4178 if (default_id.IsNone()) default_id = clause->EntryId(); | 4159 if (default_id.IsNone()) default_id = clause->EntryId(); |
4179 continue; | 4160 continue; |
4180 } | 4161 } |
4181 | 4162 |
4182 // Generate a compare and branch. | 4163 // Generate a compare and branch. |
4183 CHECK_ALIVE(VisitForValue(clause->label())); | 4164 CHECK_ALIVE(VisitForValue(clause->label())); |
4184 HValue* label_value = Pop(); | 4165 HValue* label_value = Pop(); |
4185 | 4166 |
4186 HControlInstruction* compare; | 4167 Handle<Type> label_type = clause->label()->bounds().lower; |
4187 | 4168 Handle<Type> combined_type = clause->compare_type(); |
4188 if (stmt->switch_type() == SwitchStatement::SMI_SWITCH) { | 4169 HControlInstruction* compare = BuildCompareInstruction( |
4189 if (!clause->compare_type()->Is(Type::Smi())) { | 4170 Token::EQ_STRICT, tag_value, label_value, tag_type, label_type, |
4190 Add<HDeoptimize>("Non-smi switch type", Deoptimizer::SOFT); | 4171 combined_type, stmt->tag()->position(), clause->label()->position(), |
4191 } | 4172 clause->id()); |
4192 | |
4193 HCompareNumericAndBranch* compare_ = | |
4194 New<HCompareNumericAndBranch>(tag_value, | |
4195 label_value, | |
4196 Token::EQ_STRICT); | |
4197 compare_->set_observed_input_representation( | |
4198 Representation::Smi(), Representation::Smi()); | |
4199 compare = compare_; | |
4200 } else if (stmt->switch_type() == SwitchStatement::STRING_SWITCH) { | |
4201 compare = New<HStringCompareAndBranch>(tag_value, | |
4202 label_value, | |
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); | |
4214 } | |
4215 | 4173 |
4216 HBasicBlock* next_test_block = graph()->CreateBasicBlock(); | 4174 HBasicBlock* next_test_block = graph()->CreateBasicBlock(); |
4217 HBasicBlock* body_block = graph()->CreateBasicBlock(); | 4175 HBasicBlock* body_block = graph()->CreateBasicBlock(); |
4218 body_blocks.Add(body_block, zone()); | 4176 body_blocks.Add(body_block, zone()); |
4219 compare->SetSuccessorAt(0, body_block); | 4177 compare->SetSuccessorAt(0, body_block); |
4220 compare->SetSuccessorAt(1, next_test_block); | 4178 compare->SetSuccessorAt(1, next_test_block); |
4221 FinishCurrentBlock(compare); | 4179 FinishCurrentBlock(compare); |
4222 | 4180 |
4223 set_current_block(body_block); | 4181 set_current_block(body_block); |
4224 Drop(1); // tag_value | 4182 Drop(1); // tag_value |
4225 | 4183 |
4226 set_current_block(next_test_block); | 4184 set_current_block(next_test_block); |
4227 } | 4185 } |
4228 | 4186 |
4229 // Save the current block to use for the default or to join with the | 4187 // Save the current block to use for the default or to join with the |
4230 // exit. | 4188 // exit. |
4231 HBasicBlock* last_block = current_block(); | 4189 HBasicBlock* last_block = current_block(); |
4232 Drop(1); // tag_value | 4190 Drop(1); // tag_value |
4233 | 4191 |
4234 if (not_string_block != NULL) { | |
4235 BailoutId join_id = !default_id.IsNone() ? default_id : stmt->ExitId(); | |
4236 last_block = CreateJoin(last_block, not_string_block, join_id); | |
4237 } | |
4238 | |
4239 // 2. Loop over the clauses and the linked list of tests in lockstep, | 4192 // 2. Loop over the clauses and the linked list of tests in lockstep, |
4240 // translating the clause bodies. | 4193 // translating the clause bodies. |
4241 HBasicBlock* fall_through_block = NULL; | 4194 HBasicBlock* fall_through_block = NULL; |
4242 | 4195 |
4243 BreakAndContinueInfo break_info(stmt); | 4196 BreakAndContinueInfo break_info(stmt); |
4244 { BreakAndContinueScope push(&break_info, this); | 4197 { BreakAndContinueScope push(&break_info, this); |
4245 for (int i = 0; i < clause_count; ++i) { | 4198 for (int i = 0; i < clause_count; ++i) { |
4246 CaseClause* clause = clauses->at(i); | 4199 CaseClause* clause = clauses->at(i); |
4247 | 4200 |
4248 // Identify the block where normal (non-fall-through) control flow | 4201 // Identify the block where normal (non-fall-through) control flow |
(...skipping 4886 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
9135 HValue* value = Pop(); | 9088 HValue* value = Pop(); |
9136 Literal* literal = expr->right()->AsLiteral(); | 9089 Literal* literal = expr->right()->AsLiteral(); |
9137 Handle<String> rhs = Handle<String>::cast(literal->value()); | 9090 Handle<String> rhs = Handle<String>::cast(literal->value()); |
9138 HClassOfTestAndBranch* instr = New<HClassOfTestAndBranch>(value, rhs); | 9091 HClassOfTestAndBranch* instr = New<HClassOfTestAndBranch>(value, rhs); |
9139 return ast_context()->ReturnControl(instr, expr->id()); | 9092 return ast_context()->ReturnControl(instr, expr->id()); |
9140 } | 9093 } |
9141 | 9094 |
9142 Handle<Type> left_type = expr->left()->bounds().lower; | 9095 Handle<Type> left_type = expr->left()->bounds().lower; |
9143 Handle<Type> right_type = expr->right()->bounds().lower; | 9096 Handle<Type> right_type = expr->right()->bounds().lower; |
9144 Handle<Type> combined_type = expr->combined_type(); | 9097 Handle<Type> combined_type = expr->combined_type(); |
9145 Representation combined_rep = Representation::FromType(combined_type); | |
rossberg
2013/12/11 09:41:34
Not sure this matters, but deferring the conversio
Jakob Kummerow
2013/12/11 10:00:01
Nope, doesn't matter.
The only change we'd do to
rossberg
2013/12/11 11:35:27
Yes, I assumed as much. Though I still wonder why
| |
9146 Representation left_rep = Representation::FromType(left_type); | |
9147 Representation right_rep = Representation::FromType(right_type); | |
9148 | 9098 |
9149 CHECK_ALIVE(VisitForValue(expr->left())); | 9099 CHECK_ALIVE(VisitForValue(expr->left())); |
9150 CHECK_ALIVE(VisitForValue(expr->right())); | 9100 CHECK_ALIVE(VisitForValue(expr->right())); |
9151 | 9101 |
9152 if (FLAG_emit_opt_code_positions) SetSourcePosition(expr->position()); | 9102 if (FLAG_emit_opt_code_positions) SetSourcePosition(expr->position()); |
9153 | 9103 |
9154 HValue* right = Pop(); | 9104 HValue* right = Pop(); |
9155 HValue* left = Pop(); | 9105 HValue* left = Pop(); |
9156 Token::Value op = expr->op(); | 9106 Token::Value op = expr->op(); |
9157 | 9107 |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
9211 | 9161 |
9212 // Cases handled below depend on collected type feedback. They should | 9162 // Cases handled below depend on collected type feedback. They should |
9213 // soft deoptimize when there is no type feedback. | 9163 // soft deoptimize when there is no type feedback. |
9214 if (combined_type->Is(Type::None())) { | 9164 if (combined_type->Is(Type::None())) { |
9215 Add<HDeoptimize>("Insufficient type feedback for combined type " | 9165 Add<HDeoptimize>("Insufficient type feedback for combined type " |
9216 "of binary operation", | 9166 "of binary operation", |
9217 Deoptimizer::SOFT); | 9167 Deoptimizer::SOFT); |
9218 combined_type = left_type = right_type = handle(Type::Any(), isolate()); | 9168 combined_type = left_type = right_type = handle(Type::Any(), isolate()); |
9219 } | 9169 } |
9220 | 9170 |
9171 HControlInstruction* compare = BuildCompareInstruction( | |
9172 op, left, right, left_type, right_type, combined_type, | |
9173 expr->left()->position(), expr->right()->position(), expr->id()); | |
9174 if (compare == NULL) return; // Bailed out. | |
9175 return ast_context()->ReturnControl(compare, expr->id()); | |
9176 } | |
9177 | |
9178 | |
9179 HControlInstruction* HOptimizedGraphBuilder::BuildCompareInstruction( | |
9180 Token::Value op, | |
9181 HValue* left, | |
9182 HValue* right, | |
9183 Handle<Type> left_type, | |
9184 Handle<Type> right_type, | |
9185 Handle<Type> combined_type, | |
9186 int left_position, | |
9187 int right_position, | |
9188 BailoutId bailout_id) { | |
9189 Representation left_rep = Representation::FromType(left_type); | |
9190 Representation right_rep = Representation::FromType(right_type); | |
9191 Representation combined_rep = Representation::FromType(combined_type); | |
9192 | |
9221 if (combined_type->Is(Type::Receiver())) { | 9193 if (combined_type->Is(Type::Receiver())) { |
9222 switch (op) { | 9194 if (Token::IsEqualityOp(op)) { |
9223 case Token::EQ: | 9195 // Can we get away with map check and not instance type check? |
9224 case Token::EQ_STRICT: { | 9196 if (combined_type->IsClass()) { |
9225 // Can we get away with map check and not instance type check? | 9197 Handle<Map> map = combined_type->AsClass(); |
9226 if (combined_type->IsClass()) { | 9198 AddCheckMap(left, map); |
9227 Handle<Map> map = combined_type->AsClass(); | 9199 AddCheckMap(right, map); |
9228 AddCheckMap(left, map); | 9200 HCompareObjectEqAndBranch* result = |
9229 AddCheckMap(right, map); | 9201 New<HCompareObjectEqAndBranch>(left, right); |
9230 HCompareObjectEqAndBranch* result = | 9202 if (FLAG_emit_opt_code_positions) { |
9231 New<HCompareObjectEqAndBranch>(left, right); | 9203 result->set_operand_position(zone(), 0, left_position); |
9232 if (FLAG_emit_opt_code_positions) { | 9204 result->set_operand_position(zone(), 1, right_position); |
9233 result->set_operand_position(zone(), 0, expr->left()->position()); | |
9234 result->set_operand_position(zone(), 1, expr->right()->position()); | |
9235 } | |
9236 return ast_context()->ReturnControl(result, expr->id()); | |
9237 } else { | |
9238 BuildCheckHeapObject(left); | |
9239 Add<HCheckInstanceType>(left, HCheckInstanceType::IS_SPEC_OBJECT); | |
9240 BuildCheckHeapObject(right); | |
9241 Add<HCheckInstanceType>(right, HCheckInstanceType::IS_SPEC_OBJECT); | |
9242 HCompareObjectEqAndBranch* result = | |
9243 New<HCompareObjectEqAndBranch>(left, right); | |
9244 return ast_context()->ReturnControl(result, expr->id()); | |
9245 } | 9205 } |
9206 return result; | |
9207 } else { | |
9208 BuildCheckHeapObject(left); | |
9209 Add<HCheckInstanceType>(left, HCheckInstanceType::IS_SPEC_OBJECT); | |
9210 BuildCheckHeapObject(right); | |
9211 Add<HCheckInstanceType>(right, HCheckInstanceType::IS_SPEC_OBJECT); | |
9212 HCompareObjectEqAndBranch* result = | |
9213 New<HCompareObjectEqAndBranch>(left, right); | |
9214 return result; | |
9246 } | 9215 } |
9247 default: | 9216 } else { |
9248 return Bailout(kUnsupportedNonPrimitiveCompare); | 9217 Bailout(kUnsupportedNonPrimitiveCompare); |
9218 return NULL; | |
9249 } | 9219 } |
9250 } else if (combined_type->Is(Type::InternalizedString()) && | 9220 } else if (combined_type->Is(Type::InternalizedString()) && |
9251 Token::IsEqualityOp(op)) { | 9221 Token::IsEqualityOp(op)) { |
9252 BuildCheckHeapObject(left); | 9222 BuildCheckHeapObject(left); |
9253 Add<HCheckInstanceType>(left, HCheckInstanceType::IS_INTERNALIZED_STRING); | 9223 Add<HCheckInstanceType>(left, HCheckInstanceType::IS_INTERNALIZED_STRING); |
9254 BuildCheckHeapObject(right); | 9224 BuildCheckHeapObject(right); |
9255 Add<HCheckInstanceType>(right, HCheckInstanceType::IS_INTERNALIZED_STRING); | 9225 Add<HCheckInstanceType>(right, HCheckInstanceType::IS_INTERNALIZED_STRING); |
9256 HCompareObjectEqAndBranch* result = | 9226 HCompareObjectEqAndBranch* result = |
9257 New<HCompareObjectEqAndBranch>(left, right); | 9227 New<HCompareObjectEqAndBranch>(left, right); |
9258 return ast_context()->ReturnControl(result, expr->id()); | 9228 return result; |
9259 } else if (combined_type->Is(Type::String())) { | 9229 } else if (combined_type->Is(Type::String())) { |
9260 BuildCheckHeapObject(left); | 9230 BuildCheckHeapObject(left); |
9261 Add<HCheckInstanceType>(left, HCheckInstanceType::IS_STRING); | 9231 Add<HCheckInstanceType>(left, HCheckInstanceType::IS_STRING); |
9262 BuildCheckHeapObject(right); | 9232 BuildCheckHeapObject(right); |
9263 Add<HCheckInstanceType>(right, HCheckInstanceType::IS_STRING); | 9233 Add<HCheckInstanceType>(right, HCheckInstanceType::IS_STRING); |
9264 HStringCompareAndBranch* result = | 9234 HStringCompareAndBranch* result = |
9265 New<HStringCompareAndBranch>(left, right, op); | 9235 New<HStringCompareAndBranch>(left, right, op); |
9266 return ast_context()->ReturnControl(result, expr->id()); | 9236 return result; |
9267 } else { | 9237 } else { |
9268 if (combined_rep.IsTagged() || combined_rep.IsNone()) { | 9238 if (combined_rep.IsTagged() || combined_rep.IsNone()) { |
9269 HCompareGeneric* result = New<HCompareGeneric>(left, right, op); | 9239 HCompareGeneric* result = Add<HCompareGeneric>(left, right, op); |
9270 result->set_observed_input_representation(1, left_rep); | 9240 result->set_observed_input_representation(1, left_rep); |
9271 result->set_observed_input_representation(2, right_rep); | 9241 result->set_observed_input_representation(2, right_rep); |
9272 return ast_context()->ReturnInstruction(result, expr->id()); | 9242 if (result->HasObservableSideEffects()) { |
9243 Push(result); | |
9244 AddSimulate(bailout_id, REMOVABLE_SIMULATE); | |
9245 Drop(1); | |
9246 } | |
9247 // TODO(jkummerow): Can we make this more efficient? | |
9248 HBranch* branch = New<HBranch>(result); | |
9249 return branch; | |
9273 } else { | 9250 } else { |
9274 HCompareNumericAndBranch* result = | 9251 HCompareNumericAndBranch* result = |
9275 New<HCompareNumericAndBranch>(left, right, op); | 9252 New<HCompareNumericAndBranch>(left, right, op); |
9276 result->set_observed_input_representation(left_rep, right_rep); | 9253 result->set_observed_input_representation(left_rep, right_rep); |
9277 if (FLAG_emit_opt_code_positions) { | 9254 if (FLAG_emit_opt_code_positions) { |
9278 result->SetOperandPositions(zone(), | 9255 result->SetOperandPositions(zone(), left_position, right_position); |
9279 expr->left()->position(), | |
9280 expr->right()->position()); | |
9281 } | 9256 } |
9282 return ast_context()->ReturnControl(result, expr->id()); | 9257 return result; |
9283 } | 9258 } |
9284 } | 9259 } |
9285 } | 9260 } |
9286 | 9261 |
9287 | 9262 |
9288 void HOptimizedGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr, | 9263 void HOptimizedGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr, |
9289 Expression* sub_expr, | 9264 Expression* sub_expr, |
9290 NilValue nil) { | 9265 NilValue nil) { |
9291 ASSERT(!HasStackOverflow()); | 9266 ASSERT(!HasStackOverflow()); |
9292 ASSERT(current_block() != NULL); | 9267 ASSERT(current_block() != NULL); |
(...skipping 1510 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
10803 if (ShouldProduceTraceOutput()) { | 10778 if (ShouldProduceTraceOutput()) { |
10804 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 10779 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
10805 } | 10780 } |
10806 | 10781 |
10807 #ifdef DEBUG | 10782 #ifdef DEBUG |
10808 graph_->Verify(false); // No full verify. | 10783 graph_->Verify(false); // No full verify. |
10809 #endif | 10784 #endif |
10810 } | 10785 } |
10811 | 10786 |
10812 } } // namespace v8::internal | 10787 } } // namespace v8::internal |
OLD | NEW |