[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: Michael Stanton <mvstanton@chromium.org> Cr-Commit-Position: refs/heads/master@{#50636}
This commit is contained in:
parent
6505d9b5c8
commit
02dbef1489
@ -5265,7 +5265,8 @@ Node* CodeStubAssembler::NumberToString(Node* context, Node* argument) {
|
||||
BIND(&runtime);
|
||||
{
|
||||
// No cache entry, go to the runtime.
|
||||
result.Bind(CallRuntime(Runtime::kNumberToString, context, argument));
|
||||
result.Bind(
|
||||
CallRuntime(Runtime::kNumberToStringSkipCache, context, argument));
|
||||
}
|
||||
Goto(&done);
|
||||
|
||||
|
@ -746,6 +746,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
|
||||
case IrOpcode::kCheckedTruncateTaggedToWord32:
|
||||
result = LowerCheckedTruncateTaggedToWord32(node, frame_state);
|
||||
break;
|
||||
case IrOpcode::kNumberToString:
|
||||
result = LowerNumberToString(node);
|
||||
break;
|
||||
case IrOpcode::kObjectIsArrayBufferView:
|
||||
result = LowerObjectIsArrayBufferView(node);
|
||||
break;
|
||||
@ -2028,6 +2031,19 @@ Node* EffectControlLinearizer::LowerAllocate(Node* 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* value = node->InputAt(0);
|
||||
|
||||
|
@ -90,6 +90,7 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer {
|
||||
Node* LowerTruncateTaggedToWord32(Node* node);
|
||||
Node* LowerCheckedTruncateTaggedToWord32(Node* node, Node* frame_state);
|
||||
Node* LowerAllocate(Node* node);
|
||||
Node* LowerNumberToString(Node* node);
|
||||
Node* LowerObjectIsArrayBufferView(Node* node);
|
||||
Node* LowerObjectIsBigInt(Node* node);
|
||||
Node* LowerObjectIsCallable(Node* node);
|
||||
|
@ -1045,7 +1045,9 @@ Reduction JSTypedLowering::ReduceJSToStringInput(Node* input) {
|
||||
return Replace(jsgraph()->HeapConstant(
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -318,6 +318,7 @@
|
||||
V(NumberTrunc) \
|
||||
V(NumberToBoolean) \
|
||||
V(NumberToInt32) \
|
||||
V(NumberToString) \
|
||||
V(NumberToUint32) \
|
||||
V(NumberToUint8Clamped) \
|
||||
V(NumberSilenceNaN)
|
||||
|
@ -24,6 +24,8 @@ OperationTyper::OperationTyper(Isolate* isolate, Zone* zone)
|
||||
Type* truncating_to_zero = Type::MinusZeroOrNaN();
|
||||
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_true_ = Type::HeapConstant(factory->true_value(), zone);
|
||||
singleton_the_hole_ = Type::HeapConstant(factory->the_hole_value(), zone);
|
||||
@ -503,6 +505,14 @@ Type* OperationTyper::NumberToInt32(Type* type) {
|
||||
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) {
|
||||
DCHECK(type->Is(Type::Number()));
|
||||
|
||||
|
@ -94,6 +94,8 @@ class V8_EXPORT_PRIVATE OperationTyper {
|
||||
|
||||
Type* infinity_;
|
||||
Type* minus_infinity_;
|
||||
Type* singleton_NaN_string_;
|
||||
Type* singleton_zero_string_;
|
||||
Type* singleton_false_;
|
||||
Type* singleton_true_;
|
||||
Type* singleton_the_hole_;
|
||||
|
@ -2270,6 +2270,11 @@ class RepresentationSelector {
|
||||
if (lower()) DeferReplacement(node, node->InputAt(0));
|
||||
return;
|
||||
}
|
||||
case IrOpcode::kNumberToString: {
|
||||
VisitUnop(node, UseInfo::AnyTagged(),
|
||||
MachineRepresentation::kTaggedPointer);
|
||||
return;
|
||||
}
|
||||
case IrOpcode::kNumberToUint32: {
|
||||
// Just change representation if necessary.
|
||||
VisitUnop(node, UseInfo::TruncatingWord32(),
|
||||
|
@ -650,6 +650,7 @@ bool operator==(CheckMinusZeroParameters const& lhs,
|
||||
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) \
|
||||
|
@ -465,6 +465,7 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
|
||||
const Operator* NumberTrunc();
|
||||
const Operator* NumberToBoolean();
|
||||
const Operator* NumberToInt32();
|
||||
const Operator* NumberToString();
|
||||
const Operator* NumberToUint32();
|
||||
const Operator* NumberToUint8Clamped();
|
||||
|
||||
|
@ -44,6 +44,8 @@ class TypeCache final {
|
||||
Type* const kSingletonOne = CreateRange(1.0, 1.0);
|
||||
Type* const kSingletonTen = CreateRange(10.0, 10.0);
|
||||
Type* const kSingletonMinusOne = CreateRange(-1.0, -1.0);
|
||||
Type* const kZeroOrMinusZero =
|
||||
Type::Union(kSingletonZero, Type::MinusZero(), zone());
|
||||
Type* const kZeroOrUndefined =
|
||||
Type::Union(kSingletonZero, Type::Undefined(), zone());
|
||||
Type* const kTenOrUndefined =
|
||||
|
@ -997,6 +997,11 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
|
||||
CheckValueInputIs(node, 0, Type::Number());
|
||||
CheckTypeIs(node, Type::Signed32());
|
||||
break;
|
||||
case IrOpcode::kNumberToString:
|
||||
// Number -> String
|
||||
CheckValueInputIs(node, 0, Type::Number());
|
||||
CheckTypeIs(node, Type::String());
|
||||
break;
|
||||
case IrOpcode::kNumberToUint32:
|
||||
case IrOpcode::kNumberToUint8Clamped:
|
||||
// Number -> Unsigned32
|
||||
|
@ -278,7 +278,7 @@ bool IntrinsicHasNoSideEffect(Runtime::FunctionId id) {
|
||||
V(ToString) \
|
||||
V(ToLength) \
|
||||
V(ToNumber) \
|
||||
V(NumberToString) \
|
||||
V(NumberToStringSkipCache) \
|
||||
/* Type checks */ \
|
||||
V(IsJSReceiver) \
|
||||
V(IsSmi) \
|
||||
|
@ -569,7 +569,7 @@ inherits(NumberMirror, ValueMirror);
|
||||
|
||||
|
||||
NumberMirror.prototype.toText = function() {
|
||||
return %NumberToString(this.value_);
|
||||
return '' + this.value_;
|
||||
};
|
||||
|
||||
|
||||
|
@ -69,16 +69,6 @@ RUNTIME_FUNCTION(Runtime_StringParseFloat) {
|
||||
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) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(1, args.length());
|
||||
|
@ -375,7 +375,6 @@ namespace internal {
|
||||
F(StringToNumber, 1, 1) \
|
||||
F(StringParseInt, 2, 1) \
|
||||
F(StringParseFloat, 1, 1) \
|
||||
F(NumberToString, 1, 1) \
|
||||
F(NumberToStringSkipCache, 1, 1) \
|
||||
F(NumberToSmi, 1, 1) \
|
||||
F(SmiLexicographicCompare, 2, 1) \
|
||||
|
@ -520,7 +520,7 @@ TEST(JSToString1) {
|
||||
|
||||
{ // ToString(number)
|
||||
Node* r = R.ReduceUnop(op, Type::Number());
|
||||
CHECK_EQ(IrOpcode::kJSToString, r->opcode());
|
||||
CHECK_EQ(IrOpcode::kNumberToString, r->opcode());
|
||||
}
|
||||
|
||||
{ // ToString(string)
|
||||
|
Loading…
Reference in New Issue
Block a user