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