[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 <neis@chromium.org> Reviewed-by: Leszek Swirski <leszeks@chromium.org> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Cr-Commit-Position: refs/heads/master@{#48440}
This commit is contained in:
parent
dde4cbb0b1
commit
6ff68255e9
@ -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);
|
||||
|
@ -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) \
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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(); }
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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 */ \
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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 <slot>
|
||||
//
|
||||
// Convert the object referenced by the accumulator to a numeric.
|
||||
IGNITION_HANDLER(ToNumeric, InterpreterAssembler) {
|
||||
ToNumberOrNumeric(Object::Conversion::kToNumeric);
|
||||
}
|
||||
|
||||
// ToObject <dst>
|
||||
|
@ -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") \
|
||||
|
@ -778,8 +778,16 @@ MaybeHandle<Object> Object::ToPrimitive(Handle<Object> input,
|
||||
|
||||
// static
|
||||
MaybeHandle<Object> Object::ToNumber(Handle<Object> 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> Object::ToNumeric(Handle<Object> input) {
|
||||
if (input->IsNumber() || input->IsBigInt()) return input; // Shortcut.
|
||||
return ConvertToNumberOrNumeric(HeapObject::cast(*input)->GetIsolate(), input,
|
||||
Conversion::kToNumeric);
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -155,8 +155,9 @@ MaybeHandle<JSReceiver> Object::ConvertReceiver(Isolate* isolate,
|
||||
}
|
||||
|
||||
// static
|
||||
MaybeHandle<Object> Object::ConvertToNumber(Isolate* isolate,
|
||||
Handle<Object> input) {
|
||||
MaybeHandle<Object> Object::ConvertToNumberOrNumeric(Isolate* isolate,
|
||||
Handle<Object> input,
|
||||
Conversion mode) {
|
||||
while (true) {
|
||||
if (input->IsNumber()) {
|
||||
return input;
|
||||
@ -171,6 +172,12 @@ MaybeHandle<Object> 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<JSReceiver>::cast(input),
|
||||
ToPrimitiveHint::kNumber),
|
||||
@ -181,8 +188,9 @@ MaybeHandle<Object> Object::ConvertToNumber(Isolate* isolate,
|
||||
// static
|
||||
MaybeHandle<Object> Object::ConvertToInteger(Isolate* isolate,
|
||||
Handle<Object> 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> Object::ConvertToInteger(Isolate* isolate,
|
||||
// static
|
||||
MaybeHandle<Object> Object::ConvertToInt32(Isolate* isolate,
|
||||
Handle<Object> 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> Object::ConvertToInt32(Isolate* isolate,
|
||||
// static
|
||||
MaybeHandle<Object> Object::ConvertToUint32(Isolate* isolate,
|
||||
Handle<Object> 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()));
|
||||
}
|
||||
|
@ -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<Object> ToNumber(
|
||||
Handle<Object> input);
|
||||
|
||||
MUST_USE_RESULT static inline MaybeHandle<Object> ToNumeric(
|
||||
Handle<Object> input);
|
||||
|
||||
// ES6 section 7.1.4 ToInteger
|
||||
MUST_USE_RESULT static inline MaybeHandle<Object> ToInteger(
|
||||
Isolate* isolate, Handle<Object> input);
|
||||
@ -1537,8 +1541,8 @@ class Object {
|
||||
Isolate* isolate, Handle<Object> value);
|
||||
MUST_USE_RESULT static MaybeHandle<String> ConvertToString(
|
||||
Isolate* isolate, Handle<Object> input);
|
||||
MUST_USE_RESULT static MaybeHandle<Object> ConvertToNumber(
|
||||
Isolate* isolate, Handle<Object> input);
|
||||
MUST_USE_RESULT static MaybeHandle<Object> ConvertToNumberOrNumeric(
|
||||
Isolate* isolate, Handle<Object> input, Conversion mode);
|
||||
MUST_USE_RESULT static MaybeHandle<Object> ConvertToInteger(
|
||||
Isolate* isolate, Handle<Object> input);
|
||||
MUST_USE_RESULT static MaybeHandle<Object> ConvertToInt32(
|
||||
|
@ -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);
|
||||
|
@ -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) \
|
||||
|
@ -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),
|
||||
|
@ -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),
|
||||
|
@ -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),
|
||||
|
@ -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),
|
||||
|
@ -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),
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user