Commit 630fbf67 authored by Santiago Aboy Solanes's avatar Santiago Aboy Solanes Committed by Commit Bot

[CSA] Create a PlainPrimitiveToNumberBuiltin

Previously ToNumber could be called with an empty context. In a previous
CL (https://crrev.com/c/v8/v8/+/2078580) we added DCHECKS to make sure
that some paths were not using the empty context. Now we are doing the
next step of adding a primitive to separate the cases.

Small update from delphick@ to get the builtin descriptor right.

Bug: v8:6949, v8:10933
Change-Id: Ie40b169f680f60a08eb26fac1fcfcef7d6169e65
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2428863
Commit-Queue: Santiago Aboy Solanes <solanes@chromium.org>
Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#70162}
parent fedbf2dc
...@@ -14,15 +14,18 @@ namespace internal { ...@@ -14,15 +14,18 @@ namespace internal {
// ES6 section 7.1.3 ToNumber ( argument ) // ES6 section 7.1.3 ToNumber ( argument )
TF_BUILTIN(ToNumber, CodeStubAssembler) { TF_BUILTIN(ToNumber, CodeStubAssembler) {
// TODO(solanes, v8:6949): Changing this to a TNode<Context> crashes with the TNode<Context> context = CAST(Parameter(Descriptor::kContext));
// empty context. Context might not be needed, but it is propagated all over
// the place and hard to pull out.
Node* context = Parameter(Descriptor::kContext);
TNode<Object> input = CAST(Parameter(Descriptor::kArgument)); TNode<Object> input = CAST(Parameter(Descriptor::kArgument));
Return(ToNumber(context, input)); Return(ToNumber(context, input));
} }
TF_BUILTIN(PlainPrimitiveToNumber, CodeStubAssembler) {
TNode<Object> input = CAST(Parameter(Descriptor::kArgument));
Return(PlainPrimitiveToNumber(input));
}
// Like ToNumber, but also converts BigInts. // Like ToNumber, but also converts BigInts.
TF_BUILTIN(ToNumberConvertBigInt, CodeStubAssembler) { TF_BUILTIN(ToNumberConvertBigInt, CodeStubAssembler) {
TNode<Context> context = CAST(Parameter(Descriptor::kContext)); TNode<Context> context = CAST(Parameter(Descriptor::kContext));
......
...@@ -189,6 +189,7 @@ namespace internal { ...@@ -189,6 +189,7 @@ namespace internal {
\ \
/* Type conversions */ \ /* Type conversions */ \
TFC(ToNumber, TypeConversion) \ TFC(ToNumber, TypeConversion) \
TFC(PlainPrimitiveToNumber, TypeConversionNoContext) \
TFC(ToNumberConvertBigInt, TypeConversion) \ TFC(ToNumberConvertBigInt, TypeConversion) \
TFC(Typeof, Typeof) \ TFC(Typeof, Typeof) \
TFC(GetSuperConstructor, Typeof) \ TFC(GetSuperConstructor, Typeof) \
......
...@@ -6755,6 +6755,12 @@ TNode<String> CodeStubAssembler::NumberToString(TNode<Number> input) { ...@@ -6755,6 +6755,12 @@ TNode<String> CodeStubAssembler::NumberToString(TNode<Number> input) {
return result.value(); return result.value();
} }
// TODO(solanes, v8:6949): Refactor this to check for JSReceivers first. If we
// have a JSReceiver, extract the primitive and fallthrough. Otherwise, continue
// asking for the other instance types. This will make it so that we can remove
// the loop (which was looping at most once). Also, see if we can make use of
// PlainPrimitiveNonNumberToNumber to de-duplicate code, maybe changing it to a
// TryPlainPrimitiveNonNumberToNumber with a Label* as a parameter.
TNode<Numeric> CodeStubAssembler::NonNumberToNumberOrNumeric( TNode<Numeric> CodeStubAssembler::NonNumberToNumberOrNumeric(
TNode<Context> context, TNode<HeapObject> input, Object::Conversion mode, TNode<Context> context, TNode<HeapObject> input, Object::Conversion mode,
BigIntHandling bigint_handling) { BigIntHandling bigint_handling) {
...@@ -6792,7 +6798,6 @@ TNode<Numeric> CodeStubAssembler::NonNumberToNumberOrNumeric( ...@@ -6792,7 +6798,6 @@ TNode<Numeric> CodeStubAssembler::NonNumberToNumberOrNumeric(
} }
BIND(&if_inputisbigint); BIND(&if_inputisbigint);
CSA_ASSERT(this, Word32And(TaggedIsNotSmi(context), IsContext(context)));
if (mode == Object::Conversion::kToNumeric) { if (mode == Object::Conversion::kToNumeric) {
var_result = CAST(input); var_result = CAST(input);
Goto(&end); Goto(&end);
...@@ -6817,9 +6822,9 @@ TNode<Numeric> CodeStubAssembler::NonNumberToNumberOrNumeric( ...@@ -6817,9 +6822,9 @@ TNode<Numeric> CodeStubAssembler::NonNumberToNumberOrNumeric(
BIND(&if_inputisreceiver); BIND(&if_inputisreceiver);
{ {
CSA_ASSERT(this, Word32And(TaggedIsNotSmi(context), IsContext(context))); // The {input} is a JSReceiver, we need to convert it to a Primitive
// The {input} is a JSReceiver, we need to convert it to a Primitive first // first using the ToPrimitive type conversion, preferably yielding a
// using the ToPrimitive type conversion, preferably yielding a Number. // Number.
Callable callable = CodeFactory::NonPrimitiveToPrimitive( Callable callable = CodeFactory::NonPrimitiveToPrimitive(
isolate(), ToPrimitiveHint::kNumber); isolate(), ToPrimitiveHint::kNumber);
TNode<Object> result = CallStub(callable, context, input); TNode<Object> result = CallStub(callable, context, input);
...@@ -6832,15 +6837,16 @@ TNode<Numeric> CodeStubAssembler::NonNumberToNumberOrNumeric( ...@@ -6832,15 +6837,16 @@ TNode<Numeric> CodeStubAssembler::NonNumberToNumberOrNumeric(
BIND(&if_done); BIND(&if_done);
{ {
// The ToPrimitive conversion already gave us a Number/Numeric, so we're // The ToPrimitive conversion already gave us a Number/Numeric, so
// done. // we're done.
var_result = CAST(result); var_result = CAST(result);
Goto(&end); Goto(&end);
} }
BIND(&if_notdone); BIND(&if_notdone);
{ {
// We now have a Primitive {result}, but it's not yet a Number/Numeric. // We now have a Primitive {result}, but it's not yet a
// Number/Numeric.
var_input = CAST(result); var_input = CAST(result);
Goto(&loop); Goto(&loop);
} }
...@@ -6848,7 +6854,6 @@ TNode<Numeric> CodeStubAssembler::NonNumberToNumberOrNumeric( ...@@ -6848,7 +6854,6 @@ TNode<Numeric> CodeStubAssembler::NonNumberToNumberOrNumeric(
BIND(&if_inputisother); BIND(&if_inputisother);
{ {
CSA_ASSERT(this, Word32And(TaggedIsNotSmi(context), IsContext(context)));
// The {input} is something else (e.g. Symbol), let the runtime figure // The {input} is something else (e.g. Symbol), let the runtime figure
// out the correct exception. // out the correct exception.
// Note: We cannot tail call to the runtime here, as js-to-wasm // Note: We cannot tail call to the runtime here, as js-to-wasm
...@@ -6873,14 +6878,46 @@ TNode<Numeric> CodeStubAssembler::NonNumberToNumberOrNumeric( ...@@ -6873,14 +6878,46 @@ TNode<Numeric> CodeStubAssembler::NonNumberToNumberOrNumeric(
} }
TNode<Number> CodeStubAssembler::NonNumberToNumber( TNode<Number> CodeStubAssembler::NonNumberToNumber(
SloppyTNode<Context> context, SloppyTNode<HeapObject> input, TNode<Context> context, SloppyTNode<HeapObject> input,
BigIntHandling bigint_handling) { BigIntHandling bigint_handling) {
return CAST(NonNumberToNumberOrNumeric( return CAST(NonNumberToNumberOrNumeric(
context, input, Object::Conversion::kToNumber, bigint_handling)); context, input, Object::Conversion::kToNumber, bigint_handling));
} }
TNode<Number> CodeStubAssembler::PlainPrimitiveNonNumberToNumber(
TNode<HeapObject> input) {
CSA_ASSERT(this, Word32BinaryNot(IsHeapNumber(input)));
TVARIABLE(Number, var_result);
Label done(this);
// Dispatch on the {input} instance type.
TNode<Uint16T> input_instance_type = LoadInstanceType(input);
Label if_inputisstring(this), if_inputisoddball(this);
GotoIf(IsStringInstanceType(input_instance_type), &if_inputisstring);
CSA_ASSERT(this, InstanceTypeEqual(input_instance_type, ODDBALL_TYPE));
Goto(&if_inputisoddball);
BIND(&if_inputisstring);
{
// The {input} is a String, use the fast stub to convert it to a Number.
TNode<String> string_input = CAST(input);
var_result = StringToNumber(string_input);
Goto(&done);
}
BIND(&if_inputisoddball);
{
// The {input} is an Oddball, we just need to load the Number value of it.
var_result = LoadObjectField<Number>(input, Oddball::kToNumberOffset);
Goto(&done);
}
BIND(&done);
return var_result.value();
}
TNode<Numeric> CodeStubAssembler::NonNumberToNumeric( TNode<Numeric> CodeStubAssembler::NonNumberToNumeric(
SloppyTNode<Context> context, SloppyTNode<HeapObject> input) { TNode<Context> context, SloppyTNode<HeapObject> input) {
return NonNumberToNumberOrNumeric(context, input, return NonNumberToNumberOrNumeric(context, input,
Object::Conversion::kToNumeric); Object::Conversion::kToNumeric);
} }
...@@ -6909,7 +6946,7 @@ TNode<Number> CodeStubAssembler::ToNumber_Inline(SloppyTNode<Context> context, ...@@ -6909,7 +6946,7 @@ TNode<Number> CodeStubAssembler::ToNumber_Inline(SloppyTNode<Context> context,
return var_result.value(); return var_result.value();
} }
TNode<Number> CodeStubAssembler::ToNumber(SloppyTNode<Context> context, TNode<Number> CodeStubAssembler::ToNumber(TNode<Context> context,
SloppyTNode<Object> input, SloppyTNode<Object> input,
BigIntHandling bigint_handling) { BigIntHandling bigint_handling) {
TVARIABLE(Number, var_result); TVARIABLE(Number, var_result);
...@@ -6942,6 +6979,37 @@ TNode<Number> CodeStubAssembler::ToNumber(SloppyTNode<Context> context, ...@@ -6942,6 +6979,37 @@ TNode<Number> CodeStubAssembler::ToNumber(SloppyTNode<Context> context,
return var_result.value(); return var_result.value();
} }
TNode<Number> CodeStubAssembler::PlainPrimitiveToNumber(TNode<Object> input) {
TVARIABLE(Number, var_result);
Label end(this);
Label not_smi(this, Label::kDeferred);
GotoIfNot(TaggedIsSmi(input), &not_smi);
TNode<Smi> input_smi = CAST(input);
var_result = input_smi;
Goto(&end);
BIND(&not_smi);
{
Label not_heap_number(this, Label::kDeferred);
TNode<HeapObject> input_ho = CAST(input);
GotoIfNot(IsHeapNumber(input_ho), &not_heap_number);
TNode<HeapNumber> input_hn = CAST(input_ho);
var_result = input_hn;
Goto(&end);
BIND(&not_heap_number);
{
var_result = PlainPrimitiveNonNumberToNumber(input_ho);
Goto(&end);
}
}
BIND(&end);
return var_result.value();
}
TNode<BigInt> CodeStubAssembler::ToBigInt(TNode<Context> context, TNode<BigInt> CodeStubAssembler::ToBigInt(TNode<Context> context,
TNode<Object> input) { TNode<Object> input) {
TVARIABLE(BigInt, var_result); TVARIABLE(BigInt, var_result);
......
...@@ -2464,20 +2464,23 @@ class V8_EXPORT_PRIVATE CodeStubAssembler ...@@ -2464,20 +2464,23 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
// Convert a Non-Number object to a Number. // Convert a Non-Number object to a Number.
TNode<Number> NonNumberToNumber( TNode<Number> NonNumberToNumber(
SloppyTNode<Context> context, SloppyTNode<HeapObject> input, TNode<Context> context, SloppyTNode<HeapObject> input,
BigIntHandling bigint_handling = BigIntHandling::kThrow); BigIntHandling bigint_handling = BigIntHandling::kThrow);
// Convert a Non-Number object to a Numeric. // Convert a Non-Number object to a Numeric.
TNode<Numeric> NonNumberToNumeric(SloppyTNode<Context> context, TNode<Numeric> NonNumberToNumeric(TNode<Context> context,
SloppyTNode<HeapObject> input); SloppyTNode<HeapObject> input);
// Convert any object to a Number. // Convert any object to a Number.
// Conforms to ES#sec-tonumber if {bigint_handling} == kThrow. // Conforms to ES#sec-tonumber if {bigint_handling} == kThrow.
// With {bigint_handling} == kConvertToNumber, matches behavior of // With {bigint_handling} == kConvertToNumber, matches behavior of
// tc39.github.io/proposal-bigint/#sec-number-constructor-number-value. // tc39.github.io/proposal-bigint/#sec-number-constructor-number-value.
TNode<Number> ToNumber( TNode<Number> ToNumber(
SloppyTNode<Context> context, SloppyTNode<Object> input, TNode<Context> context, SloppyTNode<Object> input,
BigIntHandling bigint_handling = BigIntHandling::kThrow); BigIntHandling bigint_handling = BigIntHandling::kThrow);
TNode<Number> ToNumber_Inline(SloppyTNode<Context> context, TNode<Number> ToNumber_Inline(SloppyTNode<Context> context,
SloppyTNode<Object> input); SloppyTNode<Object> input);
// Convert any plain primitive to a Number. No need to handle BigInts since
// they are not plain primitives.
TNode<Number> PlainPrimitiveToNumber(TNode<Object> input);
// Try to convert an object to a BigInt. Throws on failure (e.g. for Numbers). // Try to convert an object to a BigInt. Throws on failure (e.g. for Numbers).
// https://tc39.github.io/proposal-bigint/#sec-to-bigint // https://tc39.github.io/proposal-bigint/#sec-to-bigint
...@@ -3655,6 +3658,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler ...@@ -3655,6 +3658,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<UnionT<FixedArray, PropertyArray>> array, TNode<TIndex> index, TNode<UnionT<FixedArray, PropertyArray>> array, TNode<TIndex> index,
TNode<Object> value, WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER, TNode<Object> value, WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER,
int additional_offset = 0); int additional_offset = 0);
// Converts {input} to a number. {input} must be a plain primitve.
TNode<Number> PlainPrimitiveNonNumberToNumber(TNode<HeapObject> input);
}; };
class V8_EXPORT_PRIVATE CodeStubArguments { class V8_EXPORT_PRIVATE CodeStubArguments {
......
...@@ -287,6 +287,12 @@ void TypeConversionDescriptor::InitializePlatformSpecific( ...@@ -287,6 +287,12 @@ void TypeConversionDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers); data->InitializePlatformSpecific(arraysize(registers), registers);
} }
void TypeConversionNoContextDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {TypeConversionDescriptor::ArgumentRegister()};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void TypeConversionStackParameterDescriptor::InitializePlatformSpecific( void TypeConversionStackParameterDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) { CallInterfaceDescriptorData* data) {
data->InitializePlatformSpecific(0, nullptr); data->InitializePlatformSpecific(0, nullptr);
......
...@@ -93,6 +93,7 @@ namespace internal { ...@@ -93,6 +93,7 @@ namespace internal {
V(StringAtAsString) \ V(StringAtAsString) \
V(StringSubstring) \ V(StringSubstring) \
V(TypeConversion) \ V(TypeConversion) \
V(TypeConversionNoContext) \
V(TypeConversionStackParameter) \ V(TypeConversionStackParameter) \
V(Typeof) \ V(Typeof) \
V(UnaryOp_WithFeedback) \ V(UnaryOp_WithFeedback) \
...@@ -909,6 +910,13 @@ class TypeConversionDescriptor final : public CallInterfaceDescriptor { ...@@ -909,6 +910,13 @@ class TypeConversionDescriptor final : public CallInterfaceDescriptor {
static const Register ArgumentRegister(); static const Register ArgumentRegister();
}; };
class TypeConversionNoContextDescriptor final : public CallInterfaceDescriptor {
public:
DEFINE_PARAMETERS_NO_CONTEXT(kArgument)
DEFINE_PARAMETER_TYPES(MachineType::AnyTagged())
DECLARE_DESCRIPTOR(TypeConversionNoContextDescriptor, CallInterfaceDescriptor)
};
class TypeConversionStackParameterDescriptor final class TypeConversionStackParameterDescriptor final
: public CallInterfaceDescriptor { : public CallInterfaceDescriptor {
public: public:
......
...@@ -716,9 +716,9 @@ Node* GraphAssembler::UnsafePointerAdd(Node* base, Node* external) { ...@@ -716,9 +716,9 @@ Node* GraphAssembler::UnsafePointerAdd(Node* base, Node* external) {
} }
TNode<Number> JSGraphAssembler::PlainPrimitiveToNumber(TNode<Object> value) { TNode<Number> JSGraphAssembler::PlainPrimitiveToNumber(TNode<Object> value) {
return AddNode<Number>(graph()->NewNode(PlainPrimitiveToNumberOperator(), return AddNode<Number>(graph()->NewNode(
ToNumberBuiltinConstant(), value, PlainPrimitiveToNumberOperator(), PlainPrimitiveToNumberBuiltinConstant(),
NoContextConstant(), effect())); value, effect()));
} }
Node* GraphAssembler::BitcastWordToTaggedSigned(Node* value) { Node* GraphAssembler::BitcastWordToTaggedSigned(Node* value) {
...@@ -959,7 +959,8 @@ void GraphAssembler::InitializeEffectControl(Node* effect, Node* control) { ...@@ -959,7 +959,8 @@ void GraphAssembler::InitializeEffectControl(Node* effect, Node* control) {
Operator const* JSGraphAssembler::PlainPrimitiveToNumberOperator() { Operator const* JSGraphAssembler::PlainPrimitiveToNumberOperator() {
if (!to_number_operator_.is_set()) { if (!to_number_operator_.is_set()) {
Callable callable = Builtins::CallableFor(isolate(), Builtins::kToNumber); Callable callable =
Builtins::CallableFor(isolate(), Builtins::kPlainPrimitiveToNumber);
CallDescriptor::Flags flags = CallDescriptor::kNoFlags; CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
auto call_descriptor = Linkage::GetStubCallDescriptor( auto call_descriptor = Linkage::GetStubCallDescriptor(
graph()->zone(), callable.descriptor(), graph()->zone(), callable.descriptor(),
......
...@@ -127,6 +127,7 @@ class BasicBlock; ...@@ -127,6 +127,7 @@ class BasicBlock;
V(One, Number) \ V(One, Number) \
V(TheHole, Oddball) \ V(TheHole, Oddball) \
V(ToNumberBuiltin, Code) \ V(ToNumberBuiltin, Code) \
V(PlainPrimitiveToNumberBuiltin, Code) \
V(True, Boolean) \ V(True, Boolean) \
V(Undefined, Oddball) \ V(Undefined, Oddball) \
V(Zero, Number) V(Zero, Number)
......
...@@ -129,6 +129,9 @@ DEFINE_GETTER(BooleanMapConstant, HeapConstant(factory()->boolean_map())) ...@@ -129,6 +129,9 @@ DEFINE_GETTER(BooleanMapConstant, HeapConstant(factory()->boolean_map()))
DEFINE_GETTER(ToNumberBuiltinConstant, DEFINE_GETTER(ToNumberBuiltinConstant,
HeapConstant(BUILTIN_CODE(isolate(), ToNumber))) HeapConstant(BUILTIN_CODE(isolate(), ToNumber)))
DEFINE_GETTER(PlainPrimitiveToNumberBuiltinConstant,
HeapConstant(BUILTIN_CODE(isolate(), PlainPrimitiveToNumber)))
DEFINE_GETTER(EmptyFixedArrayConstant, DEFINE_GETTER(EmptyFixedArrayConstant,
HeapConstant(factory()->empty_fixed_array())) HeapConstant(factory()->empty_fixed_array()))
......
...@@ -85,6 +85,7 @@ class V8_EXPORT_PRIVATE JSGraph : public MachineGraph { ...@@ -85,6 +85,7 @@ class V8_EXPORT_PRIVATE JSGraph : public MachineGraph {
V(BigIntMapConstant) \ V(BigIntMapConstant) \
V(BooleanMapConstant) \ V(BooleanMapConstant) \
V(ToNumberBuiltinConstant) \ V(ToNumberBuiltinConstant) \
V(PlainPrimitiveToNumberBuiltinConstant) \
V(EmptyFixedArrayConstant) \ V(EmptyFixedArrayConstant) \
V(EmptyStringConstant) \ V(EmptyStringConstant) \
V(FixedArrayMapConstant) \ V(FixedArrayMapConstant) \
......
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