Commit b4deef61 authored by Leszek Swirski's avatar Leszek Swirski Committed by Commit Bot

[turbofan] Add deopt reason to CheckIf

CheckIf is lowered to DeoptimizeIfNot, but there is no deoptimization
reason given in the deopt if that check fails (the reason is hardcoded
to "no reason"). These deopts are annoying to track down.

This patch makes CheckIf an operator with a DeoptimizeReason parameter,
which is passed through to the DeoptimizeIfNot when lowered.
A couple of checks are converted to give good deoptimize reasons (some
new reasons are introduced), and the others are defaulted to kNoReason
until someone else finds a use for them.

Change-Id: I7e910cc9579ccf978dfe9d270ba7b98c8f6c2492
Reviewed-on: https://chromium-review.googlesource.com/716479Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48506}
parent 217de927
......@@ -1425,8 +1425,8 @@ Node* EffectControlLinearizer::LowerCheckInternalizedString(Node* node,
Node* EffectControlLinearizer::LowerCheckIf(Node* node, Node* frame_state) {
Node* value = node->InputAt(0);
__ DeoptimizeIfNot(DeoptimizeKind::kEager, DeoptimizeReason::kNoReason, value,
frame_state);
__ DeoptimizeIfNot(DeoptimizeKind::kEager, DeoptimizeReasonOf(node->op()),
value, frame_state);
return value;
}
......
......@@ -232,8 +232,9 @@ Reduction JSBuiltinReducer::ReduceArrayIterator(Handle<Map> receiver_map,
Node* check = effect = graph()->NewNode(
simplified()->ArrayBufferWasNeutered(), buffer, effect, control);
check = graph()->NewNode(simplified()->BooleanNot(), check);
effect =
graph()->NewNode(simplified()->CheckIf(), check, effect, control);
effect = graph()->NewNode(
simplified()->CheckIf(DeoptimizeReason::kArrayBufferWasNeutered),
check, effect, control);
}
}
......@@ -386,8 +387,9 @@ Reduction JSBuiltinReducer::ReduceFastArrayIteratorNext(
iterator, etrue1, if_true1);
Node* check_map = graph()->NewNode(simplified()->ReferenceEqual(),
array_map, orig_map);
etrue1 = graph()->NewNode(simplified()->CheckIf(), check_map, etrue1,
if_true1);
etrue1 =
graph()->NewNode(simplified()->CheckIf(DeoptimizeReason::kWrongMap),
check_map, etrue1, if_true1);
}
if (kind != IterationKind::kKeys) {
......@@ -526,8 +528,9 @@ Reduction JSBuiltinReducer::ReduceTypedArrayIteratorNext(
Node* check1 = efalse0 = graph()->NewNode(
simplified()->ArrayBufferWasNeutered(), buffer, efalse0, if_false0);
check1 = graph()->NewNode(simplified()->BooleanNot(), check1);
efalse0 =
graph()->NewNode(simplified()->CheckIf(), check1, efalse0, if_false0);
efalse0 = graph()->NewNode(
simplified()->CheckIf(DeoptimizeReason::kArrayBufferWasNeutered),
check1, efalse0, if_false0);
}
Node* length = efalse0 = graph()->NewNode(
......
......@@ -490,8 +490,9 @@ Reduction JSCallReducer::ReduceObjectPrototypeHasOwnProperty(Node* node) {
receiver, effect, control);
Node* check = graph()->NewNode(simplified()->ReferenceEqual(),
receiver_map, cache_type);
effect =
graph()->NewNode(simplified()->CheckIf(), check, effect, control);
effect = graph()->NewNode(
simplified()->CheckIf(DeoptimizeReason::kNoReason), check, effect,
control);
}
Node* value = jsgraph()->TrueConstant();
ReplaceWithValue(node, value, effect, control);
......@@ -1466,7 +1467,8 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) {
Node* check = graph()->NewNode(simplified()->ReferenceEqual(), target,
target_function);
effect =
graph()->NewNode(simplified()->CheckIf(), check, effect, control);
graph()->NewNode(simplified()->CheckIf(DeoptimizeReason::kNoReason),
check, effect, control);
// Specialize the JSCall node to the {target_function}.
NodeProperties::ReplaceValueInput(node, target_function, 0);
......@@ -1538,7 +1540,8 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
Node* check = graph()->NewNode(simplified()->ReferenceEqual(), target,
array_function);
effect =
graph()->NewNode(simplified()->CheckIf(), check, effect, control);
graph()->NewNode(simplified()->CheckIf(DeoptimizeReason::kNoReason),
check, effect, control);
// Turn the {node} into a {JSCreateArray} call.
NodeProperties::ReplaceEffectInput(node, effect);
......@@ -1560,7 +1563,8 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
Node* check = graph()->NewNode(simplified()->ReferenceEqual(),
new_target, new_target_feedback);
effect =
graph()->NewNode(simplified()->CheckIf(), check, effect, control);
graph()->NewNode(simplified()->CheckIf(DeoptimizeReason::kNoReason),
check, effect, control);
// Specialize the JSConstruct node to the {new_target_feedback}.
NodeProperties::ReplaceValueInput(node, new_target_feedback, arity + 1);
......
......@@ -465,7 +465,9 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
if (index != nullptr) {
Node* check = graph()->NewNode(simplified()->ReferenceEqual(), index,
jsgraph()->HeapConstant(name));
effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control);
effect = graph()->NewNode(
simplified()->CheckIf(DeoptimizeReason::kIndexNameMismatch), check,
effect, control);
}
// Check if we have a {receiver} to validate. If so, we need to check that
......@@ -474,7 +476,9 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
if (receiver != nullptr) {
Node* check = graph()->NewNode(simplified()->ReferenceEqual(), receiver,
jsgraph()->HeapConstant(global_proxy()));
effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control);
effect = graph()->NewNode(
simplified()->CheckIf(DeoptimizeReason::kReceiverNotAGlobalProxy),
check, effect, control);
}
if (access_mode == AccessMode::kLoad) {
......@@ -545,8 +549,9 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
Node* check =
graph()->NewNode(simplified()->ReferenceEqual(), value,
jsgraph()->Constant(property_cell_value));
effect =
graph()->NewNode(simplified()->CheckIf(), check, effect, control);
effect = graph()->NewNode(
simplified()->CheckIf(DeoptimizeReason::kValueMismatch), check,
effect, control);
break;
}
case PropertyCellType::kConstantType: {
......@@ -702,7 +707,9 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
if (index != nullptr) {
Node* check = graph()->NewNode(simplified()->ReferenceEqual(), index,
jsgraph()->HeapConstant(name));
effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control);
effect = graph()->NewNode(
simplified()->CheckIf(DeoptimizeReason::kIndexNameMismatch), check,
effect, control);
}
// Collect call nodes to rewire exception edges.
......@@ -1300,8 +1307,10 @@ Reduction JSNativeContextSpecialization::ReduceKeyedAccess(
Node* check =
graph()->NewNode(simplified()->ReferenceEqual(), elements,
jsgraph()->HeapConstant(array_elements));
effect = graph()->NewNode(simplified()->CheckIf(), check, effect,
control);
effect = graph()->NewNode(
simplified()->CheckIf(
DeoptimizeReason::kCowArrayElementsChanged),
check, effect, control);
value = jsgraph()->Constant(it.GetDataValue());
ReplaceWithValue(node, value, effect, control);
return Replace(value);
......@@ -1483,8 +1492,9 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadProperty(Node* node) {
receiver, effect, control);
Node* check = graph()->NewNode(simplified()->ReferenceEqual(),
receiver_map, enumerator);
effect =
graph()->NewNode(simplified()->CheckIf(), check, effect, control);
effect = graph()->NewNode(
simplified()->CheckIf(DeoptimizeReason::kNoReason), check, effect,
control);
}
// Load the enum cache indices from the {cache_type}.
......@@ -1505,7 +1515,8 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadProperty(Node* node) {
graph()->NewNode(simplified()->ReferenceEqual(), enum_indices,
jsgraph()->EmptyFixedArrayConstant()));
effect =
graph()->NewNode(simplified()->CheckIf(), check, effect, control);
graph()->NewNode(simplified()->CheckIf(DeoptimizeReason::kNoReason),
check, effect, control);
// Determine the index from the {enum_indices}.
index = effect = graph()->NewNode(
......@@ -1781,7 +1792,9 @@ JSNativeContextSpecialization::BuildPropertyStore(
Node* constant_value = jsgraph()->Constant(access_info.constant());
Node* check =
graph()->NewNode(simplified()->ReferenceEqual(), value, constant_value);
effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control);
effect =
graph()->NewNode(simplified()->CheckIf(DeoptimizeReason::kNoReason),
check, effect, control);
value = constant_value;
} else if (access_info.IsAccessorConstant()) {
value =
......@@ -1857,8 +1870,9 @@ JSNativeContextSpecialization::BuildPropertyStore(
Node* check = graph()->NewNode(simplified()->NumberEqual(),
current_value, value);
effect =
graph()->NewNode(simplified()->CheckIf(), check, effect, control);
effect = graph()->NewNode(
simplified()->CheckIf(DeoptimizeReason::kNoReason), check, effect,
control);
return ValueEffectControl(value, effect, control);
}
break;
......@@ -1875,8 +1889,9 @@ JSNativeContextSpecialization::BuildPropertyStore(
Node* check = graph()->NewNode(simplified()->ReferenceEqual(),
current_value, value);
effect =
graph()->NewNode(simplified()->CheckIf(), check, effect, control);
effect = graph()->NewNode(
simplified()->CheckIf(DeoptimizeReason::kNoReason), check, effect,
control);
return ValueEffectControl(value, effect, control);
}
......@@ -2011,7 +2026,8 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreDataPropertyInLiteral(
Node* name = NodeProperties::GetValueInput(node, 1);
Node* check = graph()->NewNode(simplified()->ReferenceEqual(), name,
jsgraph()->HeapConstant(cached_name));
effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control);
effect = graph()->NewNode(simplified()->CheckIf(DeoptimizeReason::kNoReason),
check, effect, control);
Node* value = NodeProperties::GetValueInput(node, 2);
Node* context = NodeProperties::GetContextInput(node);
......
......@@ -1945,7 +1945,8 @@ Reduction JSTypedLowering::ReduceJSForInNext(Node* node) {
Node* check = graph()->NewNode(simplified()->ReferenceEqual(),
receiver_map, cache_type);
effect =
graph()->NewNode(simplified()->CheckIf(), check, effect, control);
graph()->NewNode(simplified()->CheckIf(DeoptimizeReason::kNoReason),
check, effect, control);
ReplaceWithValue(node, node, effect, control);
......
......@@ -420,6 +420,11 @@ BailoutReason BailoutReasonOf(const Operator* op) {
return OpParameter<BailoutReason>(op);
}
DeoptimizeReason DeoptimizeReasonOf(const Operator* op) {
DCHECK_EQ(IrOpcode::kCheckIf, op->opcode());
return OpParameter<DeoptimizeReason>(op);
}
#define PURE_OP_LIST(V) \
V(BooleanNot, Operator::kNoProperties, 1, 0) \
V(NumberEqual, Operator::kCommutative, 2, 0) \
......@@ -526,7 +531,6 @@ BailoutReason BailoutReasonOf(const Operator* op) {
#define CHECKED_OP_LIST(V) \
V(CheckBounds, 2, 1) \
V(CheckHeapObject, 1, 1) \
V(CheckIf, 1, 0) \
V(CheckInternalizedString, 1, 1) \
V(CheckNumber, 1, 1) \
V(CheckReceiver, 1, 1) \
......@@ -570,6 +574,18 @@ struct SimplifiedOperatorGlobalCache final {
CHECKED_OP_LIST(CHECKED)
#undef CHECKED
template <DeoptimizeReason kDeoptimizeReason>
struct CheckIfOperator final : public Operator1<DeoptimizeReason> {
CheckIfOperator()
: Operator1<DeoptimizeReason>(
IrOpcode::kCheckIf, Operator::kFoldable | Operator::kNoThrow,
"CheckIf", 1, 1, 1, 0, 1, 0, kDeoptimizeReason) {}
};
#define CHECK_IF(Name, message) \
CheckIfOperator<DeoptimizeReason::k##Name> kCheckIf##Name;
DEOPTIMIZE_REASON_LIST(CHECK_IF)
#undef CHECK_IF
template <UnicodeEncoding kEncoding>
struct StringFromCodePointOperator final : public Operator1<UnicodeEncoding> {
StringFromCodePointOperator()
......@@ -795,6 +811,17 @@ const Operator* SimplifiedOperatorBuilder::RuntimeAbort(BailoutReason reason) {
reason); // parameter
}
const Operator* SimplifiedOperatorBuilder::CheckIf(DeoptimizeReason reason) {
switch (reason) {
#define CHECK_IF(Name, message) \
case DeoptimizeReason::k##Name: \
return &cache_.kCheckIf##Name;
DEOPTIMIZE_REASON_LIST(CHECK_IF)
#undef CHECK_IF
}
UNREACHABLE();
}
const Operator* SimplifiedOperatorBuilder::ChangeFloat64ToTagged(
CheckForMinusZeroMode mode) {
switch (mode) {
......@@ -1083,6 +1110,11 @@ const Operator* SimplifiedOperatorBuilder::StoreSignedSmallElement() {
"StoreSignedSmallElement", 3, 1, 1, 0, 1, 0);
}
#undef PURE_OP_LIST
#undef SPECULATIVE_NUMBER_BINOP_LIST
#undef CHECKED_OP_LIST
#undef ACCESS_OP_LIST
} // namespace compiler
} // namespace internal
} // namespace v8
......@@ -10,6 +10,7 @@
#include "src/base/compiler-specific.h"
#include "src/compiler/operator.h"
#include "src/compiler/types.h"
#include "src/deoptimize-reason.h"
#include "src/globals.h"
#include "src/handles.h"
#include "src/machine-type.h"
......@@ -257,6 +258,8 @@ UnicodeEncoding UnicodeEncodingOf(const Operator*) WARN_UNUSED_RESULT;
BailoutReason BailoutReasonOf(const Operator* op) WARN_UNUSED_RESULT;
DeoptimizeReason DeoptimizeReasonOf(const Operator* op) WARN_UNUSED_RESULT;
// Interface for building simplified operators, which represent the
// medium-level operations of V8, including adding numbers, allocating objects,
// indexing into objects and arrays, etc.
......@@ -399,7 +402,7 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
const Operator* TruncateTaggedToBit();
const Operator* TruncateTaggedPointerToBit();
const Operator* CheckIf();
const Operator* CheckIf(DeoptimizeReason deoptimize_reason);
const Operator* CheckBounds();
const Operator* CheckMaps(CheckMapsFlags, ZoneHandleSet<Map>);
const Operator* CompareMaps(ZoneHandleSet<Map>);
......
......@@ -13,13 +13,16 @@ namespace internal {
#define DEOPTIMIZE_REASON_LIST(V) \
V(AccessCheck, "Access check needed") \
V(NoReason, "no reason") \
V(ArrayBufferWasNeutered, "array buffer was neutered") \
V(ConstantGlobalVariableAssignment, "Constant global variable assignment") \
V(ConversionOverflow, "conversion overflow") \
V(CowArrayElementsChanged, "copy-on-write array's elements changed") \
V(DivisionByZero, "division by zero") \
V(ExpectedHeapNumber, "Expected heap number") \
V(ExpectedSmi, "Expected smi") \
V(ForcedDeoptToRuntime, "Forced deopt to runtime") \
V(Hole, "hole") \
V(IndexNameMismatch, "index and name do not match in access") \
V(InstanceMigrationFailed, "instance migration failed") \
V(InsufficientTypeFeedbackForCall, "Insufficient type feedback for call") \
V(InsufficientTypeFeedbackForCallWithArguments, \
......@@ -55,6 +58,7 @@ namespace internal {
V(OutsideOfRange, "Outside of range") \
V(Overflow, "overflow") \
V(Proxy, "proxy") \
V(ReceiverNotAGlobalProxy, "receiver was not a global proxy") \
V(ReceiverWasAGlobalObject, "receiver was a global object") \
V(Smi, "Smi") \
V(TooManyArguments, "too many arguments") \
......
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