Commit 02dbef14 authored by Benedikt Meurer's avatar Benedikt Meurer Committed by Commit Bot

[turbofan] Introduce NumberToString operator.

This adds a new simplified operator NumberToString, which just lowers to
a call to the NumberToString builtin, and hooks that up to the typed
lowering (addressing a long-standing TODO).

Drive-by-fix: Also remove the %NumberToString runtime entry, and just
always use the %NumberToStringSkipCache entry from CSA, since we only
go there if the cache lookup already failed.

Bug: v8:5267, v8:7109
Change-Id: I5ca698c98679653813088a404f1fd38903a73c0e
Reviewed-on: https://chromium-review.googlesource.com/779099
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarMichael Stanton <mvstanton@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50636}
parent 6505d9b5
...@@ -5265,7 +5265,8 @@ Node* CodeStubAssembler::NumberToString(Node* context, Node* argument) { ...@@ -5265,7 +5265,8 @@ Node* CodeStubAssembler::NumberToString(Node* context, Node* argument) {
BIND(&runtime); BIND(&runtime);
{ {
// No cache entry, go to the runtime. // No cache entry, go to the runtime.
result.Bind(CallRuntime(Runtime::kNumberToString, context, argument)); result.Bind(
CallRuntime(Runtime::kNumberToStringSkipCache, context, argument));
} }
Goto(&done); Goto(&done);
......
...@@ -746,6 +746,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node, ...@@ -746,6 +746,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
case IrOpcode::kCheckedTruncateTaggedToWord32: case IrOpcode::kCheckedTruncateTaggedToWord32:
result = LowerCheckedTruncateTaggedToWord32(node, frame_state); result = LowerCheckedTruncateTaggedToWord32(node, frame_state);
break; break;
case IrOpcode::kNumberToString:
result = LowerNumberToString(node);
break;
case IrOpcode::kObjectIsArrayBufferView: case IrOpcode::kObjectIsArrayBufferView:
result = LowerObjectIsArrayBufferView(node); result = LowerObjectIsArrayBufferView(node);
break; break;
...@@ -2028,6 +2031,19 @@ Node* EffectControlLinearizer::LowerAllocate(Node* node) { ...@@ -2028,6 +2031,19 @@ Node* EffectControlLinearizer::LowerAllocate(Node* node) {
return new_node; return new_node;
} }
Node* EffectControlLinearizer::LowerNumberToString(Node* node) {
Node* argument = node->InputAt(0);
Callable const callable =
Builtins::CallableFor(isolate(), Builtins::kNumberToString);
Operator::Properties properties = Operator::kEliminatable;
CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
isolate(), graph()->zone(), callable.descriptor(), 0, flags, properties);
return __ Call(desc, __ HeapConstant(callable.code()), argument,
__ NoContextConstant());
}
Node* EffectControlLinearizer::LowerObjectIsArrayBufferView(Node* node) { Node* EffectControlLinearizer::LowerObjectIsArrayBufferView(Node* node) {
Node* value = node->InputAt(0); Node* value = node->InputAt(0);
......
...@@ -90,6 +90,7 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer { ...@@ -90,6 +90,7 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer {
Node* LowerTruncateTaggedToWord32(Node* node); Node* LowerTruncateTaggedToWord32(Node* node);
Node* LowerCheckedTruncateTaggedToWord32(Node* node, Node* frame_state); Node* LowerCheckedTruncateTaggedToWord32(Node* node, Node* frame_state);
Node* LowerAllocate(Node* node); Node* LowerAllocate(Node* node);
Node* LowerNumberToString(Node* node);
Node* LowerObjectIsArrayBufferView(Node* node); Node* LowerObjectIsArrayBufferView(Node* node);
Node* LowerObjectIsBigInt(Node* node); Node* LowerObjectIsBigInt(Node* node);
Node* LowerObjectIsCallable(Node* node); Node* LowerObjectIsCallable(Node* node);
......
...@@ -1045,7 +1045,9 @@ Reduction JSTypedLowering::ReduceJSToStringInput(Node* input) { ...@@ -1045,7 +1045,9 @@ Reduction JSTypedLowering::ReduceJSToStringInput(Node* input) {
return Replace(jsgraph()->HeapConstant( return Replace(jsgraph()->HeapConstant(
factory()->NumberToString(factory()->NewNumber(input_type->Min())))); factory()->NumberToString(factory()->NewNumber(input_type->Min()))));
} }
// TODO(turbofan): js-typed-lowering of ToString(x:number) if (input_type->Is(Type::Number())) {
return Replace(graph()->NewNode(simplified()->NumberToString(), input));
}
return NoChange(); return NoChange();
} }
......
...@@ -318,6 +318,7 @@ ...@@ -318,6 +318,7 @@
V(NumberTrunc) \ V(NumberTrunc) \
V(NumberToBoolean) \ V(NumberToBoolean) \
V(NumberToInt32) \ V(NumberToInt32) \
V(NumberToString) \
V(NumberToUint32) \ V(NumberToUint32) \
V(NumberToUint8Clamped) \ V(NumberToUint8Clamped) \
V(NumberSilenceNaN) V(NumberSilenceNaN)
......
...@@ -24,6 +24,8 @@ OperationTyper::OperationTyper(Isolate* isolate, Zone* zone) ...@@ -24,6 +24,8 @@ OperationTyper::OperationTyper(Isolate* isolate, Zone* zone)
Type* truncating_to_zero = Type::MinusZeroOrNaN(); Type* truncating_to_zero = Type::MinusZeroOrNaN();
DCHECK(!truncating_to_zero->Maybe(Type::Integral32())); DCHECK(!truncating_to_zero->Maybe(Type::Integral32()));
singleton_NaN_string_ = Type::HeapConstant(factory->NaN_string(), zone);
singleton_zero_string_ = Type::HeapConstant(factory->zero_string(), zone);
singleton_false_ = Type::HeapConstant(factory->false_value(), zone); singleton_false_ = Type::HeapConstant(factory->false_value(), zone);
singleton_true_ = Type::HeapConstant(factory->true_value(), zone); singleton_true_ = Type::HeapConstant(factory->true_value(), zone);
singleton_the_hole_ = Type::HeapConstant(factory->the_hole_value(), zone); singleton_the_hole_ = Type::HeapConstant(factory->the_hole_value(), zone);
...@@ -503,6 +505,14 @@ Type* OperationTyper::NumberToInt32(Type* type) { ...@@ -503,6 +505,14 @@ Type* OperationTyper::NumberToInt32(Type* type) {
return Type::Signed32(); return Type::Signed32();
} }
Type* OperationTyper::NumberToString(Type* type) {
DCHECK(type->Is(Type::Number()));
if (type->Is(Type::NaN())) return singleton_NaN_string_;
if (type->Is(cache_.kZeroOrMinusZero)) return singleton_zero_string_;
return Type::SeqString();
}
Type* OperationTyper::NumberToUint32(Type* type) { Type* OperationTyper::NumberToUint32(Type* type) {
DCHECK(type->Is(Type::Number())); DCHECK(type->Is(Type::Number()));
......
...@@ -94,6 +94,8 @@ class V8_EXPORT_PRIVATE OperationTyper { ...@@ -94,6 +94,8 @@ class V8_EXPORT_PRIVATE OperationTyper {
Type* infinity_; Type* infinity_;
Type* minus_infinity_; Type* minus_infinity_;
Type* singleton_NaN_string_;
Type* singleton_zero_string_;
Type* singleton_false_; Type* singleton_false_;
Type* singleton_true_; Type* singleton_true_;
Type* singleton_the_hole_; Type* singleton_the_hole_;
......
...@@ -2270,6 +2270,11 @@ class RepresentationSelector { ...@@ -2270,6 +2270,11 @@ class RepresentationSelector {
if (lower()) DeferReplacement(node, node->InputAt(0)); if (lower()) DeferReplacement(node, node->InputAt(0));
return; return;
} }
case IrOpcode::kNumberToString: {
VisitUnop(node, UseInfo::AnyTagged(),
MachineRepresentation::kTaggedPointer);
return;
}
case IrOpcode::kNumberToUint32: { case IrOpcode::kNumberToUint32: {
// Just change representation if necessary. // Just change representation if necessary.
VisitUnop(node, UseInfo::TruncatingWord32(), VisitUnop(node, UseInfo::TruncatingWord32(),
......
...@@ -650,6 +650,7 @@ bool operator==(CheckMinusZeroParameters const& lhs, ...@@ -650,6 +650,7 @@ bool operator==(CheckMinusZeroParameters const& lhs,
V(NumberTrunc, Operator::kNoProperties, 1, 0) \ V(NumberTrunc, Operator::kNoProperties, 1, 0) \
V(NumberToBoolean, Operator::kNoProperties, 1, 0) \ V(NumberToBoolean, Operator::kNoProperties, 1, 0) \
V(NumberToInt32, Operator::kNoProperties, 1, 0) \ V(NumberToInt32, Operator::kNoProperties, 1, 0) \
V(NumberToString, Operator::kNoProperties, 1, 0) \
V(NumberToUint32, Operator::kNoProperties, 1, 0) \ V(NumberToUint32, Operator::kNoProperties, 1, 0) \
V(NumberToUint8Clamped, Operator::kNoProperties, 1, 0) \ V(NumberToUint8Clamped, Operator::kNoProperties, 1, 0) \
V(NumberSilenceNaN, Operator::kNoProperties, 1, 0) \ V(NumberSilenceNaN, Operator::kNoProperties, 1, 0) \
......
...@@ -465,6 +465,7 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final ...@@ -465,6 +465,7 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
const Operator* NumberTrunc(); const Operator* NumberTrunc();
const Operator* NumberToBoolean(); const Operator* NumberToBoolean();
const Operator* NumberToInt32(); const Operator* NumberToInt32();
const Operator* NumberToString();
const Operator* NumberToUint32(); const Operator* NumberToUint32();
const Operator* NumberToUint8Clamped(); const Operator* NumberToUint8Clamped();
......
...@@ -44,6 +44,8 @@ class TypeCache final { ...@@ -44,6 +44,8 @@ class TypeCache final {
Type* const kSingletonOne = CreateRange(1.0, 1.0); Type* const kSingletonOne = CreateRange(1.0, 1.0);
Type* const kSingletonTen = CreateRange(10.0, 10.0); Type* const kSingletonTen = CreateRange(10.0, 10.0);
Type* const kSingletonMinusOne = CreateRange(-1.0, -1.0); Type* const kSingletonMinusOne = CreateRange(-1.0, -1.0);
Type* const kZeroOrMinusZero =
Type::Union(kSingletonZero, Type::MinusZero(), zone());
Type* const kZeroOrUndefined = Type* const kZeroOrUndefined =
Type::Union(kSingletonZero, Type::Undefined(), zone()); Type::Union(kSingletonZero, Type::Undefined(), zone());
Type* const kTenOrUndefined = Type* const kTenOrUndefined =
......
...@@ -997,6 +997,11 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) { ...@@ -997,6 +997,11 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
CheckValueInputIs(node, 0, Type::Number()); CheckValueInputIs(node, 0, Type::Number());
CheckTypeIs(node, Type::Signed32()); CheckTypeIs(node, Type::Signed32());
break; break;
case IrOpcode::kNumberToString:
// Number -> String
CheckValueInputIs(node, 0, Type::Number());
CheckTypeIs(node, Type::String());
break;
case IrOpcode::kNumberToUint32: case IrOpcode::kNumberToUint32:
case IrOpcode::kNumberToUint8Clamped: case IrOpcode::kNumberToUint8Clamped:
// Number -> Unsigned32 // Number -> Unsigned32
......
...@@ -278,7 +278,7 @@ bool IntrinsicHasNoSideEffect(Runtime::FunctionId id) { ...@@ -278,7 +278,7 @@ bool IntrinsicHasNoSideEffect(Runtime::FunctionId id) {
V(ToString) \ V(ToString) \
V(ToLength) \ V(ToLength) \
V(ToNumber) \ V(ToNumber) \
V(NumberToString) \ V(NumberToStringSkipCache) \
/* Type checks */ \ /* Type checks */ \
V(IsJSReceiver) \ V(IsJSReceiver) \
V(IsSmi) \ V(IsSmi) \
......
...@@ -569,7 +569,7 @@ inherits(NumberMirror, ValueMirror); ...@@ -569,7 +569,7 @@ inherits(NumberMirror, ValueMirror);
NumberMirror.prototype.toText = function() { NumberMirror.prototype.toText = function() {
return %NumberToString(this.value_); return '' + this.value_;
}; };
......
...@@ -69,16 +69,6 @@ RUNTIME_FUNCTION(Runtime_StringParseFloat) { ...@@ -69,16 +69,6 @@ RUNTIME_FUNCTION(Runtime_StringParseFloat) {
return *isolate->factory()->NewNumber(value); return *isolate->factory()->NewNumber(value);
} }
RUNTIME_FUNCTION(Runtime_NumberToString) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_NUMBER_ARG_HANDLE_CHECKED(number, 0);
return *isolate->factory()->NumberToString(number);
}
RUNTIME_FUNCTION(Runtime_NumberToStringSkipCache) { RUNTIME_FUNCTION(Runtime_NumberToStringSkipCache) {
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK_EQ(1, args.length()); DCHECK_EQ(1, args.length());
......
...@@ -375,7 +375,6 @@ namespace internal { ...@@ -375,7 +375,6 @@ namespace internal {
F(StringToNumber, 1, 1) \ F(StringToNumber, 1, 1) \
F(StringParseInt, 2, 1) \ F(StringParseInt, 2, 1) \
F(StringParseFloat, 1, 1) \ F(StringParseFloat, 1, 1) \
F(NumberToString, 1, 1) \
F(NumberToStringSkipCache, 1, 1) \ F(NumberToStringSkipCache, 1, 1) \
F(NumberToSmi, 1, 1) \ F(NumberToSmi, 1, 1) \
F(SmiLexicographicCompare, 2, 1) \ F(SmiLexicographicCompare, 2, 1) \
......
...@@ -520,7 +520,7 @@ TEST(JSToString1) { ...@@ -520,7 +520,7 @@ TEST(JSToString1) {
{ // ToString(number) { // ToString(number)
Node* r = R.ReduceUnop(op, Type::Number()); Node* r = R.ReduceUnop(op, Type::Number());
CHECK_EQ(IrOpcode::kJSToString, r->opcode()); CHECK_EQ(IrOpcode::kNumberToString, r->opcode());
} }
{ // ToString(string) { // ToString(string)
......
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