Commit 5ff38bae authored by Nico Hartmann's avatar Nico Hartmann Committed by Commit Bot

[TurboFan] Fast path for JSAdd with BigInt feedback

This CL introduces the necessary infrastructure to generate speculative
BigInt operations in case of BigInt feedback. In particular, the JSAdd
operator is lowered to a speculative call to the  BigIntAdd builtin,
with a deopt bailout in case of exceptions or violated assumptions.

Bug: v8:9213
Change-Id: I05796336eef9a4389fc31d59cad2d69f75512647
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1657916
Commit-Queue: Nico Hartmann <nicohartmann@google.com>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Reviewed-by: 's avatarSigurd Schneider <sigurds@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62362}
parent fdd12a48
......@@ -61,10 +61,10 @@ namespace bigint {
return sign == kPositiveSign ? kNegativeSign : kPositiveSign;
}
macro AllocateEmptyBigInt(implicit context: Context)(
sign: uint32, length: intptr): MutableBigInt {
macro AllocateEmptyBigIntNoThrow(implicit context: Context)(
sign: uint32, length: intptr): MutableBigInt labels BigIntTooBig {
if (length > kBigIntMaxLength) {
ThrowRangeError(kBigIntTooBig);
goto BigIntTooBig;
}
const result: MutableBigInt = AllocateBigInt(length);
......@@ -72,6 +72,16 @@ namespace bigint {
return result;
}
macro AllocateEmptyBigInt(implicit context: Context)(
sign: uint32, length: intptr): MutableBigInt {
try {
return AllocateEmptyBigIntNoThrow(sign, length) otherwise BigIntTooBig;
}
label BigIntTooBig {
ThrowRangeError(kBigIntTooBig);
}
}
macro MutableBigIntAbsoluteCompare(x: BigIntBase, y: BigIntBase): int32 {
return CppAbsoluteCompare(x, y);
}
......@@ -98,7 +108,8 @@ namespace bigint {
}
macro MutableBigIntAbsoluteAdd(implicit context: Context)(
xBigint: BigInt, yBigint: BigInt, resultSign: uint32): BigInt {
xBigint: BigInt, yBigint: BigInt,
resultSign: uint32): BigInt labels BigIntTooBig {
let xlength = ReadBigIntLength(xBigint);
let ylength = ReadBigIntLength(yBigint);
......@@ -125,35 +136,55 @@ namespace bigint {
}
// case: x + y
const result = AllocateEmptyBigInt(resultSign, xlength + 1);
const result = AllocateEmptyBigIntNoThrow(resultSign, xlength + 1)
otherwise BigIntTooBig;
CppAbsoluteAddAndCanonicalize(result, x, y);
return Convert<BigInt>(result);
}
macro BigIntAddImpl(implicit context: Context)(x: BigInt, y: BigInt): BigInt
labels BigIntTooBig {
const xsign = ReadBigIntSign(x);
const ysign = ReadBigIntSign(y);
if (xsign == ysign) {
// x + y == x + y
// -x + -y == -(x + y)
return MutableBigIntAbsoluteAdd(x, y, xsign) otherwise BigIntTooBig;
}
// x + -y == x - y == -(y - x)
// -x + y == y - x == -(x - y)
if (MutableBigIntAbsoluteCompare(x, y) >= 0) {
return MutableBigIntAbsoluteSub(x, y, xsign);
}
return MutableBigIntAbsoluteSub(y, x, InvertSign(xsign));
}
builtin BigIntAddNoThrow(implicit context: Context)(x: BigInt, y: BigInt):
Numeric {
try {
return BigIntAddImpl(x, y) otherwise BigIntTooBig;
}
label BigIntTooBig {
// Smi sentinal is used to signal BigIntTooBig exception.
return Convert<Smi>(0);
}
}
builtin BigIntAdd(implicit context: Context)(xNum: Numeric, yNum: Numeric):
BigInt {
try {
const x = Cast<BigInt>(xNum) otherwise MixedTypes;
const y = Cast<BigInt>(yNum) otherwise MixedTypes;
const xsign = ReadBigIntSign(x);
const ysign = ReadBigIntSign(y);
if (xsign == ysign) {
// x + y == x + y
// -x + -y == -(x + y)
return MutableBigIntAbsoluteAdd(x, y, xsign);
}
// x + -y == x - y == -(y - x)
// -x + y == y - x == -(x - y)
if (MutableBigIntAbsoluteCompare(x, y) >= 0) {
return MutableBigIntAbsoluteSub(x, y, xsign);
}
return MutableBigIntAbsoluteSub(y, x, InvertSign(xsign));
return BigIntAddImpl(x, y) otherwise BigIntTooBig;
}
label MixedTypes {
ThrowTypeError(kBigIntMixedTypes);
}
label BigIntTooBig {
ThrowRangeError(kBigIntTooBig);
}
}
builtin BigIntUnaryMinus(implicit context: Context)(bigint: BigInt): BigInt {
......
......@@ -101,6 +101,7 @@ class EffectControlLinearizer {
Node* LowerCheckedTaggedToFloat64(Node* node, Node* frame_state);
Node* LowerCheckedTaggedToTaggedSigned(Node* node, Node* frame_state);
Node* LowerCheckedTaggedToTaggedPointer(Node* node, Node* frame_state);
Node* LowerCheckedTaggedToBigInt(Node* node, Node* frame_state);
Node* LowerCheckedCompressedToTaggedSigned(Node* node, Node* frame_state);
Node* LowerCheckedCompressedToTaggedPointer(Node* node, Node* frame_state);
Node* LowerCheckedTaggedToCompressedSigned(Node* node, Node* frame_state);
......@@ -161,6 +162,7 @@ class EffectControlLinearizer {
Node* LowerStringEqual(Node* node);
Node* LowerStringLessThan(Node* node);
Node* LowerStringLessThanOrEqual(Node* node);
Node* LowerSpeculativeBigIntAdd(Node* node, Node* frame_state);
Node* LowerCheckFloat64Hole(Node* node, Node* frame_state);
Node* LowerCheckNotTaggedHole(Node* node, Node* frame_state);
Node* LowerConvertTaggedHoleToUndefined(Node* node);
......@@ -993,6 +995,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
case IrOpcode::kCheckedTaggedToTaggedPointer:
result = LowerCheckedTaggedToTaggedPointer(node, frame_state);
break;
case IrOpcode::kCheckedTaggedToBigInt:
result = LowerCheckedTaggedToBigInt(node, frame_state);
break;
case IrOpcode::kCheckedCompressedToTaggedSigned:
result = LowerCheckedCompressedToTaggedSigned(node, frame_state);
break;
......@@ -1140,6 +1145,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
case IrOpcode::kStringLessThanOrEqual:
result = LowerStringLessThanOrEqual(node);
break;
case IrOpcode::kSpeculativeBigIntAdd:
result = LowerSpeculativeBigIntAdd(node, frame_state);
break;
case IrOpcode::kNumberIsFloat64Hole:
result = LowerNumberIsFloat64Hole(node);
break;
......@@ -2651,6 +2659,25 @@ Node* EffectControlLinearizer::LowerCheckedTaggedToTaggedPointer(
return value;
}
Node* EffectControlLinearizer::LowerCheckedTaggedToBigInt(Node* node,
Node* frame_state) {
Node* value = node->InputAt(0);
const CheckParameters& params = CheckParametersOf(node->op());
// Check for Smi.
Node* smi_check = ObjectIsSmi(value);
__ DeoptimizeIf(DeoptimizeReason::kSmi, params.feedback(), smi_check,
frame_state);
// Check for BigInt.
Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
Node* bi_check = __ WordEqual(value_map, __ BigIntMapConstant());
__ DeoptimizeIfNot(DeoptimizeReason::kWrongInstanceType, params.feedback(),
bi_check, frame_state);
return value;
}
Node* EffectControlLinearizer::LowerCheckedCompressedToTaggedSigned(
Node* node, Node* frame_state) {
Node* value = node->InputAt(0);
......@@ -4083,6 +4110,29 @@ Node* EffectControlLinearizer::LowerStringLessThanOrEqual(Node* node) {
Builtins::CallableFor(isolate(), Builtins::kStringLessThanOrEqual), node);
}
Node* EffectControlLinearizer::LowerSpeculativeBigIntAdd(Node* node,
Node* frame_state) {
const auto& p = BigIntOperationParametersOf(node->op());
Node* lhs = node->InputAt(0);
Node* rhs = node->InputAt(1);
Callable const callable =
Builtins::CallableFor(isolate(), Builtins::kBigIntAddNoThrow);
auto call_descriptor = Linkage::GetStubCallDescriptor(
graph()->zone(), callable.descriptor(),
callable.descriptor().GetStackParameterCount(), CallDescriptor::kNoFlags,
Operator::kFoldable | Operator::kNoThrow);
Node* value =
__ Call(call_descriptor, jsgraph()->HeapConstant(callable.code()), lhs,
rhs, __ NoContextConstant());
// Check for exception sentinel: Smi is returned to signal BigIntTooBig.
__ DeoptimizeIf(DeoptimizeReason::kBigIntTooBig, p.feedback(),
ObjectIsSmi(value), frame_state);
return value;
}
Node* EffectControlLinearizer::LowerCheckFloat64Hole(Node* node,
Node* frame_state) {
// If we reach this point w/o eliminating the {node} that's marked
......
......@@ -44,6 +44,25 @@ bool BinaryOperationHintToNumberOperationHint(
return false;
}
bool BinaryOperationHintToBigIntOperationHint(
BinaryOperationHint binop_hint, BigIntOperationHint* bigint_hint) {
switch (binop_hint) {
case BinaryOperationHint::kSignedSmall:
case BinaryOperationHint::kSignedSmallInputs:
case BinaryOperationHint::kSigned32:
case BinaryOperationHint::kNumber:
case BinaryOperationHint::kNumberOrOddball:
case BinaryOperationHint::kAny:
case BinaryOperationHint::kNone:
case BinaryOperationHint::kString:
return false;
case BinaryOperationHint::kBigInt:
*bigint_hint = BigIntOperationHint::kBigInt;
return true;
}
UNREACHABLE();
}
} // namespace
class JSSpeculativeBinopBuilder final {
......@@ -74,6 +93,11 @@ class JSSpeculativeBinopBuilder final {
hint);
}
bool GetBinaryBigIntOperationHint(BigIntOperationHint* hint) {
return BinaryOperationHintToBigIntOperationHint(GetBinaryOperationHint(),
hint);
}
bool GetCompareNumberOperationHint(NumberOperationHint* hint) {
switch (GetCompareOperationHint()) {
case CompareOperationHint::kSignedSmall:
......@@ -138,6 +162,17 @@ class JSSpeculativeBinopBuilder final {
UNREACHABLE();
}
const Operator* SpeculativeBigIntOp(BigIntOperationHint hint,
const VectorSlotPair& feedback) {
switch (op_->opcode()) {
case IrOpcode::kJSAdd:
return simplified()->SpeculativeBigIntAdd(hint, feedback);
default:
break;
}
UNREACHABLE();
}
const Operator* SpeculativeCompareOp(NumberOperationHint hint) {
switch (op_->opcode()) {
case IrOpcode::kJSEqual:
......@@ -179,6 +214,18 @@ class JSSpeculativeBinopBuilder final {
return nullptr;
}
Node* TryBuildBigIntBinop() {
BigIntOperationHint hint;
if (GetBinaryBigIntOperationHint(&hint)) {
FeedbackNexus nexus{feedback_vector(), slot_};
VectorSlotPair feedback{feedback_vector(), slot_, nexus.ic_state()};
const Operator* op = SpeculativeBigIntOp(hint, feedback);
Node* node = BuildSpeculativeOperation(op);
return node;
}
return nullptr;
}
Node* TryBuildNumberCompare() {
NumberOperationHint hint;
if (GetCompareNumberOperationHint(&hint)) {
......@@ -345,6 +392,11 @@ JSTypeHintLowering::LoweringResult JSTypeHintLowering::ReduceBinaryOperation(
if (Node* node = b.TryBuildNumberBinop()) {
return LoweringResult::SideEffectFree(node, node, control);
}
if (op->opcode() == IrOpcode::kJSAdd) {
if (Node* node = b.TryBuildBigIntBinop()) {
return LoweringResult::SideEffectFree(node, node, control);
}
}
break;
}
case IrOpcode::kJSExponentiate: {
......
......@@ -281,6 +281,7 @@
V(CheckedTaggedToInt64) \
V(CheckedTaggedToTaggedSigned) \
V(CheckedTaggedToTaggedPointer) \
V(CheckedTaggedToBigInt) \
V(CheckedCompressedToTaggedSigned) \
V(CheckedCompressedToTaggedPointer) \
V(CheckedTaggedToCompressedSigned) \
......@@ -464,6 +465,8 @@
V(RuntimeAbort) \
V(DateNow)
#define SIMPLIFIED_SPECULATIVE_BIGINT_BINOP_LIST(V) V(SpeculativeBigIntAdd)
#define SIMPLIFIED_OP_LIST(V) \
SIMPLIFIED_CHANGE_OP_LIST(V) \
SIMPLIFIED_CHECKED_OP_LIST(V) \
......@@ -472,6 +475,7 @@
SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(V) \
SIMPLIFIED_NUMBER_UNOP_LIST(V) \
SIMPLIFIED_SPECULATIVE_NUMBER_UNOP_LIST(V) \
SIMPLIFIED_SPECULATIVE_BIGINT_BINOP_LIST(V) \
SIMPLIFIED_OTHER_OP_LIST(V)
// Opcodes for Machine-level operators.
......
......@@ -1112,6 +1112,11 @@ SPECULATIVE_NUMBER_BINOP(NumberShiftRight)
SPECULATIVE_NUMBER_BINOP(NumberShiftRightLogical)
#undef SPECULATIVE_NUMBER_BINOP
Type OperationTyper::SpeculativeBigIntAdd(Type lhs, Type rhs) {
if (lhs.IsNone() || rhs.IsNone()) return Type::None();
return Type::BigInt();
}
Type OperationTyper::SpeculativeToNumber(Type type) {
return ToNumber(Type::Intersect(type, Type::NumberOrOddball(), zone()));
}
......
......@@ -47,10 +47,11 @@ class V8_EXPORT_PRIVATE OperationTyper {
DECLARE_METHOD(ConvertReceiver)
#undef DECLARE_METHOD
// Number binary operators.
// Numeric binary operators.
#define DECLARE_METHOD(Name) Type Name(Type lhs, Type rhs);
SIMPLIFIED_NUMBER_BINOP_LIST(DECLARE_METHOD)
SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(DECLARE_METHOD)
SIMPLIFIED_SPECULATIVE_BIGINT_BINOP_LIST(DECLARE_METHOD)
#undef DECLARE_METHOD
// Comparison operators.
......
......@@ -158,6 +158,7 @@ bool CheckSubsumes(Node const* a, Node const* b) {
case IrOpcode::kCheckedCompressedToTaggedSigned:
case IrOpcode::kCheckedTaggedToCompressedPointer:
case IrOpcode::kCheckedTaggedToCompressedSigned:
case IrOpcode::kCheckedTaggedToBigInt:
case IrOpcode::kCheckedUint32Bounds:
case IrOpcode::kCheckedUint32ToInt32:
case IrOpcode::kCheckedUint32ToTaggedSigned:
......
......@@ -171,7 +171,8 @@ Node* RepresentationChanger::GetRepresentationFor(
use_node, use_info);
case MachineRepresentation::kTaggedPointer:
DCHECK(use_info.type_check() == TypeCheckKind::kNone ||
use_info.type_check() == TypeCheckKind::kHeapObject);
use_info.type_check() == TypeCheckKind::kHeapObject ||
use_info.type_check() == TypeCheckKind::kBigInt);
return GetTaggedPointerRepresentationFor(node, output_rep, output_type,
use_node, use_info);
case MachineRepresentation::kTagged:
......@@ -449,6 +450,9 @@ Node* RepresentationChanger::GetTaggedPointerRepresentationFor(
// TODO(turbofan): Consider adding a Bailout operator that just deopts
// for TaggedSigned output representation.
op = simplified()->CheckedTaggedToTaggedPointer(use_info.feedback());
} else if (IsAnyTagged(output_rep) &&
use_info.type_check() == TypeCheckKind::kBigInt) {
op = simplified()->CheckedTaggedToBigInt(use_info.feedback());
} else if (output_rep == MachineRepresentation::kCompressedPointer) {
op = machine()->ChangeCompressedPointerToTaggedPointer();
} else if (CanBeCompressedSigned(output_rep) &&
......@@ -812,11 +816,14 @@ Node* RepresentationChanger::GetFloat64RepresentationFor(
Node* use_node, UseInfo use_info) {
NumberMatcher m(node);
if (m.HasValue()) {
// BigInts are not used as number constants.
DCHECK(use_info.type_check() != TypeCheckKind::kBigInt);
switch (use_info.type_check()) {
case TypeCheckKind::kNone:
case TypeCheckKind::kNumber:
case TypeCheckKind::kNumberOrOddball:
return jsgraph()->Float64Constant(m.Value());
case TypeCheckKind::kBigInt:
case TypeCheckKind::kHeapObject:
case TypeCheckKind::kSigned32:
case TypeCheckKind::kSigned64:
......
......@@ -112,7 +112,8 @@ enum class TypeCheckKind : uint8_t {
kSigned64,
kNumber,
kNumberOrOddball,
kHeapObject
kHeapObject,
kBigInt,
};
inline std::ostream& operator<<(std::ostream& os, TypeCheckKind type_check) {
......@@ -131,6 +132,8 @@ inline std::ostream& operator<<(std::ostream& os, TypeCheckKind type_check) {
return os << "NumberOrOddball";
case TypeCheckKind::kHeapObject:
return os << "HeapObject";
case TypeCheckKind::kBigInt:
return os << "BigInt";
}
UNREACHABLE();
}
......@@ -206,6 +209,12 @@ class UseInfo {
return UseInfo(MachineRepresentation::kTaggedPointer, Truncation::Any(),
TypeCheckKind::kHeapObject, feedback);
}
static UseInfo CheckedBigIntAsTaggedPointer(const VectorSlotPair& feedback) {
return UseInfo(MachineRepresentation::kTaggedPointer, Truncation::Any(),
TypeCheckKind::kBigInt, feedback);
}
static UseInfo CheckedSignedSmallAsTaggedSigned(
const VectorSlotPair& feedback,
IdentifyZeros identify_zeros = kDistinguishZeros) {
......
......@@ -444,6 +444,7 @@ class RepresentationSelector {
break; \
}
SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(DECLARE_CASE)
SIMPLIFIED_SPECULATIVE_BIGINT_BINOP_LIST(DECLARE_CASE)
#undef DECLARE_CASE
#define DECLARE_CASE(Name) \
......@@ -2624,6 +2625,12 @@ class RepresentationSelector {
SetOutput(node, MachineRepresentation::kTaggedPointer);
return;
}
case IrOpcode::kSpeculativeBigIntAdd: {
const auto& p = BigIntOperationParametersOf(node->op());
VisitBinop(node, UseInfo::CheckedBigIntAsTaggedPointer(p.feedback()),
MachineRepresentation::kTaggedPointer);
return;
}
case IrOpcode::kStringConcat: {
// TODO(turbofan): We currently depend on having this first length input
// to make sure that the overflow check is properly scheduled before the
......
......@@ -492,6 +492,37 @@ Handle<Map> FastMapParameterOf(const Operator* op) {
return Handle<Map>::null();
}
std::ostream& operator<<(std::ostream& os, BigIntOperationHint hint) {
switch (hint) {
case BigIntOperationHint::kBigInt:
return os << "BigInt";
}
UNREACHABLE();
}
size_t hash_value(BigIntOperationHint hint) {
return static_cast<uint8_t>(hint);
}
bool operator==(const BigIntOperationParameters& lhs,
const BigIntOperationParameters& rhs) {
return lhs.hint() == rhs.hint() && lhs.feedback() == rhs.feedback();
}
size_t hash_value(const BigIntOperationParameters& p) {
return base::hash_combine(p.hint(), p.feedback());
}
std::ostream& operator<<(std::ostream& os, const BigIntOperationParameters& p) {
return os << p.hint() << " " << p.feedback();
}
const BigIntOperationParameters& BigIntOperationParametersOf(
const Operator* op) {
DCHECK_EQ(IrOpcode::kSpeculativeBigIntAdd, op->opcode());
return OpParameter<BigIntOperationParameters>(op);
}
std::ostream& operator<<(std::ostream& os, NumberOperationHint hint) {
switch (hint) {
case NumberOperationHint::kSignedSmall:
......@@ -809,6 +840,7 @@ bool operator==(CheckMinusZeroParameters const& lhs,
V(CheckedTaggedToTaggedSigned, 1, 1) \
V(CheckedCompressedToTaggedPointer, 1, 1) \
V(CheckedCompressedToTaggedSigned, 1, 1) \
V(CheckedTaggedToBigInt, 1, 1) \
V(CheckedTaggedToCompressedPointer, 1, 1) \
V(CheckedTaggedToCompressedSigned, 1, 1) \
V(CheckedUint32ToInt32, 1, 1) \
......@@ -1433,6 +1465,14 @@ const Operator* SimplifiedOperatorBuilder::CheckFloat64Hole(
CheckFloat64HoleParameters(mode, feedback));
}
const Operator* SimplifiedOperatorBuilder::SpeculativeBigIntAdd(
BigIntOperationHint hint, const VectorSlotPair& feedback) {
return new (zone()) Operator1<BigIntOperationParameters>(
IrOpcode::kSpeculativeBigIntAdd, Operator::kFoldable | Operator::kNoThrow,
"SpeculativeBigIntAdd", 2, 1, 1, 1, 1, 0,
BigIntOperationParameters{hint, feedback});
}
const Operator* SimplifiedOperatorBuilder::SpeculativeToNumber(
NumberOperationHint hint, const VectorSlotPair& feedback) {
if (!feedback.IsValid()) {
......
......@@ -475,13 +475,40 @@ enum class NumberOperationHint : uint8_t {
kNumberOrOddball, // Inputs were Number or Oddball, output was Number.
};
enum class BigIntOperationHint : uint8_t {
kBigInt,
};
size_t hash_value(NumberOperationHint);
size_t hash_value(BigIntOperationHint);
V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, NumberOperationHint);
V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, BigIntOperationHint);
V8_EXPORT_PRIVATE NumberOperationHint NumberOperationHintOf(const Operator* op)
V8_WARN_UNUSED_RESULT;
class BigIntOperationParameters {
public:
BigIntOperationParameters(BigIntOperationHint hint,
const VectorSlotPair& feedback)
: hint_(hint), feedback_(feedback) {}
BigIntOperationHint hint() const { return hint_; }
const VectorSlotPair& feedback() const { return feedback_; }
private:
BigIntOperationHint hint_;
VectorSlotPair feedback_;
};
size_t hash_value(const BigIntOperationParameters&);
V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&,
const BigIntOperationParameters&);
bool operator==(const BigIntOperationParameters& lhs,
const BigIntOperationParameters& rhs);
const BigIntOperationParameters& BigIntOperationParametersOf(const Operator* op)
V8_WARN_UNUSED_RESULT;
class NumberOperationParameters {
public:
NumberOperationParameters(NumberOperationHint hint,
......@@ -653,6 +680,9 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
const Operator* SpeculativeNumberLessThanOrEqual(NumberOperationHint hint);
const Operator* SpeculativeNumberEqual(NumberOperationHint hint);
const Operator* SpeculativeBigIntAdd(BigIntOperationHint hint,
const VectorSlotPair& feedback);
const Operator* ReferenceEqual();
const Operator* SameValue();
const Operator* SameValueNumbersOnly();
......@@ -752,6 +782,7 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
const VectorSlotPair& feedback);
const Operator* CheckedTaggedToTaggedPointer(const VectorSlotPair& feedback);
const Operator* CheckedTaggedToTaggedSigned(const VectorSlotPair& feedback);
const Operator* CheckedTaggedToBigInt(const VectorSlotPair& feedback);
const Operator* CheckedCompressedToTaggedPointer(
const VectorSlotPair& feedback);
const Operator* CheckedCompressedToTaggedSigned(
......
......@@ -92,6 +92,7 @@ class Typer::Visitor : public Reducer {
return UpdateType(node, TypeBinaryOp(node, x));
SIMPLIFIED_NUMBER_BINOP_LIST(DECLARE_CASE)
SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(DECLARE_CASE)
SIMPLIFIED_SPECULATIVE_BIGINT_BINOP_LIST(DECLARE_CASE)
#undef DECLARE_CASE
#define DECLARE_CASE(x) \
......@@ -158,6 +159,7 @@ class Typer::Visitor : public Reducer {
return TypeBinaryOp(node, x);
SIMPLIFIED_NUMBER_BINOP_LIST(DECLARE_CASE)
SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(DECLARE_CASE)
SIMPLIFIED_SPECULATIVE_BIGINT_BINOP_LIST(DECLARE_CASE)
#undef DECLARE_CASE
#define DECLARE_CASE(x) \
......@@ -284,6 +286,7 @@ class Typer::Visitor : public Reducer {
}
SIMPLIFIED_NUMBER_BINOP_LIST(DECLARE_METHOD)
SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(DECLARE_METHOD)
SIMPLIFIED_SPECULATIVE_BIGINT_BINOP_LIST(DECLARE_METHOD)
#undef DECLARE_METHOD
static Type ObjectIsArrayBufferView(Type, Typer*);
......
......@@ -976,6 +976,9 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
case IrOpcode::kSpeculativeNumberLessThanOrEqual:
CheckTypeIs(node, Type::Boolean());
break;
case IrOpcode::kSpeculativeBigIntAdd:
CheckTypeIs(node, Type::BigInt());
break;
case IrOpcode::kNumberAdd:
case IrOpcode::kNumberSubtract:
case IrOpcode::kNumberMultiply:
......@@ -1522,6 +1525,10 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
case IrOpcode::kCheckedTaggedToCompressedPointer:
case IrOpcode::kCheckedTruncateTaggedToWord32:
break;
case IrOpcode::kCheckedTaggedToBigInt:
CheckValueInputIs(node, 0, Type::Any());
CheckTypeIs(node, Type::BigInt());
break;
case IrOpcode::kCheckFloat64Hole:
CheckValueInputIs(node, 0, Type::NumberOrHole());
......
......@@ -12,6 +12,7 @@ namespace internal {
#define DEOPTIMIZE_REASON_LIST(V) \
V(ArrayBufferWasDetached, "array buffer was detached") \
V(BigIntTooBig, "BigInt too big") \
V(CowArrayElementsChanged, "copy-on-write array's elements changed") \
V(CouldNotGrowElements, "failed to grow elements store") \
V(DeoptimizeNow, "%_DeoptimizeNow") \
......
......@@ -4006,10 +4006,21 @@ void TranslatedState::VerifyMaterializedObjects() {
bool TranslatedState::DoUpdateFeedback() {
if (!feedback_vector_handle_.is_null()) {
CHECK(!feedback_slot_.IsInvalid());
isolate()->CountUsage(v8::Isolate::kDeoptimizerDisableSpeculation);
FeedbackNexus nexus(feedback_vector_handle_, feedback_slot_);
nexus.SetSpeculationMode(SpeculationMode::kDisallowSpeculation);
return true;
const auto kind = feedback_vector_handle_->GetKind(feedback_slot_);
if (kind == FeedbackSlotKind::kCall) {
isolate()->CountUsage(v8::Isolate::kDeoptimizerDisableSpeculation);
nexus.SetSpeculationMode(SpeculationMode::kDisallowSpeculation);
return true;
} else if (kind == FeedbackSlotKind::kBinaryOp) {
// To prevent a deopt loop for binary operations (like speculative
// addition of BigInts), we generalize feedback to Any.
return nexus.SetBinaryOpFeedbackToAny();
} else {
UNREACHABLE();
}
}
return false;
}
......
......@@ -894,6 +894,16 @@ float FeedbackNexus::ComputeCallFrequency() {
return static_cast<float>(call_count / invocation_count);
}
bool FeedbackNexus::SetBinaryOpFeedbackToAny() {
DCHECK_EQ(kind(), FeedbackSlotKind::kBinaryOp);
int feedback = GetFeedback().ToSmi().value();
if (feedback == BinaryOperationFeedback::kAny) {
return false;
}
SetFeedback(Smi::FromInt(BinaryOperationFeedback::kAny));
return true;
}
void FeedbackNexus::ConfigureMonomorphic(Handle<Name> name,
Handle<Map> receiver_map,
const MaybeObjectHandle& handler) {
......
......@@ -669,6 +669,7 @@ class V8_EXPORT_PRIVATE FeedbackNexus final {
inline Isolate* GetIsolate() const;
bool SetBinaryOpFeedbackToAny();
void ConfigureMonomorphic(Handle<Name> name, Handle<Map> receiver_map,
const MaybeObjectHandle& handler);
......
// 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
const big = 2n ** BigInt((2 ** 30)-1);
function testAdd(x, y) {
return x + y;
}
%PrepareFunctionForOptimization(testAdd);
testAdd(3n, 7n);
testAdd(17n, -54n);
%OptimizeFunctionOnNextCall(testAdd);
assertEquals(testAdd(6n, 2n), 8n);
assertOptimized(testAdd);
assertThrows(() => testAdd(big, big), RangeError);
assertUnoptimized(testAdd);
%PrepareFunctionForOptimization(testAdd);
testAdd(30n, -50n);
testAdd(23n, 5n);
%OptimizeFunctionOnNextCall(testAdd);
assertEquals(testAdd(-7n, -12n), -19n);
assertOptimized(testAdd);
assertThrows(() => testAdd(big, big), RangeError);
assertOptimized(testAdd);
assertThrows(() => testAdd(big, big), RangeError);
assertOptimized(testAdd);
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