Commit 8c98cc07 authored by verwaest's avatar verwaest Committed by Commit bot

Add basic crankshaft support for slow-mode for-in to avoid disabling optimizations

BUG=

Review URL: https://codereview.chromium.org/1075933003

Cr-Commit-Position: refs/heads/master@{#27748}
parent dee044d6
......@@ -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);
{
......
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-proxies --allow-natives-syntax
"use strict";
// Test non-JSObject receiver.
function f(o) {
var result = [];
for (var i in o) {
result.push(i);
}
return result;
}
assertEquals(["0"], f("a"));
assertEquals(["0"], f("a"));
%OptimizeFunctionOnNextCall(f);
assertEquals(["0","1","2"], f("bla"));
// Test the lazy deopt points.
var keys = ["a", "b", "c", "d"];
var has_keys = [];
var deopt_has = false;
var deopt_enum = false;
var handler = {
enumerate: function(target) {
if (deopt_enum) {
%DeoptimizeFunction(f2);
deopt_enum = false;
}
return keys;
},
getPropertyDescriptor: function(k) {
if (deopt_has) {
%DeoptimizeFunction(f2);
deopt_has = false;
}
has_keys.push(k);
return {value: 10, configurable: true, writable: false, enumerable: true};
}
};
var proxy = Proxy.create(handler);
var o = {__proto__: proxy};
function f2(o) {
var result = [];
for (var i in o) {
result.push(i);
}
return result;
}
function check_f2() {
assertEquals(keys, f2(o));
assertEquals(keys, has_keys);
has_keys.length = 0;
}
check_f2();
check_f2();
// Test lazy deopt after GetPropertyNamesFast
%OptimizeFunctionOnNextCall(f2);
deopt_enum = true;
check_f2();
// Test lazy deopt after FILTER_KEY
%OptimizeFunctionOnNextCall(f2);
deopt_has = true;
check_f2();
......@@ -111,6 +111,9 @@
'regress/regress-2451': [PASS, NO_VARIANTS], # with custom snapshot and gc-stress.
'debug-multiple-breakpoints': [PASS, NO_VARIANTS], # with custom snapshot and gc-stress.
# TODO(jarin): Fix for-in deopt points in turbofan.
'for-in-opt': [PASS, NO_VARIANTS],
# TODO(mstarzinger): Optimizing top-level code flushed out some correctness
# issues on ARM and ARM64.
'es6/math-log2-log10': [PASS, NO_VARIANTS], # on ARM and ARM64.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment