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 { ...@@ -46,6 +46,10 @@ class FunctionalList {
return !(*this == other); return !(*this == other);
} }
bool TriviallyEquals(const FunctionalList<A>& other) const {
return elements_ == other.elements_;
}
const A& Front() const { const A& Front() const {
DCHECK_GT(Size(), 0); DCHECK_GT(Size(), 0);
return elements_->top; return elements_->top;
......
...@@ -2525,15 +2525,8 @@ bool JSHeapBroker::ShouldBeSerializedForCompilation( ...@@ -2525,15 +2525,8 @@ bool JSHeapBroker::ShouldBeSerializedForCompilation(
void JSHeapBroker::SetSerializedForCompilation( void JSHeapBroker::SetSerializedForCompilation(
const SharedFunctionInfoRef& shared, const FeedbackVectorRef& feedback, const SharedFunctionInfoRef& shared, const FeedbackVectorRef& feedback,
const HintsVector& arguments) { const HintsVector& arguments) {
HintsVector arguments_copy_in_broker_zone(zone()); SerializedFunction function{shared, feedback};
for (auto const& hints : arguments) { serialized_functions_.insert({function, 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});
TRACE(this, "Set function " << shared << " with " << feedback TRACE(this, "Set function " << shared << " with " << feedback
<< " as serialized for compilation"); << " as serialized for compilation");
} }
......
...@@ -33,6 +33,17 @@ class FunctionalSet { ...@@ -33,6 +33,17 @@ class FunctionalSet {
data_.PushFront(elem, zone); 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 { bool Includes(FunctionalSet<T, EqualTo> const& other) const {
return std::all_of(other.begin(), other.end(), [&](T const& other_elem) { return std::all_of(other.begin(), other.end(), [&](T const& other_elem) {
return std::any_of(this->begin(), this->end(), [&](T const& this_elem) { return std::any_of(this->begin(), this->end(), [&](T const& this_elem) {
...@@ -40,15 +51,10 @@ class FunctionalSet { ...@@ -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 { bool operator==(const FunctionalSet<T, EqualTo>& other) const {
return this->data_.Size() == other.data_.Size() && this->Includes(other) && return this->data_.TriviallyEquals(other.data_) ||
other.Includes(*this); (this->data_.Size() == other.data_.Size() && this->Includes(other) &&
other.Includes(*this));
} }
bool operator!=(const FunctionalSet<T, EqualTo>& other) const { bool operator!=(const FunctionalSet<T, EqualTo>& other) const {
return !(*this == other); return !(*this == other);
...@@ -92,46 +98,62 @@ using BlueprintsSet = ...@@ -92,46 +98,62 @@ using BlueprintsSet =
using BoundFunctionsSet = using BoundFunctionsSet =
FunctionalSet<VirtualBoundFunction, std::equal_to<VirtualBoundFunction>>; FunctionalSet<VirtualBoundFunction, std::equal_to<VirtualBoundFunction>>;
struct HintsImpl;
class Hints { class Hints {
public: public:
Hints() = default; Hints() = default; // Empty.
static Hints SingleConstant(Handle<Object> constant, Zone* zone); static Hints SingleConstant(Handle<Object> constant, Zone* zone);
const ConstantsSet& constants() const; // For inspection only.
const MapsSet& maps() const; ConstantsSet constants() const;
const BlueprintsSet& function_blueprints() const; MapsSet maps() const;
const VirtualContextsSet& virtual_contexts() const; BlueprintsSet function_blueprints() const;
const BoundFunctionsSet& virtual_bound_functions() 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 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, void AddFunctionBlueprint(FunctionBlueprint const& function_blueprint,
Zone* zone); Zone* zone);
void AddVirtualContext(VirtualContext const& virtual_context, Zone* zone); void AddVirtualContext(VirtualContext const& virtual_context, Zone* zone);
void AddVirtualBoundFunction(VirtualBoundFunction const& bound_function, void AddVirtualBoundFunction(VirtualBoundFunction const& bound_function,
Zone* zone); Zone* zone);
void Add(Hints const& other, Zone* zone);
void Add(const Hints& other, Zone* zone); private:
void AddFromChildSerializer(const Hints& other, Zone* zone); HintsImpl* impl_ = nullptr;
void Clear();
bool IsEmpty() const;
bool operator==(Hints const& other) const;
bool operator!=(Hints const& other) const { return !(*this == other); }
#ifdef ENABLE_SLOW_DCHECKS void EnsureAllocated(Zone* zone, bool check_zone_equality = true);
bool Includes(Hints const& other) const;
bool Equals(Hints const& other) const;
#endif
private: // Helper for Add and Merge.
VirtualContextsSet virtual_contexts_; void Union(Hints const& other);
ConstantsSet constants_;
MapsSet maps_;
BlueprintsSet function_blueprints_;
BoundFunctionsSet virtual_bound_functions_;
}; };
using HintsVector = ZoneVector<Hints>; 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 @@ ...@@ -1083,6 +1083,7 @@
'compiler/diamond-followedby-branch': [SKIP], 'compiler/diamond-followedby-branch': [SKIP],
'compiler/load-elimination-const-field': [SKIP], 'compiler/load-elimination-const-field': [SKIP],
'compiler/constant-fold-add-static': [SKIP], 'compiler/constant-fold-add-static': [SKIP],
'compiler/serializer-feedback-propagation-*': [SKIP],
# Some tests rely on inlining. # Some tests rely on inlining.
'compiler/opt-higher-order-functions': [SKIP], '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