blob: da3785f35e2b618dff94d56c8d1d727a8e03f20e [file] [log] [blame]
// 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/feedback-source.h"
#include "src/compiler/heap-refs.h"
namespace v8 {
namespace internal {
namespace compiler {
class BinaryOperationFeedback;
class CallFeedback;
class CompareOperationFeedback;
class ElementAccessFeedback;
class ForInFeedback;
class GlobalAccessFeedback;
class InstanceOfFeedback;
class LiteralFeedback;
class MinimorphicLoadPropertyAccessFeedback;
class NamedAccessFeedback;
class RegExpLiteralFeedback;
class TemplateObjectFeedback;
class ProcessedFeedback : public ZoneObject {
public:
enum Kind {
kInsufficient,
kBinaryOperation,
kCall,
kCompareOperation,
kElementAccess,
kForIn,
kGlobalAccess,
kInstanceOf,
kLiteral,
kMinimorphicPropertyAccess,
kNamedAccess,
kRegExpLiteral,
kTemplateObject,
};
Kind kind() const { return kind_; }
FeedbackSlotKind slot_kind() const { return slot_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;
GlobalAccessFeedback const& AsGlobalAccess() const;
InstanceOfFeedback const& AsInstanceOf() const;
NamedAccessFeedback const& AsNamedAccess() const;
MinimorphicLoadPropertyAccessFeedback const& AsMinimorphicPropertyAccess()
const;
LiteralFeedback const& AsLiteral() const;
RegExpLiteralFeedback const& AsRegExpLiteral() const;
TemplateObjectFeedback const& AsTemplateObject() const;
protected:
ProcessedFeedback(Kind kind, FeedbackSlotKind slot_kind);
private:
Kind const kind_;
FeedbackSlotKind const slot_kind_;
};
class InsufficientFeedback final : public ProcessedFeedback {
public:
explicit InsufficientFeedback(FeedbackSlotKind slot_kind);
};
class GlobalAccessFeedback : public ProcessedFeedback {
public:
GlobalAccessFeedback(PropertyCellRef cell, FeedbackSlotKind slot_kind);
GlobalAccessFeedback(ContextRef script_context, int slot_index,
bool immutable, FeedbackSlotKind slot_kind);
explicit GlobalAccessFeedback(FeedbackSlotKind slot_kind); // Megamorphic
bool IsMegamorphic() const;
bool IsPropertyCell() const;
PropertyCellRef property_cell() const;
bool IsScriptContextSlot() const;
ContextRef script_context() const;
int slot_index() const;
bool immutable() const;
base::Optional<ObjectRef> GetConstantHint() const;
private:
base::Optional<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,
FeedbackSlotKind slot_kind);
KeyedAccessMode keyed_mode() const;
// A transition group is a target and a possibly empty set of sources that can
// transition to the target. It is represented as a non-empty vector with the
// target at index 0.
using TransitionGroup = ZoneVector<Handle<Map>>;
ZoneVector<TransitionGroup> const& transition_groups() const;
bool HasOnlyStringMaps(JSHeapBroker* broker) const;
void AddGroup(TransitionGroup&& group);
// Refine {this} by trying to restrict it to the maps in {inferred_maps}. A
// transition group's target is kept iff it is in {inferred_maps} or if more
// than one of its sources is in {inferred_maps}. Here's an (unrealistic)
// example showing all the possible situations:
//
// inferred_maps = [a0, a2, c1, c2, d1, e0, e1]
//
// Groups before: Groups after:
// [a0, a1, a2] [a0, a2]
// [b0]
// [c0, c1, c2, c3] [c0, c1, c2]
// [d0, d1] [d1]
// [e0, e1] [e0, e1]
//
ElementAccessFeedback const& Refine(
ZoneVector<Handle<Map>> const& inferred_maps, Zone* zone) const;
private:
KeyedAccessMode const keyed_mode_;
ZoneVector<TransitionGroup> transition_groups_;
};
class NamedAccessFeedback : public ProcessedFeedback {
public:
NamedAccessFeedback(NameRef const& name, ZoneVector<Handle<Map>> const& maps,
FeedbackSlotKind slot_kind);
NameRef const& name() const { return name_; }
ZoneVector<Handle<Map>> const& maps() const { return maps_; }
private:
NameRef const name_;
ZoneVector<Handle<Map>> const maps_;
};
class MinimorphicLoadPropertyAccessFeedback : public ProcessedFeedback {
public:
MinimorphicLoadPropertyAccessFeedback(NameRef const& name,
FeedbackSlotKind slot_kind,
Handle<Object> handler,
ZoneVector<Handle<Map>> const& maps,
bool has_migration_target_maps);
NameRef const& name() const { return name_; }
bool is_monomorphic() const { return maps_.size() == 1; }
Handle<Object> handler() const { return handler_; }
ZoneVector<Handle<Map>> const& maps() const { return maps_; }
bool has_migration_target_maps() const { return has_migration_target_maps_; }
private:
NameRef const name_;
Handle<Object> const handler_;
ZoneVector<Handle<Map>> const maps_;
bool const has_migration_target_maps_;
};
class CallFeedback : public ProcessedFeedback {
public:
CallFeedback(base::Optional<HeapObjectRef> target, float frequency,
SpeculationMode mode, FeedbackSlotKind slot_kind)
: ProcessedFeedback(kCall, slot_kind),
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, FeedbackSlotKind slot_kind)
: ProcessedFeedback(K, slot_kind), value_(value) {
DCHECK(
(K == kBinaryOperation && slot_kind == FeedbackSlotKind::kBinaryOp) ||
(K == kCompareOperation && slot_kind == FeedbackSlotKind::kCompareOp) ||
(K == kForIn && slot_kind == FeedbackSlotKind::kForIn) ||
(K == kInstanceOf && slot_kind == FeedbackSlotKind::kInstanceOf) ||
((K == kLiteral || K == kRegExpLiteral || K == kTemplateObject) &&
slot_kind == FeedbackSlotKind::kLiteral));
}
T value() const { return value_; }
private:
T const value_;
};
class InstanceOfFeedback
: public SingleValueFeedback<base::Optional<JSObjectRef>,
ProcessedFeedback::kInstanceOf> {
using SingleValueFeedback::SingleValueFeedback;
};
class LiteralFeedback
: public SingleValueFeedback<AllocationSiteRef,
ProcessedFeedback::kLiteral> {
using SingleValueFeedback::SingleValueFeedback;
};
class RegExpLiteralFeedback
: public SingleValueFeedback<JSRegExpRef,
ProcessedFeedback::kRegExpLiteral> {
using SingleValueFeedback::SingleValueFeedback;
};
class TemplateObjectFeedback
: public SingleValueFeedback<JSArrayRef,
ProcessedFeedback::kTemplateObject> {
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_