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

[turbofan] Propagate feedback to hints

Allow sharing of hints and modification of shared hints such that
feedback can be propagated to the hints for the corresponding
register, AND all alias registers. Even propagation from an inlined
callee back to the caller is possible.

Bug: v8:7790
Change-Id: I96b3c5e41613efa5711ab758db1c3ef7f7ae6418
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1914560
Commit-Queue: Georg Neis <neis@chromium.org>
Reviewed-by: 's avatarMaya Lekova <mslekova@chromium.org>
Reviewed-by: 's avatarMichael Stanton <mvstanton@chromium.org>
Cr-Commit-Position: refs/heads/master@{#65139}
parent 026a0c21
......@@ -46,6 +46,10 @@ class FunctionalList {
return !(*this == other);
}
bool TriviallyEquals(const FunctionalList<A>& other) const {
return elements_ == other.elements_;
}
const A& Front() const {
DCHECK_GT(Size(), 0);
return elements_->top;
......
......@@ -2525,15 +2525,8 @@ bool JSHeapBroker::ShouldBeSerializedForCompilation(
void JSHeapBroker::SetSerializedForCompilation(
const SharedFunctionInfoRef& shared, const FeedbackVectorRef& feedback,
const HintsVector& arguments) {
HintsVector arguments_copy_in_broker_zone(zone());
for (auto const& hints : arguments) {
Hints hint_copy_in_broker_zone;
hint_copy_in_broker_zone.AddFromChildSerializer(hints, zone());
arguments_copy_in_broker_zone.push_back(hint_copy_in_broker_zone);
}
SerializedFunction function = {shared, feedback};
serialized_functions_.insert({function, arguments_copy_in_broker_zone});
SerializedFunction function{shared, feedback};
serialized_functions_.insert({function, arguments});
TRACE(this, "Set function " << shared << " with " << feedback
<< " as serialized for compilation");
}
......
......@@ -33,6 +33,17 @@ class FunctionalSet {
data_.PushFront(elem, zone);
}
void Union(FunctionalSet<T, EqualTo> other, Zone* zone) {
if (!data_.TriviallyEquals(other.data_)) {
// Choose the larger side as tail.
if (data_.Size() < other.data_.Size()) std::swap(data_, other.data_);
for (auto const& elem : other.data_) Add(elem, zone);
}
}
bool IsEmpty() const { return data_.begin() == data_.end(); }
// Warning: quadratic time complexity.
bool Includes(FunctionalSet<T, EqualTo> const& other) const {
return std::all_of(other.begin(), other.end(), [&](T const& other_elem) {
return std::any_of(this->begin(), this->end(), [&](T const& this_elem) {
......@@ -40,15 +51,10 @@ class FunctionalSet {
});
});
}
bool IsEmpty() const { return data_.begin() == data_.end(); }
void Clear() { data_.Clear(); }
// Warning: quadratic time complexity.
bool operator==(const FunctionalSet<T, EqualTo>& other) const {
return this->data_.Size() == other.data_.Size() && this->Includes(other) &&
other.Includes(*this);
return this->data_.TriviallyEquals(other.data_) ||
(this->data_.Size() == other.data_.Size() && this->Includes(other) &&
other.Includes(*this));
}
bool operator!=(const FunctionalSet<T, EqualTo>& other) const {
return !(*this == other);
......@@ -92,46 +98,62 @@ using BlueprintsSet =
using BoundFunctionsSet =
FunctionalSet<VirtualBoundFunction, std::equal_to<VirtualBoundFunction>>;
struct HintsImpl;
class Hints {
public:
Hints() = default;
Hints() = default; // Empty.
static Hints SingleConstant(Handle<Object> constant, Zone* zone);
const ConstantsSet& constants() const;
const MapsSet& maps() const;
const BlueprintsSet& function_blueprints() const;
const VirtualContextsSet& virtual_contexts() const;
const BoundFunctionsSet& virtual_bound_functions() const;
// For inspection only.
ConstantsSet constants() const;
MapsSet maps() const;
BlueprintsSet function_blueprints() const;
VirtualContextsSet virtual_contexts() const;
BoundFunctionsSet virtual_bound_functions() const;
bool IsEmpty() const;
bool operator==(Hints const& other) const;
bool operator!=(Hints const& other) const;
#ifdef ENABLE_SLOW_DCHECKS
bool Includes(Hints const& other) const;
#endif
Hints Copy(Zone* zone) const; // Shallow.
Hints CopyToParentZone(Zone* zone) const; // Deep.
// As an optimization, empty hints can be represented as {impl_} being
// {nullptr}, i.e., as not having allocated a {HintsImpl} object. As a
// consequence, some operations need to force allocation prior to doing their
// job. In particular, backpropagation from a child serialization
// can only work if the hints were already allocated in the parent zone.
bool IsAllocated() const { return impl_ != nullptr; }
void EnsureShareable(Zone* zone) { EnsureAllocated(zone, false); }
// Make {this} an alias of {other}.
void Reset(Hints* other, Zone* zone);
void Merge(Hints const& other, Zone* zone);
// Destructive updates: if the hints are shared by several registers,
// then the following updates will be seen by all of them:
void AddConstant(Handle<Object> constant, Zone* zone);
void AddMap(Handle<Map> map, Zone* zone);
void AddMap(Handle<Map> map, Zone* zone, bool check_zone_equality = true);
void AddFunctionBlueprint(FunctionBlueprint const& function_blueprint,
Zone* zone);
void AddVirtualContext(VirtualContext const& virtual_context, Zone* zone);
void AddVirtualBoundFunction(VirtualBoundFunction const& bound_function,
Zone* zone);
void Add(Hints const& other, Zone* zone);
void Add(const Hints& other, Zone* zone);
void AddFromChildSerializer(const Hints& other, Zone* zone);
void Clear();
bool IsEmpty() const;
bool operator==(Hints const& other) const;
bool operator!=(Hints const& other) const { return !(*this == other); }
private:
HintsImpl* impl_ = nullptr;
#ifdef ENABLE_SLOW_DCHECKS
bool Includes(Hints const& other) const;
bool Equals(Hints const& other) const;
#endif
void EnsureAllocated(Zone* zone, bool check_zone_equality = true);
private:
VirtualContextsSet virtual_contexts_;
ConstantsSet constants_;
MapsSet maps_;
BlueprintsSet function_blueprints_;
BoundFunctionsSet virtual_bound_functions_;
// Helper for Add and Merge.
void Union(Hints const& other);
};
using HintsVector = ZoneVector<Hints>;
......
// 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
var obj = Object.create(Object.create({blu: 42}));
obj.bla = 1;
function bar(o) {
return o.blu;
}
function foo(o) {
o.bla;
%TurbofanStaticAssert(bar(o) == 42);
}
%PrepareFunctionForOptimization(bar);
%PrepareFunctionForOptimization(foo);
bar({});
bar({bla: 1});
bar({blu: 1});
bar({blo: 1});
foo(obj);
%OptimizeFunctionOnNextCall(foo);
foo(obj);
// 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
var obj = Object.create(Object.create({blu: 42}));
obj.bla = 1;
function bar(o) {
return o.blu;
}
function baz(o) {
return o.bla;
}
function foo(o) {
baz(o);
%TurbofanStaticAssert(bar(o) == 42);
}
%PrepareFunctionForOptimization(bar);
%PrepareFunctionForOptimization(baz);
%PrepareFunctionForOptimization(foo);
bar({});
bar({bla: 1});
bar({blu: 1});
bar({blo: 1});
foo(obj);
%OptimizeFunctionOnNextCall(foo);
foo(obj);
......@@ -1083,6 +1083,7 @@
'compiler/diamond-followedby-branch': [SKIP],
'compiler/load-elimination-const-field': [SKIP],
'compiler/constant-fold-add-static': [SKIP],
'compiler/serializer-feedback-propagation-*': [SKIP],
# Some tests rely on inlining.
'compiler/opt-higher-order-functions': [SKIP],
......
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