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

Revert "[TurboFan] Brokerize remaining feedback vector slots"

This reverts commit 9499ec0d.

Reason for revert: Breaks lots of stuff, e.g.
https://ci.chromium.org/p/v8/builders/ci/V8-Blink%20Linux%2064%20-%20future/9401

Original change's description:
> [TurboFan] Brokerize remaining feedback vector slots
> 
> This CL adds new ProcessedFeedback subclasses, corresponding to various IC
> types:
> 
> * ForIn
> * Comparison ops
> * Binary/Unary ops
> * InstanceOf
> * Calls
> 
> The feedback is gathered at serialization time and used in several places,
> namely:
> 
> * Bytecode graph building,
> * and its helper class JSTypeHintLowering (with its "early lowering")
> * Native context specialization
> * JSCallReducer
> 
> Design doc: https://docs.google.com/document/d/1JLG0VFV8xmsAIJexU19xzlbNyP51ONqfo_Gf_2DcPC8/edit?usp=sharing
> 
> Bug: v8:7790
> Change-Id: I53c3d7a17f844384f38c4ee0f0b082c114217a02
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1710663
> Commit-Queue: Georg Neis <neis@chromium.org>
> Reviewed-by: Maya Lekova <mslekova@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#63028}

TBR=mvstanton@chromium.org,neis@chromium.org,mslekova@chromium.org

# Not skipping CQ checks because original CL landed > 1 day ago.

Bug: v8:7790
Change-Id: Id0c4d6651611fc3964010f7615d0ad0485169ebc
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1735315Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Reviewed-by: 's avatarMichael Achenbach <machenbach@chromium.org>
Reviewed-by: 's avatarTamer Tas <tmrts@chromium.org>
Commit-Queue: Georg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#63073}
parent cdfadf4a
......@@ -245,12 +245,11 @@ class BytecodeGraphBuilder {
ForInMode GetForInMode(int operand_index);
// Helper function to compute call frequency from the recorded type
// feedback. Returns unknown if invocation count is unknown. Returns 0 if
// feedback is insufficient.
// feedback.
CallFrequency ComputeCallFrequency(int slot_id) const;
// Helper function to extract the speculation mode from the recorded type
// feedback. Returns kDisallowSpeculation if feedback is insufficient.
// feedback.
SpeculationMode GetSpeculationMode(int slot_id) const;
// Control flow plumbing.
......@@ -951,7 +950,7 @@ BytecodeGraphBuilder::BytecodeGraphBuilder(
bytecode_array_(bytecode_array),
feedback_vector_(feedback_vector),
type_hint_lowering_(
broker, jsgraph, feedback_vector,
jsgraph, feedback_vector.object(),
(flags & BytecodeGraphBuilderFlag::kBailoutOnUninitialized)
? JSTypeHintLowering::kBailoutOnUninitialized
: JSTypeHintLowering::kNoFlags),
......@@ -1017,7 +1016,6 @@ Node* BytecodeGraphBuilder::BuildLoadNativeContextField(int index) {
VectorSlotPair BytecodeGraphBuilder::CreateVectorSlotPair(int slot_id) {
FeedbackSlot slot = FeedbackVector::ToSlot(slot_id);
// TODO(mvstanton): eliminate this use of a FeedbackNexus.
FeedbackNexus nexus(feedback_vector().object(), slot);
return VectorSlotPair(feedback_vector().object(), slot, nexus.ic_state());
}
......@@ -2143,11 +2141,11 @@ void BytecodeGraphBuilder::BuildCall(ConvertReceiverMode receiver_mode,
PrepareEagerCheckpoint();
VectorSlotPair feedback = CreateVectorSlotPair(slot_id);
CallFrequency frequency = ComputeCallFrequency(slot_id);
SpeculationMode speculation_mode = GetSpeculationMode(slot_id);
const Operator* op = javascript()->Call(arg_count, frequency, feedback,
receiver_mode, speculation_mode);
CallFrequency frequency = ComputeCallFrequency(slot_id);
const Operator* op =
javascript()->Call(arg_count, frequency, feedback, receiver_mode,
GetSpeculationMode(slot_id));
JSTypeHintLowering::LoweringResult lowering = TryBuildSimplifiedCall(
op, args, static_cast<int>(arg_count), feedback.slot());
if (lowering.IsExit()) return;
......@@ -2328,6 +2326,7 @@ void BytecodeGraphBuilder::VisitCallWithSpread() {
first_arg, arg_count);
int const slot_id = bytecode_iterator().GetIndexOperand(3);
VectorSlotPair feedback = CreateVectorSlotPair(slot_id);
CallFrequency frequency = ComputeCallFrequency(slot_id);
const Operator* op = javascript()->CallWithSpread(
static_cast<int>(reg_count + 1), frequency, feedback);
......@@ -2641,23 +2640,23 @@ void BytecodeGraphBuilder::BuildBinaryOp(const Operator* op) {
BinaryOperationHint BytecodeGraphBuilder::GetBinaryOperationHint(
int operand_index) {
FeedbackSlot slot = bytecode_iterator().GetSlotOperand(operand_index);
FeedbackSource source(feedback_vector(), slot);
return broker()->GetFeedbackForBinaryOperation(source);
FeedbackNexus nexus(feedback_vector().object(), slot);
return nexus.GetBinaryOperationFeedback();
}
// Helper function to create compare operation hint from the recorded type
// feedback.
CompareOperationHint BytecodeGraphBuilder::GetCompareOperationHint() {
FeedbackSlot slot = bytecode_iterator().GetSlotOperand(1);
FeedbackSource source(feedback_vector(), slot);
return broker()->GetFeedbackForCompareOperation(source);
FeedbackNexus nexus(feedback_vector().object(), slot);
return nexus.GetCompareOperationFeedback();
}
// Helper function to create for-in mode from the recorded type feedback.
ForInMode BytecodeGraphBuilder::GetForInMode(int operand_index) {
FeedbackSlot slot = bytecode_iterator().GetSlotOperand(operand_index);
FeedbackSource source(feedback_vector(), slot);
switch (broker()->GetFeedbackForForIn(source)) {
FeedbackNexus nexus(feedback_vector().object(), slot);
switch (nexus.GetForInFeedback()) {
case ForInHint::kNone:
case ForInHint::kEnumCacheKeysAndIndices:
return ForInMode::kUseEnumCacheKeysAndIndices;
......@@ -2671,13 +2670,11 @@ ForInMode BytecodeGraphBuilder::GetForInMode(int operand_index) {
CallFrequency BytecodeGraphBuilder::ComputeCallFrequency(int slot_id) const {
if (invocation_frequency_.IsUnknown()) return CallFrequency();
FeedbackSlot slot = FeedbackVector::ToSlot(slot_id);
FeedbackSource source(feedback_vector(), slot);
ProcessedFeedback const* feedback = broker()->GetFeedbackForCall(source);
CHECK_NOT_NULL(feedback);
float feedback_frequency =
feedback->IsInsufficient() ? 0.0f : feedback->AsCall()->frequency();
if (feedback_frequency == 0.0f) { // Prevent multiplying zero and infinity.
FeedbackNexus nexus(feedback_vector().object(),
FeedbackVector::ToSlot(slot_id));
float feedback_frequency = nexus.ComputeCallFrequency();
if (feedback_frequency == 0.0f) {
// This is to prevent multiplying zero and infinity.
return CallFrequency(0.0f);
} else {
return CallFrequency(feedback_frequency * invocation_frequency_.value());
......@@ -2685,12 +2682,9 @@ CallFrequency BytecodeGraphBuilder::ComputeCallFrequency(int slot_id) const {
}
SpeculationMode BytecodeGraphBuilder::GetSpeculationMode(int slot_id) const {
FeedbackSlot slot = FeedbackVector::ToSlot(slot_id);
FeedbackSource source(feedback_vector(), slot);
ProcessedFeedback const* feedback = broker()->GetFeedbackForCall(source);
CHECK_NOT_NULL(feedback);
return feedback->IsInsufficient() ? SpeculationMode::kDisallowSpeculation
: feedback->AsCall()->speculation_mode();
FeedbackNexus nexus(feedback_vector().object(),
FeedbackVector::ToSlot(slot_id));
return nexus.GetSpeculationMode();
}
void BytecodeGraphBuilder::VisitBitwiseNot() {
......
......@@ -801,6 +801,121 @@ class InternalizedStringRef : public StringRef {
using StringRef::StringRef;
Handle<InternalizedString> object() const;
};
class ElementAccessFeedback;
class NamedAccessFeedback;
class ProcessedFeedback : public ZoneObject {
public:
enum Kind { kInsufficient, kGlobalAccess, kNamedAccess, kElementAccess };
Kind kind() const { return kind_; }
ElementAccessFeedback const* AsElementAccess() const;
NamedAccessFeedback const* AsNamedAccess() const;
protected:
explicit ProcessedFeedback(Kind kind) : kind_(kind) {}
private:
Kind const kind_;
};
class InsufficientFeedback final : public ProcessedFeedback {
public:
InsufficientFeedback();
};
class GlobalAccessFeedback : public ProcessedFeedback {
public:
explicit GlobalAccessFeedback(PropertyCellRef cell);
GlobalAccessFeedback(ContextRef script_context, int slot_index,
bool immutable);
bool IsPropertyCell() const;
PropertyCellRef property_cell() const;
bool IsScriptContextSlot() const { return !IsPropertyCell(); }
ContextRef script_context() const;
int slot_index() const;
bool immutable() const;
base::Optional<ObjectRef> GetConstantHint() const;
private:
ObjectRef const cell_or_context_;
int const index_and_immutable_;
};
class KeyedAccessMode {
public:
static KeyedAccessMode FromNexus(FeedbackNexus const& nexus);
AccessMode access_mode() const;
bool IsLoad() const;
bool IsStore() const;
KeyedAccessLoadMode load_mode() const;
KeyedAccessStoreMode store_mode() const;
private:
AccessMode const access_mode_;
union LoadStoreMode {
LoadStoreMode(KeyedAccessLoadMode load_mode);
LoadStoreMode(KeyedAccessStoreMode store_mode);
KeyedAccessLoadMode load_mode;
KeyedAccessStoreMode store_mode;
} const load_store_mode_;
KeyedAccessMode(AccessMode access_mode, KeyedAccessLoadMode load_mode);
KeyedAccessMode(AccessMode access_mode, KeyedAccessStoreMode store_mode);
};
class ElementAccessFeedback : public ProcessedFeedback {
public:
ElementAccessFeedback(Zone* zone, KeyedAccessMode const& keyed_mode);
// No transition sources appear in {receiver_maps}.
// All transition targets appear in {receiver_maps}.
ZoneVector<Handle<Map>> receiver_maps;
ZoneVector<std::pair<Handle<Map>, Handle<Map>>> transitions;
KeyedAccessMode const keyed_mode;
class MapIterator {
public:
bool done() const;
void advance();
MapRef current() const;
private:
friend class ElementAccessFeedback;
explicit MapIterator(ElementAccessFeedback const& processed,
JSHeapBroker* broker);
ElementAccessFeedback const& processed_;
JSHeapBroker* const broker_;
size_t index_ = 0;
};
// Iterator over all maps: first {receiver_maps}, then transition sources.
MapIterator all_maps(JSHeapBroker* broker) const;
};
class NamedAccessFeedback : public ProcessedFeedback {
public:
NamedAccessFeedback(NameRef const& name,
ZoneVector<PropertyAccessInfo> const& access_infos);
NameRef const& name() const { return name_; }
ZoneVector<PropertyAccessInfo> const& access_infos() const {
return access_infos_;
}
private:
NameRef const name_;
ZoneVector<PropertyAccessInfo> const access_infos_;
};
} // namespace compiler
} // namespace internal
} // namespace v8
......
......@@ -3226,6 +3226,13 @@ bool ShouldUseCallICFeedback(Node* node) {
return true;
}
base::Optional<HeapObjectRef> GetHeapObjectFeedback(
JSHeapBroker* broker, const FeedbackNexus& nexus) {
HeapObject object;
if (!nexus.GetFeedback()->GetHeapObject(&object)) return base::nullopt;
return HeapObjectRef(broker, handle(object, broker->isolate()));
}
} // namespace
Reduction JSCallReducer::ReduceJSCall(Node* node) {
......@@ -3344,18 +3351,19 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) {
return reduction.Changed() ? reduction : Changed(node);
}
// Extract feedback from the {node} using the FeedbackNexus.
if (!p.feedback().IsValid()) return NoChange();
ProcessedFeedback const* feedback =
broker()->GetFeedbackForCall(FeedbackSource(p.feedback()));
if (feedback->IsInsufficient()) {
FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
if (nexus.IsUninitialized()) {
return ReduceSoftDeoptimize(
node, DeoptimizeReason::kInsufficientTypeFeedbackForCall);
}
base::Optional<HeapObjectRef> feedback_target = feedback->AsCall()->target();
if (feedback_target.has_value() && ShouldUseCallICFeedback(target) &&
feedback_target->map().is_callable()) {
Node* target_function = jsgraph()->Constant(*feedback_target);
base::Optional<HeapObjectRef> feedback =
GetHeapObjectFeedback(broker(), nexus);
if (feedback.has_value() && ShouldUseCallICFeedback(target) &&
feedback->map().is_callable()) {
Node* target_function = jsgraph()->Constant(*feedback);
// Check that the {target} is still the {target_function}.
Node* check = graph()->NewNode(simplified()->ReferenceEqual(), target,
......@@ -3758,10 +3766,6 @@ Reduction JSCallReducer::ReduceJSCallWithSpread(Node* node) {
}
Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
// TODO(mslekova): Remove once ReduceJSConstruct is brokerized.
AllowHandleDereference allow_handle_dereference;
AllowHandleAllocation allow_handle_allocation;
DCHECK_EQ(IrOpcode::kJSConstruct, node->opcode());
ConstructParameters const& p = ConstructParametersOf(node->op());
DCHECK_LE(2u, p.arity());
......@@ -3771,17 +3775,17 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
// Extract feedback from the {node} using the FeedbackNexus.
if (p.feedback().IsValid()) {
ProcessedFeedback const* feedback =
broker()->GetFeedbackForCall(FeedbackSource(p.feedback()));
if (feedback->IsInsufficient()) {
FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
if (nexus.IsUninitialized()) {
return ReduceSoftDeoptimize(
node, DeoptimizeReason::kInsufficientTypeFeedbackForConstruct);
}
base::Optional<HeapObjectRef> feedback_target =
feedback->AsCall()->target();
if (feedback_target.has_value() && feedback_target->IsAllocationSite()) {
base::Optional<HeapObjectRef> feedback =
GetHeapObjectFeedback(broker(), nexus);
if (feedback.has_value() && feedback->IsAllocationSite()) {
// The feedback is an AllocationSite, which means we have called the
// Array function and collected transition (and pretenuring) feedback
// for the resulting arrays. This has to be kept in sync with the
......@@ -3806,12 +3810,12 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
NodeProperties::ReplaceValueInput(node, array_function, 1);
NodeProperties::ChangeOp(
node, javascript()->CreateArray(
arity, feedback_target->AsAllocationSite().object()));
arity, feedback->AsAllocationSite().object()));
return Changed(node);
} else if (feedback_target.has_value() &&
} else if (feedback.has_value() &&
!HeapObjectMatcher(new_target).HasValue() &&
feedback_target->map().is_constructor()) {
Node* new_target_feedback = jsgraph()->Constant(*feedback_target);
feedback->map().is_constructor()) {
Node* new_target_feedback = jsgraph()->Constant(*feedback);
// Check that the {new_target} is still the {new_target_feedback}.
Node* check = graph()->NewNode(simplified()->ReferenceEqual(), new_target,
......@@ -6076,7 +6080,7 @@ Reduction JSCallReducer::ReducePromisePrototypeFinally(Node* node) {
}
Reduction JSCallReducer::ReducePromisePrototypeThen(Node* node) {
DisallowHeapAccessIf no_heap_access(FLAG_concurrent_inlining);
DisallowHeapAccessIf no_heap_acess(FLAG_concurrent_inlining);
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
......@@ -6144,7 +6148,7 @@ Reduction JSCallReducer::ReducePromisePrototypeThen(Node* node) {
// ES section #sec-promise.resolve
Reduction JSCallReducer::ReducePromiseResolveTrampoline(Node* node) {
DisallowHeapAccessIf no_heap_access(FLAG_concurrent_inlining);
DisallowHeapAccessIf no_heap_acess(FLAG_concurrent_inlining);
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
Node* receiver = NodeProperties::GetValueInput(node, 1);
......
......@@ -3998,20 +3998,11 @@ NamedAccessFeedback::NamedAccessFeedback(
CHECK(!access_infos.empty());
}
FeedbackSource::FeedbackSource(Handle<FeedbackVector> vector_,
FeedbackSlot slot_)
: vector(vector_), slot(slot_) {
DCHECK(!slot.IsInvalid());
}
FeedbackSource::FeedbackSource(FeedbackVectorRef vector_, FeedbackSlot slot_)
: FeedbackSource(vector_.object(), slot_) {}
FeedbackSource::FeedbackSource(FeedbackNexus const& nexus)
: FeedbackSource(nexus.vector_handle(), nexus.slot()) {}
: vector(nexus.vector_handle()), slot(nexus.slot()) {}
FeedbackSource::FeedbackSource(VectorSlotPair const& pair)
: FeedbackSource(pair.vector(), pair.slot()) {}
: vector(pair.vector()), slot(pair.slot()) {}
void JSHeapBroker::SetFeedback(FeedbackSource const& source,
ProcessedFeedback const* feedback) {
......@@ -4135,155 +4126,6 @@ GlobalAccessFeedback const* JSHeapBroker::ProcessFeedbackForGlobalAccess(
return new (zone()) GlobalAccessFeedback(cell);
}
bool JSHeapBroker::FeedbackIsInsufficient(FeedbackSource const& source) const {
if (FLAG_concurrent_inlining) {
ProcessedFeedback const* feedback = GetFeedback(source);
// TODO(mvstanton): handling nullptr is a workaround until
// we find a way to express megamorphic feedback.
return feedback != nullptr && feedback->IsInsufficient();
}
return FeedbackNexus(source.vector, source.slot).IsUninitialized();
}
BinaryOperationHint JSHeapBroker::ReadBinaryOperationFeedback(
FeedbackSource const& source) const {
return FeedbackNexus(source.vector, source.slot).GetBinaryOperationFeedback();
}
CompareOperationHint JSHeapBroker::ReadCompareOperationFeedback(
FeedbackSource const& source) const {
return FeedbackNexus(source.vector, source.slot)
.GetCompareOperationFeedback();
}
ForInHint JSHeapBroker::ReadForInFeedback(FeedbackSource const& source) const {
return FeedbackNexus(source.vector, source.slot).GetForInFeedback();
}
ProcessedFeedback const* JSHeapBroker::ReadInstanceOfFeedback(
FeedbackSource const& source) {
FeedbackNexus nexus(source.vector, source.slot);
if (nexus.IsUninitialized()) return new (zone()) InsufficientFeedback();
base::Optional<JSObjectRef> optional_constructor;
{
MaybeHandle<JSObject> maybe_constructor = nexus.GetConstructorFeedback();
Handle<JSObject> constructor;
if (maybe_constructor.ToHandle(&constructor)) {
optional_constructor = JSObjectRef(this, constructor);
}
}
return new (zone()) InstanceOfFeedback(optional_constructor);
}
ProcessedFeedback const* JSHeapBroker::ReadCallFeedback(
FeedbackSource const& source) {
FeedbackNexus nexus(source.vector, source.slot);
if (nexus.IsUninitialized()) return new (zone()) InsufficientFeedback();
base::Optional<HeapObjectRef> target_ref;
{
MaybeObject maybe_target = nexus.GetFeedback();
HeapObject target_object;
if (maybe_target->GetHeapObject(&target_object)) {
target_ref = HeapObjectRef(this, handle(target_object, isolate()));
}
}
float frequency = nexus.ComputeCallFrequency();
SpeculationMode mode = nexus.GetSpeculationMode();
return new (zone()) CallFeedback(target_ref, frequency, mode);
}
BinaryOperationHint JSHeapBroker::GetFeedbackForBinaryOperation(
FeedbackSource const& source) const {
if (!FLAG_concurrent_inlining) return ReadBinaryOperationFeedback(source);
ProcessedFeedback const* feedback = GetFeedback(source);
return feedback->IsInsufficient() ? BinaryOperationHint::kNone
: feedback->AsBinaryOperation()->value();
}
CompareOperationHint JSHeapBroker::GetFeedbackForCompareOperation(
FeedbackSource const& source) const {
if (!FLAG_concurrent_inlining) return ReadCompareOperationFeedback(source);
ProcessedFeedback const* feedback = GetFeedback(source);
return feedback->IsInsufficient() ? CompareOperationHint::kNone
: feedback->AsCompareOperation()->value();
}
ForInHint JSHeapBroker::GetFeedbackForForIn(
FeedbackSource const& source) const {
if (!FLAG_concurrent_inlining) return ReadForInFeedback(source);
ProcessedFeedback const* feedback = GetFeedback(source);
return feedback->IsInsufficient() ? ForInHint::kNone
: feedback->AsForIn()->value();
}
ProcessedFeedback const* JSHeapBroker::GetFeedbackForInstanceOf(
FeedbackSource const& source) {
return FLAG_concurrent_inlining ? GetFeedback(source)
: ReadInstanceOfFeedback(source);
}
ProcessedFeedback const* JSHeapBroker::GetFeedbackForCall(
FeedbackSource const& source) {
return FLAG_concurrent_inlining ? GetFeedback(source)
: ReadCallFeedback(source);
}
void JSHeapBroker::ProcessFeedbackForBinaryOperation(
FeedbackSource const& source) {
if (HasFeedback(source)) return;
BinaryOperationHint hint = ReadBinaryOperationFeedback(source);
ProcessedFeedback const* feedback;
if (hint == BinaryOperationHint::kNone) {
feedback = new (zone()) InsufficientFeedback();
} else {
feedback = new (zone()) BinaryOperationFeedback(hint);
}
SetFeedback(source, feedback);
}
void JSHeapBroker::ProcessFeedbackForCompareOperation(
FeedbackSource const& source) {
if (HasFeedback(source)) return;
CompareOperationHint hint = ReadCompareOperationFeedback(source);
ProcessedFeedback const* feedback;
if (hint == CompareOperationHint::kNone) {
feedback = new (zone()) InsufficientFeedback();
} else {
feedback = new (zone()) CompareOperationFeedback(hint);
}
SetFeedback(source, feedback);
}
void JSHeapBroker::ProcessFeedbackForForIn(FeedbackSource const& source) {
if (HasFeedback(source)) return;
ForInHint hint = ReadForInFeedback(source);
ProcessedFeedback const* feedback;
if (hint == ForInHint::kNone) {
feedback = new (zone()) InsufficientFeedback();
} else {
feedback = new (zone()) ForInFeedback(hint);
}
SetFeedback(source, feedback);
}
ProcessedFeedback const* JSHeapBroker::ProcessFeedbackForInstanceOf(
FeedbackSource const& source) {
if (HasFeedback(source)) return GetFeedback(source);
ProcessedFeedback const* feedback = ReadInstanceOfFeedback(source);
SetFeedback(source, feedback);
return feedback;
}
ProcessedFeedback const* JSHeapBroker::ProcessFeedbackForCall(
FeedbackSource const& source) {
if (HasFeedback(source)) return GetFeedback(source);
ProcessedFeedback const* feedback = ReadCallFeedback(source);
SetFeedback(source, feedback);
return feedback;
}
std::ostream& operator<<(std::ostream& os, const ObjectRef& ref) {
return os << ref.data();
}
......@@ -4385,31 +4227,6 @@ NamedAccessFeedback const* ProcessedFeedback::AsNamedAccess() const {
return static_cast<NamedAccessFeedback const*>(this);
}
CallFeedback const* ProcessedFeedback::AsCall() const {
CHECK_EQ(kCall, kind());
return static_cast<CallFeedback const*>(this);
}
InstanceOfFeedback const* ProcessedFeedback::AsInstanceOf() const {
CHECK_EQ(kInstanceOf, kind());
return static_cast<InstanceOfFeedback const*>(this);
}
BinaryOperationFeedback const* ProcessedFeedback::AsBinaryOperation() const {
CHECK_EQ(kBinaryOperation, kind());
return static_cast<BinaryOperationFeedback const*>(this);
}
CompareOperationFeedback const* ProcessedFeedback::AsCompareOperation() const {
CHECK_EQ(kCompareOperation, kind());
return static_cast<CompareOperationFeedback const*>(this);
}
ForInFeedback const* ProcessedFeedback::AsForIn() const {
CHECK_EQ(kForIn, kind());
return static_cast<ForInFeedback const*>(this);
}
BytecodeAnalysis const& JSHeapBroker::GetBytecodeAnalysis(
Handle<BytecodeArray> bytecode_array, BailoutId osr_bailout_id,
bool analyze_liveness, bool serialize) {
......
......@@ -9,7 +9,6 @@
#include "src/base/optional.h"
#include "src/common/globals.h"
#include "src/compiler/access-info.h"
#include "src/compiler/processed-feedback.h"
#include "src/compiler/refs-map.h"
#include "src/handles/handles.h"
#include "src/interpreter/bytecode-array-accessor.h"
......@@ -28,8 +27,8 @@ class ObjectRef;
std::ostream& operator<<(std::ostream& os, const ObjectRef& ref);
struct FeedbackSource {
FeedbackSource(Handle<FeedbackVector> vector_, FeedbackSlot slot_);
FeedbackSource(FeedbackVectorRef vector_, FeedbackSlot slot_);
FeedbackSource(Handle<FeedbackVector> vector_, FeedbackSlot slot_)
: vector(vector_), slot(slot_) {}
explicit FeedbackSource(FeedbackNexus const& nexus);
explicit FeedbackSource(VectorSlotPair const& pair);
......@@ -127,32 +126,11 @@ class V8_EXPORT_PRIVATE JSHeapBroker {
MapHandles const& maps, KeyedAccessMode const& keyed_mode);
GlobalAccessFeedback const* ProcessFeedbackForGlobalAccess(
FeedbackSource const& source);
BytecodeAnalysis const& GetBytecodeAnalysis(
Handle<BytecodeArray> bytecode_array, BailoutId osr_offset,
bool analyze_liveness, bool serialize);
// Binary, comparison and for-in hints can be fully expressed via
// an enum. Insufficient feedback is signaled by <Hint enum>::kNone.
BinaryOperationHint GetFeedbackForBinaryOperation(
FeedbackSource const& source) const;
CompareOperationHint GetFeedbackForCompareOperation(
FeedbackSource const& source) const;
ForInHint GetFeedbackForForIn(FeedbackSource const& source) const;
ProcessedFeedback const* GetFeedbackForCall(FeedbackSource const& source);
ProcessedFeedback const* GetFeedbackForInstanceOf(
FeedbackSource const& source);
void ProcessFeedbackForBinaryOperation(FeedbackSource const& source);
void ProcessFeedbackForCompareOperation(FeedbackSource const& source);
void ProcessFeedbackForForIn(FeedbackSource const& source);
ProcessedFeedback const* ProcessFeedbackForCall(FeedbackSource const& source);
ProcessedFeedback const* ProcessFeedbackForInstanceOf(
FeedbackSource const& source);
bool FeedbackIsInsufficient(FeedbackSource const& source) const;
base::Optional<NameRef> GetNameFeedback(FeedbackNexus const& nexus);
// If there is no result stored for {map}, we return an Invalid
......@@ -178,17 +156,6 @@ class V8_EXPORT_PRIVATE JSHeapBroker {
friend class ObjectRef;
friend class ObjectData;
// Bottleneck FeedbackNexus access here, for storage in the broker
// or on-the-fly usage elsewhere in the compiler.
ForInHint ReadForInFeedback(FeedbackSource const& source) const;
CompareOperationHint ReadCompareOperationFeedback(
FeedbackSource const& source) const;
BinaryOperationHint ReadBinaryOperationFeedback(
FeedbackSource const& source) const;
ProcessedFeedback const* ReadCallFeedback(FeedbackSource const& source);
ProcessedFeedback const* ReadInstanceOfFeedback(FeedbackSource const& source);
void SerializeShareableObjects();
void CollectArrayAndObjectPrototypes();
......
......@@ -381,7 +381,9 @@ Reduction JSNativeContextSpecialization::ReduceJSGetSuperConstructor(
}
Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
DisallowHeapAccessIf no_heap_access(FLAG_concurrent_inlining);
// TODO(neis): Eliminate heap accesses.
AllowHandleDereference allow_handle_dereference;
AllowHandleAllocation allow_handle_allocation;
DCHECK_EQ(IrOpcode::kJSInstanceOf, node->opcode());
FeedbackParameter const& p = FeedbackParameterOf(node->op());
......@@ -399,13 +401,10 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
if (m.HasValue() && m.Ref(broker()).IsJSObject()) {
receiver = m.Ref(broker()).AsJSObject().object();
} else if (p.feedback().IsValid()) {
ProcessedFeedback const* feedback =
broker()->GetFeedbackForInstanceOf(FeedbackSource(p.feedback()));
if (feedback->IsInsufficient()) return NoChange();
base::Optional<JSObjectRef> maybe_receiver =
feedback->AsInstanceOf()->value();
if (!maybe_receiver.has_value()) return NoChange();
receiver = maybe_receiver->object();
FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
if (!nexus.GetConstructorFeedback().ToHandle(&receiver)) {
return NoChange();
}
} else {
return NoChange();
}
......@@ -1810,7 +1809,7 @@ Reduction JSNativeContextSpecialization::ReducePropertyAccess(
access_mode);
return ReduceElementAccess(node, key, value,
*processed->AsElementAccess());
default:
case ProcessedFeedback::kGlobalAccess:
UNREACHABLE();
}
}
......
......@@ -6,7 +6,6 @@
#include "src/compiler/access-builder.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/js-heap-broker.h"
#include "src/compiler/operator-properties.h"
#include "src/compiler/simplified-operator.h"
#include "src/objects/feedback-vector.h"
......@@ -79,6 +78,16 @@ class JSSpeculativeBinopBuilder final {
control_(control),
slot_(slot) {}
BinaryOperationHint GetBinaryOperationHint() {
FeedbackNexus nexus(feedback_vector(), slot_);
return nexus.GetBinaryOperationFeedback();
}
CompareOperationHint GetCompareOperationHint() {
FeedbackNexus nexus(feedback_vector(), slot_);
return nexus.GetCompareOperationFeedback();
}
bool GetBinaryNumberOperationHint(NumberOperationHint* hint) {
return BinaryOperationHintToNumberOperationHint(GetBinaryOperationHint(),
hint);
......@@ -230,52 +239,34 @@ class JSSpeculativeBinopBuilder final {
JSOperatorBuilder* javascript() { return jsgraph()->javascript(); }
SimplifiedOperatorBuilder* simplified() { return jsgraph()->simplified(); }
CommonOperatorBuilder* common() { return jsgraph()->common(); }
private:
BinaryOperationHint GetBinaryOperationHint() {
return lowering_->GetBinaryOperationHint(slot_);
}
CompareOperationHint GetCompareOperationHint() {
return lowering_->GetCompareOperationHint(slot_);
const Handle<FeedbackVector>& feedback_vector() const {
return lowering_->feedback_vector();
}
JSTypeHintLowering const* const lowering_;
Operator const* const op_;
private:
const JSTypeHintLowering* lowering_;
const Operator* op_;
Node* left_;
Node* right_;
Node* const effect_;
Node* const control_;
FeedbackSlot const slot_;
Node* effect_;
Node* control_;
FeedbackSlot slot_;
};
JSTypeHintLowering::JSTypeHintLowering(JSHeapBroker* broker, JSGraph* jsgraph,
FeedbackVectorRef feedback_vector,
JSTypeHintLowering::JSTypeHintLowering(JSGraph* jsgraph,
Handle<FeedbackVector> feedback_vector,
Flags flags)
: broker_(broker),
jsgraph_(jsgraph),
flags_(flags),
feedback_vector_(feedback_vector) {}
: jsgraph_(jsgraph), flags_(flags), feedback_vector_(feedback_vector) {}
Isolate* JSTypeHintLowering::isolate() const { return jsgraph()->isolate(); }
BinaryOperationHint JSTypeHintLowering::GetBinaryOperationHint(
FeedbackSlot slot) const {
FeedbackSource source(feedback_vector(), slot);
return broker()->GetFeedbackForBinaryOperation(source);
}
CompareOperationHint JSTypeHintLowering::GetCompareOperationHint(
FeedbackSlot slot) const {
FeedbackSource source(feedback_vector(), slot);
return broker()->GetFeedbackForCompareOperation(source);
}
JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceUnaryOperation(
const Operator* op, Node* operand, Node* effect, Node* control,
FeedbackSlot slot) const {
DCHECK(!slot.IsInvalid());
FeedbackNexus nexus(feedback_vector(), slot);
if (Node* node = TryBuildSoftDeopt(
slot, effect, control,
nexus, effect, control,
DeoptimizeReason::kInsufficientTypeFeedbackForUnaryOperation)) {
return LoweringResult::Exit(node);
}
......@@ -318,7 +309,9 @@ JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceUnaryOperation(
control, slot);
node = b.TryBuildNumberBinop();
if (!node) {
if (GetBinaryOperationHint(slot) == BinaryOperationHint::kBigInt) {
FeedbackNexus nexus(feedback_vector(), slot);
if (nexus.GetBinaryOperationFeedback() ==
BinaryOperationHint::kBigInt) {
const Operator* op = jsgraph()->simplified()->SpeculativeBigIntNegate(
BigIntOperationHint::kBigInt);
node = jsgraph()->graph()->NewNode(op, operand, effect, control);
......@@ -342,8 +335,10 @@ JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceBinaryOperation(
FeedbackSlot slot) const {
switch (op->opcode()) {
case IrOpcode::kJSStrictEqual: {
DCHECK(!slot.IsInvalid());
FeedbackNexus nexus(feedback_vector(), slot);
if (Node* node = TryBuildSoftDeopt(
slot, effect, control,
nexus, effect, control,
DeoptimizeReason::kInsufficientTypeFeedbackForCompareOperation)) {
return LoweringResult::Exit(node);
}
......@@ -356,8 +351,10 @@ JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceBinaryOperation(
case IrOpcode::kJSGreaterThan:
case IrOpcode::kJSLessThanOrEqual:
case IrOpcode::kJSGreaterThanOrEqual: {
DCHECK(!slot.IsInvalid());
FeedbackNexus nexus(feedback_vector(), slot);
if (Node* node = TryBuildSoftDeopt(
slot, effect, control,
nexus, effect, control,
DeoptimizeReason::kInsufficientTypeFeedbackForCompareOperation)) {
return LoweringResult::Exit(node);
}
......@@ -368,8 +365,10 @@ JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceBinaryOperation(
break;
}
case IrOpcode::kJSInstanceOf: {
DCHECK(!slot.IsInvalid());
FeedbackNexus nexus(feedback_vector(), slot);
if (Node* node = TryBuildSoftDeopt(
slot, effect, control,
nexus, effect, control,
DeoptimizeReason::kInsufficientTypeFeedbackForCompareOperation)) {
return LoweringResult::Exit(node);
}
......@@ -388,8 +387,10 @@ JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceBinaryOperation(
case IrOpcode::kJSMultiply:
case IrOpcode::kJSDivide:
case IrOpcode::kJSModulus: {
DCHECK(!slot.IsInvalid());
FeedbackNexus nexus(feedback_vector(), slot);
if (Node* node = TryBuildSoftDeopt(
slot, effect, control,
nexus, effect, control,
DeoptimizeReason::kInsufficientTypeFeedbackForBinaryOperation)) {
return LoweringResult::Exit(node);
}
......@@ -417,8 +418,10 @@ JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceBinaryOperation(
JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceForInNextOperation(
Node* receiver, Node* cache_array, Node* cache_type, Node* index,
Node* effect, Node* control, FeedbackSlot slot) const {
DCHECK(!slot.IsInvalid());
FeedbackNexus nexus(feedback_vector(), slot);
if (Node* node = TryBuildSoftDeopt(
slot, effect, control,
nexus, effect, control,
DeoptimizeReason::kInsufficientTypeFeedbackForForIn)) {
return LoweringResult::Exit(node);
}
......@@ -429,8 +432,10 @@ JSTypeHintLowering::LoweringResult
JSTypeHintLowering::ReduceForInPrepareOperation(Node* enumerator, Node* effect,
Node* control,
FeedbackSlot slot) const {
DCHECK(!slot.IsInvalid());
FeedbackNexus nexus(feedback_vector(), slot);
if (Node* node = TryBuildSoftDeopt(
slot, effect, control,
nexus, effect, control,
DeoptimizeReason::kInsufficientTypeFeedbackForForIn)) {
return LoweringResult::Exit(node);
}
......@@ -440,9 +445,10 @@ JSTypeHintLowering::ReduceForInPrepareOperation(Node* enumerator, Node* effect,
JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceToNumberOperation(
Node* input, Node* effect, Node* control, FeedbackSlot slot) const {
DCHECK(!slot.IsInvalid());
FeedbackNexus nexus(feedback_vector(), slot);
NumberOperationHint hint;
if (BinaryOperationHintToNumberOperationHint(GetBinaryOperationHint(slot),
&hint)) {
if (BinaryOperationHintToNumberOperationHint(
nexus.GetBinaryOperationFeedback(), &hint)) {
Node* node = jsgraph()->graph()->NewNode(
jsgraph()->simplified()->SpeculativeToNumber(hint, VectorSlotPair()),
input, effect, control);
......@@ -456,8 +462,10 @@ JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceCallOperation(
Node* control, FeedbackSlot slot) const {
DCHECK(op->opcode() == IrOpcode::kJSCall ||
op->opcode() == IrOpcode::kJSCallWithSpread);
DCHECK(!slot.IsInvalid());
FeedbackNexus nexus(feedback_vector(), slot);
if (Node* node = TryBuildSoftDeopt(
slot, effect, control,
nexus, effect, control,
DeoptimizeReason::kInsufficientTypeFeedbackForCall)) {
return LoweringResult::Exit(node);
}
......@@ -469,8 +477,10 @@ JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceConstructOperation(
Node* control, FeedbackSlot slot) const {
DCHECK(op->opcode() == IrOpcode::kJSConstruct ||
op->opcode() == IrOpcode::kJSConstructWithSpread);
DCHECK(!slot.IsInvalid());
FeedbackNexus nexus(feedback_vector(), slot);
if (Node* node = TryBuildSoftDeopt(
slot, effect, control,
nexus, effect, control,
DeoptimizeReason::kInsufficientTypeFeedbackForConstruct)) {
return LoweringResult::Exit(node);
}
......@@ -481,8 +491,10 @@ JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceLoadNamedOperation(
const Operator* op, Node* receiver, Node* effect, Node* control,
FeedbackSlot slot) const {
DCHECK_EQ(IrOpcode::kJSLoadNamed, op->opcode());
DCHECK(!slot.IsInvalid());
FeedbackNexus nexus(feedback_vector(), slot);
if (Node* node = TryBuildSoftDeopt(
slot, effect, control,
nexus, effect, control,
DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess)) {
return LoweringResult::Exit(node);
}
......@@ -493,8 +505,10 @@ JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceLoadKeyedOperation(
const Operator* op, Node* obj, Node* key, Node* effect, Node* control,
FeedbackSlot slot) const {
DCHECK_EQ(IrOpcode::kJSLoadProperty, op->opcode());
DCHECK(!slot.IsInvalid());
FeedbackNexus nexus(feedback_vector(), slot);
if (Node* node = TryBuildSoftDeopt(
slot, effect, control,
nexus, effect, control,
DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess)) {
return LoweringResult::Exit(node);
}
......@@ -508,8 +522,10 @@ JSTypeHintLowering::ReduceStoreNamedOperation(const Operator* op, Node* obj,
FeedbackSlot slot) const {
DCHECK(op->opcode() == IrOpcode::kJSStoreNamed ||
op->opcode() == IrOpcode::kJSStoreNamedOwn);
DCHECK(!slot.IsInvalid());
FeedbackNexus nexus(feedback_vector(), slot);
if (Node* node = TryBuildSoftDeopt(
slot, effect, control,
nexus, effect, control,
DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess)) {
return LoweringResult::Exit(node);
}
......@@ -523,30 +539,30 @@ JSTypeHintLowering::ReduceStoreKeyedOperation(const Operator* op, Node* obj,
FeedbackSlot slot) const {
DCHECK(op->opcode() == IrOpcode::kJSStoreProperty ||
op->opcode() == IrOpcode::kJSStoreInArrayLiteral);
DCHECK(!slot.IsInvalid());
FeedbackNexus nexus(feedback_vector(), slot);
if (Node* node = TryBuildSoftDeopt(
slot, effect, control,
nexus, effect, control,
DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess)) {
return LoweringResult::Exit(node);
}
return LoweringResult::NoChange();
}
Node* JSTypeHintLowering::TryBuildSoftDeopt(FeedbackSlot slot, Node* effect,
Node* control,
Node* JSTypeHintLowering::TryBuildSoftDeopt(FeedbackNexus const& nexus,
Node* effect, Node* control,
DeoptimizeReason reason) const {
if (!(flags() & kBailoutOnUninitialized)) return nullptr;
FeedbackSource source(feedback_vector(), slot);
if (!broker()->FeedbackIsInsufficient(source)) return nullptr;
Node* deoptimize = jsgraph()->graph()->NewNode(
jsgraph()->common()->Deoptimize(DeoptimizeKind::kSoft, reason,
VectorSlotPair()),
jsgraph()->Dead(), effect, control);
Node* frame_state =
NodeProperties::FindFrameStateBefore(deoptimize, jsgraph()->Dead());
deoptimize->ReplaceInput(0, frame_state);
return deoptimize;
if ((flags() & kBailoutOnUninitialized) && nexus.IsUninitialized()) {
Node* deoptimize = jsgraph()->graph()->NewNode(
jsgraph()->common()->Deoptimize(DeoptimizeKind::kSoft, reason,
VectorSlotPair()),
jsgraph()->Dead(), effect, control);
Node* frame_state =
NodeProperties::FindFrameStateBefore(deoptimize, jsgraph()->Dead());
deoptimize->ReplaceInput(0, frame_state);
return deoptimize;
}
return nullptr;
}
} // namespace compiler
......
......@@ -41,8 +41,8 @@ class JSTypeHintLowering {
enum Flag { kNoFlags = 0u, kBailoutOnUninitialized = 1u << 1 };
using Flags = base::Flags<Flag>;
JSTypeHintLowering(JSHeapBroker* broker, JSGraph* jsgraph,
FeedbackVectorRef feedback_vector, Flags flags);
JSTypeHintLowering(JSGraph* jsgraph, Handle<FeedbackVector> feedback_vector,
Flags flags);
// {LoweringResult} describes the result of lowering. The following outcomes
// are possible:
......@@ -153,22 +153,19 @@ class JSTypeHintLowering {
private:
friend class JSSpeculativeBinopBuilder;
Node* TryBuildSoftDeopt(FeedbackNexus const& nexus, Node* effect,
Node* control, DeoptimizeReason reson) const;
BinaryOperationHint GetBinaryOperationHint(FeedbackSlot slot) const;
CompareOperationHint GetCompareOperationHint(FeedbackSlot slot) const;
Node* TryBuildSoftDeopt(FeedbackSlot slot, Node* effect, Node* control,
DeoptimizeReason reson) const;
JSHeapBroker* broker() const { return broker_; }
JSGraph* jsgraph() const { return jsgraph_; }
Isolate* isolate() const;
Flags flags() const { return flags_; }
FeedbackVectorRef const& feedback_vector() const { return feedback_vector_; }
const Handle<FeedbackVector>& feedback_vector() const {
return feedback_vector_;
}
JSHeapBroker* const broker_;
JSGraph* const jsgraph_;
JSGraph* jsgraph_;
Flags const flags_;
FeedbackVectorRef const feedback_vector_;
Handle<FeedbackVector> feedback_vector_;
DISALLOW_COPY_AND_ASSIGN(JSTypeHintLowering);
};
......
// 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.
#ifndef V8_COMPILER_PROCESSED_FEEDBACK_H_
#define V8_COMPILER_PROCESSED_FEEDBACK_H_
#include "src/compiler/heap-refs.h"
namespace v8 {
namespace internal {
namespace compiler {
class BinaryOperationFeedback;
class CallFeedback;
class CompareOperationFeedback;
class ElementAccessFeedback;
class ForInFeedback;
class InstanceOfFeedback;
class NamedAccessFeedback;
class ProcessedFeedback : public ZoneObject {
public:
enum Kind {
kInsufficient,
kBinaryOperation,
kCall,
kCompareOperation,
kElementAccess,
kForIn,
kGlobalAccess,
kInstanceOf,
kNamedAccess,
};
Kind kind() const { return kind_; }
bool IsInsufficient() const { return kind() == kInsufficient; }
BinaryOperationFeedback const* AsBinaryOperation() const;
CallFeedback const* AsCall() const;
CompareOperationFeedback const* AsCompareOperation() const;
ElementAccessFeedback const* AsElementAccess() const;
ForInFeedback const* AsForIn() const;
InstanceOfFeedback const* AsInstanceOf() const;
NamedAccessFeedback const* AsNamedAccess() const;
protected:
explicit ProcessedFeedback(Kind kind) : kind_(kind) {}
private:
Kind const kind_;
};
class InsufficientFeedback final : public ProcessedFeedback {
public:
InsufficientFeedback();
};
class GlobalAccessFeedback : public ProcessedFeedback {
public:
explicit GlobalAccessFeedback(PropertyCellRef cell);
GlobalAccessFeedback(ContextRef script_context, int slot_index,
bool immutable);
bool IsPropertyCell() const;
PropertyCellRef property_cell() const;
bool IsScriptContextSlot() const { return !IsPropertyCell(); }
ContextRef script_context() const;
int slot_index() const;
bool immutable() const;
base::Optional<ObjectRef> GetConstantHint() const;
private:
ObjectRef const cell_or_context_;
int const index_and_immutable_;
};
class KeyedAccessMode {
public:
static KeyedAccessMode FromNexus(FeedbackNexus const& nexus);
AccessMode access_mode() const;
bool IsLoad() const;
bool IsStore() const;
KeyedAccessLoadMode load_mode() const;
KeyedAccessStoreMode store_mode() const;
private:
AccessMode const access_mode_;
union LoadStoreMode {
LoadStoreMode(KeyedAccessLoadMode load_mode);
LoadStoreMode(KeyedAccessStoreMode store_mode);
KeyedAccessLoadMode load_mode;
KeyedAccessStoreMode store_mode;
} const load_store_mode_;
KeyedAccessMode(AccessMode access_mode, KeyedAccessLoadMode load_mode);
KeyedAccessMode(AccessMode access_mode, KeyedAccessStoreMode store_mode);
};
class ElementAccessFeedback : public ProcessedFeedback {
public:
ElementAccessFeedback(Zone* zone, KeyedAccessMode const& keyed_mode);
// No transition sources appear in {receiver_maps}.
// All transition targets appear in {receiver_maps}.
ZoneVector<Handle<Map>> receiver_maps;
ZoneVector<std::pair<Handle<Map>, Handle<Map>>> transitions;
KeyedAccessMode const keyed_mode;
class MapIterator {
public:
bool done() const;
void advance();
MapRef current() const;
private:
friend class ElementAccessFeedback;
explicit MapIterator(ElementAccessFeedback const& processed,
JSHeapBroker* broker);
ElementAccessFeedback const& processed_;
JSHeapBroker* const broker_;
size_t index_ = 0;
};
// Iterator over all maps: first {receiver_maps}, then transition sources.
MapIterator all_maps(JSHeapBroker* broker) const;
};
class NamedAccessFeedback : public ProcessedFeedback {
public:
NamedAccessFeedback(NameRef const& name,
ZoneVector<PropertyAccessInfo> const& access_infos);
NameRef const& name() const { return name_; }
ZoneVector<PropertyAccessInfo> const& access_infos() const {
return access_infos_;
}
private:
NameRef const name_;
ZoneVector<PropertyAccessInfo> const access_infos_;
};
class CallFeedback : public ProcessedFeedback {
public:
CallFeedback(base::Optional<HeapObjectRef> target, float frequency,
SpeculationMode mode)
: ProcessedFeedback(kCall),
target_(target),
frequency_(frequency),
mode_(mode) {}
base::Optional<HeapObjectRef> target() const { return target_; }
float frequency() const { return frequency_; }
SpeculationMode speculation_mode() const { return mode_; }
private:
base::Optional<HeapObjectRef> const target_;
float const frequency_;
SpeculationMode const mode_;
};
template <class T, ProcessedFeedback::Kind K>
class SingleValueFeedback : public ProcessedFeedback {
public:
explicit SingleValueFeedback(T value) : ProcessedFeedback(K), value_(value) {}
T value() const { return value_; }
private:
T const value_;
};
class InstanceOfFeedback
: public SingleValueFeedback<base::Optional<JSObjectRef>,
ProcessedFeedback::kInstanceOf> {
using SingleValueFeedback::SingleValueFeedback;
};
class BinaryOperationFeedback
: public SingleValueFeedback<BinaryOperationHint,
ProcessedFeedback::kBinaryOperation> {
using SingleValueFeedback::SingleValueFeedback;
};
class CompareOperationFeedback
: public SingleValueFeedback<CompareOperationHint,
ProcessedFeedback::kCompareOperation> {
using SingleValueFeedback::SingleValueFeedback;
};
class ForInFeedback
: public SingleValueFeedback<ForInHint, ProcessedFeedback::kForIn> {
using SingleValueFeedback::SingleValueFeedback;
};
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_COMPILER_PROCESSED_FEEDBACK_H_
......@@ -38,6 +38,15 @@ namespace compiler {
V(Throw)
#define CLEAR_ACCUMULATOR_LIST(V) \
V(Add) \
V(AddSmi) \
V(BitwiseAnd) \
V(BitwiseAndSmi) \
V(BitwiseNot) \
V(BitwiseOr) \
V(BitwiseOrSmi) \
V(BitwiseXor) \
V(BitwiseXorSmi) \
V(CallRuntime) \
V(CloneObject) \
V(CreateArrayFromIterable) \
......@@ -49,16 +58,42 @@ namespace compiler {
V(CreateRegExpLiteral) \
V(CreateRestParameter) \
V(CreateUnmappedArguments) \
V(Dec) \
V(DeletePropertySloppy) \
V(DeletePropertyStrict) \
V(Div) \
V(DivSmi) \
V(Exp) \
V(ExpSmi) \
V(ForInContinue) \
V(ForInEnumerate) \
V(ForInNext) \
V(ForInStep) \
V(Inc) \
V(LdaLookupSlot) \
V(LdaLookupSlotInsideTypeof) \
V(LogicalNot) \
V(Mod) \
V(ModSmi) \
V(Mul) \
V(MulSmi) \
V(Negate) \
V(SetPendingMessage) \
V(ShiftLeft) \
V(ShiftLeftSmi) \
V(ShiftRight) \
V(ShiftRightLogical) \
V(ShiftRightLogicalSmi) \
V(ShiftRightSmi) \
V(StaLookupSlot) \
V(Sub) \
V(SubSmi) \
V(TestEqual) \
V(TestEqualStrict) \
V(TestGreaterThan) \
V(TestGreaterThanOrEqual) \
V(TestLessThan) \
V(TestLessThanOrEqual) \
V(TestNull) \
V(TestReferenceEqual) \
V(TestTypeOf) \
......@@ -66,6 +101,8 @@ namespace compiler {
V(TestUndetectable) \
V(ToBooleanLogicalNot) \
V(ToName) \
V(ToNumber) \
V(ToNumeric) \
V(ToString) \
V(TypeOf)
......@@ -109,46 +146,6 @@ namespace compiler {
V(Illegal) \
V(Wide)
#define BINARY_OP_LIST(V) \
V(Add) \
V(AddSmi) \
V(BitwiseAnd) \
V(BitwiseAndSmi) \
V(BitwiseOr) \
V(BitwiseOrSmi) \
V(BitwiseXor) \
V(BitwiseXorSmi) \
V(Div) \
V(DivSmi) \
V(Exp) \
V(ExpSmi) \
V(Mod) \
V(ModSmi) \
V(Mul) \
V(MulSmi) \
V(ShiftLeft) \
V(ShiftLeftSmi) \
V(ShiftRight) \
V(ShiftRightSmi) \
V(ShiftRightLogical) \
V(ShiftRightLogicalSmi) \
V(Sub) \
V(SubSmi)
#define UNARY_OP_LIST(V) \
V(BitwiseNot) \
V(Dec) \
V(Inc) \
V(Negate)
#define COMPARE_OP_LIST(V) \
V(TestEqual) \
V(TestEqualStrict) \
V(TestGreaterThan) \
V(TestGreaterThanOrEqual) \
V(TestLessThan) \
V(TestLessThanOrEqual)
#define SUPPORTED_BYTECODE_LIST(V) \
V(CallAnyReceiver) \
V(CallJSRuntime) \
......@@ -169,8 +166,6 @@ namespace compiler {
V(CreateEvalContext) \
V(CreateFunctionContext) \
V(CreateWithContext) \
V(ForInNext) \
V(ForInPrepare) \
V(GetSuperConstructor) \
V(GetTemplateObject) \
V(InvokeIntrinsic) \
......@@ -213,16 +208,11 @@ namespace compiler {
V(SwitchOnSmiNoFeedback) \
V(TestIn) \
V(TestInstanceOf) \
V(ToNumber) \
V(ToNumeric) \
BINARY_OP_LIST(V) \
COMPARE_OP_LIST(V) \
CLEAR_ACCUMULATOR_LIST(V) \
CLEAR_ENVIRONMENT_LIST(V) \
CONDITIONAL_JUMPS_LIST(V) \
IGNORED_BYTECODE_LIST(V) \
KILL_ENVIRONMENT_LIST(V) \
UNARY_OP_LIST(V) \
UNCONDITIONAL_JUMPS_LIST(V) \
UNREACHABLE_BYTECODE_LIST(V)
......@@ -405,18 +395,11 @@ class SerializerForBackgroundCompilation {
Hints const& instance_hints);
GlobalAccessFeedback const* ProcessFeedbackForGlobalAccess(FeedbackSlot slot);
NamedAccessFeedback const* ProcessFeedbackMapsForNamedAccess(
const MapHandles& maps, AccessMode mode, NameRef const& name);
ElementAccessFeedback const* ProcessFeedbackMapsForElementAccess(
const MapHandles& maps, AccessMode mode,
KeyedAccessMode const& keyed_mode);
void ProcessFeedbackForCompareOperation(FeedbackSlot slot);
void ProcessFeedbackForForIn(FeedbackSlot slot);
void ProcessFeedbackForUnaryOrBinaryOperation(
FeedbackSlot slot, bool honor_bailout_on_uninitialized);
void ProcessFeedbackForPropertyAccess(FeedbackSlot slot, AccessMode mode,
base::Optional<NameRef> static_name);
PropertyAccessInfo ProcessMapForNamedPropertyAccess(
......@@ -1303,18 +1286,6 @@ void SerializerForBackgroundCompilation::VisitCreateCatchContext(
ProcessCreateContext();
}
void SerializerForBackgroundCompilation::VisitForInNext(
BytecodeArrayIterator* iterator) {
FeedbackSlot slot = iterator->GetSlotOperand(3);
ProcessFeedbackForForIn(slot);
}
void SerializerForBackgroundCompilation::VisitForInPrepare(
BytecodeArrayIterator* iterator) {
FeedbackSlot slot = iterator->GetSlotOperand(1);
ProcessFeedbackForForIn(slot);
}
void SerializerForBackgroundCompilation::ProcessCreateContext() {
Hints& accumulator_hints = environment()->accumulator_hints();
accumulator_hints.Clear();
......@@ -1504,6 +1475,22 @@ Hints SerializerForBackgroundCompilation::RunChildSerializer(
return child_serializer.Run();
}
namespace {
base::Optional<HeapObjectRef> GetHeapObjectFeedback(
JSHeapBroker* broker, Handle<FeedbackVector> feedback_vector,
FeedbackSlot slot) {
if (slot.IsInvalid()) return base::nullopt;
FeedbackNexus nexus(feedback_vector, slot);
VectorSlotPair feedback(feedback_vector, slot, nexus.ic_state());
DCHECK(feedback.IsValid());
if (nexus.IsUninitialized()) return base::nullopt;
HeapObject object;
if (!nexus.GetFeedback()->GetHeapObject(&object)) return base::nullopt;
return HeapObjectRef(broker, handle(object, broker->isolate()));
}
} // namespace
bool SerializerForBackgroundCompilation::ProcessSFIForCallOrConstruct(
Handle<SharedFunctionInfo> shared, const HintsVector& arguments,
SpeculationMode speculation_mode) {
......@@ -1569,31 +1556,26 @@ MaybeHandle<JSFunction> UnrollBoundFunction(
void SerializerForBackgroundCompilation::ProcessCallOrConstruct(
Hints callee, base::Optional<Hints> new_target,
const HintsVector& arguments, FeedbackSlot slot, bool with_spread) {
// TODO(neis): Make this part of ProcessFeedback*?
if (BailoutOnUninitialized(slot)) return;
FeedbackSource source(environment()->function().feedback_vector(), slot);
ProcessedFeedback const* feedback = broker()->ProcessFeedbackForCall(source);
// Incorporate feedback into hints.
SpeculationMode speculation_mode = SpeculationMode::kDisallowSpeculation;
if (!feedback->IsInsufficient()) {
speculation_mode = feedback->AsCall()->speculation_mode();
base::Optional<HeapObjectRef> target = feedback->AsCall()->target();
if (target.has_value() && target->map().is_callable()) {
// TODO(mvstanton): if the map isn't callable then we have an allocation
// site, and it may make sense to add the Array JSFunction constant.
if (new_target.has_value()) {
// Construct; feedback is new_target, which often is also the callee.
new_target->AddConstant(target->object());
callee.AddConstant(target->object());
} else {
// Call; target is callee.
callee.AddConstant(target->object());
}
base::Optional<HeapObjectRef> feedback = GetHeapObjectFeedback(
broker(), environment()->function().feedback_vector(), slot);
if (feedback.has_value() && feedback->map().is_callable()) {
if (new_target.has_value()) {
// Construct; feedback is new_target, which often is also the callee.
new_target->AddConstant(feedback->object());
callee.AddConstant(feedback->object());
} else {
// Call; feedback is callee.
callee.AddConstant(feedback->object());
}
}
environment()->accumulator_hints().Clear();
FeedbackNexus nexus(environment()->function().feedback_vector(), slot);
SpeculationMode speculation_mode = nexus.GetSpeculationMode();
// For JSCallReducer::ReduceJSCall and JSCallReducer::ReduceJSConstruct.
for (auto hint : callee.constants()) {
......@@ -2154,32 +2136,6 @@ SerializerForBackgroundCompilation::ProcessFeedbackMapsForElementAccess(
return result;
}
void SerializerForBackgroundCompilation::ProcessFeedbackForCompareOperation(
FeedbackSlot slot) {
if (BailoutOnUninitialized(slot)) return;
FeedbackSource source(environment()->function().feedback_vector(), slot);
broker()->ProcessFeedbackForCompareOperation(source);
environment()->accumulator_hints().Clear();
}
void SerializerForBackgroundCompilation::ProcessFeedbackForForIn(
FeedbackSlot slot) {
if (BailoutOnUninitialized(slot)) return;
FeedbackSource source(environment()->function().feedback_vector(), slot);
broker()->ProcessFeedbackForForIn(source);
environment()->accumulator_hints().Clear();
}
void SerializerForBackgroundCompilation::
ProcessFeedbackForUnaryOrBinaryOperation(
FeedbackSlot slot, bool honor_bailout_on_uninitialized) {
if (honor_bailout_on_uninitialized && BailoutOnUninitialized(slot)) return;
FeedbackSource source(environment()->function().feedback_vector(), slot);
// Internally V8 uses binary op feedback also for unary ops.
broker()->ProcessFeedbackForBinaryOperation(source);
environment()->accumulator_hints().Clear();
}
NamedAccessFeedback const*
SerializerForBackgroundCompilation::ProcessFeedbackMapsForNamedAccess(
const MapHandles& maps, AccessMode mode, NameRef const& name) {
......@@ -2510,21 +2466,17 @@ void SerializerForBackgroundCompilation::VisitTestInstanceOf(
environment()->register_hints(iterator->GetRegisterOperand(0));
Hints& rhs = environment()->accumulator_hints();
FeedbackSlot slot = iterator->GetSlotOperand(1);
if (BailoutOnUninitialized(slot)) return;
// Incorporate feedback (about the rhs of the operator) into hints.
{
Handle<FeedbackVector> feedback_vector =
environment()->function().feedback_vector();
FeedbackSource source(feedback_vector, slot);
ProcessedFeedback const* feedback =
broker()->ProcessFeedbackForInstanceOf(source);
if (!feedback->IsInsufficient()) {
InstanceOfFeedback const* rhs_feedback = feedback->AsInstanceOf();
if (rhs_feedback->value().has_value()) {
Handle<JSObject> constructor = rhs_feedback->value()->object();
rhs.AddConstant(constructor);
}
FeedbackNexus nexus(feedback_vector, slot);
VectorSlotPair rhs_feedback(feedback_vector, slot, nexus.ic_state());
Handle<JSObject> constructor;
if (rhs_feedback.IsValid() &&
nexus.GetConstructorFeedback().ToHandle(&constructor)) {
rhs.AddConstant(constructor);
}
}
......@@ -2536,18 +2488,6 @@ void SerializerForBackgroundCompilation::VisitTestInstanceOf(
if (walk_prototypes) ProcessHintsForHasInPrototypeChain(lhs);
}
void SerializerForBackgroundCompilation::VisitToNumeric(
BytecodeArrayIterator* iterator) {
FeedbackSlot slot = iterator->GetSlotOperand(0);
ProcessFeedbackForUnaryOrBinaryOperation(slot, false);
}
void SerializerForBackgroundCompilation::VisitToNumber(
BytecodeArrayIterator* iterator) {
FeedbackSlot slot = iterator->GetSlotOperand(0);
ProcessFeedbackForUnaryOrBinaryOperation(slot, false);
}
void SerializerForBackgroundCompilation::VisitStaKeyedProperty(
BytecodeArrayIterator* iterator) {
Hints const& receiver =
......@@ -2623,44 +2563,14 @@ UNREACHABLE_BYTECODE_LIST(DEFINE_UNREACHABLE)
KILL_ENVIRONMENT_LIST(DEFINE_KILL)
#undef DEFINE_KILL
#define DEFINE_BINARY_OP(name, ...) \
void SerializerForBackgroundCompilation::Visit##name( \
BytecodeArrayIterator* iterator) { \
FeedbackSlot slot = iterator->GetSlotOperand(1); \
ProcessFeedbackForUnaryOrBinaryOperation(slot, true); \
}
BINARY_OP_LIST(DEFINE_BINARY_OP)
#undef DEFINE_BINARY_OP
#define DEFINE_COMPARE_OP(name, ...) \
void SerializerForBackgroundCompilation::Visit##name( \
BytecodeArrayIterator* iterator) { \
FeedbackSlot slot = iterator->GetSlotOperand(1); \
ProcessFeedbackForCompareOperation(slot); \
}
COMPARE_OP_LIST(DEFINE_COMPARE_OP)
#undef DEFINE_COMPARE_OP
#define DEFINE_UNARY_OP(name, ...) \
void SerializerForBackgroundCompilation::Visit##name( \
BytecodeArrayIterator* iterator) { \
FeedbackSlot slot = iterator->GetSlotOperand(0); \
ProcessFeedbackForUnaryOrBinaryOperation(slot, true); \
}
UNARY_OP_LIST(DEFINE_UNARY_OP)
#undef DEFINE_UNARY_OP
#undef BINARY_OP_LIST
#undef CLEAR_ACCUMULATOR_LIST
#undef CLEAR_ENVIRONMENT_LIST
#undef COMPARE_OP_LIST
#undef CONDITIONAL_JUMPS_LIST
#undef IGNORED_BYTECODE_LIST
#undef KILL_ENVIRONMENT_LIST
#undef SUPPORTED_BYTECODE_LIST
#undef UNARY_OP_LIST
#undef CLEAR_ACCUMULATOR_LIST
#undef UNCONDITIONAL_JUMPS_LIST
#undef CONDITIONAL_JUMPS_LIST
#undef IGNORED_BYTECODE_LIST
#undef UNREACHABLE_BYTECODE_LIST
#undef SUPPORTED_BYTECODE_LIST
} // namespace compiler
} // namespace internal
......
......@@ -887,7 +887,8 @@ float FeedbackNexus::ComputeCallFrequency() {
double const invocation_count = vector().invocation_count();
double const call_count = GetCallCount();
if (invocation_count == 0.0) { // Prevent division by 0.
if (invocation_count == 0) {
// Prevent division by 0.
return 0.0f;
}
return static_cast<float>(call_count / invocation_count);
......
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