[turbofan] Inline BigInt Constructor for Integral32 input

This CL introduces two JS operators JSToBigInt and
JSToBigIntConvertNumber and one simplified operator
Integral32OrMinusZeroToBigInt.

- BigInt constructors are lowered to JSToBigIntConvertNumber in the
  inlining phase.
- JSToBigIntConvertNumber is replaced with
  Integral32OrMinusZeroToBigInt if the input is typed as Integral32
  in typed lowering.
- In simplified lowering, Integral32OrMinusZeroToBigInt is lowered
  to conversion to word64 accordingly.
- If the input is not Integral32 or BigInt, JSToBigIntConvertNumber
  is lowered to a builtin call in generic lowering.

Bug: v8:9407
Change-Id: I8539d742e82cce515bd9350797f5f9b0876ee6f2
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4055670
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Reviewed-by: Nico Hartmann <nicohartmann@chromium.org>
Commit-Queue: Qifan Pan <panq@google.com>
Cr-Commit-Position: refs/heads/main@{#84761}
This commit is contained in:
Qifan Pan 2022-12-07 12:05:09 +01:00 committed by V8 LUCI CQ
parent 458cda96fe
commit 753584c74b
26 changed files with 459 additions and 128 deletions

View File

@ -21,6 +21,13 @@ TF_BUILTIN(ToNumber, CodeStubAssembler) {
Return(ToNumber(context, input));
}
TF_BUILTIN(ToBigInt, CodeStubAssembler) {
auto context = Parameter<Context>(Descriptor::kContext);
auto input = Parameter<Object>(Descriptor::kArgument);
Return(ToBigInt(context, input));
}
TF_BUILTIN(ToNumber_Baseline, CodeStubAssembler) {
auto input = Parameter<Object>(Descriptor::kArgument);
auto slot = UncheckedParameter<UintPtrT>(Descriptor::kSlot);
@ -63,6 +70,13 @@ TF_BUILTIN(ToNumberConvertBigInt, CodeStubAssembler) {
Return(ToNumber(context, input, BigIntHandling::kConvertToNumber));
}
TF_BUILTIN(ToBigIntConvertNumber, CodeStubAssembler) {
auto context = Parameter<Context>(Descriptor::kContext);
auto input = Parameter<Object>(Descriptor::kArgument);
Return(ToBigIntConvertNumber(context, input));
}
// ES6 section 7.1.2 ToBoolean ( argument )
// Requires parameter on stack so that it can be used as a continuation from a
// LAZY deopt.

View File

@ -257,10 +257,12 @@ namespace internal {
\
/* Type conversions */ \
TFC(ToNumber, TypeConversion) \
TFC(ToBigInt, TypeConversion) \
TFC(ToNumber_Baseline, TypeConversion_Baseline) \
TFC(ToNumeric_Baseline, TypeConversion_Baseline) \
TFC(PlainPrimitiveToNumber, TypeConversionNoContext) \
TFC(ToNumberConvertBigInt, TypeConversion) \
TFC(ToBigIntConvertNumber, TypeConversion) \
TFC(Typeof, Typeof) \
TFC(BigIntToI64, BigIntToI64) \
TFC(BigIntToI32Pair, BigIntToI32Pair) \

View File

@ -7960,6 +7960,28 @@ TNode<BigInt> CodeStubAssembler::ToBigInt(TNode<Context> context,
return var_result.value();
}
TNode<BigInt> CodeStubAssembler::ToBigIntConvertNumber(TNode<Context> context,
TNode<Object> input) {
TVARIABLE(BigInt, var_result);
Label if_bigint(this), if_not_bigint(this), done(this);
GotoIf(TaggedIsSmi(input), &if_not_bigint);
GotoIf(IsBigInt(CAST(input)), &if_bigint);
Goto(&if_not_bigint);
BIND(&if_bigint);
var_result = CAST(input);
Goto(&done);
BIND(&if_not_bigint);
var_result =
CAST(CallRuntime(Runtime::kToBigIntConvertNumber, context, input));
Goto(&done);
BIND(&done);
return var_result.value();
}
void CodeStubAssembler::TaggedToBigIntWithFeedback(
TNode<Context> context, TNode<Object> value, Label* if_not_bigint,
Label* if_bigint, Label* if_bigint64, TVariable<BigInt>* var_bigint,

View File

@ -2871,6 +2871,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
// Try to convert an object to a BigInt. Throws on failure (e.g. for Numbers).
// https://tc39.github.io/proposal-bigint/#sec-to-bigint
TNode<BigInt> ToBigInt(TNode<Context> context, TNode<Object> input);
// Try to convert any object to a BigInt, including Numbers.
TNode<BigInt> ToBigIntConvertNumber(TNode<Context> context,
TNode<Object> input);
// Converts |input| to one of 2^32 integer values in the range 0 through
// 2^32-1, inclusive.

View File

@ -3144,7 +3144,7 @@ Node* EffectControlLinearizer::LowerChangeInt64ToBigInt(Node* node) {
Node* bitfield =
__ Word32Or(__ Int32Constant(BigInt::LengthBits::encode(1)), sign);
// We use (value XOR (value >>> 63)) - (value >>> 63) to compute the
// We use (value XOR (value >> 63)) - (value >> 63) to compute the
// absolute value, in a branchless fashion.
Node* sign_mask = __ Word64Sar(value, __ Int64Constant(63));
Node* absolute_value = __ Int64Sub(__ Word64Xor(value, sign_mask), sign_mask);

View File

@ -4892,6 +4892,8 @@ Reduction JSCallReducer::ReduceJSCall(Node* node,
return ReduceDateNow(node);
case Builtin::kNumberConstructor:
return ReduceNumberConstructor(node);
case Builtin::kBigIntConstructor:
return ReduceBigIntConstructor(node);
case Builtin::kBigIntAsIntN:
case Builtin::kBigIntAsUintN:
return ReduceBigIntAsN(node, builtin);
@ -8328,6 +8330,39 @@ Reduction JSCallReducer::ReduceNumberConstructor(Node* node) {
return Changed(node);
}
// ES section #sec-bigint-constructor
Reduction JSCallReducer::ReduceBigIntConstructor(Node* node) {
if (!jsgraph()->machine()->Is64()) return NoChange();
JSCallNode n(node);
if (n.ArgumentCount() < 1) {
return NoChange();
}
Node* target = n.target();
Node* receiver = n.receiver();
Node* value = n.Argument(0);
Node* context = n.context();
FrameState frame_state = n.frame_state();
// Create the artificial frame state in the middle of the BigInt constructor.
SharedFunctionInfoRef shared_info =
native_context().bigint_function().shared();
Node* stack_parameters[] = {receiver};
int stack_parameter_count = arraysize(stack_parameters);
Node* continuation_frame_state =
CreateJavaScriptBuiltinContinuationFrameState(
jsgraph(), shared_info, Builtin::kGenericLazyDeoptContinuation,
target, context, stack_parameters, stack_parameter_count, frame_state,
ContinuationFrameStateMode::LAZY);
// Convert the {value} to a BigInt.
NodeProperties::ReplaceValueInputs(node, value);
NodeProperties::ChangeOp(node, javascript()->ToBigIntConvertNumber());
NodeProperties::ReplaceFrameStateInput(node, continuation_frame_state);
return Changed(node);
}
Reduction JSCallReducer::ReduceBigIntAsN(Node* node, Builtin builtin) {
DCHECK(builtin == Builtin::kBigIntAsIntN ||
builtin == Builtin::kBigIntAsUintN);

View File

@ -231,6 +231,7 @@ class V8_EXPORT_PRIVATE JSCallReducer final : public AdvancedReducer {
Reduction ReduceNumberParseInt(Node* node);
Reduction ReduceNumberConstructor(Node* node);
Reduction ReduceBigIntConstructor(Node* node);
Reduction ReduceBigIntAsN(Node* node, Builtin builtin);
base::Optional<Reduction> TryReduceJSCallMathMinMaxWithArrayLike(Node* node);

View File

@ -63,6 +63,8 @@ Reduction JSGenericLowering::Reduce(Node* node) {
REPLACE_STUB_CALL(ToLength)
REPLACE_STUB_CALL(ToNumber)
REPLACE_STUB_CALL(ToNumberConvertBigInt)
REPLACE_STUB_CALL(ToBigInt)
REPLACE_STUB_CALL(ToBigIntConvertNumber)
REPLACE_STUB_CALL(ToNumeric)
REPLACE_STUB_CALL(ToName)
REPLACE_STUB_CALL(ToObject)

View File

@ -741,6 +741,8 @@ Type JSWasmCallNode::TypeForWasmReturnType(const wasm::ValueType& type) {
V(ToName, Operator::kNoProperties, 1, 1) \
V(ToNumber, Operator::kNoProperties, 1, 1) \
V(ToNumberConvertBigInt, Operator::kNoProperties, 1, 1) \
V(ToBigInt, Operator::kNoProperties, 1, 1) \
V(ToBigIntConvertNumber, Operator::kNoProperties, 1, 1) \
V(ToNumeric, Operator::kNoProperties, 1, 1) \
V(ToObject, Operator::kFoldable, 1, 1) \
V(ToString, Operator::kNoProperties, 1, 1) \

View File

@ -935,6 +935,8 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final
const Operator* ToName();
const Operator* ToNumber();
const Operator* ToNumberConvertBigInt();
const Operator* ToBigInt();
const Operator* ToBigIntConvertNumber();
const Operator* ToNumeric();
const Operator* ToObject();
const Operator* ToString();

View File

@ -1044,6 +1044,37 @@ Reduction JSTypedLowering::ReduceJSToNumber(Node* node) {
return NoChange();
}
Reduction JSTypedLowering::ReduceJSToBigInt(Node* node) {
// TODO(panq): Reduce constant inputs.
Node* const input = node->InputAt(0);
Type const input_type = NodeProperties::GetType(input);
if (input_type.Is(Type::BigInt())) {
ReplaceWithValue(node, input);
return Changed(input);
}
return NoChange();
}
Reduction JSTypedLowering::ReduceJSToBigIntConvertNumber(Node* node) {
// TODO(panq): Reduce constant inputs.
Node* const input = node->InputAt(0);
Type const input_type = NodeProperties::GetType(input);
if (input_type.Is(Type::BigInt())) {
ReplaceWithValue(node, input);
return Changed(input);
} else if (input_type.Is(Type::Integral32OrMinusZero())) {
RelaxEffectsAndControls(node);
node->TrimInputCount(1);
Type node_type = NodeProperties::GetType(node);
NodeProperties::SetType(
node, Type::Intersect(node_type, Type::BigInt(), graph()->zone()));
NodeProperties::ChangeOp(node,
simplified()->Integral32OrMinusZeroToBigInt());
return Changed(node);
}
return NoChange();
}
Reduction JSTypedLowering::ReduceJSToNumeric(Node* node) {
Node* const input = NodeProperties::GetValueInput(node, 0);
Type const input_type = NodeProperties::GetType(input);
@ -2395,6 +2426,10 @@ Reduction JSTypedLowering::Reduce(Node* node) {
case IrOpcode::kJSToNumber:
case IrOpcode::kJSToNumberConvertBigInt:
return ReduceJSToNumber(node);
case IrOpcode::kJSToBigInt:
return ReduceJSToBigInt(node);
case IrOpcode::kJSToBigIntConvertNumber:
return ReduceJSToBigIntConvertNumber(node);
case IrOpcode::kJSToNumeric:
return ReduceJSToNumeric(node);
case IrOpcode::kJSToString:

View File

@ -61,6 +61,8 @@ class V8_EXPORT_PRIVATE JSTypedLowering final
Reduction ReduceJSToName(Node* node);
Reduction ReduceJSToNumberInput(Node* input);
Reduction ReduceJSToNumber(Node* node);
Reduction ReduceJSToBigInt(Node* node);
Reduction ReduceJSToBigIntConvertNumber(Node* node);
Reduction ReduceJSToNumeric(Node* node);
Reduction ReduceJSToStringInput(Node* input);
Reduction ReduceJSToString(Node* node);

View File

@ -133,6 +133,8 @@
V(JSToName) \
V(JSToNumber) \
V(JSToNumberConvertBigInt) \
V(JSToBigInt) \
V(JSToBigIntConvertNumber) \
V(JSToNumeric) \
V(JSToObject) \
V(JSToString) \
@ -409,6 +411,7 @@
V(NumberToString) \
V(NumberToUint32) \
V(NumberToUint8Clamped) \
V(Integral32OrMinusZeroToBigInt) \
V(NumberSilenceNaN)
#define SIMPLIFIED_BIGINT_UNOP_LIST(V) \

View File

@ -310,6 +310,27 @@ Type OperationTyper::ToNumberConvertBigInt(Type type) {
return maybe_bigint ? Type::Union(type, cache_->kInteger, zone()) : type;
}
Type OperationTyper::ToBigInt(Type type) {
if (type.Is(Type::BigInt())) {
return type;
}
return Type::BigInt();
}
Type OperationTyper::ToBigIntConvertNumber(Type type) {
if (type.Is(Type::Signed32OrMinusZero())) {
return Type::SignedBigInt64();
} else if (type.Is(Type::Unsigned32OrMinusZero())) {
return Type::UnsignedBigInt63();
}
bool maybe_number =
type.Maybe(Type::Number()) || type.Maybe(Type::Receiver());
type = ToBigInt(Type::Intersect(type, Type::NonNumber(), zone()));
return maybe_number ? Type::Union(type, Type::BigInt(), zone()) : type;
}
Type OperationTyper::ToNumeric(Type type) {
// If the {type} includes any receivers, then the callbacks
// might actually produce BigInt primitive values here.
@ -566,6 +587,18 @@ Type OperationTyper::NumberToUint8Clamped(Type type) {
return cache_->kUint8;
}
Type OperationTyper::Integral32OrMinusZeroToBigInt(Type type) {
DCHECK(type.Is(Type::Number()));
if (type.Is(Type::Signed32())) {
return Type::SignedBigInt64();
}
if (type.Is(Type::Unsigned32())) {
return Type::UnsignedBigInt63();
}
return Type::BigInt();
}
Type OperationTyper::NumberSilenceNaN(Type type) {
DCHECK(type.Is(Type::Number()));
// TODO(jarin): This is a terrible hack; we definitely need a dedicated type

View File

@ -54,6 +54,8 @@ class V8_EXPORT_PRIVATE OperationTyper {
Type ToPrimitive(Type type);
Type ToNumber(Type type);
Type ToNumberConvertBigInt(Type type);
Type ToBigInt(Type type);
Type ToBigIntConvertNumber(Type type);
Type ToNumeric(Type type);
Type ToBoolean(Type type);

View File

@ -213,6 +213,8 @@ bool OperatorProperties::HasFrameStateInput(const Operator* op) {
case IrOpcode::kJSToName:
case IrOpcode::kJSToNumber:
case IrOpcode::kJSToNumberConvertBigInt:
case IrOpcode::kJSToBigInt:
case IrOpcode::kJSToBigIntConvertNumber:
case IrOpcode::kJSToNumeric:
case IrOpcode::kJSToObject:
case IrOpcode::kJSToString:

View File

@ -1252,7 +1252,10 @@ Node* RepresentationChanger::GetWord64RepresentationFor(
use_node, use_info);
op = simplified()->TruncateBigIntToWord64();
} else if (CanBeTaggedPointer(output_rep)) {
if (output_type.Is(cache_->kDoubleRepresentableInt64)) {
if (output_type.Is(cache_->kDoubleRepresentableInt64) ||
(output_type.Is(Type::MinusZero()) &&
use_info.minus_zero_check() ==
CheckForMinusZeroMode::kDontCheckForMinusZero)) {
op = simplified()->ChangeTaggedToInt64();
} else if (use_info.type_check() == TypeCheckKind::kSigned64) {
op = simplified()->CheckedTaggedToInt64(

View File

@ -2274,6 +2274,12 @@ class RepresentationSelector {
}
return;
}
case IrOpcode::kJSToBigInt:
case IrOpcode::kJSToBigIntConvertNumber: {
VisitInputs<T>(node);
SetOutput<T>(node, MachineRepresentation::kTaggedPointer);
return;
}
//------------------------------------------------------------------
// Simplified operators.
@ -3199,6 +3205,16 @@ class RepresentationSelector {
}
return;
}
case IrOpcode::kIntegral32OrMinusZeroToBigInt: {
VisitUnop<T>(node, UseInfo::Word64(kIdentifyZeros),
MachineRepresentation::kWord64);
if (lower<T>()) {
DeferReplacement(
node, InsertTypeOverrideForVerifier(NodeProperties::GetType(node),
node->InputAt(0)));
}
return;
}
case IrOpcode::kReferenceEqual: {
VisitBinop<T>(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
if (lower<T>()) {

View File

@ -683,129 +683,130 @@ bool operator==(CheckMinusZeroParameters const& lhs,
return lhs.mode() == rhs.mode() && lhs.feedback() == rhs.feedback();
}
#define PURE_OP_LIST(V) \
V(BooleanNot, Operator::kNoProperties, 1, 0) \
V(NumberEqual, Operator::kCommutative, 2, 0) \
V(NumberLessThan, Operator::kNoProperties, 2, 0) \
V(NumberLessThanOrEqual, Operator::kNoProperties, 2, 0) \
V(NumberAdd, Operator::kCommutative, 2, 0) \
V(NumberSubtract, Operator::kNoProperties, 2, 0) \
V(NumberMultiply, Operator::kCommutative, 2, 0) \
V(NumberDivide, Operator::kNoProperties, 2, 0) \
V(NumberModulus, Operator::kNoProperties, 2, 0) \
V(NumberBitwiseOr, Operator::kCommutative, 2, 0) \
V(NumberBitwiseXor, Operator::kCommutative, 2, 0) \
V(NumberBitwiseAnd, Operator::kCommutative, 2, 0) \
V(NumberShiftLeft, Operator::kNoProperties, 2, 0) \
V(NumberShiftRight, Operator::kNoProperties, 2, 0) \
V(NumberShiftRightLogical, Operator::kNoProperties, 2, 0) \
V(NumberImul, Operator::kCommutative, 2, 0) \
V(NumberAbs, Operator::kNoProperties, 1, 0) \
V(NumberClz32, Operator::kNoProperties, 1, 0) \
V(NumberCeil, Operator::kNoProperties, 1, 0) \
V(NumberFloor, Operator::kNoProperties, 1, 0) \
V(NumberFround, Operator::kNoProperties, 1, 0) \
V(NumberAcos, Operator::kNoProperties, 1, 0) \
V(NumberAcosh, Operator::kNoProperties, 1, 0) \
V(NumberAsin, Operator::kNoProperties, 1, 0) \
V(NumberAsinh, Operator::kNoProperties, 1, 0) \
V(NumberAtan, Operator::kNoProperties, 1, 0) \
V(NumberAtan2, Operator::kNoProperties, 2, 0) \
V(NumberAtanh, Operator::kNoProperties, 1, 0) \
V(NumberCbrt, Operator::kNoProperties, 1, 0) \
V(NumberCos, Operator::kNoProperties, 1, 0) \
V(NumberCosh, Operator::kNoProperties, 1, 0) \
V(NumberExp, Operator::kNoProperties, 1, 0) \
V(NumberExpm1, Operator::kNoProperties, 1, 0) \
V(NumberLog, Operator::kNoProperties, 1, 0) \
V(NumberLog1p, Operator::kNoProperties, 1, 0) \
V(NumberLog10, Operator::kNoProperties, 1, 0) \
V(NumberLog2, Operator::kNoProperties, 1, 0) \
V(NumberMax, Operator::kNoProperties, 2, 0) \
V(NumberMin, Operator::kNoProperties, 2, 0) \
V(NumberPow, Operator::kNoProperties, 2, 0) \
V(NumberRound, Operator::kNoProperties, 1, 0) \
V(NumberSign, Operator::kNoProperties, 1, 0) \
V(NumberSin, Operator::kNoProperties, 1, 0) \
V(NumberSinh, Operator::kNoProperties, 1, 0) \
V(NumberSqrt, Operator::kNoProperties, 1, 0) \
V(NumberTan, Operator::kNoProperties, 1, 0) \
V(NumberTanh, Operator::kNoProperties, 1, 0) \
V(NumberTrunc, Operator::kNoProperties, 1, 0) \
V(NumberToBoolean, Operator::kNoProperties, 1, 0) \
V(NumberToInt32, Operator::kNoProperties, 1, 0) \
V(NumberToString, Operator::kNoProperties, 1, 0) \
V(NumberToUint32, Operator::kNoProperties, 1, 0) \
V(NumberToUint8Clamped, Operator::kNoProperties, 1, 0) \
V(NumberSilenceNaN, Operator::kNoProperties, 1, 0) \
V(BigIntNegate, Operator::kNoProperties, 1, 0) \
V(StringConcat, Operator::kNoProperties, 3, 0) \
V(StringToNumber, Operator::kNoProperties, 1, 0) \
V(StringFromSingleCharCode, Operator::kNoProperties, 1, 0) \
V(StringFromSingleCodePoint, Operator::kNoProperties, 1, 0) \
V(StringIndexOf, Operator::kNoProperties, 3, 0) \
V(StringLength, Operator::kNoProperties, 1, 0) \
V(StringToLowerCaseIntl, Operator::kNoProperties, 1, 0) \
V(StringToUpperCaseIntl, Operator::kNoProperties, 1, 0) \
V(TypeOf, Operator::kNoProperties, 1, 1) \
V(PlainPrimitiveToNumber, Operator::kNoProperties, 1, 0) \
V(PlainPrimitiveToWord32, Operator::kNoProperties, 1, 0) \
V(PlainPrimitiveToFloat64, Operator::kNoProperties, 1, 0) \
V(ChangeTaggedSignedToInt32, Operator::kNoProperties, 1, 0) \
V(ChangeTaggedSignedToInt64, Operator::kNoProperties, 1, 0) \
V(ChangeTaggedToInt32, Operator::kNoProperties, 1, 0) \
V(ChangeTaggedToInt64, Operator::kNoProperties, 1, 0) \
V(ChangeTaggedToUint32, Operator::kNoProperties, 1, 0) \
V(ChangeTaggedToFloat64, Operator::kNoProperties, 1, 0) \
V(ChangeTaggedToTaggedSigned, Operator::kNoProperties, 1, 0) \
V(ChangeFloat64ToTaggedPointer, Operator::kNoProperties, 1, 0) \
V(ChangeInt31ToTaggedSigned, Operator::kNoProperties, 1, 0) \
V(ChangeInt32ToTagged, Operator::kNoProperties, 1, 0) \
V(ChangeInt64ToTagged, Operator::kNoProperties, 1, 0) \
V(ChangeUint32ToTagged, Operator::kNoProperties, 1, 0) \
V(ChangeUint64ToTagged, Operator::kNoProperties, 1, 0) \
V(ChangeTaggedToBit, Operator::kNoProperties, 1, 0) \
V(ChangeBitToTagged, Operator::kNoProperties, 1, 0) \
V(TruncateBigIntToWord64, Operator::kNoProperties, 1, 0) \
V(ChangeInt64ToBigInt, Operator::kNoProperties, 1, 0) \
V(ChangeUint64ToBigInt, Operator::kNoProperties, 1, 0) \
V(TruncateTaggedToBit, Operator::kNoProperties, 1, 0) \
V(TruncateTaggedPointerToBit, Operator::kNoProperties, 1, 0) \
V(TruncateTaggedToWord32, Operator::kNoProperties, 1, 0) \
V(TruncateTaggedToFloat64, Operator::kNoProperties, 1, 0) \
V(ObjectIsArrayBufferView, Operator::kNoProperties, 1, 0) \
V(ObjectIsBigInt, Operator::kNoProperties, 1, 0) \
V(ObjectIsCallable, Operator::kNoProperties, 1, 0) \
V(ObjectIsConstructor, Operator::kNoProperties, 1, 0) \
V(ObjectIsDetectableCallable, Operator::kNoProperties, 1, 0) \
V(ObjectIsMinusZero, Operator::kNoProperties, 1, 0) \
V(NumberIsMinusZero, Operator::kNoProperties, 1, 0) \
V(ObjectIsNaN, Operator::kNoProperties, 1, 0) \
V(NumberIsNaN, Operator::kNoProperties, 1, 0) \
V(ObjectIsNonCallable, Operator::kNoProperties, 1, 0) \
V(ObjectIsNumber, Operator::kNoProperties, 1, 0) \
V(ObjectIsReceiver, Operator::kNoProperties, 1, 0) \
V(ObjectIsSmi, Operator::kNoProperties, 1, 0) \
V(ObjectIsString, Operator::kNoProperties, 1, 0) \
V(ObjectIsSymbol, Operator::kNoProperties, 1, 0) \
V(ObjectIsUndetectable, Operator::kNoProperties, 1, 0) \
V(NumberIsFloat64Hole, Operator::kNoProperties, 1, 0) \
V(NumberIsFinite, Operator::kNoProperties, 1, 0) \
V(ObjectIsFiniteNumber, Operator::kNoProperties, 1, 0) \
V(NumberIsInteger, Operator::kNoProperties, 1, 0) \
V(ObjectIsSafeInteger, Operator::kNoProperties, 1, 0) \
V(NumberIsSafeInteger, Operator::kNoProperties, 1, 0) \
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) \
V(StringLessThan, Operator::kNoProperties, 2, 0) \
V(StringLessThanOrEqual, Operator::kNoProperties, 2, 0) \
V(ToBoolean, Operator::kNoProperties, 1, 0) \
V(NewConsString, Operator::kNoProperties, 3, 0) \
#define PURE_OP_LIST(V) \
V(BooleanNot, Operator::kNoProperties, 1, 0) \
V(NumberEqual, Operator::kCommutative, 2, 0) \
V(NumberLessThan, Operator::kNoProperties, 2, 0) \
V(NumberLessThanOrEqual, Operator::kNoProperties, 2, 0) \
V(NumberAdd, Operator::kCommutative, 2, 0) \
V(NumberSubtract, Operator::kNoProperties, 2, 0) \
V(NumberMultiply, Operator::kCommutative, 2, 0) \
V(NumberDivide, Operator::kNoProperties, 2, 0) \
V(NumberModulus, Operator::kNoProperties, 2, 0) \
V(NumberBitwiseOr, Operator::kCommutative, 2, 0) \
V(NumberBitwiseXor, Operator::kCommutative, 2, 0) \
V(NumberBitwiseAnd, Operator::kCommutative, 2, 0) \
V(NumberShiftLeft, Operator::kNoProperties, 2, 0) \
V(NumberShiftRight, Operator::kNoProperties, 2, 0) \
V(NumberShiftRightLogical, Operator::kNoProperties, 2, 0) \
V(NumberImul, Operator::kCommutative, 2, 0) \
V(NumberAbs, Operator::kNoProperties, 1, 0) \
V(NumberClz32, Operator::kNoProperties, 1, 0) \
V(NumberCeil, Operator::kNoProperties, 1, 0) \
V(NumberFloor, Operator::kNoProperties, 1, 0) \
V(NumberFround, Operator::kNoProperties, 1, 0) \
V(NumberAcos, Operator::kNoProperties, 1, 0) \
V(NumberAcosh, Operator::kNoProperties, 1, 0) \
V(NumberAsin, Operator::kNoProperties, 1, 0) \
V(NumberAsinh, Operator::kNoProperties, 1, 0) \
V(NumberAtan, Operator::kNoProperties, 1, 0) \
V(NumberAtan2, Operator::kNoProperties, 2, 0) \
V(NumberAtanh, Operator::kNoProperties, 1, 0) \
V(NumberCbrt, Operator::kNoProperties, 1, 0) \
V(NumberCos, Operator::kNoProperties, 1, 0) \
V(NumberCosh, Operator::kNoProperties, 1, 0) \
V(NumberExp, Operator::kNoProperties, 1, 0) \
V(NumberExpm1, Operator::kNoProperties, 1, 0) \
V(NumberLog, Operator::kNoProperties, 1, 0) \
V(NumberLog1p, Operator::kNoProperties, 1, 0) \
V(NumberLog10, Operator::kNoProperties, 1, 0) \
V(NumberLog2, Operator::kNoProperties, 1, 0) \
V(NumberMax, Operator::kNoProperties, 2, 0) \
V(NumberMin, Operator::kNoProperties, 2, 0) \
V(NumberPow, Operator::kNoProperties, 2, 0) \
V(NumberRound, Operator::kNoProperties, 1, 0) \
V(NumberSign, Operator::kNoProperties, 1, 0) \
V(NumberSin, Operator::kNoProperties, 1, 0) \
V(NumberSinh, Operator::kNoProperties, 1, 0) \
V(NumberSqrt, Operator::kNoProperties, 1, 0) \
V(NumberTan, Operator::kNoProperties, 1, 0) \
V(NumberTanh, Operator::kNoProperties, 1, 0) \
V(NumberTrunc, Operator::kNoProperties, 1, 0) \
V(NumberToBoolean, Operator::kNoProperties, 1, 0) \
V(NumberToInt32, Operator::kNoProperties, 1, 0) \
V(NumberToString, Operator::kNoProperties, 1, 0) \
V(NumberToUint32, Operator::kNoProperties, 1, 0) \
V(NumberToUint8Clamped, Operator::kNoProperties, 1, 0) \
V(Integral32OrMinusZeroToBigInt, Operator::kNoProperties, 1, 0) \
V(NumberSilenceNaN, Operator::kNoProperties, 1, 0) \
V(BigIntNegate, Operator::kNoProperties, 1, 0) \
V(StringConcat, Operator::kNoProperties, 3, 0) \
V(StringToNumber, Operator::kNoProperties, 1, 0) \
V(StringFromSingleCharCode, Operator::kNoProperties, 1, 0) \
V(StringFromSingleCodePoint, Operator::kNoProperties, 1, 0) \
V(StringIndexOf, Operator::kNoProperties, 3, 0) \
V(StringLength, Operator::kNoProperties, 1, 0) \
V(StringToLowerCaseIntl, Operator::kNoProperties, 1, 0) \
V(StringToUpperCaseIntl, Operator::kNoProperties, 1, 0) \
V(TypeOf, Operator::kNoProperties, 1, 1) \
V(PlainPrimitiveToNumber, Operator::kNoProperties, 1, 0) \
V(PlainPrimitiveToWord32, Operator::kNoProperties, 1, 0) \
V(PlainPrimitiveToFloat64, Operator::kNoProperties, 1, 0) \
V(ChangeTaggedSignedToInt32, Operator::kNoProperties, 1, 0) \
V(ChangeTaggedSignedToInt64, Operator::kNoProperties, 1, 0) \
V(ChangeTaggedToInt32, Operator::kNoProperties, 1, 0) \
V(ChangeTaggedToInt64, Operator::kNoProperties, 1, 0) \
V(ChangeTaggedToUint32, Operator::kNoProperties, 1, 0) \
V(ChangeTaggedToFloat64, Operator::kNoProperties, 1, 0) \
V(ChangeTaggedToTaggedSigned, Operator::kNoProperties, 1, 0) \
V(ChangeFloat64ToTaggedPointer, Operator::kNoProperties, 1, 0) \
V(ChangeInt31ToTaggedSigned, Operator::kNoProperties, 1, 0) \
V(ChangeInt32ToTagged, Operator::kNoProperties, 1, 0) \
V(ChangeInt64ToTagged, Operator::kNoProperties, 1, 0) \
V(ChangeUint32ToTagged, Operator::kNoProperties, 1, 0) \
V(ChangeUint64ToTagged, Operator::kNoProperties, 1, 0) \
V(ChangeTaggedToBit, Operator::kNoProperties, 1, 0) \
V(ChangeBitToTagged, Operator::kNoProperties, 1, 0) \
V(TruncateBigIntToWord64, Operator::kNoProperties, 1, 0) \
V(ChangeInt64ToBigInt, Operator::kNoProperties, 1, 0) \
V(ChangeUint64ToBigInt, Operator::kNoProperties, 1, 0) \
V(TruncateTaggedToBit, Operator::kNoProperties, 1, 0) \
V(TruncateTaggedPointerToBit, Operator::kNoProperties, 1, 0) \
V(TruncateTaggedToWord32, Operator::kNoProperties, 1, 0) \
V(TruncateTaggedToFloat64, Operator::kNoProperties, 1, 0) \
V(ObjectIsArrayBufferView, Operator::kNoProperties, 1, 0) \
V(ObjectIsBigInt, Operator::kNoProperties, 1, 0) \
V(ObjectIsCallable, Operator::kNoProperties, 1, 0) \
V(ObjectIsConstructor, Operator::kNoProperties, 1, 0) \
V(ObjectIsDetectableCallable, Operator::kNoProperties, 1, 0) \
V(ObjectIsMinusZero, Operator::kNoProperties, 1, 0) \
V(NumberIsMinusZero, Operator::kNoProperties, 1, 0) \
V(ObjectIsNaN, Operator::kNoProperties, 1, 0) \
V(NumberIsNaN, Operator::kNoProperties, 1, 0) \
V(ObjectIsNonCallable, Operator::kNoProperties, 1, 0) \
V(ObjectIsNumber, Operator::kNoProperties, 1, 0) \
V(ObjectIsReceiver, Operator::kNoProperties, 1, 0) \
V(ObjectIsSmi, Operator::kNoProperties, 1, 0) \
V(ObjectIsString, Operator::kNoProperties, 1, 0) \
V(ObjectIsSymbol, Operator::kNoProperties, 1, 0) \
V(ObjectIsUndetectable, Operator::kNoProperties, 1, 0) \
V(NumberIsFloat64Hole, Operator::kNoProperties, 1, 0) \
V(NumberIsFinite, Operator::kNoProperties, 1, 0) \
V(ObjectIsFiniteNumber, Operator::kNoProperties, 1, 0) \
V(NumberIsInteger, Operator::kNoProperties, 1, 0) \
V(ObjectIsSafeInteger, Operator::kNoProperties, 1, 0) \
V(NumberIsSafeInteger, Operator::kNoProperties, 1, 0) \
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) \
V(StringLessThan, Operator::kNoProperties, 2, 0) \
V(StringLessThanOrEqual, Operator::kNoProperties, 2, 0) \
V(ToBoolean, Operator::kNoProperties, 1, 0) \
V(NewConsString, Operator::kNoProperties, 3, 0) \
V(Unsigned32Divide, Operator::kNoProperties, 2, 0)
#define EFFECT_DEPENDENT_OP_LIST(V) \

View File

@ -779,6 +779,7 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
const Operator* NumberToString();
const Operator* NumberToUint32();
const Operator* NumberToUint8Clamped();
const Operator* Integral32OrMinusZeroToBigInt();
const Operator* NumberSilenceNaN();

View File

@ -341,6 +341,8 @@ class Typer::Visitor : public Reducer {
static Type ToName(Type, Typer*);
static Type ToNumber(Type, Typer*);
static Type ToNumberConvertBigInt(Type, Typer*);
static Type ToBigInt(Type, Typer*);
static Type ToBigIntConvertNumber(Type, Typer*);
static Type ToNumeric(Type, Typer*);
static Type ToObject(Type, Typer*);
static Type ToString(Type, Typer*);
@ -674,6 +676,16 @@ Type Typer::Visitor::ToNumberConvertBigInt(Type type, Typer* t) {
return t->operation_typer_.ToNumberConvertBigInt(type);
}
// static
Type Typer::Visitor::ToBigInt(Type type, Typer* t) {
return t->operation_typer_.ToBigInt(type);
}
// static
Type Typer::Visitor::ToBigIntConvertNumber(Type type, Typer* t) {
return t->operation_typer_.ToBigIntConvertNumber(type);
}
// static
Type Typer::Visitor::ToNumeric(Type type, Typer* t) {
return t->operation_typer_.ToNumeric(type);
@ -1361,6 +1373,8 @@ DEFINE_METHOD(ToLength)
DEFINE_METHOD(ToName)
DEFINE_METHOD(ToNumber)
DEFINE_METHOD(ToNumberConvertBigInt)
DEFINE_METHOD(ToBigInt)
DEFINE_METHOD(ToBigIntConvertNumber)
DEFINE_METHOD(ToNumeric)
DEFINE_METHOD(ToObject)
DEFINE_METHOD(ToString)

View File

@ -200,8 +200,9 @@ class UseInfo {
return UseInfo(MachineRepresentation::kWord64, Truncation::Any(),
TypeCheckKind::kBigInt64, feedback);
}
static UseInfo Word64() {
return UseInfo(MachineRepresentation::kWord64, Truncation::Any());
static UseInfo Word64(IdentifyZeros identify_zeros = kDistinguishZeros) {
return UseInfo(MachineRepresentation::kWord64,
Truncation::Any(identify_zeros));
}
static UseInfo Word() {
return UseInfo(MachineType::PointerRepresentation(), Truncation::Any());

View File

@ -674,6 +674,10 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
case IrOpcode::kJSToNumberConvertBigInt:
CheckTypeIs(node, Type::Number());
break;
case IrOpcode::kJSToBigInt:
case IrOpcode::kJSToBigIntConvertNumber:
CheckTypeIs(node, Type::BigInt());
break;
case IrOpcode::kJSToNumeric:
CheckTypeIs(node, Type::Numeric());
break;
@ -1121,6 +1125,10 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
CheckValueInputIs(node, 0, Type::Number());
CheckTypeIs(node, Type::Unsigned32());
break;
case IrOpcode::kIntegral32OrMinusZeroToBigInt:
CheckValueInputIs(node, 0, Type::Integral32OrMinusZero());
CheckTypeIs(node, Type::BigInt());
break;
case IrOpcode::kUnsigned32Divide:
CheckValueInputIs(node, 0, Type::Unsigned32());
CheckValueInputIs(node, 1, Type::Unsigned32());

View File

@ -94,6 +94,25 @@ RUNTIME_FUNCTION(Runtime_ToBigInt) {
RETURN_RESULT_OR_FAILURE(isolate, BigInt::FromObject(isolate, x));
}
RUNTIME_FUNCTION(Runtime_ToBigIntConvertNumber) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
Handle<Object> x = args.at(0);
if (x->IsJSReceiver()) {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, x,
JSReceiver::ToPrimitive(isolate, Handle<JSReceiver>::cast(x),
ToPrimitiveHint::kNumber));
}
if (x->IsNumber()) {
RETURN_RESULT_OR_FAILURE(isolate, BigInt::FromNumber(isolate, x));
} else {
RETURN_RESULT_OR_FAILURE(isolate, BigInt::FromObject(isolate, x));
}
}
RUNTIME_FUNCTION(Runtime_BigIntBinaryOp) {
HandleScope scope(isolate);
DCHECK_EQ(3, args.length());

View File

@ -80,7 +80,8 @@ namespace internal {
F(BigIntToBoolean, 1, 1) \
F(BigIntToNumber, 1, 1) \
F(BigIntUnaryOp, 2, 1) \
F(ToBigInt, 1, 1)
F(ToBigInt, 1, 1) \
F(ToBigIntConvertNumber, 1, 1)
#define FOR_EACH_INTRINSIC_CLASSES(F, I) \
F(DefineClass, -1 /* >= 3 */, 1) \

View File

@ -0,0 +1,107 @@
// 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 () {
function ToBigInt(x) {
return BigInt(x);
}
%PrepareFunctionForOptimization(ToBigInt);
assertEquals(0n, ToBigInt(0));
%OptimizeFunctionOnNextCall(ToBigInt);
// Test the builtin ToBigIntConvertNumber.
assertThrows(() => ToBigInt(undefined), TypeError);
assertEquals(0n, ToBigInt(false));
assertEquals(1n, ToBigInt(true));
assertEquals(42n, ToBigInt(42n));
assertEquals(3n, ToBigInt(3));
assertEquals(0xdeadbeefn, ToBigInt(0xdeadbeef));
assertEquals(-0xdeadbeefn, ToBigInt(-0xdeadbeef));
assertEquals(2n, ToBigInt("2"));
assertEquals(0xdeadbeefdeadbeefdn, ToBigInt("0xdeadbeefdeadbeefd"));
assertThrows(() => ToBigInt("-0x10"), SyntaxError);
assertThrows(() => ToBigInt(Symbol("foo")), TypeError);
assertOptimized(ToBigInt);
})();
{
// Test constants to BigInts.
function OptimizeAndTest(expected, fun) {
%PrepareFunctionForOptimization(fun);
assertEquals(expected, fun());
%OptimizeFunctionOnNextCall(fun);
assertEquals(expected, fun());
assertOptimized(fun);
}
OptimizeAndTest(42n, () => BigInt(42n));
// MinusZero
OptimizeAndTest(0n, () => BigInt(-0));
OptimizeAndTest(0n, () => BigInt.asIntN(32, BigInt(-0)));
OptimizeAndTest(0n, () => BigInt.asUintN(32, BigInt(-0)));
OptimizeAndTest(0n, () => 0n + BigInt(-0));
// Smi
OptimizeAndTest(42n, () => BigInt(42));
OptimizeAndTest(42n, () => BigInt.asIntN(32, BigInt(42)));
OptimizeAndTest(42n, () => BigInt.asUintN(32, BigInt(42)));
OptimizeAndTest(42n, () => 0n + BigInt(42));
// Signed32
OptimizeAndTest(-0x80000000n, () => BigInt(-0x80000000));
OptimizeAndTest(-0x80000000n, () => BigInt.asIntN(32, BigInt(-0x80000000)));
OptimizeAndTest(0x80000000n, () => BigInt.asUintN(32, BigInt(-0x80000000)));
OptimizeAndTest(-0x80000000n, () => 0n + BigInt(-0x80000000));
// Unsigned32
OptimizeAndTest(0x80000000n, () => BigInt(0x80000000));
OptimizeAndTest(-0x80000000n, () => BigInt.asIntN(32, BigInt(0x80000000)));
OptimizeAndTest(0x80000000n, () => BigInt.asUintN(32, BigInt(0x80000000)));
OptimizeAndTest(0x80000000n, () => 0n + BigInt(0x80000000));
}
(function () {
function SmiToBigInt(arr) {
return BigInt(arr[0]);
}
// Element kind: PACKED_SMI_ELEMENTS
const numbers = [0x3fffffff, 0, -0x40000000];
%PrepareFunctionForOptimization(SmiToBigInt);
assertEquals(0x3fffffffn, SmiToBigInt(numbers));
%OptimizeFunctionOnNextCall(SmiToBigInt);
assertEquals(0x3fffffffn, SmiToBigInt(numbers));
assertOptimized(SmiToBigInt);
// Change the map of {numbers}.
numbers[1] = 0x80000000;
assertEquals(0x3fffffffn, SmiToBigInt(numbers));
assertUnoptimized(SmiToBigInt);
})();
(function () {
function ToBigInt() {
return BigInt(123);
}
%PrepareFunctionForOptimization(ToBigInt);
assertEquals(123n, ToBigInt());
%OptimizeFunctionOnNextCall(ToBigInt);
assertEquals(123n, ToBigInt());
assertOptimized(ToBigInt);
// Replace the global BigInt object.
BigInt = () => 42;
assertUnoptimized(ToBigInt);
assertEquals(42, ToBigInt());
})();