[turbofan] Optimize JSResolvePromise with unreliable resolution maps.

When InferReceiverMaps doesn't provide us with reliable maps for the
resolution, we can still utilize the information if all the maps that
are found are stable - aka leaf - maps. But in that case we need to
make sure that we add proper dependencies on the stability of these
maps.

Bug: v8:7253
Change-Id: I6f5825583acc3f2575e83a244d55609ac64d04d3
Reviewed-on: https://chromium-review.googlesource.com/c/1288633
Reviewed-by: Georg Neis <neis@chromium.org>
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56789}
This commit is contained in:
Benedikt Meurer 2018-10-18 19:26:23 +02:00 committed by Commit Bot
parent 2e70a9f7ee
commit 39e68c5e40
2 changed files with 77 additions and 1 deletions

View File

@ -689,9 +689,17 @@ Reduction JSNativeContextSpecialization::ReduceJSResolvePromise(Node* node) {
NodeProperties::InferReceiverMapsResult result =
NodeProperties::InferReceiverMaps(broker(), resolution, effect,
&resolution_maps);
if (result != NodeProperties::kReliableReceiverMaps) return NoChange();
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
DCHECK_NE(0, resolution_maps.size());
// When the {resolution_maps} information is unreliable, we can
// still optimize if all individual {resolution_maps} are stable.
if (result == NodeProperties::kUnreliableReceiverMaps) {
for (Handle<Map> resolution_map : resolution_maps) {
if (!resolution_map->is_stable()) return NoChange();
}
}
// Compute property access info for "then" on {resolution}.
PropertyAccessInfo access_info;
AccessInfoFactory access_info_factory(
@ -714,6 +722,13 @@ Reduction JSNativeContextSpecialization::ReduceJSResolvePromise(Node* node) {
broker(), access_info.receiver_maps(), JSObjectRef(broker(), holder));
}
// Add stability dependencies on the {resolution_maps}.
if (result == NodeProperties::kUnreliableReceiverMaps) {
for (Handle<Map> resolution_map : resolution_maps) {
dependencies()->DependOnStableMap(MapRef(broker(), resolution_map));
}
}
// Simply fulfill the {promise} with the {resolution}.
Node* value = effect =
graph()->NewNode(javascript()->FulfillPromise(), promise, resolution,

View File

@ -0,0 +1,61 @@
// Copyright 2018 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: --allow-natives-syntax --opt --noalways-opt
// Test that JSResolvePromise takes a proper stability dependency
// on the resolutions map if the infer receiver maps are unreliable
// (as is the case for HeapConstants).
(function() {
// We need an object literal which gets a stable map initially.
function makeObjectWithStableMap() {
return {a:1, b:1, c:1};
}
const a = makeObjectWithStableMap();
function foo() {
return Promise.resolve(a);
}
assertInstanceof(foo(), Promise);
assertInstanceof(foo(), Promise);
%OptimizeFunctionOnNextCall(foo);
assertInstanceof(foo(), Promise);
assertOptimized(foo);
// Now invalidate the stability of a's map.
const b = makeObjectWithStableMap();
b.d = 1;
// This should deoptimize foo.
assertUnoptimized(foo);
})();
// Same test with async functions.
(function() {
// We need an object literal which gets a stable map initially,
// it needs to be different from the above, otherwise the map
// is already not stable when we get here.
function makeObjectWithStableMap() {
return {x:1, y:1};
}
const a = makeObjectWithStableMap();
async function foo() {
return a;
}
assertInstanceof(foo(), Promise);
assertInstanceof(foo(), Promise);
%OptimizeFunctionOnNextCall(foo);
assertInstanceof(foo(), Promise);
assertOptimized(foo);
// Now invalidate the stability of a's map.
const b = makeObjectWithStableMap();
b.z = 1;
// This should deoptimize foo.
assertUnoptimized(foo);
})();