From 6ff68255e9e74cd0e2ae51bcfc33002605851ba6 Mon Sep 17 00:00:00 2001 From: Georg Neis Date: Tue, 10 Oct 2017 18:00:31 +0200 Subject: [PATCH] [bigint] Introduce ToNumeric conversion. This introduces a ToNumeric conversion to the runtime and interpreter. ToNumeric behaves like ToNumber, except that it also lets BigInts pass. Bug: v8:6791 Change-Id: Idf9d0b5d283638459fe5893de41cc120356247a7 Reviewed-on: https://chromium-review.googlesource.com/707013 Commit-Queue: Georg Neis Reviewed-by: Leszek Swirski Reviewed-by: Jakob Kummerow Cr-Commit-Position: refs/heads/master@{#48440} --- src/builtins/builtins-conversion-gen.cc | 7 +++ src/builtins/builtins-definitions.h | 1 + src/code-stub-assembler.cc | 63 +++++++++++++++---- src/code-stub-assembler.h | 7 +++ src/compiler/bytecode-graph-builder.cc | 6 ++ src/interpreter/bytecode-array-builder.cc | 5 ++ src/interpreter/bytecode-array-builder.h | 1 + src/interpreter/bytecodes.h | 1 + src/interpreter/interpreter-assembler.cc | 59 +++++++++++++++++ src/interpreter/interpreter-assembler.h | 2 + src/interpreter/interpreter-generator.cc | 49 +++------------ src/messages.h | 1 + src/objects-inl.h | 12 +++- src/objects.cc | 26 +++++--- src/objects.h | 10 ++- src/runtime/runtime-object.cc | 6 ++ src/runtime/runtime.h | 5 +- .../AsyncGenerators.golden | 2 +- .../bytecode_expectations/ForAwaitOf.golden | 8 +-- .../bytecode_expectations/ForOf.golden | 8 +-- .../bytecode_expectations/ForOfLoop.golden | 18 +++--- .../bytecode_expectations/Generators.golden | 2 +- .../StandardForLoop.golden | 2 +- test/mjsunit/harmony/bigint.js | 29 +++++++++ .../bytecode-array-builder-unittest.cc | 2 +- 25 files changed, 241 insertions(+), 91 deletions(-) diff --git a/src/builtins/builtins-conversion-gen.cc b/src/builtins/builtins-conversion-gen.cc index c61ea70cf4..43761b145b 100644 --- a/src/builtins/builtins-conversion-gen.cc +++ b/src/builtins/builtins-conversion-gen.cc @@ -121,6 +121,13 @@ TF_BUILTIN(NonNumberToNumber, CodeStubAssembler) { Return(NonNumberToNumber(context, input)); } +TF_BUILTIN(NonNumberToNumeric, CodeStubAssembler) { + Node* context = Parameter(Descriptor::kContext); + Node* input = Parameter(Descriptor::kArgument); + + Return(NonNumberToNumeric(context, input)); +} + // ES6 section 7.1.3 ToNumber ( argument ) TF_BUILTIN(ToNumber, CodeStubAssembler) { Node* context = Parameter(Descriptor::kContext); diff --git a/src/builtins/builtins-definitions.h b/src/builtins/builtins-definitions.h index 746051b6cd..63385e72d8 100644 --- a/src/builtins/builtins-definitions.h +++ b/src/builtins/builtins-definitions.h @@ -183,6 +183,7 @@ namespace internal { TFC(StringToNumber, TypeConversion, 1) \ TFC(ToName, TypeConversion, 1) \ TFC(NonNumberToNumber, TypeConversion, 1) \ + TFC(NonNumberToNumeric, TypeConversion, 1) \ TFC(ToNumber, TypeConversion, 1) \ TFC(ToString, TypeConversion, 1) \ TFC(ToInteger, TypeConversion, 1) \ diff --git a/src/code-stub-assembler.cc b/src/code-stub-assembler.cc index 612d9b76af..38259fd078 100644 --- a/src/code-stub-assembler.cc +++ b/src/code-stub-assembler.cc @@ -3956,6 +3956,13 @@ Node* CodeStubAssembler::IsJSRegExp(Node* object) { return HasInstanceType(object, JS_REGEXP_TYPE); } +Node* CodeStubAssembler::IsNumeric(Node* object) { + return Select( + TaggedIsSmi(object), [=] { return Int32Constant(1); }, + [=] { return Word32Or(IsHeapNumber(object), IsBigInt(object)); }, + MachineRepresentation::kWord32); +} + Node* CodeStubAssembler::IsNumber(Node* object) { return Select(TaggedIsSmi(object), [=] { return Int32Constant(1); }, [=] { return IsHeapNumber(object); }, @@ -4869,8 +4876,8 @@ Node* CodeStubAssembler::ToName(Node* context, Node* value) { return var_result.value(); } -Node* CodeStubAssembler::NonNumberToNumber(Node* context, Node* input) { - // Assert input is a HeapObject (not smi or heap number) +Node* CodeStubAssembler::NonNumberToNumberOrNumeric(Node* context, Node* input, + Object::Conversion mode) { CSA_ASSERT(this, Word32BinaryNot(TaggedIsSmi(input))); CSA_ASSERT(this, Word32BinaryNot(IsHeapNumber(input))); @@ -4888,9 +4895,10 @@ Node* CodeStubAssembler::NonNumberToNumber(Node* context, Node* input) { // Dispatch on the {input} instance type. Node* input_instance_type = LoadInstanceType(input); Label if_inputisstring(this), if_inputisoddball(this), - if_inputisreceiver(this, Label::kDeferred), + if_inputisbigint(this), if_inputisreceiver(this, Label::kDeferred), if_inputisother(this, Label::kDeferred); GotoIf(IsStringInstanceType(input_instance_type), &if_inputisstring); + GotoIf(IsBigIntInstanceType(input_instance_type), &if_inputisbigint); GotoIf(Word32Equal(input_instance_type, Int32Constant(ODDBALL_TYPE)), &if_inputisoddball); Branch(IsJSReceiverInstanceType(input_instance_type), &if_inputisreceiver, @@ -4903,6 +4911,15 @@ Node* CodeStubAssembler::NonNumberToNumber(Node* context, Node* input) { Goto(&end); } + BIND(&if_inputisbigint); + if (mode == Object::Conversion::kToNumeric) { + var_result.Bind(input); + Goto(&end); + } else { + DCHECK(mode == Object::Conversion::kToNumber); + Goto(&if_inputisother); + } + BIND(&if_inputisoddball); { // The {input} is an Oddball, we just need to load the Number value of it. @@ -4918,21 +4935,23 @@ Node* CodeStubAssembler::NonNumberToNumber(Node* context, Node* input) { isolate(), ToPrimitiveHint::kNumber); Node* result = CallStub(callable, context, input); - // Check if the {result} is already a Number. - Label if_resultisnumber(this), if_resultisnotnumber(this); - GotoIf(TaggedIsSmi(result), &if_resultisnumber); - Branch(IsHeapNumber(result), &if_resultisnumber, &if_resultisnotnumber); + // Check if the {result} is already a Number/Numeric. + Label if_done(this), if_notdone(this); + Branch(mode == Object::Conversion::kToNumber ? IsNumber(result) + : IsNumeric(result), + &if_done, &if_notdone); - BIND(&if_resultisnumber); + BIND(&if_done); { - // The ToPrimitive conversion already gave us a Number, so we're done. + // The ToPrimitive conversion already gave us a Number/Numeric, so we're + // done. var_result.Bind(result); Goto(&end); } - BIND(&if_resultisnotnumber); + BIND(&if_notdone); { - // We now have a Primitive {result}, but it's not yet a Number. + // We now have a Primitive {result}, but it's not yet a Number/Numeric. var_input.Bind(result); Goto(&loop); } @@ -4946,16 +4965,34 @@ Node* CodeStubAssembler::NonNumberToNumber(Node* context, Node* input) { // trampolines also use this code currently, and they declare all // outgoing parameters as untagged, while we would push a tagged // object here. - var_result.Bind(CallRuntime(Runtime::kToNumber, context, input)); + auto function_id = mode == Object::Conversion::kToNumber + ? Runtime::kToNumber + : Runtime::kToNumeric; + var_result.Bind(CallRuntime(function_id, context, input)); Goto(&end); } } BIND(&end); - CSA_ASSERT(this, IsNumber(var_result.value())); + if (mode == Object::Conversion::kToNumeric) { + CSA_ASSERT(this, IsNumeric(var_result.value())); + } else { + DCHECK(mode == Object::Conversion::kToNumber); + CSA_ASSERT(this, IsNumber(var_result.value())); + } return var_result.value(); } +Node* CodeStubAssembler::NonNumberToNumber(Node* context, Node* input) { + return NonNumberToNumberOrNumeric(context, input, + Object::Conversion::kToNumber); +} + +Node* CodeStubAssembler::NonNumberToNumeric(Node* context, Node* input) { + return NonNumberToNumberOrNumeric(context, input, + Object::Conversion::kToNumeric); +} + Node* CodeStubAssembler::ToNumber(Node* context, Node* input) { VARIABLE(var_result, MachineRepresentation::kTagged); Label end(this); diff --git a/src/code-stub-assembler.h b/src/code-stub-assembler.h index 7c7777e1ac..28221753da 100644 --- a/src/code-stub-assembler.h +++ b/src/code-stub-assembler.h @@ -954,6 +954,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { // True iff |object| is a Smi or a HeapNumber. Node* IsNumber(Node* object); + // True iff |object| is a Smi or a HeapNumber or a BigInt. + Node* IsNumeric(Node* object); // True iff |number| is either a Smi, or a HeapNumber whose value is not // within Smi range. @@ -1016,6 +1018,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { Node* ToName(Node* context, Node* input); // Convert a Non-Number object to a Number. Node* NonNumberToNumber(Node* context, Node* input); + // Convert a Non-Number object to a Numeric. + Node* NonNumberToNumeric(Node* context, Node* input); // Convert any object to a Number. Node* ToNumber(Node* context, Node* input); @@ -1723,6 +1727,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { Node* character_count); static const int kElementLoopUnrollThreshold = 8; + + Node* NonNumberToNumberOrNumeric(Node* context, Node* input, + Object::Conversion mode); }; class CodeStubArguments { diff --git a/src/compiler/bytecode-graph-builder.cc b/src/compiler/bytecode-graph-builder.cc index ca3a70ab1f..245a044ee8 100644 --- a/src/compiler/bytecode-graph-builder.cc +++ b/src/compiler/bytecode-graph-builder.cc @@ -2516,6 +2516,12 @@ void BytecodeGraphBuilder::VisitToNumber() { environment()->BindAccumulator(node, Environment::kAttachFrameState); } +void BytecodeGraphBuilder::VisitToNumeric() { + // TODO(neis): This is currently only correct in the absence of bigints. + DCHECK(!FLAG_harmony_bigint); + VisitToNumber(); +} + void BytecodeGraphBuilder::VisitJump() { BuildJump(); } void BytecodeGraphBuilder::VisitJumpConstant() { BuildJump(); } diff --git a/src/interpreter/bytecode-array-builder.cc b/src/interpreter/bytecode-array-builder.cc index 09789fe8b2..a865bd02aa 100644 --- a/src/interpreter/bytecode-array-builder.cc +++ b/src/interpreter/bytecode-array-builder.cc @@ -1020,6 +1020,11 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::ToNumber(int feedback_slot) { return *this; } +BytecodeArrayBuilder& BytecodeArrayBuilder::ToNumeric(int feedback_slot) { + OutputToNumeric(feedback_slot); + return *this; +} + BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(BytecodeLabel* label) { // Flush the register optimizer when binding a label to ensure all // expected registers are valid when jumping to this label. diff --git a/src/interpreter/bytecode-array-builder.h b/src/interpreter/bytecode-array-builder.h index e536b98cda..8d286887b6 100644 --- a/src/interpreter/bytecode-array-builder.h +++ b/src/interpreter/bytecode-array-builder.h @@ -361,6 +361,7 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final // Converts accumulator and stores result back in accumulator. BytecodeArrayBuilder& ToNumber(int feedback_slot); + BytecodeArrayBuilder& ToNumeric(int feedback_slot); // Flow Control. BytecodeArrayBuilder& Bind(BytecodeLabel* label); diff --git a/src/interpreter/bytecodes.h b/src/interpreter/bytecodes.h index e7bcd50611..485d27fdd7 100644 --- a/src/interpreter/bytecodes.h +++ b/src/interpreter/bytecodes.h @@ -218,6 +218,7 @@ namespace interpreter { /* Cast operators */ \ V(ToName, AccumulatorUse::kRead, OperandType::kRegOut) \ V(ToNumber, AccumulatorUse::kReadWrite, OperandType::kIdx) \ + V(ToNumeric, AccumulatorUse::kReadWrite, OperandType::kIdx) \ V(ToObject, AccumulatorUse::kRead, OperandType::kRegOut) \ \ /* Literals */ \ diff --git a/src/interpreter/interpreter-assembler.cc b/src/interpreter/interpreter-assembler.cc index 2db780b979..1f04db0422 100644 --- a/src/interpreter/interpreter-assembler.cc +++ b/src/interpreter/interpreter-assembler.cc @@ -1549,6 +1549,65 @@ int InterpreterAssembler::CurrentBytecodeSize() const { return Bytecodes::Size(bytecode_, operand_scale_); } +void InterpreterAssembler::ToNumberOrNumeric(Object::Conversion mode) { + Node* object = GetAccumulator(); + Node* context = GetContext(); + + Variable var_type_feedback(this, MachineRepresentation::kTaggedSigned); + Variable var_result(this, MachineRepresentation::kTagged); + Label if_done(this), if_objectissmi(this), if_objectisheapnumber(this), + if_objectisother(this, Label::kDeferred); + + GotoIf(TaggedIsSmi(object), &if_objectissmi); + Branch(IsHeapNumber(object), &if_objectisheapnumber, &if_objectisother); + + BIND(&if_objectissmi); + { + var_result.Bind(object); + var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kSignedSmall)); + Goto(&if_done); + } + + BIND(&if_objectisheapnumber); + { + var_result.Bind(object); + var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber)); + Goto(&if_done); + } + + BIND(&if_objectisother); + { + auto builtin = Builtins::kNonNumberToNumber; + if (mode == Object::Conversion::kToNumeric) { + builtin = Builtins::kNonNumberToNumeric; + // Special case for collecting BigInt feedback. + Label not_bigint(this); + GotoIfNot(IsBigInt(object), ¬_bigint); + { + var_result.Bind(object); + var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kBigInt)); + Goto(&if_done); + } + BIND(¬_bigint); + } + + // Convert {object} by calling out to the appropriate builtin. + var_result.Bind(CallBuiltin(builtin, context, object)); + var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny)); + Goto(&if_done); + } + + BIND(&if_done); + + // Record the type feedback collected for {object}. + Node* slot_index = BytecodeOperandIdx(0); + Node* feedback_vector = LoadFeedbackVector(); + UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_index); + + SetAccumulator(var_result.value()); + Dispatch(); +} + } // namespace interpreter } // namespace internal } // namespace v8 diff --git a/src/interpreter/interpreter-assembler.h b/src/interpreter/interpreter-assembler.h index 312fa3198d..487ebdd04c 100644 --- a/src/interpreter/interpreter-assembler.h +++ b/src/interpreter/interpreter-assembler.h @@ -245,6 +245,8 @@ class V8_EXPORT_PRIVATE InterpreterAssembler : public CodeStubAssembler { Bytecode bytecode() const { return bytecode_; } static bool TargetSupportsUnalignedAccess(); + void ToNumberOrNumeric(Object::Conversion mode); + private: // Returns a tagged pointer to the current function's BytecodeArray object. compiler::Node* BytecodeArrayTaggedPointer(); diff --git a/src/interpreter/interpreter-generator.cc b/src/interpreter/interpreter-generator.cc index 6b2e2d8190..e38393233e 100644 --- a/src/interpreter/interpreter-generator.cc +++ b/src/interpreter/interpreter-generator.cc @@ -1327,49 +1327,14 @@ IGNITION_HANDLER(ToName, InterpreterAssembler) { // // Convert the object referenced by the accumulator to a number. IGNITION_HANDLER(ToNumber, InterpreterAssembler) { - Node* object = GetAccumulator(); - Node* context = GetContext(); + ToNumberOrNumeric(Object::Conversion::kToNumber); +} - // Convert the {object} to a Number and collect feedback for the {object}. - Variable var_type_feedback(this, MachineRepresentation::kTaggedSigned); - Variable var_result(this, MachineRepresentation::kTagged); - Label if_done(this), if_objectissmi(this), if_objectisnumber(this), - if_objectisother(this, Label::kDeferred); - - GotoIf(TaggedIsSmi(object), &if_objectissmi); - Branch(IsHeapNumber(object), &if_objectisnumber, &if_objectisother); - - BIND(&if_objectissmi); - { - var_result.Bind(object); - var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kSignedSmall)); - Goto(&if_done); - } - - BIND(&if_objectisnumber); - { - var_result.Bind(object); - var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber)); - Goto(&if_done); - } - - BIND(&if_objectisother); - { - // Convert the {object} to a Number. - var_result.Bind(CallBuiltin(Builtins::kNonNumberToNumber, context, object)); - var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny)); - Goto(&if_done); - } - - BIND(&if_done); - - // Record the type feedback collected for {object}. - Node* slot_index = BytecodeOperandIdx(0); - Node* feedback_vector = LoadFeedbackVector(); - UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_index); - - SetAccumulator(var_result.value()); - Dispatch(); +// ToNumeric +// +// Convert the object referenced by the accumulator to a numeric. +IGNITION_HANDLER(ToNumeric, InterpreterAssembler) { + ToNumberOrNumeric(Object::Conversion::kToNumeric); } // ToObject diff --git a/src/messages.h b/src/messages.h index 51a6258215..31dc00b60b 100644 --- a/src/messages.h +++ b/src/messages.h @@ -276,6 +276,7 @@ class ErrorUtils : public AllStatic { T(BigIntMixedTypes, \ "Cannot mix BigInt and other types, use explicit conversions") \ T(BigIntShr, "BigInts have no unsigned right shift, use >> instead") \ + T(BigIntToNumber, "Cannot convert a BigInt value to a number") \ T(CalledNonCallable, "% is not a function") \ T(CalledOnNonObject, "% called on non-object") \ T(CalledOnNullOrUndefined, "% called on null or undefined") \ diff --git a/src/objects-inl.h b/src/objects-inl.h index 7212a43d27..72c9be96f8 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -778,8 +778,16 @@ MaybeHandle Object::ToPrimitive(Handle input, // static MaybeHandle Object::ToNumber(Handle input) { - if (input->IsNumber()) return input; - return ConvertToNumber(HeapObject::cast(*input)->GetIsolate(), input); + if (input->IsNumber()) return input; // Shortcut. + return ConvertToNumberOrNumeric(HeapObject::cast(*input)->GetIsolate(), input, + Conversion::kToNumber); +} + +// static +MaybeHandle Object::ToNumeric(Handle input) { + if (input->IsNumber() || input->IsBigInt()) return input; // Shortcut. + return ConvertToNumberOrNumeric(HeapObject::cast(*input)->GetIsolate(), input, + Conversion::kToNumeric); } // static diff --git a/src/objects.cc b/src/objects.cc index 7b7728c301..17e24bf4e1 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -155,8 +155,9 @@ MaybeHandle Object::ConvertReceiver(Isolate* isolate, } // static -MaybeHandle Object::ConvertToNumber(Isolate* isolate, - Handle input) { +MaybeHandle Object::ConvertToNumberOrNumeric(Isolate* isolate, + Handle input, + Conversion mode) { while (true) { if (input->IsNumber()) { return input; @@ -171,6 +172,12 @@ MaybeHandle Object::ConvertToNumber(Isolate* isolate, THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToNumber), Object); } + if (input->IsBigInt()) { + if (mode == Conversion::kToNumeric) return input; + DCHECK(mode == Conversion::kToNumber); + THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kBigIntToNumber), + Object); + } ASSIGN_RETURN_ON_EXCEPTION( isolate, input, JSReceiver::ToPrimitive(Handle::cast(input), ToPrimitiveHint::kNumber), @@ -181,8 +188,9 @@ MaybeHandle Object::ConvertToNumber(Isolate* isolate, // static MaybeHandle Object::ConvertToInteger(Isolate* isolate, Handle input) { - ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ConvertToNumber(isolate, input), - Object); + ASSIGN_RETURN_ON_EXCEPTION( + isolate, input, + ConvertToNumberOrNumeric(isolate, input, Conversion::kToNumber), Object); if (input->IsSmi()) return input; return isolate->factory()->NewNumber(DoubleToInteger(input->Number())); } @@ -190,8 +198,9 @@ MaybeHandle Object::ConvertToInteger(Isolate* isolate, // static MaybeHandle Object::ConvertToInt32(Isolate* isolate, Handle input) { - ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ConvertToNumber(isolate, input), - Object); + ASSIGN_RETURN_ON_EXCEPTION( + isolate, input, + ConvertToNumberOrNumeric(isolate, input, Conversion::kToNumber), Object); if (input->IsSmi()) return input; return isolate->factory()->NewNumberFromInt(DoubleToInt32(input->Number())); } @@ -199,8 +208,9 @@ MaybeHandle Object::ConvertToInt32(Isolate* isolate, // static MaybeHandle Object::ConvertToUint32(Isolate* isolate, Handle input) { - ASSIGN_RETURN_ON_EXCEPTION(isolate, input, ConvertToNumber(isolate, input), - Object); + ASSIGN_RETURN_ON_EXCEPTION( + isolate, input, + ConvertToNumberOrNumeric(isolate, input, Conversion::kToNumber), Object); if (input->IsSmi()) return handle(Smi::cast(*input)->ToUint32Smi(), isolate); return isolate->factory()->NewNumberFromUint(DoubleToUint32(input->Number())); } diff --git a/src/objects.h b/src/objects.h index 18911a77fa..b00436e1af 100644 --- a/src/objects.h +++ b/src/objects.h @@ -913,7 +913,6 @@ enum class ComparisonResult { kUndefined // at least one of x or y was undefined or NaN }; - class AbstractCode; class AccessorPair; class AllocationSite; @@ -1158,6 +1157,8 @@ class Object { enum ShouldThrow { THROW_ON_ERROR, DONT_THROW }; + enum class Conversion { kToNumber, kToNumeric }; + #define RETURN_FAILURE(isolate, should_throw, call) \ do { \ if ((should_throw) == DONT_THROW) { \ @@ -1268,6 +1269,9 @@ class Object { MUST_USE_RESULT static inline MaybeHandle ToNumber( Handle input); + MUST_USE_RESULT static inline MaybeHandle ToNumeric( + Handle input); + // ES6 section 7.1.4 ToInteger MUST_USE_RESULT static inline MaybeHandle ToInteger( Isolate* isolate, Handle input); @@ -1537,8 +1541,8 @@ class Object { Isolate* isolate, Handle value); MUST_USE_RESULT static MaybeHandle ConvertToString( Isolate* isolate, Handle input); - MUST_USE_RESULT static MaybeHandle ConvertToNumber( - Isolate* isolate, Handle input); + MUST_USE_RESULT static MaybeHandle ConvertToNumberOrNumeric( + Isolate* isolate, Handle input, Conversion mode); MUST_USE_RESULT static MaybeHandle ConvertToInteger( Isolate* isolate, Handle input); MUST_USE_RESULT static MaybeHandle ConvertToInt32( diff --git a/src/runtime/runtime-object.cc b/src/runtime/runtime-object.cc index 711a55e2ff..808acaa62c 100644 --- a/src/runtime/runtime-object.cc +++ b/src/runtime/runtime-object.cc @@ -1070,6 +1070,12 @@ RUNTIME_FUNCTION(Runtime_ToNumber) { RETURN_RESULT_OR_FAILURE(isolate, Object::ToNumber(input)); } +RUNTIME_FUNCTION(Runtime_ToNumeric) { + HandleScope scope(isolate); + DCHECK_EQ(1, args.length()); + CONVERT_ARG_HANDLE_CHECKED(Object, input, 0); + RETURN_RESULT_OR_FAILURE(isolate, Object::ToNumeric(input)); +} RUNTIME_FUNCTION(Runtime_ToInteger) { HandleScope scope(isolate); diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index a84efc1032..bd4111d80a 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -69,9 +69,9 @@ namespace internal { F(SetAllowAtomicsWait, 1, 1) #define FOR_EACH_INTRINSIC_BIGINT(F) \ + F(BigIntBinaryOp, 3, 1) \ F(BigIntEqual, 2, 1) \ - F(BigIntToBoolean, 1, 1) \ - F(BigIntBinaryOp, 3, 1) + F(BigIntToBoolean, 1, 1) #define FOR_EACH_INTRINSIC_CLASSES(F) \ F(ThrowUnsupportedSuperError, 0, 1) \ @@ -418,6 +418,7 @@ namespace internal { F(ToPrimitive, 1, 1) \ F(ToPrimitive_Number, 1, 1) \ F(ToNumber, 1, 1) \ + F(ToNumeric, 1, 1) \ F(ToInteger, 1, 1) \ F(ToLength, 1, 1) \ F(ToString, 1, 1) \ diff --git a/test/cctest/interpreter/bytecode_expectations/AsyncGenerators.golden b/test/cctest/interpreter/bytecode_expectations/AsyncGenerators.golden index 84fdd0f715..71f376e7da 100644 --- a/test/cctest/interpreter/bytecode_expectations/AsyncGenerators.golden +++ b/test/cctest/interpreter/bytecode_expectations/AsyncGenerators.golden @@ -428,7 +428,7 @@ bytecodes: [ B(TestTypeOf), U8(5), B(JumpIfFalse), U8(4), B(Jump), U8(18), - B(Wide), B(LdaSmi), I16(137), + B(Wide), B(LdaSmi), I16(138), B(Star), R(18), B(LdaConstant), U8(16), B(Star), R(19), diff --git a/test/cctest/interpreter/bytecode_expectations/ForAwaitOf.golden b/test/cctest/interpreter/bytecode_expectations/ForAwaitOf.golden index f02cb544d0..763566ec2c 100644 --- a/test/cctest/interpreter/bytecode_expectations/ForAwaitOf.golden +++ b/test/cctest/interpreter/bytecode_expectations/ForAwaitOf.golden @@ -143,7 +143,7 @@ bytecodes: [ B(TestTypeOf), U8(5), B(JumpIfFalse), U8(4), B(Jump), U8(18), - B(Wide), B(LdaSmi), I16(137), + B(Wide), B(LdaSmi), I16(138), B(Star), R(19), B(LdaConstant), U8(13), B(Star), R(20), @@ -432,7 +432,7 @@ bytecodes: [ B(TestTypeOf), U8(5), B(JumpIfFalse), U8(4), B(Jump), U8(18), - B(Wide), B(LdaSmi), I16(137), + B(Wide), B(LdaSmi), I16(138), B(Star), R(19), B(LdaConstant), U8(13), B(Star), R(20), @@ -743,7 +743,7 @@ bytecodes: [ B(TestTypeOf), U8(5), B(JumpIfFalse), U8(4), B(Jump), U8(18), - B(Wide), B(LdaSmi), I16(137), + B(Wide), B(LdaSmi), I16(138), B(Star), R(19), B(LdaConstant), U8(13), B(Star), R(20), @@ -991,7 +991,7 @@ bytecodes: [ B(TestTypeOf), U8(5), B(JumpIfFalse), U8(4), B(Jump), U8(18), - B(Wide), B(LdaSmi), I16(137), + B(Wide), B(LdaSmi), I16(138), B(Star), R(16), B(LdaConstant), U8(10), B(Star), R(17), diff --git a/test/cctest/interpreter/bytecode_expectations/ForOf.golden b/test/cctest/interpreter/bytecode_expectations/ForOf.golden index 9ef001a264..7c409c43bb 100644 --- a/test/cctest/interpreter/bytecode_expectations/ForOf.golden +++ b/test/cctest/interpreter/bytecode_expectations/ForOf.golden @@ -86,7 +86,7 @@ bytecodes: [ B(TestTypeOf), U8(5), B(JumpIfFalse), U8(4), B(Jump), U8(18), - B(Wide), B(LdaSmi), I16(137), + B(Wide), B(LdaSmi), I16(138), B(Star), R(11), B(LdaConstant), U8(8), B(Star), R(12), @@ -227,7 +227,7 @@ bytecodes: [ B(TestTypeOf), U8(5), B(JumpIfFalse), U8(4), B(Jump), U8(18), - B(Wide), B(LdaSmi), I16(137), + B(Wide), B(LdaSmi), I16(138), B(Star), R(12), B(LdaConstant), U8(8), B(Star), R(13), @@ -380,7 +380,7 @@ bytecodes: [ B(TestTypeOf), U8(5), B(JumpIfFalse), U8(4), B(Jump), U8(18), - B(Wide), B(LdaSmi), I16(137), + B(Wide), B(LdaSmi), I16(138), B(Star), R(11), B(LdaConstant), U8(8), B(Star), R(12), @@ -523,7 +523,7 @@ bytecodes: [ B(TestTypeOf), U8(5), B(JumpIfFalse), U8(4), B(Jump), U8(18), - B(Wide), B(LdaSmi), I16(137), + B(Wide), B(LdaSmi), I16(138), B(Star), R(10), B(LdaConstant), U8(10), B(Star), R(11), diff --git a/test/cctest/interpreter/bytecode_expectations/ForOfLoop.golden b/test/cctest/interpreter/bytecode_expectations/ForOfLoop.golden index af992d39ec..864352cb14 100644 --- a/test/cctest/interpreter/bytecode_expectations/ForOfLoop.golden +++ b/test/cctest/interpreter/bytecode_expectations/ForOfLoop.golden @@ -90,7 +90,7 @@ bytecodes: [ B(TestTypeOf), U8(5), B(JumpIfFalse), U8(4), B(Jump), U8(18), - B(Wide), B(LdaSmi), I16(137), + B(Wide), B(LdaSmi), I16(138), B(Star), R(13), B(LdaConstant), U8(7), B(Star), R(14), @@ -268,7 +268,7 @@ bytecodes: [ B(TestTypeOf), U8(5), B(JumpIfFalse), U8(4), B(Jump), U8(18), - B(Wide), B(LdaSmi), I16(137), + B(Wide), B(LdaSmi), I16(138), B(Star), R(13), B(LdaConstant), U8(11), B(Star), R(14), @@ -422,7 +422,7 @@ bytecodes: [ B(TestTypeOf), U8(5), B(JumpIfFalse), U8(4), B(Jump), U8(18), - B(Wide), B(LdaSmi), I16(137), + B(Wide), B(LdaSmi), I16(138), B(Star), R(11), B(LdaConstant), U8(9), B(Star), R(12), @@ -524,7 +524,7 @@ bytecodes: [ B(JumpIfUndefined), U8(6), B(Ldar), R(6), B(JumpIfNotNull), U8(16), - B(LdaSmi), I8(67), + B(LdaSmi), I8(68), B(Star), R(17), B(LdaConstant), U8(4), B(Star), R(18), @@ -580,7 +580,7 @@ bytecodes: [ B(TestTypeOf), U8(5), B(JumpIfFalse), U8(4), B(Jump), U8(18), - B(Wide), B(LdaSmi), I16(137), + B(Wide), B(LdaSmi), I16(138), B(Star), R(16), B(LdaConstant), U8(9), B(Star), R(17), @@ -754,7 +754,7 @@ bytecodes: [ B(TestTypeOf), U8(5), B(JumpIfFalse), U8(4), B(Jump), U8(18), - B(Wide), B(LdaSmi), I16(137), + B(Wide), B(LdaSmi), I16(138), B(Star), R(16), B(LdaConstant), U8(10), B(Star), R(17), @@ -953,7 +953,7 @@ bytecodes: [ B(TestTypeOf), U8(5), B(JumpIfFalse), U8(4), B(Jump), U8(18), - B(Wide), B(LdaSmi), I16(137), + B(Wide), B(LdaSmi), I16(138), B(Star), R(15), B(LdaConstant), U8(14), B(Star), R(16), @@ -1116,7 +1116,7 @@ bytecodes: [ B(TestTypeOf), U8(5), B(JumpIfFalse), U8(4), B(Jump), U8(18), - B(Wide), B(LdaSmi), I16(137), + B(Wide), B(LdaSmi), I16(138), B(Star), R(20), B(LdaConstant), U8(7), B(Star), R(21), @@ -1358,7 +1358,7 @@ bytecodes: [ B(TestTypeOf), U8(5), B(JumpIfFalse), U8(4), B(Jump), U8(18), - B(Wide), B(LdaSmi), I16(137), + B(Wide), B(LdaSmi), I16(138), B(Star), R(20), B(LdaConstant), U8(9), B(Star), R(21), diff --git a/test/cctest/interpreter/bytecode_expectations/Generators.golden b/test/cctest/interpreter/bytecode_expectations/Generators.golden index bf2eb53a4f..38273681b1 100644 --- a/test/cctest/interpreter/bytecode_expectations/Generators.golden +++ b/test/cctest/interpreter/bytecode_expectations/Generators.golden @@ -257,7 +257,7 @@ bytecodes: [ B(TestTypeOf), U8(5), B(JumpIfFalse), U8(4), B(Jump), U8(18), - B(Wide), B(LdaSmi), I16(137), + B(Wide), B(LdaSmi), I16(138), B(Star), R(14), B(LdaConstant), U8(15), B(Star), R(15), diff --git a/test/cctest/interpreter/bytecode_expectations/StandardForLoop.golden b/test/cctest/interpreter/bytecode_expectations/StandardForLoop.golden index 4194925e41..e0945f236b 100644 --- a/test/cctest/interpreter/bytecode_expectations/StandardForLoop.golden +++ b/test/cctest/interpreter/bytecode_expectations/StandardForLoop.golden @@ -231,7 +231,7 @@ bytecodes: [ B(JumpIfUndefined), U8(6), B(Ldar), R(3), B(JumpIfNotNull), U8(16), - B(LdaSmi), I8(67), + B(LdaSmi), I8(68), B(Star), R(4), B(LdaConstant), U8(1), B(Star), R(5), diff --git a/test/mjsunit/harmony/bigint.js b/test/mjsunit/harmony/bigint.js index 4406f12b11..d08275d829 100644 --- a/test/mjsunit/harmony/bigint.js +++ b/test/mjsunit/harmony/bigint.js @@ -6,6 +6,7 @@ 'use strict' +const minus_one = BigInt(-1); const zero = BigInt(0); const another_zero = BigInt(0); const one = BigInt(1); @@ -313,6 +314,34 @@ const six = BigInt(6); assertTrue(new Map([[one, 42]]).has(another_one)); } +// ToNumber +{ + assertThrows(() => isNaN(zero), TypeError); + assertThrows(() => isNaN(one), TypeError); + + assertThrows(() => +zero, TypeError); + assertThrows(() => +one, TypeError); +} +{ + let Zero = {valueOf() { return zero }}; + let One = {valueOf() { return one }}; + + assertThrows(() => isNaN(Zero), TypeError); + assertThrows(() => isNaN(One), TypeError); + + assertThrows(() => +Zero, TypeError); + assertThrows(() => +One, TypeError); +}{ + let Zero = {valueOf() { return Object(NaN) }, toString() { return zero }}; + let One = {valueOf() { return one }, toString() { return NaN }}; + + assertThrows(() => isNaN(Zero), TypeError); + assertThrows(() => isNaN(One), TypeError); + + assertThrows(() => +Zero, TypeError); + assertThrows(() => +One, TypeError); +} + // Binary ops. { assertTrue(one + two === three); diff --git a/test/unittests/interpreter/bytecode-array-builder-unittest.cc b/test/unittests/interpreter/bytecode-array-builder-unittest.cc index 5cdce7fc00..e3c0486e1f 100644 --- a/test/unittests/interpreter/bytecode-array-builder-unittest.cc +++ b/test/unittests/interpreter/bytecode-array-builder-unittest.cc @@ -227,7 +227,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { .CompareNull(); // Emit conversion operator invocations. - builder.ToNumber(1).ToObject(reg).ToName(reg); + builder.ToNumber(1).ToNumeric(1).ToObject(reg).ToName(reg); // Emit GetSuperConstructor. builder.GetSuperConstructor(reg);