Index: src/hydrogen.cc |
diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
index d6cbc1444ad52eac67ab0f98ecd35f3a8e3943ae..a20343d6d45c68c784404fc0c1c53060c346e0e9 100644 |
--- a/src/hydrogen.cc |
+++ b/src/hydrogen.cc |
@@ -5050,10 +5050,6 @@ void HOptimizedGraphBuilder::VisitForInStatement(ForInStatement* stmt) { |
return Bailout(kForInStatementOptimizationIsDisabled); |
} |
- if (stmt->for_in_type() != ForInStatement::FAST_FOR_IN) { |
- return Bailout(kForInStatementIsNotFastCase); |
- } |
- |
if (!stmt->each()->IsVariableProxy() || |
!stmt->each()->AsVariableProxy()->var()->IsStackLocal()) { |
return Bailout(kForInStatementWithNonLocalEachVariable); |
@@ -5064,13 +5060,42 @@ void HOptimizedGraphBuilder::VisitForInStatement(ForInStatement* stmt) { |
CHECK_ALIVE(VisitForValue(stmt->enumerable())); |
HValue* enumerable = Top(); // Leave enumerable at the top. |
- HInstruction* map = Add<HForInPrepareMap>(enumerable); |
- Add<HSimulate>(stmt->PrepareId()); |
- |
- HInstruction* array = Add<HForInCacheArray>( |
- enumerable, map, DescriptorArray::kEnumCacheBridgeCacheIndex); |
+ HInstruction* map; |
+ HInstruction* array; |
+ HInstruction* enum_length; |
+ bool fast = stmt->for_in_type() == ForInStatement::FAST_FOR_IN; |
+ if (fast) { |
+ map = Add<HForInPrepareMap>(enumerable); |
+ Add<HSimulate>(stmt->PrepareId()); |
+ |
+ array = Add<HForInCacheArray>(enumerable, map, |
+ DescriptorArray::kEnumCacheBridgeCacheIndex); |
+ enum_length = Add<HMapEnumLength>(map); |
+ |
+ HInstruction* index_cache = Add<HForInCacheArray>( |
+ enumerable, map, DescriptorArray::kEnumCacheBridgeIndicesCacheIndex); |
+ HForInCacheArray::cast(array) |
+ ->set_index_cache(HForInCacheArray::cast(index_cache)); |
+ } else { |
+ Add<HSimulate>(stmt->PrepareId()); |
+ { |
+ NoObservableSideEffectsScope no_effects(this); |
+ BuildJSObjectCheck(enumerable, 0); |
+ } |
+ Add<HSimulate>(stmt->ToObjectId()); |
- HInstruction* enum_length = Add<HMapEnumLength>(map); |
+ map = graph()->GetConstant1(); |
+ Runtime::FunctionId function_id = Runtime::kGetPropertyNamesFast; |
+ Add<HPushArguments>(enumerable); |
+ array = Add<HCallRuntime>(isolate()->factory()->empty_string(), |
+ Runtime::FunctionForId(function_id), 1); |
+ Push(array); |
+ Add<HSimulate>(stmt->EnumId()); |
+ Drop(1); |
+ Handle<Map> array_map = isolate()->factory()->fixed_array_map(); |
+ HValue* check = Add<HCheckMaps>(array, array_map); |
+ enum_length = AddLoadFixedArrayLength(array, check); |
+ } |
HInstruction* start_index = Add<HConstant>(0); |
@@ -5079,13 +5104,12 @@ void HOptimizedGraphBuilder::VisitForInStatement(ForInStatement* stmt) { |
Push(enum_length); |
Push(start_index); |
- HInstruction* index_cache = Add<HForInCacheArray>( |
- enumerable, map, DescriptorArray::kEnumCacheBridgeIndicesCacheIndex); |
- HForInCacheArray::cast(array)->set_index_cache( |
- HForInCacheArray::cast(index_cache)); |
- |
HBasicBlock* loop_entry = BuildLoopEntry(stmt); |
+ // Reload the values to ensure we have up-to-date values inside of the loop. |
+ // This is relevant especially for OSR where the values don't come from the |
+ // computation above, but from the OSR entry block. |
+ enumerable = environment()->ExpressionStackAt(4); |
HValue* index = environment()->ExpressionStackAt(0); |
HValue* limit = environment()->ExpressionStackAt(1); |
@@ -5107,18 +5131,23 @@ void HOptimizedGraphBuilder::VisitForInStatement(ForInStatement* stmt) { |
set_current_block(loop_body); |
- HValue* key = Add<HLoadKeyed>( |
- environment()->ExpressionStackAt(2), // Enum cache. |
- environment()->ExpressionStackAt(0), // Iteration index. |
- environment()->ExpressionStackAt(0), |
- FAST_ELEMENTS); |
+ HValue* key = |
+ Add<HLoadKeyed>(environment()->ExpressionStackAt(2), // Enum cache. |
+ index, index, FAST_ELEMENTS); |
- // Check if the expected map still matches that of the enumerable. |
- // If not just deoptimize. |
- Add<HCheckMapValue>(environment()->ExpressionStackAt(4), |
- environment()->ExpressionStackAt(3)); |
- |
- Bind(each_var, key); |
+ if (fast) { |
+ // Check if the expected map still matches that of the enumerable. |
+ // If not just deoptimize. |
+ Add<HCheckMapValue>(enumerable, environment()->ExpressionStackAt(3)); |
+ Bind(each_var, key); |
+ } else { |
+ HValue* function = AddLoadJSBuiltin(Builtins::FILTER_KEY); |
+ Add<HPushArguments>(enumerable, key); |
+ key = Add<HInvokeFunction>(function, 2); |
+ Bind(each_var, key); |
+ Add<HSimulate>(stmt->AssignmentId()); |
+ Add<HCheckHeapObject>(key); |
+ } |
BreakAndContinueInfo break_info(stmt, scope(), 5); |
{ |