Index: src/hydrogen.cc |
diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
index 393e02c9f97ba6381ad0697aa220dfe2df319d63..46f0bfe04370879dd148a56b9071d27640d6ea67 100644 |
--- a/src/hydrogen.cc |
+++ b/src/hydrogen.cc |
@@ -5051,10 +5051,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); |
@@ -5065,13 +5061,57 @@ 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); |
+ IfBuilder if_undefined_or_null(this); |
+ if_undefined_or_null.If<HCompareObjectEqAndBranch>( |
+ enumerable, graph()->GetConstantUndefined()); |
+ if_undefined_or_null.Or(); |
+ if_undefined_or_null.If<HCompareObjectEqAndBranch>( |
+ enumerable, graph()->GetConstantNull()); |
+ if_undefined_or_null.ThenDeopt(Deoptimizer::kUndefinedOrNullInForIn); |
+ if_undefined_or_null.End(); |
+ BuildForInBody(stmt, each_var, enumerable); |
+} |
+ |
+ |
+void HOptimizedGraphBuilder::BuildForInBody(ForInStatement* stmt, |
+ Variable* each_var, |
+ HValue* enumerable) { |
+ 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); |
@@ -5080,13 +5120,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); |
@@ -5110,15 +5149,21 @@ void HOptimizedGraphBuilder::VisitForInStatement(ForInStatement* stmt) { |
HValue* key = |
Add<HLoadKeyed>(environment()->ExpressionStackAt(2), // Enum cache. |
- environment()->ExpressionStackAt(0), // Iteration index. |
- environment()->ExpressionStackAt(0), FAST_ELEMENTS); |
+ 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); |
{ |