Commit e8e3bbe8 authored by Georg Neis's avatar Georg Neis Committed by Commit Bot

[turbofan] Propagate a store's transition map to receiver hints

This brings the number of optimization misses (with concurrent
inlining) in Octane's typescript from 179 down to 3 (the actual
score doesn't seem to change but it's already on par with the
default configuration).

Bug: v8:7790
Change-Id: Ia4ade2eafc035491d3eac9081383c72b435e8df6
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1924441
Commit-Queue: Georg Neis <neis@chromium.org>
Reviewed-by: 's avatarMichael Stanton <mvstanton@chromium.org>
Reviewed-by: 's avatarMaya Lekova <mslekova@chromium.org>
Cr-Commit-Position: refs/heads/master@{#65152}
parent a3a0f80d
...@@ -482,8 +482,9 @@ class SerializerForBackgroundCompilation { ...@@ -482,8 +482,9 @@ class SerializerForBackgroundCompilation {
bool honor_bailout_on_uninitialized); bool honor_bailout_on_uninitialized);
PropertyAccessInfo ProcessMapForNamedPropertyAccess( PropertyAccessInfo ProcessMapForNamedPropertyAccess(
MapRef receiver_map, NameRef const& name, AccessMode access_mode, Hints* receiver, MapRef receiver_map, NameRef const& name,
base::Optional<JSObjectRef> receiver, Hints* result_hints); AccessMode access_mode, base::Optional<JSObjectRef> concrete_receiver,
Hints* result_hints);
void ProcessCreateContext(interpreter::BytecodeArrayIterator* iterator, void ProcessCreateContext(interpreter::BytecodeArrayIterator* iterator,
int scopeinfo_operand_index); int scopeinfo_operand_index);
...@@ -2860,8 +2861,9 @@ void SerializerForBackgroundCompilation::ProcessUnaryOrBinaryOperation( ...@@ -2860,8 +2861,9 @@ void SerializerForBackgroundCompilation::ProcessUnaryOrBinaryOperation(
PropertyAccessInfo PropertyAccessInfo
SerializerForBackgroundCompilation::ProcessMapForNamedPropertyAccess( SerializerForBackgroundCompilation::ProcessMapForNamedPropertyAccess(
MapRef receiver_map, NameRef const& name, AccessMode access_mode, Hints* receiver, MapRef receiver_map, NameRef const& name,
base::Optional<JSObjectRef> receiver, Hints* result_hints) { AccessMode access_mode, base::Optional<JSObjectRef> concrete_receiver,
Hints* result_hints) {
// For JSNativeContextSpecialization::InferReceiverRootMap // For JSNativeContextSpecialization::InferReceiverRootMap
receiver_map.SerializeRootMap(); receiver_map.SerializeRootMap();
...@@ -2916,28 +2918,45 @@ SerializerForBackgroundCompilation::ProcessMapForNamedPropertyAccess( ...@@ -2916,28 +2918,45 @@ SerializerForBackgroundCompilation::ProcessMapForNamedPropertyAccess(
CellRef(broker(), access_info.constant()); CellRef(broker(), access_info.constant());
} }
// For PropertyAccessBuilder::TryBuildLoadConstantDataField switch (access_mode) {
if (access_mode == AccessMode::kLoad) { case AccessMode::kLoad:
if (access_info.IsDataConstant()) { // For PropertyAccessBuilder::TryBuildLoadConstantDataField
base::Optional<JSObjectRef> holder; if (access_info.IsDataConstant()) {
Handle<JSObject> prototype; base::Optional<JSObjectRef> holder;
if (access_info.holder().ToHandle(&prototype)) { Handle<JSObject> prototype;
holder = JSObjectRef(broker(), prototype); if (access_info.holder().ToHandle(&prototype)) {
} else { holder = JSObjectRef(broker(), prototype);
CHECK_IMPLIES(receiver.has_value(), } else {
receiver->map().equals(receiver_map)); CHECK_IMPLIES(concrete_receiver.has_value(),
holder = receiver; concrete_receiver->map().equals(receiver_map));
} holder = concrete_receiver;
}
if (holder.has_value()) { if (holder.has_value()) {
base::Optional<ObjectRef> constant(holder->GetOwnDataProperty( base::Optional<ObjectRef> constant(holder->GetOwnDataProperty(
access_info.field_representation(), access_info.field_index(), access_info.field_representation(), access_info.field_index(),
SerializationPolicy::kSerializeIfNeeded)); SerializationPolicy::kSerializeIfNeeded));
if (constant.has_value()) { if (constant.has_value()) {
result_hints->AddConstant(constant->object(), zone()); result_hints->AddConstant(constant->object(), zone());
}
} }
} }
} break;
case AccessMode::kStore:
case AccessMode::kStoreInLiteral:
// For MapInference (StoreField case).
if (access_info.IsDataField() || access_info.IsDataConstant()) {
Handle<Map> transition_map;
if (access_info.transition_map().ToHandle(&transition_map)) {
MapRef map_ref(broker(), transition_map);
TRACE_BROKER(broker(), "Propagating transition map "
<< map_ref << " to receiver hints.");
receiver->AddMap(transition_map, zone(), false);
}
}
break;
case AccessMode::kHas:
break;
} }
return access_info; return access_info;
...@@ -3029,16 +3048,17 @@ void SerializerForBackgroundCompilation::ProcessNamedAccess( ...@@ -3029,16 +3048,17 @@ void SerializerForBackgroundCompilation::ProcessNamedAccess(
for (Handle<Map> map : for (Handle<Map> map :
GetRelevantReceiverMaps(broker()->isolate(), receiver->maps())) { GetRelevantReceiverMaps(broker()->isolate(), receiver->maps())) {
MapRef map_ref(broker(), map); MapRef map_ref(broker(), map);
ProcessMapForNamedPropertyAccess(map_ref, feedback.name(), access_mode, ProcessMapForNamedPropertyAccess(receiver, map_ref, feedback.name(),
base::nullopt, result_hints); access_mode, base::nullopt, result_hints);
} }
for (Handle<Object> hint : receiver->constants()) { for (Handle<Object> hint : receiver->constants()) {
ObjectRef object(broker(), hint); ObjectRef object(broker(), hint);
if (access_mode == AccessMode::kLoad && object.IsJSObject()) { if (access_mode == AccessMode::kLoad && object.IsJSObject()) {
MapRef map_ref = object.AsJSObject().map(); MapRef map_ref = object.AsJSObject().map();
ProcessMapForNamedPropertyAccess(map_ref, feedback.name(), access_mode, ProcessMapForNamedPropertyAccess(receiver, map_ref, feedback.name(),
object.AsJSObject(), result_hints); access_mode, object.AsJSObject(),
result_hints);
} }
// For JSNativeContextSpecialization::ReduceJSLoadNamed. // For JSNativeContextSpecialization::ReduceJSLoadNamed.
if (access_mode == AccessMode::kLoad && object.IsJSFunction() && if (access_mode == AccessMode::kLoad && object.IsJSFunction() &&
......
// Copyright 2019 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
function C() {
this.a = 1;
%TurbofanStaticAssert(this.x == 42);
};
function D() {
this.x = 42;
C.call(this);
};
function E() {
D.call(this);
}
function F() {
E.call(this);
};
function G() {
F.call(this);
};
function foo() {
new D;
}
%PrepareFunctionForOptimization(C);
%PrepareFunctionForOptimization(D);
%PrepareFunctionForOptimization(E);
%PrepareFunctionForOptimization(F);
%PrepareFunctionForOptimization(G);
%PrepareFunctionForOptimization(foo);
// Make 'this.x' access in C megamorhpic.
new C;
new D;
new E;
new F;
new G;
foo();
foo();
%OptimizeFunctionOnNextCall(foo);
foo();
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