[turbofan] Fix missing checks for UnsignedBigInt64

Output of type UnsignedBigInt64 can be out of the range of small
BigInts. This CL inserts necessary conversion and checks for it.

Bug: chromium:1371935, v8:9407
Change-Id: I2553679452caa63111b97c89d072dd5fcc98aa7c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3939668
Reviewed-by: Nico Hartmann <nicohartmann@chromium.org>
Commit-Queue: Qifan Pan <panq@google.com>
Cr-Commit-Position: refs/heads/main@{#83661}
This commit is contained in:
Qifan Pan 2022-10-12 17:57:02 +02:00 committed by V8 LUCI CQ
parent aa388de13d
commit b3e243c53b
8 changed files with 60 additions and 4 deletions

View File

@ -103,6 +103,7 @@ class EffectControlLinearizer {
Node* LowerCheckedUint32ToTaggedSigned(Node* node, Node* frame_state);
Node* LowerCheckedUint64Bounds(Node* node, Node* frame_state);
Node* LowerCheckedUint64ToInt32(Node* node, Node* frame_state);
Node* LowerCheckedUint64ToInt64(Node* node, Node* frame_state);
Node* LowerCheckedUint64ToTaggedSigned(Node* node, Node* frame_state);
Node* LowerCheckedFloat64ToInt32(Node* node, Node* frame_state);
Node* LowerCheckedFloat64ToInt64(Node* node, Node* frame_state);
@ -1002,6 +1003,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
case IrOpcode::kCheckString:
result = LowerCheckString(node, frame_state);
break;
case IrOpcode::kCheckedUint64ToInt64:
result = LowerCheckedUint64ToInt64(node, frame_state);
break;
case IrOpcode::kCheckBigInt:
result = LowerCheckBigInt(node, frame_state);
break;
@ -2563,6 +2567,18 @@ Node* EffectControlLinearizer::LowerCheckedUint64ToInt32(Node* node,
return __ TruncateInt64ToInt32(value);
}
Node* EffectControlLinearizer::LowerCheckedUint64ToInt64(Node* node,
Node* frame_state) {
Node* value = node->InputAt(0);
const CheckParameters& params = CheckParametersOf(node->op());
Node* check = __ Uint64LessThanOrEqual(
value, __ Uint64Constant(std::numeric_limits<int64_t>::max()));
__ DeoptimizeIfNot(DeoptimizeReason::kLostPrecision, params.feedback(), check,
frame_state);
return value;
}
Node* EffectControlLinearizer::LowerCheckedUint64ToTaggedSigned(
Node* node, Node* frame_state) {
Node* value = node->InputAt(0);

View File

@ -288,6 +288,7 @@
V(CheckedUint32ToTaggedSigned) \
V(CheckedUint64Bounds) \
V(CheckedUint64ToInt32) \
V(CheckedUint64ToInt64) \
V(CheckedUint64ToTaggedSigned) \
V(CheckedFloat64ToInt32) \
V(CheckedFloat64ToInt64) \

View File

@ -496,12 +496,15 @@ Node* RepresentationChanger::GetTaggedPointerRepresentationFor(
// for TaggedSigned output representation.
op = simplified()->CheckedTaggedToTaggedPointer(use_info.feedback());
} else if (IsAnyTagged(output_rep)) {
if (output_type.Is(Type::BigInt())) {
return node;
}
if (use_info.type_check() == TypeCheckKind::kBigInt) {
if (output_type.Is(Type::BigInt())) {
return node;
}
op = simplified()->CheckBigInt(use_info.feedback());
} else if (use_info.type_check() == TypeCheckKind::kBigInt64) {
if (output_type.Is(Type::SignedBigInt64())) {
return node;
}
op = simplified()->CheckBigInt64(use_info.feedback());
} else {
return TypeError(node, output_rep, output_type,
@ -1254,9 +1257,17 @@ Node* RepresentationChanger::GetWord64RepresentationFor(
}
} else if (output_rep == MachineRepresentation::kWord64) {
DCHECK(TypeCheckIsBigInt(use_info.type_check()));
if (output_type.Is(Type::BigInt())) {
if (output_type.Is(Type::UnsignedBigInt64()) &&
use_info.type_check() == TypeCheckKind::kBigInt64) {
op = simplified()->CheckedUint64ToInt64(use_info.feedback());
} else if ((output_type.Is(Type::BigInt()) &&
use_info.type_check() == TypeCheckKind::kBigInt) ||
(output_type.Is(Type::SignedBigInt64()) &&
use_info.type_check() == TypeCheckKind::kBigInt64)) {
return node;
} else {
DCHECK(output_type != Type::BigInt() ||
use_info.type_check() != TypeCheckKind::kBigInt64);
Node* unreachable = InsertUnconditionalDeopt(
use_node, DeoptimizeReason::kNotABigInt, use_info.feedback());
return jsgraph()->graph()->NewNode(

View File

@ -432,6 +432,7 @@ void SimplifiedLoweringVerifier::VisitNode(Node* node,
CASE(CheckedUint32ToTaggedSigned)
CASE(CheckedUint64Bounds)
CASE(CheckedUint64ToInt32)
CASE(CheckedUint64ToInt64)
CASE(CheckedUint64ToTaggedSigned)
CASE(CheckedFloat64ToInt64)
CASE(CheckedTaggedSignedToInt32)

View File

@ -850,6 +850,7 @@ bool operator==(CheckMinusZeroParameters const& lhs,
V(CheckedUint32ToInt32, 1, 1) \
V(CheckedUint32ToTaggedSigned, 1, 1) \
V(CheckedUint64ToInt32, 1, 1) \
V(CheckedUint64ToInt64, 1, 1) \
V(CheckedUint64ToTaggedSigned, 1, 1)
#define CHECKED_BOUNDS_OP_LIST(V) \

View File

@ -940,6 +940,7 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
const Operator* CheckedUint32ToInt32(const FeedbackSource& feedback);
const Operator* CheckedUint32ToTaggedSigned(const FeedbackSource& feedback);
const Operator* CheckedUint64ToInt32(const FeedbackSource& feedback);
const Operator* CheckedUint64ToInt64(const FeedbackSource& feedback);
const Operator* CheckedUint64ToTaggedSigned(const FeedbackSource& feedback);
const Operator* ConvertReceiver(ConvertReceiverMode);

View File

@ -1516,6 +1516,7 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
case IrOpcode::kCheckedUint32ToTaggedSigned:
case IrOpcode::kCheckedUint64Bounds:
case IrOpcode::kCheckedUint64ToInt32:
case IrOpcode::kCheckedUint64ToInt64:
case IrOpcode::kCheckedUint64ToTaggedSigned:
case IrOpcode::kCheckedFloat64ToInt32:
case IrOpcode::kCheckedFloat64ToInt64:

View File

@ -0,0 +1,24 @@
// Copyright 2022 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 --turbofan --no-always-turbofan
function f(a, b, c) {
// CheckBigInt64 is required if the type of input is UnsignedBigInt64
// because its value can be out of the range of SignedBigInt64.
let t = BigInt.asUintN(64, a + b);
// The addition is speculated as CheckedBigInt64Add and triggers the deopt
// for the large value coming in through <t>.
return t + c;
}
%PrepareFunctionForOptimization(f);
assertEquals(12n, f(9n, 2n, 1n));
%OptimizeFunctionOnNextCall(f);
assertEquals(12n, f(9n, 2n, 1n));
assertOptimized(f);
assertEquals(2n ** 64n, f(1n, -2n, 1n));
if (%Is64Bit()) {
assertUnoptimized(f);
}