[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:
Georg Neis 2017-10-10 18:00:31 +02:00 committed by Commit Bot
parent dde4cbb0b1
commit 6ff68255e9
25 changed files with 241 additions and 91 deletions

View File

@ -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);

View File

@ -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) \

View File

@ -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);

View File

@ -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 {

View File

@ -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(); }

View File

@ -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.

View File

@ -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);

View File

@ -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 */ \

View File

@ -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), &not_bigint);
{
var_result.Bind(object);
var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kBigInt));
Goto(&if_done);
}
BIND(&not_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

View File

@ -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();

View File

@ -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>

View File

@ -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") \

View File

@ -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

View File

@ -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()));
}

View File

@ -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(

View File

@ -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);

View File

@ -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) \

View File

@ -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),

View File

@ -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),

View File

@ -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),

View File

@ -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),

View File

@ -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),

View File

@ -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),

View File

@ -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);

View File

@ -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);