OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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/hydrogen.h" | 5 #include "src/hydrogen.h" |
6 | 6 |
7 #include <sstream> | 7 #include <sstream> |
8 | 8 |
9 #include "src/v8.h" | 9 #include "src/v8.h" |
10 | 10 |
(...skipping 5033 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5044 | 5044 |
5045 void HOptimizedGraphBuilder::VisitForInStatement(ForInStatement* stmt) { | 5045 void HOptimizedGraphBuilder::VisitForInStatement(ForInStatement* stmt) { |
5046 DCHECK(!HasStackOverflow()); | 5046 DCHECK(!HasStackOverflow()); |
5047 DCHECK(current_block() != NULL); | 5047 DCHECK(current_block() != NULL); |
5048 DCHECK(current_block()->HasPredecessor()); | 5048 DCHECK(current_block()->HasPredecessor()); |
5049 | 5049 |
5050 if (!FLAG_optimize_for_in) { | 5050 if (!FLAG_optimize_for_in) { |
5051 return Bailout(kForInStatementOptimizationIsDisabled); | 5051 return Bailout(kForInStatementOptimizationIsDisabled); |
5052 } | 5052 } |
5053 | 5053 |
5054 if (stmt->for_in_type() != ForInStatement::FAST_FOR_IN) { | |
5055 return Bailout(kForInStatementIsNotFastCase); | |
5056 } | |
5057 | |
5058 if (!stmt->each()->IsVariableProxy() || | 5054 if (!stmt->each()->IsVariableProxy() || |
5059 !stmt->each()->AsVariableProxy()->var()->IsStackLocal()) { | 5055 !stmt->each()->AsVariableProxy()->var()->IsStackLocal()) { |
5060 return Bailout(kForInStatementWithNonLocalEachVariable); | 5056 return Bailout(kForInStatementWithNonLocalEachVariable); |
5061 } | 5057 } |
5062 | 5058 |
5063 Variable* each_var = stmt->each()->AsVariableProxy()->var(); | 5059 Variable* each_var = stmt->each()->AsVariableProxy()->var(); |
5064 | 5060 |
5065 CHECK_ALIVE(VisitForValue(stmt->enumerable())); | 5061 CHECK_ALIVE(VisitForValue(stmt->enumerable())); |
5066 HValue* enumerable = Top(); // Leave enumerable at the top. | 5062 HValue* enumerable = Top(); // Leave enumerable at the top. |
5067 | 5063 |
5068 HInstruction* map = Add<HForInPrepareMap>(enumerable); | 5064 IfBuilder if_undefined_or_null(this); |
5069 Add<HSimulate>(stmt->PrepareId()); | 5065 if_undefined_or_null.If<HCompareObjectEqAndBranch>( |
| 5066 enumerable, graph()->GetConstantUndefined()); |
| 5067 if_undefined_or_null.Or(); |
| 5068 if_undefined_or_null.If<HCompareObjectEqAndBranch>( |
| 5069 enumerable, graph()->GetConstantNull()); |
| 5070 if_undefined_or_null.ThenDeopt(Deoptimizer::kUndefinedOrNullInForIn); |
| 5071 if_undefined_or_null.End(); |
| 5072 BuildForInBody(stmt, each_var, enumerable); |
| 5073 } |
5070 | 5074 |
5071 HInstruction* array = Add<HForInCacheArray>( | |
5072 enumerable, map, DescriptorArray::kEnumCacheBridgeCacheIndex); | |
5073 | 5075 |
5074 HInstruction* enum_length = Add<HMapEnumLength>(map); | 5076 void HOptimizedGraphBuilder::BuildForInBody(ForInStatement* stmt, |
| 5077 Variable* each_var, |
| 5078 HValue* enumerable) { |
| 5079 HInstruction* map; |
| 5080 HInstruction* array; |
| 5081 HInstruction* enum_length; |
| 5082 bool fast = stmt->for_in_type() == ForInStatement::FAST_FOR_IN; |
| 5083 if (fast) { |
| 5084 map = Add<HForInPrepareMap>(enumerable); |
| 5085 Add<HSimulate>(stmt->PrepareId()); |
| 5086 |
| 5087 array = Add<HForInCacheArray>(enumerable, map, |
| 5088 DescriptorArray::kEnumCacheBridgeCacheIndex); |
| 5089 enum_length = Add<HMapEnumLength>(map); |
| 5090 |
| 5091 HInstruction* index_cache = Add<HForInCacheArray>( |
| 5092 enumerable, map, DescriptorArray::kEnumCacheBridgeIndicesCacheIndex); |
| 5093 HForInCacheArray::cast(array) |
| 5094 ->set_index_cache(HForInCacheArray::cast(index_cache)); |
| 5095 } else { |
| 5096 Add<HSimulate>(stmt->PrepareId()); |
| 5097 { |
| 5098 NoObservableSideEffectsScope no_effects(this); |
| 5099 BuildJSObjectCheck(enumerable, 0); |
| 5100 } |
| 5101 Add<HSimulate>(stmt->ToObjectId()); |
| 5102 |
| 5103 map = graph()->GetConstant1(); |
| 5104 Runtime::FunctionId function_id = Runtime::kGetPropertyNamesFast; |
| 5105 Add<HPushArguments>(enumerable); |
| 5106 array = Add<HCallRuntime>(isolate()->factory()->empty_string(), |
| 5107 Runtime::FunctionForId(function_id), 1); |
| 5108 Push(array); |
| 5109 Add<HSimulate>(stmt->EnumId()); |
| 5110 Drop(1); |
| 5111 Handle<Map> array_map = isolate()->factory()->fixed_array_map(); |
| 5112 HValue* check = Add<HCheckMaps>(array, array_map); |
| 5113 enum_length = AddLoadFixedArrayLength(array, check); |
| 5114 } |
5075 | 5115 |
5076 HInstruction* start_index = Add<HConstant>(0); | 5116 HInstruction* start_index = Add<HConstant>(0); |
5077 | 5117 |
5078 Push(map); | 5118 Push(map); |
5079 Push(array); | 5119 Push(array); |
5080 Push(enum_length); | 5120 Push(enum_length); |
5081 Push(start_index); | 5121 Push(start_index); |
5082 | 5122 |
5083 HInstruction* index_cache = Add<HForInCacheArray>( | |
5084 enumerable, map, DescriptorArray::kEnumCacheBridgeIndicesCacheIndex); | |
5085 HForInCacheArray::cast(array) | |
5086 ->set_index_cache(HForInCacheArray::cast(index_cache)); | |
5087 | |
5088 HBasicBlock* loop_entry = BuildLoopEntry(stmt); | 5123 HBasicBlock* loop_entry = BuildLoopEntry(stmt); |
5089 | 5124 |
| 5125 // Reload the values to ensure we have up-to-date values inside of the loop. |
| 5126 // This is relevant especially for OSR where the values don't come from the |
| 5127 // computation above, but from the OSR entry block. |
| 5128 enumerable = environment()->ExpressionStackAt(4); |
5090 HValue* index = environment()->ExpressionStackAt(0); | 5129 HValue* index = environment()->ExpressionStackAt(0); |
5091 HValue* limit = environment()->ExpressionStackAt(1); | 5130 HValue* limit = environment()->ExpressionStackAt(1); |
5092 | 5131 |
5093 // Check that we still have more keys. | 5132 // Check that we still have more keys. |
5094 HCompareNumericAndBranch* compare_index = | 5133 HCompareNumericAndBranch* compare_index = |
5095 New<HCompareNumericAndBranch>(index, limit, Token::LT); | 5134 New<HCompareNumericAndBranch>(index, limit, Token::LT); |
5096 compare_index->set_observed_input_representation( | 5135 compare_index->set_observed_input_representation( |
5097 Representation::Smi(), Representation::Smi()); | 5136 Representation::Smi(), Representation::Smi()); |
5098 | 5137 |
5099 HBasicBlock* loop_body = graph()->CreateBasicBlock(); | 5138 HBasicBlock* loop_body = graph()->CreateBasicBlock(); |
5100 HBasicBlock* loop_successor = graph()->CreateBasicBlock(); | 5139 HBasicBlock* loop_successor = graph()->CreateBasicBlock(); |
5101 | 5140 |
5102 compare_index->SetSuccessorAt(0, loop_body); | 5141 compare_index->SetSuccessorAt(0, loop_body); |
5103 compare_index->SetSuccessorAt(1, loop_successor); | 5142 compare_index->SetSuccessorAt(1, loop_successor); |
5104 FinishCurrentBlock(compare_index); | 5143 FinishCurrentBlock(compare_index); |
5105 | 5144 |
5106 set_current_block(loop_successor); | 5145 set_current_block(loop_successor); |
5107 Drop(5); | 5146 Drop(5); |
5108 | 5147 |
5109 set_current_block(loop_body); | 5148 set_current_block(loop_body); |
5110 | 5149 |
5111 HValue* key = | 5150 HValue* key = |
5112 Add<HLoadKeyed>(environment()->ExpressionStackAt(2), // Enum cache. | 5151 Add<HLoadKeyed>(environment()->ExpressionStackAt(2), // Enum cache. |
5113 environment()->ExpressionStackAt(0), // Iteration index. | 5152 index, index, FAST_ELEMENTS); |
5114 environment()->ExpressionStackAt(0), FAST_ELEMENTS); | |
5115 | 5153 |
5116 // Check if the expected map still matches that of the enumerable. | 5154 if (fast) { |
5117 // If not just deoptimize. | 5155 // Check if the expected map still matches that of the enumerable. |
5118 Add<HCheckMapValue>(environment()->ExpressionStackAt(4), | 5156 // If not just deoptimize. |
5119 environment()->ExpressionStackAt(3)); | 5157 Add<HCheckMapValue>(enumerable, environment()->ExpressionStackAt(3)); |
5120 | 5158 Bind(each_var, key); |
5121 Bind(each_var, key); | 5159 } else { |
| 5160 HValue* function = AddLoadJSBuiltin(Builtins::FILTER_KEY); |
| 5161 Add<HPushArguments>(enumerable, key); |
| 5162 key = Add<HInvokeFunction>(function, 2); |
| 5163 Bind(each_var, key); |
| 5164 Add<HSimulate>(stmt->AssignmentId()); |
| 5165 Add<HCheckHeapObject>(key); |
| 5166 } |
5122 | 5167 |
5123 BreakAndContinueInfo break_info(stmt, scope(), 5); | 5168 BreakAndContinueInfo break_info(stmt, scope(), 5); |
5124 { | 5169 { |
5125 BreakAndContinueScope push(&break_info, this); | 5170 BreakAndContinueScope push(&break_info, this); |
5126 CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry)); | 5171 CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry)); |
5127 } | 5172 } |
5128 | 5173 |
5129 HBasicBlock* body_exit = | 5174 HBasicBlock* body_exit = |
5130 JoinContinue(stmt, current_block(), break_info.continue_block()); | 5175 JoinContinue(stmt, current_block(), break_info.continue_block()); |
5131 | 5176 |
(...skipping 7787 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12919 if (ShouldProduceTraceOutput()) { | 12964 if (ShouldProduceTraceOutput()) { |
12920 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 12965 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
12921 } | 12966 } |
12922 | 12967 |
12923 #ifdef DEBUG | 12968 #ifdef DEBUG |
12924 graph_->Verify(false); // No full verify. | 12969 graph_->Verify(false); // No full verify. |
12925 #endif | 12970 #endif |
12926 } | 12971 } |
12927 | 12972 |
12928 } } // namespace v8::internal | 12973 } } // namespace v8::internal |
OLD | NEW |