Commit 9eca23e9 authored by Sigurd Schneider's avatar Sigurd Schneider Committed by Commit Bot

[turbofan] Inline Number constructor in certain cases

This CL adds inlining for the Number constructor if new.target is not
present. The lowering is BigInt compatible, i.e. it converts BigInts to
numbers.

Bug: v8:7904
Change-Id: If03b9f872d82e50b6ded7709069181c33dc44e82
Reviewed-on: https://chromium-review.googlesource.com/1118557
Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#54454}
parent efaece9c
...@@ -142,6 +142,14 @@ TF_BUILTIN(ToNumber, CodeStubAssembler) { ...@@ -142,6 +142,14 @@ TF_BUILTIN(ToNumber, CodeStubAssembler) {
Return(ToNumber(context, input)); Return(ToNumber(context, input));
} }
// Like ToNumber, but also converts BigInts.
TF_BUILTIN(ToNumberConvertBigInt, CodeStubAssembler) {
Node* context = Parameter(Descriptor::kContext);
Node* input = Parameter(Descriptor::kArgument);
Return(ToNumber(context, input, BigIntHandling::kConvertToNumber));
}
// ES section #sec-tostring-applied-to-the-number-type // ES section #sec-tostring-applied-to-the-number-type
TF_BUILTIN(NumberToString, CodeStubAssembler) { TF_BUILTIN(NumberToString, CodeStubAssembler) {
TNode<Number> input = CAST(Parameter(Descriptor::kArgument)); TNode<Number> input = CAST(Parameter(Descriptor::kArgument));
......
...@@ -186,6 +186,7 @@ namespace internal { ...@@ -186,6 +186,7 @@ namespace internal {
TFC(NonNumberToNumber, TypeConversion, 1) \ TFC(NonNumberToNumber, TypeConversion, 1) \
TFC(NonNumberToNumeric, TypeConversion, 1) \ TFC(NonNumberToNumeric, TypeConversion, 1) \
TFC(ToNumber, TypeConversion, 1) \ TFC(ToNumber, TypeConversion, 1) \
TFC(ToNumberConvertBigInt, TypeConversion, 1) \
TFC(ToNumeric, TypeConversion, 1) \ TFC(ToNumeric, TypeConversion, 1) \
TFC(NumberToString, TypeConversion, 1) \ TFC(NumberToString, TypeConversion, 1) \
TFC(ToString, TypeConversion, 1) \ TFC(ToString, TypeConversion, 1) \
......
...@@ -3665,6 +3665,8 @@ Reduction JSCallReducer::ReduceJSCall(Node* node, ...@@ -3665,6 +3665,8 @@ Reduction JSCallReducer::ReduceJSCall(Node* node,
return ReduceDatePrototypeGetTime(node); return ReduceDatePrototypeGetTime(node);
case Builtins::kDateNow: case Builtins::kDateNow:
return ReduceDateNow(node); return ReduceDateNow(node);
case Builtins::kNumberConstructor:
return ReduceNumberConstructor(node);
default: default:
break; break;
} }
...@@ -7157,6 +7159,26 @@ Reduction JSCallReducer::ReduceRegExpPrototypeTest(Node* node) { ...@@ -7157,6 +7159,26 @@ Reduction JSCallReducer::ReduceRegExpPrototypeTest(Node* node) {
return Changed(node); return Changed(node);
} }
// ES section #sec-number-constructor
Reduction JSCallReducer::ReduceNumberConstructor(Node* node) {
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
if (p.arity() <= 2) {
ReplaceWithValue(node, jsgraph()->ZeroConstant());
}
// We don't have a new.target argument, so we can convert to number,
// but must also convert BigInts.
if (p.arity() == 3) {
Node* value = NodeProperties::GetValueInput(node, 2);
NodeProperties::ReplaceValueInputs(node, value);
NodeProperties::ChangeOp(node, javascript()->ToNumberConvertBigInt());
return Changed(node);
}
return NoChange();
}
Graph* JSCallReducer::graph() const { return jsgraph()->graph(); } Graph* JSCallReducer::graph() const { return jsgraph()->graph(); }
Isolate* JSCallReducer::isolate() const { return jsgraph()->isolate(); } Isolate* JSCallReducer::isolate() const { return jsgraph()->isolate(); }
......
...@@ -190,6 +190,8 @@ class V8_EXPORT_PRIVATE JSCallReducer final : public AdvancedReducer { ...@@ -190,6 +190,8 @@ class V8_EXPORT_PRIVATE JSCallReducer final : public AdvancedReducer {
Reduction ReduceDateNow(Node* node); Reduction ReduceDateNow(Node* node);
Reduction ReduceNumberParseInt(Node* node); Reduction ReduceNumberParseInt(Node* node);
Reduction ReduceNumberConstructor(Node* node);
// Returns the updated {to} node, and updates control and effect along the // Returns the updated {to} node, and updates control and effect along the
// way. // way.
Node* DoFilterPostCallbackWork(ElementsKind kind, Node** control, Node* DoFilterPostCallbackWork(ElementsKind kind, Node** control,
......
...@@ -82,6 +82,7 @@ REPLACE_STUB_CALL(Equal) ...@@ -82,6 +82,7 @@ REPLACE_STUB_CALL(Equal)
REPLACE_STUB_CALL(ToInteger) REPLACE_STUB_CALL(ToInteger)
REPLACE_STUB_CALL(ToLength) REPLACE_STUB_CALL(ToLength)
REPLACE_STUB_CALL(ToNumber) REPLACE_STUB_CALL(ToNumber)
REPLACE_STUB_CALL(ToNumberConvertBigInt)
REPLACE_STUB_CALL(ToNumeric) REPLACE_STUB_CALL(ToNumeric)
REPLACE_STUB_CALL(ToName) REPLACE_STUB_CALL(ToName)
REPLACE_STUB_CALL(ToObject) REPLACE_STUB_CALL(ToObject)
......
...@@ -589,6 +589,7 @@ CompareOperationHint CompareOperationHintOf(const Operator* op) { ...@@ -589,6 +589,7 @@ CompareOperationHint CompareOperationHintOf(const Operator* op) {
V(ToLength, Operator::kNoProperties, 1, 1) \ V(ToLength, Operator::kNoProperties, 1, 1) \
V(ToName, Operator::kNoProperties, 1, 1) \ V(ToName, Operator::kNoProperties, 1, 1) \
V(ToNumber, Operator::kNoProperties, 1, 1) \ V(ToNumber, Operator::kNoProperties, 1, 1) \
V(ToNumberConvertBigInt, Operator::kNoProperties, 1, 1) \
V(ToNumeric, Operator::kNoProperties, 1, 1) \ V(ToNumeric, Operator::kNoProperties, 1, 1) \
V(ToObject, Operator::kFoldable, 1, 1) \ V(ToObject, Operator::kFoldable, 1, 1) \
V(ToString, Operator::kNoProperties, 1, 1) \ V(ToString, Operator::kNoProperties, 1, 1) \
......
...@@ -685,6 +685,7 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final ...@@ -685,6 +685,7 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final
const Operator* ToLength(); const Operator* ToLength();
const Operator* ToName(); const Operator* ToName();
const Operator* ToNumber(); const Operator* ToNumber();
const Operator* ToNumberConvertBigInt();
const Operator* ToNumeric(); const Operator* ToNumeric();
const Operator* ToObject(); const Operator* ToObject();
const Operator* ToString(); const Operator* ToString();
......
...@@ -2329,6 +2329,7 @@ Reduction JSTypedLowering::Reduce(Node* node) { ...@@ -2329,6 +2329,7 @@ Reduction JSTypedLowering::Reduce(Node* node) {
case IrOpcode::kJSToName: case IrOpcode::kJSToName:
return ReduceJSToName(node); return ReduceJSToName(node);
case IrOpcode::kJSToNumber: case IrOpcode::kJSToNumber:
case IrOpcode::kJSToNumberConvertBigInt:
case IrOpcode::kJSToNumeric: case IrOpcode::kJSToNumeric:
return ReduceJSToNumberOrNumeric(node); return ReduceJSToNumberOrNumeric(node);
case IrOpcode::kJSToString: case IrOpcode::kJSToString:
......
...@@ -240,7 +240,8 @@ InductionVariable* LoopVariableOptimizer::TryGetInductionVariable(Node* phi) { ...@@ -240,7 +240,8 @@ InductionVariable* LoopVariableOptimizer::TryGetInductionVariable(Node* phi) {
// TODO(jarin) Support both sides. // TODO(jarin) Support both sides.
Node* input = arith->InputAt(0); Node* input = arith->InputAt(0);
if (input->opcode() == IrOpcode::kSpeculativeToNumber || if (input->opcode() == IrOpcode::kSpeculativeToNumber ||
input->opcode() == IrOpcode::kJSToNumber) { input->opcode() == IrOpcode::kJSToNumber ||
input->opcode() == IrOpcode::kJSToNumberConvertBigInt) {
input = input->InputAt(0); input = input->InputAt(0);
} }
if (input != phi) return nullptr; if (input != phi) return nullptr;
......
...@@ -602,6 +602,7 @@ bool NodeProperties::CanBeNullOrUndefined(Isolate* isolate, Node* receiver, ...@@ -602,6 +602,7 @@ bool NodeProperties::CanBeNullOrUndefined(Isolate* isolate, Node* receiver,
case IrOpcode::kJSToLength: case IrOpcode::kJSToLength:
case IrOpcode::kJSToName: case IrOpcode::kJSToName:
case IrOpcode::kJSToNumber: case IrOpcode::kJSToNumber:
case IrOpcode::kJSToNumberConvertBigInt:
case IrOpcode::kJSToNumeric: case IrOpcode::kJSToNumeric:
case IrOpcode::kJSToString: case IrOpcode::kJSToString:
case IrOpcode::kToBoolean: case IrOpcode::kToBoolean:
......
...@@ -121,6 +121,7 @@ ...@@ -121,6 +121,7 @@
V(JSToLength) \ V(JSToLength) \
V(JSToName) \ V(JSToName) \
V(JSToNumber) \ V(JSToNumber) \
V(JSToNumberConvertBigInt) \
V(JSToNumeric) \ V(JSToNumeric) \
V(JSToObject) \ V(JSToObject) \
V(JSToString) \ V(JSToString) \
......
...@@ -265,7 +265,9 @@ Type OperationTyper::ConvertReceiver(Type type) { ...@@ -265,7 +265,9 @@ Type OperationTyper::ConvertReceiver(Type type) {
return type; return type;
} }
Type OperationTyper::ToNumberOrNumeric(Object::Conversion mode, Type type) { // Returns the result type of converting {type} to number, if the
// result does not depend on conversion options.
base::Optional<Type> OperationTyper::ToNumberCommon(Type type) {
if (type.Is(Type::Number())) return type; if (type.Is(Type::Number())) return type;
if (type.Is(Type::NullOrUndefined())) { if (type.Is(Type::NullOrUndefined())) {
if (type.Is(Type::Null())) return cache_.kSingletonZero; if (type.Is(Type::Null())) return cache_.kSingletonZero;
...@@ -289,6 +291,13 @@ Type OperationTyper::ToNumberOrNumeric(Object::Conversion mode, Type type) { ...@@ -289,6 +291,13 @@ Type OperationTyper::ToNumberOrNumeric(Object::Conversion mode, Type type) {
} }
return Type::Intersect(type, Type::Number(), zone()); return Type::Intersect(type, Type::Number(), zone());
} }
return base::Optional<Type>();
}
Type OperationTyper::ToNumberOrNumeric(Object::Conversion mode, Type type) {
if (base::Optional<Type> maybe_result_type = ToNumberCommon(type)) {
return *maybe_result_type;
}
if (type.Is(Type::BigInt())) { if (type.Is(Type::BigInt())) {
return mode == Object::Conversion::kToNumber ? Type::None() : type; return mode == Object::Conversion::kToNumber ? Type::None() : type;
} }
...@@ -300,6 +309,13 @@ Type OperationTyper::ToNumber(Type type) { ...@@ -300,6 +309,13 @@ Type OperationTyper::ToNumber(Type type) {
return ToNumberOrNumeric(Object::Conversion::kToNumber, type); return ToNumberOrNumeric(Object::Conversion::kToNumber, type);
} }
Type OperationTyper::ToNumberConvertBigInt(Type type) {
if (base::Optional<Type> maybe_result_type = ToNumberCommon(type)) {
return *maybe_result_type;
}
return Type::Number();
}
Type OperationTyper::ToNumeric(Type type) { Type OperationTyper::ToNumeric(Type type) {
return ToNumberOrNumeric(Object::Conversion::kToNumeric, type); return ToNumberOrNumeric(Object::Conversion::kToNumeric, type);
} }
......
...@@ -35,6 +35,7 @@ class V8_EXPORT_PRIVATE OperationTyper { ...@@ -35,6 +35,7 @@ class V8_EXPORT_PRIVATE OperationTyper {
Type ToPrimitive(Type type); Type ToPrimitive(Type type);
Type ToNumber(Type type); Type ToNumber(Type type);
Type ToNumberConvertBigInt(Type type);
Type ToNumeric(Type type); Type ToNumeric(Type type);
Type ToBoolean(Type type); Type ToBoolean(Type type);
...@@ -78,6 +79,7 @@ class V8_EXPORT_PRIVATE OperationTyper { ...@@ -78,6 +79,7 @@ class V8_EXPORT_PRIVATE OperationTyper {
typedef base::Flags<ComparisonOutcomeFlags> ComparisonOutcome; typedef base::Flags<ComparisonOutcomeFlags> ComparisonOutcome;
Type ToNumberOrNumeric(Object::Conversion mode, Type type); Type ToNumberOrNumeric(Object::Conversion mode, Type type);
base::Optional<Type> ToNumberCommon(Type type);
ComparisonOutcome Invert(ComparisonOutcome); ComparisonOutcome Invert(ComparisonOutcome);
Type Invert(Type); Type Invert(Type);
......
...@@ -93,6 +93,7 @@ bool OperatorProperties::HasFrameStateInput(const Operator* op) { ...@@ -93,6 +93,7 @@ bool OperatorProperties::HasFrameStateInput(const Operator* op) {
case IrOpcode::kJSToLength: case IrOpcode::kJSToLength:
case IrOpcode::kJSToName: case IrOpcode::kJSToName:
case IrOpcode::kJSToNumber: case IrOpcode::kJSToNumber:
case IrOpcode::kJSToNumberConvertBigInt:
case IrOpcode::kJSToNumeric: case IrOpcode::kJSToNumeric:
case IrOpcode::kJSToObject: case IrOpcode::kJSToObject:
case IrOpcode::kJSToString: case IrOpcode::kJSToString:
......
...@@ -1563,6 +1563,7 @@ class RepresentationSelector { ...@@ -1563,6 +1563,7 @@ class RepresentationSelector {
return; return;
} }
case IrOpcode::kJSToNumber: case IrOpcode::kJSToNumber:
case IrOpcode::kJSToNumberConvertBigInt:
case IrOpcode::kJSToNumeric: { case IrOpcode::kJSToNumeric: {
VisitInputs(node); VisitInputs(node);
// TODO(bmeurer): Optimize somewhat based on input type? // TODO(bmeurer): Optimize somewhat based on input type?
...@@ -3297,6 +3298,7 @@ void SimplifiedLowering::LowerAllNodes() { ...@@ -3297,6 +3298,7 @@ void SimplifiedLowering::LowerAllNodes() {
void SimplifiedLowering::DoJSToNumberOrNumericTruncatesToFloat64( void SimplifiedLowering::DoJSToNumberOrNumericTruncatesToFloat64(
Node* node, RepresentationSelector* selector) { Node* node, RepresentationSelector* selector) {
DCHECK(node->opcode() == IrOpcode::kJSToNumber || DCHECK(node->opcode() == IrOpcode::kJSToNumber ||
node->opcode() == IrOpcode::kJSToNumberConvertBigInt ||
node->opcode() == IrOpcode::kJSToNumeric); node->opcode() == IrOpcode::kJSToNumeric);
Node* value = node->InputAt(0); Node* value = node->InputAt(0);
Node* context = node->InputAt(1); Node* context = node->InputAt(1);
...@@ -3320,11 +3322,17 @@ void SimplifiedLowering::DoJSToNumberOrNumericTruncatesToFloat64( ...@@ -3320,11 +3322,17 @@ void SimplifiedLowering::DoJSToNumberOrNumericTruncatesToFloat64(
Node* efalse0 = effect; Node* efalse0 = effect;
Node* vfalse0; Node* vfalse0;
{ {
Operator const* op = node->opcode() == IrOpcode::kJSToNumber Operator const* op =
? ToNumberOperator() node->opcode() == IrOpcode::kJSToNumber
: ToNumericOperator(); ? (node->opcode() == IrOpcode::kJSToNumberConvertBigInt
Node* code = node->opcode() == IrOpcode::kJSToNumber ? ToNumberCode() ? ToNumberConvertBigIntOperator()
: ToNumericCode(); : ToNumberOperator())
: ToNumericOperator();
Node* code = node->opcode() == IrOpcode::kJSToNumber
? ToNumberCode()
: (node->opcode() == IrOpcode::kJSToNumberConvertBigInt
? ToNumberConvertBigIntCode()
: ToNumericCode());
vfalse0 = efalse0 = if_false0 = graph()->NewNode( vfalse0 = efalse0 = if_false0 = graph()->NewNode(
op, code, value, context, frame_state, efalse0, if_false0); op, code, value, context, frame_state, efalse0, if_false0);
...@@ -3392,6 +3400,7 @@ void SimplifiedLowering::DoJSToNumberOrNumericTruncatesToFloat64( ...@@ -3392,6 +3400,7 @@ void SimplifiedLowering::DoJSToNumberOrNumericTruncatesToFloat64(
void SimplifiedLowering::DoJSToNumberOrNumericTruncatesToWord32( void SimplifiedLowering::DoJSToNumberOrNumericTruncatesToWord32(
Node* node, RepresentationSelector* selector) { Node* node, RepresentationSelector* selector) {
DCHECK(node->opcode() == IrOpcode::kJSToNumber || DCHECK(node->opcode() == IrOpcode::kJSToNumber ||
node->opcode() == IrOpcode::kJSToNumberConvertBigInt ||
node->opcode() == IrOpcode::kJSToNumeric); node->opcode() == IrOpcode::kJSToNumeric);
Node* value = node->InputAt(0); Node* value = node->InputAt(0);
Node* context = node->InputAt(1); Node* context = node->InputAt(1);
...@@ -3412,11 +3421,17 @@ void SimplifiedLowering::DoJSToNumberOrNumericTruncatesToWord32( ...@@ -3412,11 +3421,17 @@ void SimplifiedLowering::DoJSToNumberOrNumericTruncatesToWord32(
Node* efalse0 = effect; Node* efalse0 = effect;
Node* vfalse0; Node* vfalse0;
{ {
Operator const* op = node->opcode() == IrOpcode::kJSToNumber Operator const* op =
? ToNumberOperator() node->opcode() == IrOpcode::kJSToNumber
: ToNumericOperator(); ? (node->opcode() == IrOpcode::kJSToNumberConvertBigInt
Node* code = node->opcode() == IrOpcode::kJSToNumber ? ToNumberCode() ? ToNumberConvertBigIntOperator()
: ToNumericCode(); : ToNumberOperator())
: ToNumericOperator();
Node* code = node->opcode() == IrOpcode::kJSToNumber
? ToNumberCode()
: (node->opcode() == IrOpcode::kJSToNumberConvertBigInt
? ToNumberConvertBigIntCode()
: ToNumericCode());
vfalse0 = efalse0 = if_false0 = graph()->NewNode( vfalse0 = efalse0 = if_false0 = graph()->NewNode(
op, code, value, context, frame_state, efalse0, if_false0); op, code, value, context, frame_state, efalse0, if_false0);
...@@ -3922,6 +3937,16 @@ Node* SimplifiedLowering::ToNumberCode() { ...@@ -3922,6 +3937,16 @@ Node* SimplifiedLowering::ToNumberCode() {
return to_number_code_.get(); return to_number_code_.get();
} }
Node* SimplifiedLowering::ToNumberConvertBigIntCode() {
if (!to_number_convert_big_int_code_.is_set()) {
Callable callable =
Builtins::CallableFor(isolate(), Builtins::kToNumberConvertBigInt);
to_number_convert_big_int_code_.set(
jsgraph()->HeapConstant(callable.code()));
}
return to_number_convert_big_int_code_.get();
}
Node* SimplifiedLowering::ToNumericCode() { Node* SimplifiedLowering::ToNumericCode() {
if (!to_numeric_code_.is_set()) { if (!to_numeric_code_.is_set()) {
Callable callable = Builtins::CallableFor(isolate(), Builtins::kToNumeric); Callable callable = Builtins::CallableFor(isolate(), Builtins::kToNumeric);
...@@ -3942,6 +3967,19 @@ Operator const* SimplifiedLowering::ToNumberOperator() { ...@@ -3942,6 +3967,19 @@ Operator const* SimplifiedLowering::ToNumberOperator() {
return to_number_operator_.get(); return to_number_operator_.get();
} }
Operator const* SimplifiedLowering::ToNumberConvertBigIntOperator() {
if (!to_number_convert_big_int_operator_.is_set()) {
Callable callable =
Builtins::CallableFor(isolate(), Builtins::kToNumberConvertBigInt);
CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
auto call_descriptor =
Linkage::GetStubCallDescriptor(graph()->zone(), callable.descriptor(),
0, flags, Operator::kNoProperties);
to_number_convert_big_int_operator_.set(common()->Call(call_descriptor));
}
return to_number_convert_big_int_operator_.get();
}
Operator const* SimplifiedLowering::ToNumericOperator() { Operator const* SimplifiedLowering::ToNumericOperator() {
if (!to_numeric_operator_.is_set()) { if (!to_numeric_operator_.is_set()) {
Callable callable = Builtins::CallableFor(isolate(), Builtins::kToNumeric); Callable callable = Builtins::CallableFor(isolate(), Builtins::kToNumeric);
......
...@@ -52,8 +52,10 @@ class V8_EXPORT_PRIVATE SimplifiedLowering final { ...@@ -52,8 +52,10 @@ class V8_EXPORT_PRIVATE SimplifiedLowering final {
Zone* const zone_; Zone* const zone_;
TypeCache const& type_cache_; TypeCache const& type_cache_;
SetOncePointer<Node> to_number_code_; SetOncePointer<Node> to_number_code_;
SetOncePointer<Node> to_number_convert_big_int_code_;
SetOncePointer<Node> to_numeric_code_; SetOncePointer<Node> to_numeric_code_;
SetOncePointer<Operator const> to_number_operator_; SetOncePointer<Operator const> to_number_operator_;
SetOncePointer<Operator const> to_number_convert_big_int_operator_;
SetOncePointer<Operator const> to_numeric_operator_; SetOncePointer<Operator const> to_numeric_operator_;
// TODO(danno): SimplifiedLowering shouldn't know anything about the source // TODO(danno): SimplifiedLowering shouldn't know anything about the source
...@@ -76,8 +78,10 @@ class V8_EXPORT_PRIVATE SimplifiedLowering final { ...@@ -76,8 +78,10 @@ class V8_EXPORT_PRIVATE SimplifiedLowering final {
Node* Uint32Mod(Node* const node); Node* Uint32Mod(Node* const node);
Node* ToNumberCode(); Node* ToNumberCode();
Node* ToNumberConvertBigIntCode();
Node* ToNumericCode(); Node* ToNumericCode();
Operator const* ToNumberOperator(); Operator const* ToNumberOperator();
Operator const* ToNumberConvertBigIntOperator();
Operator const* ToNumericOperator(); Operator const* ToNumericOperator();
friend class RepresentationSelector; friend class RepresentationSelector;
......
...@@ -266,6 +266,7 @@ class Typer::Visitor : public Reducer { ...@@ -266,6 +266,7 @@ class Typer::Visitor : public Reducer {
static Type ToLength(Type, Typer*); static Type ToLength(Type, Typer*);
static Type ToName(Type, Typer*); static Type ToName(Type, Typer*);
static Type ToNumber(Type, Typer*); static Type ToNumber(Type, Typer*);
static Type ToNumberConvertBigInt(Type, Typer*);
static Type ToNumeric(Type, Typer*); static Type ToNumeric(Type, Typer*);
static Type ToObject(Type, Typer*); static Type ToObject(Type, Typer*);
static Type ToString(Type, Typer*); static Type ToString(Type, Typer*);
...@@ -529,6 +530,11 @@ Type Typer::Visitor::ToNumber(Type type, Typer* t) { ...@@ -529,6 +530,11 @@ Type Typer::Visitor::ToNumber(Type type, Typer* t) {
return t->operation_typer_.ToNumber(type); return t->operation_typer_.ToNumber(type);
} }
// static
Type Typer::Visitor::ToNumberConvertBigInt(Type type, Typer* t) {
return t->operation_typer_.ToNumberConvertBigInt(type);
}
// static // static
Type Typer::Visitor::ToNumeric(Type type, Typer* t) { Type Typer::Visitor::ToNumeric(Type type, Typer* t) {
return t->operation_typer_.ToNumeric(type); return t->operation_typer_.ToNumeric(type);
...@@ -1125,6 +1131,10 @@ Type Typer::Visitor::TypeJSToNumber(Node* node) { ...@@ -1125,6 +1131,10 @@ Type Typer::Visitor::TypeJSToNumber(Node* node) {
return TypeUnaryOp(node, ToNumber); return TypeUnaryOp(node, ToNumber);
} }
Type Typer::Visitor::TypeJSToNumberConvertBigInt(Node* node) {
return TypeUnaryOp(node, ToNumberConvertBigInt);
}
Type Typer::Visitor::TypeJSToNumeric(Node* node) { Type Typer::Visitor::TypeJSToNumeric(Node* node) {
return TypeUnaryOp(node, ToNumeric); return TypeUnaryOp(node, ToNumeric);
} }
......
...@@ -629,6 +629,7 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) { ...@@ -629,6 +629,7 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
CheckTypeIs(node, Type::Name()); CheckTypeIs(node, Type::Name());
break; break;
case IrOpcode::kJSToNumber: case IrOpcode::kJSToNumber:
case IrOpcode::kJSToNumberConvertBigInt:
// Type is Number. // Type is Number.
CheckTypeIs(node, Type::Number()); CheckTypeIs(node, Type::Number());
break; break;
......
...@@ -605,7 +605,8 @@ static void CheckIsConvertedToNumber(Node* val, Node* converted) { ...@@ -605,7 +605,8 @@ static void CheckIsConvertedToNumber(Node* val, Node* converted) {
CHECK_EQ(val, converted); CHECK_EQ(val, converted);
} else { } else {
if (converted->opcode() == IrOpcode::kNumberConstant) return; if (converted->opcode() == IrOpcode::kNumberConstant) return;
CHECK_EQ(IrOpcode::kJSToNumber, converted->opcode()); CHECK(IrOpcode::kJSToNumber == converted->opcode() ||
IrOpcode::kJSToNumberConvertBigInt == converted->opcode());
CHECK_EQ(val, converted->InputAt(0)); CHECK_EQ(val, converted->InputAt(0));
} }
} }
......
...@@ -1039,6 +1039,19 @@ ...@@ -1039,6 +1039,19 @@
{"name": "OneLineComments"}, {"name": "OneLineComments"},
{"name": "MultiLineComment"} {"name": "MultiLineComment"}
] ]
},
{
"name": "Numbers",
"path": ["Numbers"],
"main": "run.js",
"flags": ["--allow-natives-syntax"],
"resources": [ "toNumber.js"],
"results_regexp": "^%s\\-Numbers\\(Score\\): (.+)$",
"tests": [
{"name": "Constructor"},
{"name": "UnaryPlus"},
{"name": "ParseFloat"}
]
} }
] ]
} }
// Copyright 2018 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.
load('../base.js');
load('toNumber.js');
function PrintResult(name, result) {
console.log(name);
console.log(name + '-Numbers(Score): ' + result);
}
function PrintError(name, error) {
PrintResult(name, error);
}
BenchmarkSuite.config.doWarmup = undefined;
BenchmarkSuite.config.doDeterministic = undefined;
BenchmarkSuite.RunSuites({ NotifyResult: PrintResult,
NotifyError: PrintError });
// Copyright 2018 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.
const A = [undefined, 12, "123"];
function NumberConstructor() {
Number.isNaN(Number(A[0]))
Number.isNaN(Number(A[1]))
Number.isNaN(Number(A[2]))
}
createSuite('Constructor', 1000, NumberConstructor, ()=>{});
function NumberPlus() {
Number.isNaN(+(A[0]))
Number.isNaN(+(A[1]))
Number.isNaN(+(A[2]))
}
createSuite('UnaryPlus', 1000, NumberPlus, ()=>{});
function NumberParseFloat() {
Number.isNaN(parseFloat(A[0]))
Number.isNaN(parseFloat(A[1]))
Number.isNaN(parseFloat(A[2]))
}
createSuite('ParseFloat', 1000, NumberParseFloat, ()=>{});
// Copyright 2018 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 --harmony-bigint
function f(x, b) {
if (b) return Math.trunc(+(x))
else return Math.trunc(Number(x))
}
f("1", true);
f("2", true);
f("2", false);
%OptimizeFunctionOnNextCall(f);
f(3n);
...@@ -31,7 +31,7 @@ function Test(f, ...cases) { ...@@ -31,7 +31,7 @@ function Test(f, ...cases) {
function V(input, expected_value) { function V(input, expected_value) {
function check(result) { function check(result) {
assertFalse(result.exception, input); assertFalse(result.exception, `unexpected exception ${result.value} on input ${input}`);
assertEquals(expected_value, result.value); assertEquals(expected_value, result.value);
} }
return {input, check}; return {input, check};
...@@ -39,7 +39,7 @@ function V(input, expected_value) { ...@@ -39,7 +39,7 @@ function V(input, expected_value) {
function E(input, expected_exception) { function E(input, expected_exception) {
function check(result) { function check(result) {
assertTrue(result.exception, input); assertTrue(result.exception, `expected exception ${expected_exception.name} on input ${input}`);
assertInstanceof(result.value, expected_exception); assertInstanceof(result.value, expected_exception);
} }
return {input, check}; return {input, check};
...@@ -56,10 +56,15 @@ const six = {[Symbol.toPrimitive]() {return 6n}}; ...@@ -56,10 +56,15 @@ const six = {[Symbol.toPrimitive]() {return 6n}};
// inputs. // inputs.
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
Test(x => Number(x), Test(x => Number(x),
V(1n, 1), V(1, 1), V("", 0), V(1.4, 1.4), V(null, 0), V(six, 6)); V(1n, 1), V(1, 1), V("", 0), V(1.4, 1.4), V(null, 0), V(six, 6));
Test(x => Math.trunc(+x),
E(1n, TypeError), V(1, 1), V("", 0), V(1.4, 1), V(null, 0), E(six, TypeError));
Test(x => Math.trunc(Number(x)),
V(1n, 1), V(1, 1), V("", 0), V(1.4, 1), V(null, 0), V(six, 6));
Test(x => String(x), Test(x => String(x),
V(1n, "1"), V(1, "1"), V(1.4, "1.4"), V(null, "null"), V(six, "6")); V(1n, "1"), V(1, "1"), V(1.4, "1.4"), V(null, "null"), V(six, "6"));
......
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