[turbofan] Use the right comparison for constant field store.
This uses the same comparison as the ICs to make sure that ICs learn after deoptimization (see https://chromium-review.googlesource.com/c/v8/v8/+/1561319 for the IC fix). Bug: v8:9139 Change-Id: I67a361d85ee0c8a4ad4a6abc2d33ac4ca5fa22bc Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1569438 Commit-Queue: Jaroslav Sevcik <jarin@chromium.org> Reviewed-by: Georg Neis <neis@chromium.org> Cr-Commit-Position: refs/heads/master@{#60917}
This commit is contained in:
parent
45a6503ca6
commit
2c5f11fba2
@ -752,6 +752,7 @@ namespace internal {
|
||||
TFC(GreaterThanOrEqual, Compare) \
|
||||
TFC(Equal, Compare) \
|
||||
TFC(SameValue, Compare) \
|
||||
TFC(SameValueNumbersOnly, Compare) \
|
||||
TFC(StrictEqual, Compare) \
|
||||
TFS(BitwiseNot, kValue) \
|
||||
TFS(Decrement, kValue) \
|
||||
|
@ -646,6 +646,20 @@ TF_BUILTIN(SameValue, CodeStubAssembler) {
|
||||
Return(FalseConstant());
|
||||
}
|
||||
|
||||
TF_BUILTIN(SameValueNumbersOnly, CodeStubAssembler) {
|
||||
Node* lhs = Parameter(Descriptor::kLeft);
|
||||
Node* rhs = Parameter(Descriptor::kRight);
|
||||
|
||||
Label if_true(this), if_false(this);
|
||||
BranchIfSameValue(lhs, rhs, &if_true, &if_false, SameValueMode::kNumbersOnly);
|
||||
|
||||
BIND(&if_true);
|
||||
Return(TrueConstant());
|
||||
|
||||
BIND(&if_false);
|
||||
Return(FalseConstant());
|
||||
}
|
||||
|
||||
class InternalBuiltinsAssembler : public CodeStubAssembler {
|
||||
public:
|
||||
explicit InternalBuiltinsAssembler(compiler::CodeAssemblerState* state)
|
||||
|
@ -905,6 +905,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
|
||||
case IrOpcode::kSameValue:
|
||||
result = LowerSameValue(node);
|
||||
break;
|
||||
case IrOpcode::kSameValueNumbersOnly:
|
||||
result = LowerSameValueNumbersOnly(node);
|
||||
break;
|
||||
case IrOpcode::kNumberSameValue:
|
||||
result = LowerNumberSameValue(node);
|
||||
break;
|
||||
@ -3443,6 +3446,21 @@ Node* EffectControlLinearizer::LowerSameValue(Node* node) {
|
||||
__ NoContextConstant());
|
||||
}
|
||||
|
||||
Node* EffectControlLinearizer::LowerSameValueNumbersOnly(Node* node) {
|
||||
Node* lhs = node->InputAt(0);
|
||||
Node* rhs = node->InputAt(1);
|
||||
|
||||
Callable const callable =
|
||||
Builtins::CallableFor(isolate(), Builtins::kSameValueNumbersOnly);
|
||||
Operator::Properties properties = Operator::kEliminatable;
|
||||
CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
|
||||
auto call_descriptor = Linkage::GetStubCallDescriptor(
|
||||
graph()->zone(), callable.descriptor(),
|
||||
callable.descriptor().GetStackParameterCount(), flags, properties);
|
||||
return __ Call(call_descriptor, __ HeapConstant(callable.code()), lhs, rhs,
|
||||
__ NoContextConstant());
|
||||
}
|
||||
|
||||
Node* EffectControlLinearizer::LowerNumberSameValue(Node* node) {
|
||||
Node* lhs = node->InputAt(0);
|
||||
Node* rhs = node->InputAt(1);
|
||||
|
@ -146,6 +146,7 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer {
|
||||
Node* LowerNewConsTwoByteString(Node* node);
|
||||
Node* LowerNewConsString(Node* node);
|
||||
Node* LowerSameValue(Node* node);
|
||||
Node* LowerSameValueNumbersOnly(Node* node);
|
||||
Node* LowerNumberSameValue(Node* node);
|
||||
Node* LowerDeadValue(Node* node);
|
||||
Node* LowerStringConcat(Node* node);
|
||||
|
@ -2330,7 +2330,7 @@ JSNativeContextSpecialization::BuildPropertyStore(
|
||||
Node* current_value = effect = graph()->NewNode(
|
||||
simplified()->LoadField(field_access), storage, effect, control);
|
||||
|
||||
Node* check = graph()->NewNode(simplified()->ReferenceEqual(),
|
||||
Node* check = graph()->NewNode(simplified()->SameValueNumbersOnly(),
|
||||
current_value, value);
|
||||
effect = graph()->NewNode(
|
||||
simplified()->CheckIf(DeoptimizeReason::kWrongValue), check,
|
||||
|
@ -293,6 +293,7 @@
|
||||
V(SpeculativeNumberLessThanOrEqual) \
|
||||
V(ReferenceEqual) \
|
||||
V(SameValue) \
|
||||
V(SameValueNumbersOnly) \
|
||||
V(NumberSameValue) \
|
||||
V(StringEqual) \
|
||||
V(StringLessThan) \
|
||||
|
@ -1187,6 +1187,13 @@ Type OperationTyper::SameValue(Type lhs, Type rhs) {
|
||||
return Type::Boolean();
|
||||
}
|
||||
|
||||
Type OperationTyper::SameValueNumbersOnly(Type lhs, Type rhs) {
|
||||
// SameValue and SamevalueNumbersOnly only differ in treatment of
|
||||
// strings and biginits. Since the SameValue typer does not do anything
|
||||
// special about strings or bigints, we can just use it here.
|
||||
return SameValue(lhs, rhs);
|
||||
}
|
||||
|
||||
Type OperationTyper::StrictEqual(Type lhs, Type rhs) {
|
||||
if (!JSType(lhs).Maybe(JSType(rhs))) return singleton_false();
|
||||
if (lhs.Is(Type::NaN()) || rhs.Is(Type::NaN())) return singleton_false();
|
||||
|
@ -55,6 +55,7 @@ class V8_EXPORT_PRIVATE OperationTyper {
|
||||
|
||||
// Comparison operators.
|
||||
Type SameValue(Type lhs, Type rhs);
|
||||
Type SameValueNumbersOnly(Type lhs, Type rhs);
|
||||
Type StrictEqual(Type lhs, Type rhs);
|
||||
|
||||
// String operators.
|
||||
|
@ -2585,6 +2585,11 @@ class RepresentationSelector {
|
||||
}
|
||||
return;
|
||||
}
|
||||
case IrOpcode::kSameValueNumbersOnly: {
|
||||
VisitBinop(node, UseInfo::AnyTagged(),
|
||||
MachineRepresentation::kTaggedPointer);
|
||||
return;
|
||||
}
|
||||
case IrOpcode::kSameValue: {
|
||||
if (truncation.IsUnused()) return VisitUnused(node);
|
||||
if (BothInputsAre(node, Type::Number())) {
|
||||
|
@ -736,6 +736,7 @@ bool operator==(CheckMinusZeroParameters const& lhs,
|
||||
V(ObjectIsInteger, Operator::kNoProperties, 1, 0) \
|
||||
V(ConvertTaggedHoleToUndefined, Operator::kNoProperties, 1, 0) \
|
||||
V(SameValue, Operator::kCommutative, 2, 0) \
|
||||
V(SameValueNumbersOnly, Operator::kCommutative, 2, 0) \
|
||||
V(NumberSameValue, Operator::kCommutative, 2, 0) \
|
||||
V(ReferenceEqual, Operator::kCommutative, 2, 0) \
|
||||
V(StringEqual, Operator::kCommutative, 2, 0) \
|
||||
|
@ -617,6 +617,7 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
|
||||
|
||||
const Operator* ReferenceEqual();
|
||||
const Operator* SameValue();
|
||||
const Operator* SameValueNumbersOnly();
|
||||
|
||||
const Operator* TypeOf();
|
||||
|
||||
|
@ -317,6 +317,7 @@ class Typer::Visitor : public Reducer {
|
||||
static Type NumberLessThanOrEqualTyper(Type, Type, Typer*);
|
||||
static Type ReferenceEqualTyper(Type, Type, Typer*);
|
||||
static Type SameValueTyper(Type, Type, Typer*);
|
||||
static Type SameValueNumbersOnlyTyper(Type, Type, Typer*);
|
||||
static Type StringFromSingleCharCodeTyper(Type, Typer*);
|
||||
static Type StringFromSingleCodePointTyper(Type, Typer*);
|
||||
|
||||
@ -1992,10 +1993,19 @@ Type Typer::Visitor::SameValueTyper(Type lhs, Type rhs, Typer* t) {
|
||||
return t->operation_typer()->SameValue(lhs, rhs);
|
||||
}
|
||||
|
||||
// static
|
||||
Type Typer::Visitor::SameValueNumbersOnlyTyper(Type lhs, Type rhs, Typer* t) {
|
||||
return t->operation_typer()->SameValueNumbersOnly(lhs, rhs);
|
||||
}
|
||||
|
||||
Type Typer::Visitor::TypeSameValue(Node* node) {
|
||||
return TypeBinaryOp(node, SameValueTyper);
|
||||
}
|
||||
|
||||
Type Typer::Visitor::TypeSameValueNumbersOnly(Node* node) {
|
||||
return TypeBinaryOp(node, SameValueNumbersOnlyTyper);
|
||||
}
|
||||
|
||||
Type Typer::Visitor::TypeNumberSameValue(Node* node) { UNREACHABLE(); }
|
||||
|
||||
Type Typer::Visitor::TypeStringEqual(Node* node) { return Type::Boolean(); }
|
||||
|
@ -1185,6 +1185,7 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
|
||||
CheckTypeIs(node, Type::Boolean());
|
||||
break;
|
||||
case IrOpcode::kSameValue:
|
||||
case IrOpcode::kSameValueNumbersOnly:
|
||||
// (Any, Any) -> Boolean
|
||||
CheckValueInputIs(node, 0, Type::Any());
|
||||
CheckValueInputIs(node, 1, Type::Any());
|
||||
|
20
test/mjsunit/compiler/regress-v8-9139.js
Normal file
20
test/mjsunit/compiler/regress-v8-9139.js
Normal file
@ -0,0 +1,20 @@
|
||||
// Copyright 2019 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --allow-natives-syntax --opt --no-always-opt
|
||||
|
||||
let dummy = { x : {} };
|
||||
|
||||
let o = { x : 0.1 };
|
||||
|
||||
function f(o, a, b) {
|
||||
o.x = a + b;
|
||||
}
|
||||
|
||||
%PrepareFunctionForOptimization(f);
|
||||
f(o, 0.05, 0.05);
|
||||
f(o, 0.05, 0.05);
|
||||
%OptimizeFunctionOnNextCall(f);
|
||||
f(o, 0.05, 0.05);
|
||||
assertOptimized(f);
|
Loading…
Reference in New Issue
Block a user