[turbofan] mark Deoptimize{If,Unless} nodes if they are safety checks

Change-Id: I2e9a6e706d75a579033a3bdaf275a5af4512c8d1
Reviewed-on: https://chromium-review.googlesource.com/897492
Reviewed-by: Jaroslav Sevcik <jarin@chromium.org>
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51026}
This commit is contained in:
Tobias Tebbi 2018-02-01 12:04:15 +01:00 committed by Commit Bot
parent bb9d073a2c
commit 0320986a80
4 changed files with 130 additions and 84 deletions

View File

@ -2988,7 +2988,7 @@ void BytecodeGraphBuilder::BuildJump() {
}
void BytecodeGraphBuilder::BuildJumpIf(Node* condition) {
NewBranch(condition, BranchHint::kNone, BranchKind::kNoSafetyCheck);
NewBranch(condition, BranchHint::kNone, IsSafetyCheck::kNoSafetyCheck);
{
SubEnvironment sub_environment(this);
NewIfTrue();
@ -2998,7 +2998,7 @@ void BytecodeGraphBuilder::BuildJumpIf(Node* condition) {
}
void BytecodeGraphBuilder::BuildJumpIfNot(Node* condition) {
NewBranch(condition, BranchHint::kNone, BranchKind::kNoSafetyCheck);
NewBranch(condition, BranchHint::kNone, IsSafetyCheck::kNoSafetyCheck);
{
SubEnvironment sub_environment(this);
NewIfFalse();
@ -3023,7 +3023,7 @@ void BytecodeGraphBuilder::BuildJumpIfNotEqual(Node* comperand) {
void BytecodeGraphBuilder::BuildJumpIfFalse() {
NewBranch(environment()->LookupAccumulator(), BranchHint::kNone,
BranchKind::kNoSafetyCheck);
IsSafetyCheck::kNoSafetyCheck);
{
SubEnvironment sub_environment(this);
NewIfFalse();
@ -3036,7 +3036,7 @@ void BytecodeGraphBuilder::BuildJumpIfFalse() {
void BytecodeGraphBuilder::BuildJumpIfTrue() {
NewBranch(environment()->LookupAccumulator(), BranchHint::kNone,
BranchKind::kNoSafetyCheck);
IsSafetyCheck::kNoSafetyCheck);
{
SubEnvironment sub_environment(this);
NewIfTrue();

View File

@ -101,8 +101,8 @@ class BytecodeGraphBuilder {
Node* NewMerge() { return NewNode(common()->Merge(1), true); }
Node* NewLoop() { return NewNode(common()->Loop(1), true); }
Node* NewBranch(Node* condition, BranchHint hint = BranchHint::kNone,
BranchKind kind = BranchKind::kSafetyCheck) {
return NewNode(common()->Branch(hint, kind), condition);
IsSafetyCheck is_safety_check = IsSafetyCheck::kSafetyCheck) {
return NewNode(common()->Branch(hint, is_safety_check), condition);
}
Node* NewSwitch(Node* condition, int control_output_count) {
return NewNode(common()->Switch(control_output_count), condition);

View File

@ -29,17 +29,20 @@ std::ostream& operator<<(std::ostream& os, BranchHint hint) {
UNREACHABLE();
}
std::ostream& operator<<(std::ostream& os, BranchOperatorInfo info) {
os << info.hint;
switch (info.kind) {
case BranchKind::kSafetyCheck:
return os << "|SafetyCheck";
case BranchKind::kNoSafetyCheck:
return os << "|NoSafetyCheck";
std::ostream& operator<<(std::ostream& os, IsSafetyCheck is_safety_check) {
switch (is_safety_check) {
case IsSafetyCheck::kSafetyCheck:
return os << "SafetyCheck";
case IsSafetyCheck::kNoSafetyCheck:
return os << "NoSafetyCheck";
}
UNREACHABLE();
}
std::ostream& operator<<(std::ostream& os, BranchOperatorInfo info) {
return os << info.hint << "|" << info.is_safety_check;
}
const BranchOperatorInfo& BranchOperatorInfoOf(const Operator* const op) {
DCHECK_EQ(IrOpcode::kBranch, op->opcode());
return OpParameter<BranchOperatorInfo>(op);
@ -58,7 +61,8 @@ int ValueInputCountOfReturn(Operator const* const op) {
bool operator==(DeoptimizeParameters lhs, DeoptimizeParameters rhs) {
return lhs.kind() == rhs.kind() && lhs.reason() == rhs.reason() &&
lhs.feedback() == rhs.feedback();
lhs.feedback() == rhs.feedback() &&
lhs.is_safety_check() == rhs.is_safety_check();
}
bool operator!=(DeoptimizeParameters lhs, DeoptimizeParameters rhs) {
@ -66,11 +70,12 @@ bool operator!=(DeoptimizeParameters lhs, DeoptimizeParameters rhs) {
}
size_t hash_value(DeoptimizeParameters p) {
return base::hash_combine(p.kind(), p.reason(), p.feedback());
return base::hash_combine(p.kind(), p.reason(), p.feedback(),
p.is_safety_check());
}
std::ostream& operator<<(std::ostream& os, DeoptimizeParameters p) {
os << p.kind() << ":" << p.reason();
os << p.kind() << ":" << p.reason() << ":" << p.is_safety_check();
if (p.feedback().IsValid()) {
os << "; " << p.feedback();
}
@ -84,6 +89,12 @@ DeoptimizeParameters const& DeoptimizeParametersOf(Operator const* const op) {
return OpParameter<DeoptimizeParameters>(op);
}
IsSafetyCheck IsSafetyCheckOf(const Operator* op) {
if (op->opcode() == IrOpcode::kBranch) {
return BranchOperatorInfoOf(op).is_safety_check;
}
return DeoptimizeParametersOf(op).is_safety_check();
}
bool operator==(SelectParameters const& lhs, SelectParameters const& rhs) {
return lhs.representation() == rhs.representation() &&
@ -439,22 +450,28 @@ ZoneVector<MachineType> const* MachineTypesOf(Operator const* op) {
V(Soft, InsufficientTypeFeedbackForGenericKeyedAccess) \
V(Soft, InsufficientTypeFeedbackForGenericNamedAccess)
#define CACHED_DEOPTIMIZE_IF_LIST(V) \
V(Eager, DivisionByZero) \
V(Eager, Hole) \
V(Eager, MinusZero) \
V(Eager, Overflow) \
V(Eager, Smi)
#define CACHED_DEOPTIMIZE_IF_LIST(V) \
V(Eager, DivisionByZero, NoSafetyCheck) \
V(Eager, DivisionByZero, SafetyCheck) \
V(Eager, Hole, NoSafetyCheck) \
V(Eager, Hole, SafetyCheck) \
V(Eager, MinusZero, NoSafetyCheck) \
V(Eager, MinusZero, SafetyCheck) \
V(Eager, Overflow, NoSafetyCheck) \
V(Eager, Overflow, SafetyCheck) \
V(Eager, Smi, SafetyCheck)
#define CACHED_DEOPTIMIZE_UNLESS_LIST(V) \
V(Eager, LostPrecision) \
V(Eager, LostPrecisionOrNaN) \
V(Eager, NotAHeapNumber) \
V(Eager, NotANumberOrOddball) \
V(Eager, NotASmi) \
V(Eager, OutOfBounds) \
V(Eager, WrongInstanceType) \
V(Eager, WrongMap)
#define CACHED_DEOPTIMIZE_UNLESS_LIST(V) \
V(Eager, LostPrecision, NoSafetyCheck) \
V(Eager, LostPrecision, SafetyCheck) \
V(Eager, LostPrecisionOrNaN, NoSafetyCheck) \
V(Eager, LostPrecisionOrNaN, SafetyCheck) \
V(Eager, NotAHeapNumber, SafetyCheck) \
V(Eager, NotANumberOrOddball, SafetyCheck) \
V(Eager, NotASmi, SafetyCheck) \
V(Eager, OutOfBounds, SafetyCheck) \
V(Eager, WrongInstanceType, SafetyCheck) \
V(Eager, WrongMap, SafetyCheck)
#define CACHED_TRAP_IF_LIST(V) \
V(TrapDivUnrepresentable) \
@ -556,18 +573,18 @@ struct CommonOperatorGlobalCache final {
CACHED_RETURN_LIST(CACHED_RETURN)
#undef CACHED_RETURN
template <BranchHint hint, BranchKind kind>
template <BranchHint hint, IsSafetyCheck is_safety_check>
struct BranchOperator final : public Operator1<BranchOperatorInfo> {
BranchOperator()
: Operator1<BranchOperatorInfo>( // --
IrOpcode::kBranch, Operator::kKontrol, // opcode
"Branch", // name
1, 0, 1, 0, 0, 2, // counts
BranchOperatorInfo{hint, kind}) {} // parameter
: Operator1<BranchOperatorInfo>( // --
IrOpcode::kBranch, Operator::kKontrol, // opcode
"Branch", // name
1, 0, 1, 0, 0, 2, // counts
BranchOperatorInfo{hint, is_safety_check}) {} // parameter
};
#define CACHED_BRANCH(Hint, Kind) \
BranchOperator<BranchHint::k##Hint, BranchKind::k##Kind> \
kBranch##Hint##Kind##Operator;
#define CACHED_BRANCH(Hint, IsCheck) \
BranchOperator<BranchHint::k##Hint, IsSafetyCheck::k##IsCheck> \
kBranch##Hint##IsCheck##Operator;
CACHED_BRANCH_LIST(CACHED_BRANCH)
#undef CACHED_BRANCH
@ -632,7 +649,8 @@ struct CommonOperatorGlobalCache final {
Operator::kFoldable | Operator::kNoThrow, // properties
"Deoptimize", // name
1, 1, 1, 0, 0, 1, // counts
DeoptimizeParameters(kKind, kReason, VectorSlotPair())) {}
DeoptimizeParameters(kKind, kReason, VectorSlotPair(),
IsSafetyCheck::kNoSafetyCheck)) {}
};
#define CACHED_DEOPTIMIZE(Kind, Reason) \
DeoptimizeOperator<DeoptimizeKind::k##Kind, DeoptimizeReason::k##Reason> \
@ -640,7 +658,8 @@ struct CommonOperatorGlobalCache final {
CACHED_DEOPTIMIZE_LIST(CACHED_DEOPTIMIZE)
#undef CACHED_DEOPTIMIZE
template <DeoptimizeKind kKind, DeoptimizeReason kReason>
template <DeoptimizeKind kKind, DeoptimizeReason kReason,
IsSafetyCheck is_safety_check>
struct DeoptimizeIfOperator final : public Operator1<DeoptimizeParameters> {
DeoptimizeIfOperator()
: Operator1<DeoptimizeParameters>( // --
@ -648,15 +667,18 @@ struct CommonOperatorGlobalCache final {
Operator::kFoldable | Operator::kNoThrow, // properties
"DeoptimizeIf", // name
2, 1, 1, 0, 1, 1, // counts
DeoptimizeParameters(kKind, kReason, VectorSlotPair())) {}
DeoptimizeParameters(kKind, kReason, VectorSlotPair(),
is_safety_check)) {}
};
#define CACHED_DEOPTIMIZE_IF(Kind, Reason) \
DeoptimizeIfOperator<DeoptimizeKind::k##Kind, DeoptimizeReason::k##Reason> \
kDeoptimizeIf##Kind##Reason##Operator;
#define CACHED_DEOPTIMIZE_IF(Kind, Reason, IsCheck) \
DeoptimizeIfOperator<DeoptimizeKind::k##Kind, DeoptimizeReason::k##Reason, \
IsSafetyCheck::k##IsCheck> \
kDeoptimizeIf##Kind##Reason##IsCheck##Operator;
CACHED_DEOPTIMIZE_IF_LIST(CACHED_DEOPTIMIZE_IF)
#undef CACHED_DEOPTIMIZE_IF
template <DeoptimizeKind kKind, DeoptimizeReason kReason>
template <DeoptimizeKind kKind, DeoptimizeReason kReason,
IsSafetyCheck is_safety_check>
struct DeoptimizeUnlessOperator final
: public Operator1<DeoptimizeParameters> {
DeoptimizeUnlessOperator()
@ -665,12 +687,14 @@ struct CommonOperatorGlobalCache final {
Operator::kFoldable | Operator::kNoThrow, // properties
"DeoptimizeUnless", // name
2, 1, 1, 0, 1, 1, // counts
DeoptimizeParameters(kKind, kReason, VectorSlotPair())) {}
DeoptimizeParameters(kKind, kReason, VectorSlotPair(),
is_safety_check)) {}
};
#define CACHED_DEOPTIMIZE_UNLESS(Kind, Reason) \
#define CACHED_DEOPTIMIZE_UNLESS(Kind, Reason, IsCheck) \
DeoptimizeUnlessOperator<DeoptimizeKind::k##Kind, \
DeoptimizeReason::k##Reason> \
kDeoptimizeUnless##Kind##Reason##Operator;
DeoptimizeReason::k##Reason, \
IsSafetyCheck::k##IsCheck> \
kDeoptimizeUnless##Kind##Reason##IsCheck##Operator;
CACHED_DEOPTIMIZE_UNLESS_LIST(CACHED_DEOPTIMIZE_UNLESS)
#undef CACHED_DEOPTIMIZE_UNLESS
@ -831,10 +855,11 @@ const Operator* CommonOperatorBuilder::Return(int value_input_count) {
}
const Operator* CommonOperatorBuilder::Branch(BranchHint hint,
BranchKind kind) {
#define CACHED_BRANCH(Hint, Kind) \
if (hint == BranchHint::k##Hint && kind == BranchKind::k##Kind) { \
return &cache_.kBranch##Hint##Kind##Operator; \
IsSafetyCheck is_safety_check) {
#define CACHED_BRANCH(Hint, IsCheck) \
if (hint == BranchHint::k##Hint && \
is_safety_check == IsSafetyCheck::k##IsCheck) { \
return &cache_.kBranch##Hint##IsCheck##Operator; \
}
CACHED_BRANCH_LIST(CACHED_BRANCH)
#undef CACHED_BRANCH
@ -852,7 +877,8 @@ const Operator* CommonOperatorBuilder::Deoptimize(
CACHED_DEOPTIMIZE_LIST(CACHED_DEOPTIMIZE)
#undef CACHED_DEOPTIMIZE
// Uncached
DeoptimizeParameters parameter(kind, reason, feedback);
DeoptimizeParameters parameter(kind, reason, feedback,
IsSafetyCheck::kNoSafetyCheck);
return new (zone()) Operator1<DeoptimizeParameters>( // --
IrOpcode::kDeoptimize, // opcodes
Operator::kFoldable | Operator::kNoThrow, // properties
@ -863,16 +889,17 @@ const Operator* CommonOperatorBuilder::Deoptimize(
const Operator* CommonOperatorBuilder::DeoptimizeIf(
DeoptimizeKind kind, DeoptimizeReason reason,
VectorSlotPair const& feedback) {
#define CACHED_DEOPTIMIZE_IF(Kind, Reason) \
if (kind == DeoptimizeKind::k##Kind && \
reason == DeoptimizeReason::k##Reason && !feedback.IsValid()) { \
return &cache_.kDeoptimizeIf##Kind##Reason##Operator; \
VectorSlotPair const& feedback, IsSafetyCheck is_safety_check) {
#define CACHED_DEOPTIMIZE_IF(Kind, Reason, IsCheck) \
if (kind == DeoptimizeKind::k##Kind && \
reason == DeoptimizeReason::k##Reason && \
is_safety_check == IsSafetyCheck::k##IsCheck && !feedback.IsValid()) { \
return &cache_.kDeoptimizeIf##Kind##Reason##IsCheck##Operator; \
}
CACHED_DEOPTIMIZE_IF_LIST(CACHED_DEOPTIMIZE_IF)
#undef CACHED_DEOPTIMIZE_IF
// Uncached
DeoptimizeParameters parameter(kind, reason, feedback);
DeoptimizeParameters parameter(kind, reason, feedback, is_safety_check);
return new (zone()) Operator1<DeoptimizeParameters>( // --
IrOpcode::kDeoptimizeIf, // opcode
Operator::kFoldable | Operator::kNoThrow, // properties
@ -883,16 +910,17 @@ const Operator* CommonOperatorBuilder::DeoptimizeIf(
const Operator* CommonOperatorBuilder::DeoptimizeUnless(
DeoptimizeKind kind, DeoptimizeReason reason,
VectorSlotPair const& feedback) {
#define CACHED_DEOPTIMIZE_UNLESS(Kind, Reason) \
if (kind == DeoptimizeKind::k##Kind && \
reason == DeoptimizeReason::k##Reason && !feedback.IsValid()) { \
return &cache_.kDeoptimizeUnless##Kind##Reason##Operator; \
VectorSlotPair const& feedback, IsSafetyCheck is_safety_check) {
#define CACHED_DEOPTIMIZE_UNLESS(Kind, Reason, IsCheck) \
if (kind == DeoptimizeKind::k##Kind && \
reason == DeoptimizeReason::k##Reason && \
is_safety_check == IsSafetyCheck::k##IsCheck && !feedback.IsValid()) { \
return &cache_.kDeoptimizeUnless##Kind##Reason##IsCheck##Operator; \
}
CACHED_DEOPTIMIZE_UNLESS_LIST(CACHED_DEOPTIMIZE_UNLESS)
#undef CACHED_DEOPTIMIZE_UNLESS
// Uncached
DeoptimizeParameters parameter(kind, reason, feedback);
DeoptimizeParameters parameter(kind, reason, feedback, is_safety_check);
return new (zone()) Operator1<DeoptimizeParameters>( // --
IrOpcode::kDeoptimizeUnless, // opcode
Operator::kFoldable | Operator::kNoThrow, // properties

View File

@ -28,12 +28,6 @@ class Node;
// Prediction hint for branches.
enum class BranchHint : uint8_t { kNone, kTrue, kFalse };
enum class BranchKind : uint8_t { kSafetyCheck, kNoSafetyCheck };
struct BranchOperatorInfo {
BranchHint hint;
BranchKind kind;
};
inline BranchHint NegateBranchHint(BranchHint hint) {
switch (hint) {
@ -51,15 +45,27 @@ inline size_t hash_value(BranchHint hint) { return static_cast<size_t>(hint); }
V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, BranchHint);
enum class IsSafetyCheck : uint8_t { kSafetyCheck, kNoSafetyCheck };
V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, IsSafetyCheck);
inline size_t hash_value(IsSafetyCheck is_safety_check) {
return static_cast<size_t>(is_safety_check);
}
struct BranchOperatorInfo {
BranchHint hint;
IsSafetyCheck is_safety_check;
};
inline size_t hash_value(const BranchOperatorInfo& info) {
return base::hash_combine(info.hint, static_cast<size_t>(info.kind));
return base::hash_combine(info.hint, info.is_safety_check);
}
V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, BranchOperatorInfo);
inline bool operator==(const BranchOperatorInfo& a,
const BranchOperatorInfo& b) {
return a.hint == b.hint && a.kind == b.kind;
return a.hint == b.hint && a.is_safety_check == b.is_safety_check;
}
V8_EXPORT_PRIVATE const BranchOperatorInfo& BranchOperatorInfoOf(
@ -73,17 +79,23 @@ int ValueInputCountOfReturn(Operator const* const op);
class DeoptimizeParameters final {
public:
DeoptimizeParameters(DeoptimizeKind kind, DeoptimizeReason reason,
VectorSlotPair const& feedback)
: kind_(kind), reason_(reason), feedback_(feedback) {}
VectorSlotPair const& feedback,
IsSafetyCheck is_safety_check)
: kind_(kind),
reason_(reason),
feedback_(feedback),
is_safety_check_(is_safety_check) {}
DeoptimizeKind kind() const { return kind_; }
DeoptimizeReason reason() const { return reason_; }
const VectorSlotPair& feedback() const { return feedback_; }
IsSafetyCheck is_safety_check() const { return is_safety_check_; }
private:
DeoptimizeKind const kind_;
DeoptimizeReason const reason_;
VectorSlotPair const feedback_;
IsSafetyCheck is_safety_check_;
};
bool operator==(DeoptimizeParameters, DeoptimizeParameters);
@ -95,6 +107,7 @@ std::ostream& operator<<(std::ostream&, DeoptimizeParameters p);
DeoptimizeParameters const& DeoptimizeParametersOf(Operator const* const);
IsSafetyCheck IsSafetyCheckOf(const Operator* op);
class SelectParameters final {
public:
@ -374,8 +387,9 @@ class V8_EXPORT_PRIVATE CommonOperatorBuilder final
const Operator* DeadValue(MachineRepresentation rep);
const Operator* Unreachable();
const Operator* End(size_t control_input_count);
const Operator* Branch(BranchHint = BranchHint::kNone,
BranchKind kind = BranchKind::kSafetyCheck);
const Operator* Branch(
BranchHint = BranchHint::kNone,
IsSafetyCheck is_safety_check = IsSafetyCheck::kSafetyCheck);
const Operator* IfTrue();
const Operator* IfFalse();
const Operator* IfSuccess();
@ -386,10 +400,14 @@ class V8_EXPORT_PRIVATE CommonOperatorBuilder final
const Operator* Throw();
const Operator* Deoptimize(DeoptimizeKind kind, DeoptimizeReason reason,
VectorSlotPair const& feedback);
const Operator* DeoptimizeIf(DeoptimizeKind kind, DeoptimizeReason reason,
VectorSlotPair const& feedback);
const Operator* DeoptimizeUnless(DeoptimizeKind kind, DeoptimizeReason reason,
VectorSlotPair const& feedback);
const Operator* DeoptimizeIf(
DeoptimizeKind kind, DeoptimizeReason reason,
VectorSlotPair const& feedback,
IsSafetyCheck is_safety_check = IsSafetyCheck::kSafetyCheck);
const Operator* DeoptimizeUnless(
DeoptimizeKind kind, DeoptimizeReason reason,
VectorSlotPair const& feedback,
IsSafetyCheck is_safety_check = IsSafetyCheck::kSafetyCheck);
const Operator* TrapIf(int32_t trap_id);
const Operator* TrapUnless(int32_t trap_id);
const Operator* Return(int value_input_count = 1);