| 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); | |
| 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 |