Commit 7ac19fe5 authored by bmeurer's avatar bmeurer Committed by Commit bot

[builtins] Migrate Number predicates and make them optimizable.

Migrate the isNaN, isFinite, Number.isFinite, Number.isInteger,
Number.isSafeInteger and Number.isNaN predicates to TurboFan
builtins and make them optimizable (for certain input types) in
JavaScript callees being optimized by TurboFan. That means both
the baseline and the optimized version is now always at maximum,
consistent performance. Especially TurboFan suffered from poor
baseline (and optimized) performance because it cannot play the
same weird tricks that Crankshaft plays for %_IsSmi.

This also adds a bunch of new tests to properly cover the use
of the Harmony predicates in optimized code.

R=franzih@chromium.org
BUG=v8:5049,v8:5267

Review-Url: https://codereview.chromium.org/2313073002
Cr-Commit-Position: refs/heads/master@{#39242}
parent d06495b1
...@@ -1305,6 +1305,15 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object, ...@@ -1305,6 +1305,15 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
// Install i18n fallback functions. // Install i18n fallback functions.
SimpleInstallFunction(prototype, "toLocaleString", SimpleInstallFunction(prototype, "toLocaleString",
Builtins::kNumberPrototypeToLocaleString, 0, false); Builtins::kNumberPrototypeToLocaleString, 0, false);
// Install the Number functions.
SimpleInstallFunction(number_fun, "isFinite", Builtins::kNumberIsFinite, 1,
true);
SimpleInstallFunction(number_fun, "isInteger", Builtins::kNumberIsInteger,
1, true);
SimpleInstallFunction(number_fun, "isNaN", Builtins::kNumberIsNaN, 1, true);
SimpleInstallFunction(number_fun, "isSafeInteger",
Builtins::kNumberIsSafeInteger, 1, true);
} }
{ // --- B o o l e a n --- { // --- B o o l e a n ---
...@@ -3145,6 +3154,14 @@ bool Genesis::InstallNatives(GlobalContextType context_type) { ...@@ -3145,6 +3154,14 @@ bool Genesis::InstallNatives(GlobalContextType context_type) {
native_context()->set_global_eval_fun(*eval); native_context()->set_global_eval_fun(*eval);
} }
// Install Global.isFinite
SimpleInstallFunction(global_object, "isFinite", Builtins::kGlobalIsFinite, 1,
true, kGlobalIsFinite);
// Install Global.isNaN
SimpleInstallFunction(global_object, "isNaN", Builtins::kGlobalIsNaN, 1, true,
kGlobalIsNaN);
// Install Array.prototype.concat // Install Array.prototype.concat
{ {
Handle<JSFunction> array_constructor(native_context()->array_function()); Handle<JSFunction> array_constructor(native_context()->array_function());
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "src/builtins/builtins.h" #include "src/builtins/builtins.h"
#include "src/builtins/builtins-utils.h" #include "src/builtins/builtins-utils.h"
#include "src/code-factory.h"
#include "src/compiler.h" #include "src/compiler.h"
#include "src/uri.h" #include "src/uri.h"
...@@ -99,5 +100,113 @@ BUILTIN(GlobalEval) { ...@@ -99,5 +100,113 @@ BUILTIN(GlobalEval) {
Execution::Call(isolate, function, target_global_proxy, 0, nullptr)); Execution::Call(isolate, function, target_global_proxy, 0, nullptr));
} }
// ES6 section 18.2.2 isFinite ( number )
void Builtins::Generate_GlobalIsFinite(CodeStubAssembler* assembler) {
typedef CodeStubAssembler::Label Label;
typedef compiler::Node Node;
typedef CodeStubAssembler::Variable Variable;
Node* context = assembler->Parameter(4);
Label return_true(assembler), return_false(assembler);
// We might need to loop once for ToNumber conversion.
Variable var_num(assembler, MachineRepresentation::kTagged);
Label loop(assembler, &var_num);
var_num.Bind(assembler->Parameter(1));
assembler->Goto(&loop);
assembler->Bind(&loop);
{
// Load the current {num} value.
Node* num = var_num.value();
// Check if {num} is a Smi or a HeapObject.
assembler->GotoIf(assembler->WordIsSmi(num), &return_true);
// Check if {num} is a HeapNumber.
Label if_numisheapnumber(assembler),
if_numisnotheapnumber(assembler, Label::kDeferred);
assembler->Branch(assembler->WordEqual(assembler->LoadMap(num),
assembler->HeapNumberMapConstant()),
&if_numisheapnumber, &if_numisnotheapnumber);
assembler->Bind(&if_numisheapnumber);
{
// Check if {num} contains a finite, non-NaN value.
Node* num_value = assembler->LoadHeapNumberValue(num);
assembler->BranchIfFloat64IsNaN(
assembler->Float64Sub(num_value, num_value), &return_false,
&return_true);
}
assembler->Bind(&if_numisnotheapnumber);
{
// Need to convert {num} to a Number first.
Callable callable = CodeFactory::NonNumberToNumber(assembler->isolate());
var_num.Bind(assembler->CallStub(callable, context, num));
assembler->Goto(&loop);
}
}
assembler->Bind(&return_true);
assembler->Return(assembler->BooleanConstant(true));
assembler->Bind(&return_false);
assembler->Return(assembler->BooleanConstant(false));
}
// ES6 section 18.2.3 isNaN ( number )
void Builtins::Generate_GlobalIsNaN(CodeStubAssembler* assembler) {
typedef CodeStubAssembler::Label Label;
typedef compiler::Node Node;
typedef CodeStubAssembler::Variable Variable;
Node* context = assembler->Parameter(4);
Label return_true(assembler), return_false(assembler);
// We might need to loop once for ToNumber conversion.
Variable var_num(assembler, MachineRepresentation::kTagged);
Label loop(assembler, &var_num);
var_num.Bind(assembler->Parameter(1));
assembler->Goto(&loop);
assembler->Bind(&loop);
{
// Load the current {num} value.
Node* num = var_num.value();
// Check if {num} is a Smi or a HeapObject.
assembler->GotoIf(assembler->WordIsSmi(num), &return_false);
// Check if {num} is a HeapNumber.
Label if_numisheapnumber(assembler),
if_numisnotheapnumber(assembler, Label::kDeferred);
assembler->Branch(assembler->WordEqual(assembler->LoadMap(num),
assembler->HeapNumberMapConstant()),
&if_numisheapnumber, &if_numisnotheapnumber);
assembler->Bind(&if_numisheapnumber);
{
// Check if {num} contains a NaN.
Node* num_value = assembler->LoadHeapNumberValue(num);
assembler->BranchIfFloat64IsNaN(num_value, &return_true, &return_false);
}
assembler->Bind(&if_numisnotheapnumber);
{
// Need to convert {num} to a Number first.
Callable callable = CodeFactory::NonNumberToNumber(assembler->isolate());
var_num.Bind(assembler->CallStub(callable, context, num));
assembler->Goto(&loop);
}
}
assembler->Bind(&return_true);
assembler->Return(assembler->BooleanConstant(true));
assembler->Bind(&return_false);
assembler->Return(assembler->BooleanConstant(false));
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -11,6 +11,144 @@ namespace internal { ...@@ -11,6 +11,144 @@ namespace internal {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// ES6 section 20.1 Number Objects // ES6 section 20.1 Number Objects
// ES6 section 20.1.2.2 Number.isFinite ( number )
void Builtins::Generate_NumberIsFinite(CodeStubAssembler* assembler) {
typedef CodeStubAssembler::Label Label;
typedef compiler::Node Node;
Node* number = assembler->Parameter(1);
Label return_true(assembler), return_false(assembler);
// Check if {number} is a Smi.
assembler->GotoIf(assembler->WordIsSmi(number), &return_true);
// Check if {number} is a HeapNumber.
assembler->GotoUnless(
assembler->WordEqual(assembler->LoadMap(number),
assembler->HeapNumberMapConstant()),
&return_false);
// Check if {number} contains a finite, non-NaN value.
Node* number_value = assembler->LoadHeapNumberValue(number);
assembler->BranchIfFloat64IsNaN(
assembler->Float64Sub(number_value, number_value), &return_false,
&return_true);
assembler->Bind(&return_true);
assembler->Return(assembler->BooleanConstant(true));
assembler->Bind(&return_false);
assembler->Return(assembler->BooleanConstant(false));
}
// ES6 section 20.1.2.3 Number.isInteger ( number )
void Builtins::Generate_NumberIsInteger(CodeStubAssembler* assembler) {
typedef CodeStubAssembler::Label Label;
typedef compiler::Node Node;
Node* number = assembler->Parameter(1);
Label return_true(assembler), return_false(assembler);
// Check if {number} is a Smi.
assembler->GotoIf(assembler->WordIsSmi(number), &return_true);
// Check if {number} is a HeapNumber.
assembler->GotoUnless(
assembler->WordEqual(assembler->LoadMap(number),
assembler->HeapNumberMapConstant()),
&return_false);
// Load the actual value of {number}.
Node* number_value = assembler->LoadHeapNumberValue(number);
// Truncate the value of {number} to an integer (or an infinity).
Node* integer = assembler->Float64Trunc(number_value);
// Check if {number}s value matches the integer (ruling out the infinities).
assembler->BranchIfFloat64Equal(assembler->Float64Sub(number_value, integer),
assembler->Float64Constant(0.0), &return_true,
&return_false);
assembler->Bind(&return_true);
assembler->Return(assembler->BooleanConstant(true));
assembler->Bind(&return_false);
assembler->Return(assembler->BooleanConstant(false));
}
// ES6 section 20.1.2.4 Number.isNaN ( number )
void Builtins::Generate_NumberIsNaN(CodeStubAssembler* assembler) {
typedef CodeStubAssembler::Label Label;
typedef compiler::Node Node;
Node* number = assembler->Parameter(1);
Label return_true(assembler), return_false(assembler);
// Check if {number} is a Smi.
assembler->GotoIf(assembler->WordIsSmi(number), &return_false);
// Check if {number} is a HeapNumber.
assembler->GotoUnless(
assembler->WordEqual(assembler->LoadMap(number),
assembler->HeapNumberMapConstant()),
&return_false);
// Check if {number} contains a NaN value.
Node* number_value = assembler->LoadHeapNumberValue(number);
assembler->BranchIfFloat64IsNaN(number_value, &return_true, &return_false);
assembler->Bind(&return_true);
assembler->Return(assembler->BooleanConstant(true));
assembler->Bind(&return_false);
assembler->Return(assembler->BooleanConstant(false));
}
// ES6 section 20.1.2.5 Number.isSafeInteger ( number )
void Builtins::Generate_NumberIsSafeInteger(CodeStubAssembler* assembler) {
typedef CodeStubAssembler::Label Label;
typedef compiler::Node Node;
Node* number = assembler->Parameter(1);
Label return_true(assembler), return_false(assembler);
// Check if {number} is a Smi.
assembler->GotoIf(assembler->WordIsSmi(number), &return_true);
// Check if {number} is a HeapNumber.
assembler->GotoUnless(
assembler->WordEqual(assembler->LoadMap(number),
assembler->HeapNumberMapConstant()),
&return_false);
// Load the actual value of {number}.
Node* number_value = assembler->LoadHeapNumberValue(number);
// Truncate the value of {number} to an integer (or an infinity).
Node* integer = assembler->Float64Trunc(number_value);
// Check if {number}s value matches the integer (ruling out the infinities).
assembler->GotoUnless(
assembler->Float64Equal(assembler->Float64Sub(number_value, integer),
assembler->Float64Constant(0.0)),
&return_false);
// Check if the {integer} value is in safe integer range.
assembler->BranchIfFloat64LessThanOrEqual(
assembler->Float64Abs(integer),
assembler->Float64Constant(kMaxSafeInteger), &return_true, &return_false);
assembler->Bind(&return_true);
assembler->Return(assembler->BooleanConstant(true));
assembler->Bind(&return_false);
assembler->Return(assembler->BooleanConstant(false));
}
// ES6 section 20.1.3.2 Number.prototype.toExponential ( fractionDigits ) // ES6 section 20.1.3.2 Number.prototype.toExponential ( fractionDigits )
BUILTIN(NumberPrototypeToExponential) { BUILTIN(NumberPrototypeToExponential) {
HandleScope scope(isolate); HandleScope scope(isolate);
......
...@@ -361,16 +361,18 @@ namespace internal { ...@@ -361,16 +361,18 @@ namespace internal {
TFJ(GeneratorPrototypeThrow, 2) \ TFJ(GeneratorPrototypeThrow, 2) \
CPP(AsyncFunctionConstructor) \ CPP(AsyncFunctionConstructor) \
\ \
/* Encode and decode */ \ /* Global object */ \
CPP(GlobalDecodeURI) \ CPP(GlobalDecodeURI) \
CPP(GlobalDecodeURIComponent) \ CPP(GlobalDecodeURIComponent) \
CPP(GlobalEncodeURI) \ CPP(GlobalEncodeURI) \
CPP(GlobalEncodeURIComponent) \ CPP(GlobalEncodeURIComponent) \
CPP(GlobalEscape) \ CPP(GlobalEscape) \
CPP(GlobalUnescape) \ CPP(GlobalUnescape) \
\
/* Eval */ \
CPP(GlobalEval) \ CPP(GlobalEval) \
/* ES6 section 18.2.2 isFinite ( number ) */ \
TFJ(GlobalIsFinite, 2) \
/* ES6 section 18.2.3 isNaN ( number ) */ \
TFJ(GlobalIsNaN, 2) \
\ \
/* JSON */ \ /* JSON */ \
CPP(JsonParse) \ CPP(JsonParse) \
...@@ -451,6 +453,14 @@ namespace internal { ...@@ -451,6 +453,14 @@ namespace internal {
ASM(NumberConstructor) \ ASM(NumberConstructor) \
/* ES6 section 20.1.1.1 Number ( [ value ] ) for the [[Construct]] case */ \ /* ES6 section 20.1.1.1 Number ( [ value ] ) for the [[Construct]] case */ \
ASM(NumberConstructor_ConstructStub) \ ASM(NumberConstructor_ConstructStub) \
/* ES6 section 20.1.2.2 Number.isFinite ( number ) */ \
TFJ(NumberIsFinite, 2) \
/* ES6 section 20.1.2.3 Number.isInteger ( number ) */ \
TFJ(NumberIsInteger, 2) \
/* ES6 section 20.1.2.4 Number.isNaN ( number ) */ \
TFJ(NumberIsNaN, 2) \
/* ES6 section 20.1.2.5 Number.isSafeInteger ( number ) */ \
TFJ(NumberIsSafeInteger, 2) \
CPP(NumberPrototypeToExponential) \ CPP(NumberPrototypeToExponential) \
CPP(NumberPrototypeToFixed) \ CPP(NumberPrototypeToFixed) \
CPP(NumberPrototypeToLocaleString) \ CPP(NumberPrototypeToLocaleString) \
......
...@@ -375,6 +375,34 @@ Reduction JSBuiltinReducer::ReduceDateGetTime(Node* node) { ...@@ -375,6 +375,34 @@ Reduction JSBuiltinReducer::ReduceDateGetTime(Node* node) {
return NoChange(); return NoChange();
} }
// ES6 section 18.2.2 isFinite ( number )
Reduction JSBuiltinReducer::ReduceGlobalIsFinite(Node* node) {
JSCallReduction r(node);
if (r.InputsMatchOne(Type::PlainPrimitive())) {
// isFinite(a:plain-primitive) -> NumberEqual(a', a')
// where a' = NumberSubtract(ToNumber(a), ToNumber(a))
Node* input = ToNumber(r.GetJSCallInput(0));
Node* diff = graph()->NewNode(simplified()->NumberSubtract(), input, input);
Node* value = graph()->NewNode(simplified()->NumberEqual(), diff, diff);
return Replace(value);
}
return NoChange();
}
// ES6 section 18.2.3 isNaN ( number )
Reduction JSBuiltinReducer::ReduceGlobalIsNaN(Node* node) {
JSCallReduction r(node);
if (r.InputsMatchOne(Type::PlainPrimitive())) {
// isNaN(a:plain-primitive) -> BooleanNot(NumberEqual(a', a'))
// where a' = ToNumber(a)
Node* input = ToNumber(r.GetJSCallInput(0));
Node* check = graph()->NewNode(simplified()->NumberEqual(), input, input);
Node* value = graph()->NewNode(simplified()->BooleanNot(), check);
return Replace(value);
}
return NoChange();
}
// ES6 section 20.2.2.1 Math.abs ( x ) // ES6 section 20.2.2.1 Math.abs ( x )
Reduction JSBuiltinReducer::ReduceMathAbs(Node* node) { Reduction JSBuiltinReducer::ReduceMathAbs(Node* node) {
JSCallReduction r(node); JSCallReduction r(node);
...@@ -789,6 +817,60 @@ Reduction JSBuiltinReducer::ReduceMathTrunc(Node* node) { ...@@ -789,6 +817,60 @@ Reduction JSBuiltinReducer::ReduceMathTrunc(Node* node) {
return NoChange(); return NoChange();
} }
// ES6 section 20.1.2.2 Number.isFinite ( number )
Reduction JSBuiltinReducer::ReduceNumberIsFinite(Node* node) {
JSCallReduction r(node);
if (r.InputsMatchOne(Type::Number())) {
// Number.isFinite(a:number) -> NumberEqual(a', a')
// where a' = NumberSubtract(a, a)
Node* input = r.GetJSCallInput(0);
Node* diff = graph()->NewNode(simplified()->NumberSubtract(), input, input);
Node* value = graph()->NewNode(simplified()->NumberEqual(), diff, diff);
return Replace(value);
}
return NoChange();
}
// ES6 section 20.1.2.3 Number.isInteger ( number )
Reduction JSBuiltinReducer::ReduceNumberIsInteger(Node* node) {
JSCallReduction r(node);
if (r.InputsMatchOne(Type::Number())) {
// Number.isInteger(x:number) -> NumberEqual(NumberSubtract(x, x'), #0)
// where x' = NumberTrunc(x)
Node* input = r.GetJSCallInput(0);
Node* trunc = graph()->NewNode(simplified()->NumberTrunc(), input);
Node* diff = graph()->NewNode(simplified()->NumberSubtract(), input, trunc);
Node* value = graph()->NewNode(simplified()->NumberEqual(), diff,
jsgraph()->ZeroConstant());
return Replace(value);
}
return NoChange();
}
// ES6 section 20.1.2.4 Number.isNaN ( number )
Reduction JSBuiltinReducer::ReduceNumberIsNaN(Node* node) {
JSCallReduction r(node);
if (r.InputsMatchOne(Type::Number())) {
// Number.isNaN(a:number) -> BooleanNot(NumberEqual(a, a))
Node* input = r.GetJSCallInput(0);
Node* check = graph()->NewNode(simplified()->NumberEqual(), input, input);
Node* value = graph()->NewNode(simplified()->BooleanNot(), check);
return Replace(value);
}
return NoChange();
}
// ES6 section 20.1.2.5 Number.isSafeInteger ( number )
Reduction JSBuiltinReducer::ReduceNumberIsSafeInteger(Node* node) {
JSCallReduction r(node);
if (r.InputsMatchOne(type_cache_.kSafeInteger)) {
// Number.isInteger(x:safe-integer) -> #true
Node* value = jsgraph()->TrueConstant();
return Replace(value);
}
return NoChange();
}
// ES6 section 20.1.2.13 Number.parseInt ( string, radix ) // ES6 section 20.1.2.13 Number.parseInt ( string, radix )
Reduction JSBuiltinReducer::ReduceNumberParseInt(Node* node) { Reduction JSBuiltinReducer::ReduceNumberParseInt(Node* node) {
JSCallReduction r(node); JSCallReduction r(node);
...@@ -981,6 +1063,12 @@ Reduction JSBuiltinReducer::Reduce(Node* node) { ...@@ -981,6 +1063,12 @@ Reduction JSBuiltinReducer::Reduce(Node* node) {
return ReduceArrayPush(node); return ReduceArrayPush(node);
case kDateGetTime: case kDateGetTime:
return ReduceDateGetTime(node); return ReduceDateGetTime(node);
case kGlobalIsFinite:
reduction = ReduceGlobalIsFinite(node);
break;
case kGlobalIsNaN:
reduction = ReduceGlobalIsNaN(node);
break;
case kMathAbs: case kMathAbs:
reduction = ReduceMathAbs(node); reduction = ReduceMathAbs(node);
break; break;
...@@ -1080,6 +1168,18 @@ Reduction JSBuiltinReducer::Reduce(Node* node) { ...@@ -1080,6 +1168,18 @@ Reduction JSBuiltinReducer::Reduce(Node* node) {
case kMathTrunc: case kMathTrunc:
reduction = ReduceMathTrunc(node); reduction = ReduceMathTrunc(node);
break; break;
case kNumberIsFinite:
reduction = ReduceNumberIsFinite(node);
break;
case kNumberIsInteger:
reduction = ReduceNumberIsInteger(node);
break;
case kNumberIsNaN:
reduction = ReduceNumberIsNaN(node);
break;
case kNumberIsSafeInteger:
reduction = ReduceNumberIsSafeInteger(node);
break;
case kNumberParseInt: case kNumberParseInt:
reduction = ReduceNumberParseInt(node); reduction = ReduceNumberParseInt(node);
break; break;
......
...@@ -43,6 +43,8 @@ class JSBuiltinReducer final : public AdvancedReducer { ...@@ -43,6 +43,8 @@ class JSBuiltinReducer final : public AdvancedReducer {
Reduction ReduceArrayPop(Node* node); Reduction ReduceArrayPop(Node* node);
Reduction ReduceArrayPush(Node* node); Reduction ReduceArrayPush(Node* node);
Reduction ReduceDateGetTime(Node* node); Reduction ReduceDateGetTime(Node* node);
Reduction ReduceGlobalIsFinite(Node* node);
Reduction ReduceGlobalIsNaN(Node* node);
Reduction ReduceMathAbs(Node* node); Reduction ReduceMathAbs(Node* node);
Reduction ReduceMathAcos(Node* node); Reduction ReduceMathAcos(Node* node);
Reduction ReduceMathAcosh(Node* node); Reduction ReduceMathAcosh(Node* node);
...@@ -76,6 +78,10 @@ class JSBuiltinReducer final : public AdvancedReducer { ...@@ -76,6 +78,10 @@ class JSBuiltinReducer final : public AdvancedReducer {
Reduction ReduceMathTan(Node* node); Reduction ReduceMathTan(Node* node);
Reduction ReduceMathTanh(Node* node); Reduction ReduceMathTanh(Node* node);
Reduction ReduceMathTrunc(Node* node); Reduction ReduceMathTrunc(Node* node);
Reduction ReduceNumberIsFinite(Node* node);
Reduction ReduceNumberIsInteger(Node* node);
Reduction ReduceNumberIsNaN(Node* node);
Reduction ReduceNumberIsSafeInteger(Node* node);
Reduction ReduceNumberParseInt(Node* node); Reduction ReduceNumberParseInt(Node* node);
Reduction ReduceStringCharAt(Node* node); Reduction ReduceStringCharAt(Node* node);
Reduction ReduceStringCharCodeAt(Node* node); Reduction ReduceStringCharCodeAt(Node* node);
......
...@@ -1340,6 +1340,11 @@ Type* Typer::Visitor::JSCallFunctionTyper(Type* fun, Typer* t) { ...@@ -1340,6 +1340,11 @@ Type* Typer::Visitor::JSCallFunctionTyper(Type* fun, Typer* t) {
case kDateGetTime: case kDateGetTime:
return t->cache_.kJSDateValueType; return t->cache_.kJSDateValueType;
// Number functions. // Number functions.
case kNumberIsFinite:
case kNumberIsInteger:
case kNumberIsNaN:
case kNumberIsSafeInteger:
return Type::Boolean();
case kNumberParseInt: case kNumberParseInt:
return t->cache_.kIntegerOrMinusZeroOrNaN; return t->cache_.kIntegerOrMinusZeroOrNaN;
case kNumberToString: case kNumberToString:
...@@ -1370,6 +1375,9 @@ Type* Typer::Visitor::JSCallFunctionTyper(Type* fun, Typer* t) { ...@@ -1370,6 +1375,9 @@ Type* Typer::Visitor::JSCallFunctionTyper(Type* fun, Typer* t) {
case kGlobalEscape: case kGlobalEscape:
case kGlobalUnescape: case kGlobalUnescape:
return Type::String(); return Type::String();
case kGlobalIsFinite:
case kGlobalIsNaN:
return Type::Boolean();
default: default:
break; break;
} }
......
...@@ -16,7 +16,6 @@ var GlobalSet = global.Set; ...@@ -16,7 +16,6 @@ var GlobalSet = global.Set;
var hashCodeSymbol = utils.ImportNow("hash_code_symbol"); var hashCodeSymbol = utils.ImportNow("hash_code_symbol");
var MathRandom; var MathRandom;
var MapIterator; var MapIterator;
var NumberIsNaN;
var SetIterator; var SetIterator;
var speciesSymbol = utils.ImportNow("species_symbol"); var speciesSymbol = utils.ImportNow("species_symbol");
var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol"); var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol");
...@@ -24,7 +23,6 @@ var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol"); ...@@ -24,7 +23,6 @@ var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol");
utils.Import(function(from) { utils.Import(function(from) {
MathRandom = from.MathRandom; MathRandom = from.MathRandom;
MapIterator = from.MapIterator; MapIterator = from.MapIterator;
NumberIsNaN = from.NumberIsNaN;
SetIterator = from.SetIterator; SetIterator = from.SetIterator;
}); });
...@@ -42,9 +40,9 @@ function SetFindEntry(table, numBuckets, key, hash) { ...@@ -42,9 +40,9 @@ function SetFindEntry(table, numBuckets, key, hash) {
if (entry === NOT_FOUND) return entry; if (entry === NOT_FOUND) return entry;
var candidate = ORDERED_HASH_SET_KEY_AT(table, entry, numBuckets); var candidate = ORDERED_HASH_SET_KEY_AT(table, entry, numBuckets);
if (key === candidate) return entry; if (key === candidate) return entry;
var keyIsNaN = NumberIsNaN(key); var keyIsNaN = NUMBER_IS_NAN(key);
while (true) { while (true) {
if (keyIsNaN && NumberIsNaN(candidate)) { if (keyIsNaN && NUMBER_IS_NAN(candidate)) {
return entry; return entry;
} }
entry = ORDERED_HASH_SET_CHAIN_AT(table, entry, numBuckets); entry = ORDERED_HASH_SET_CHAIN_AT(table, entry, numBuckets);
...@@ -62,9 +60,9 @@ function MapFindEntry(table, numBuckets, key, hash) { ...@@ -62,9 +60,9 @@ function MapFindEntry(table, numBuckets, key, hash) {
if (entry === NOT_FOUND) return entry; if (entry === NOT_FOUND) return entry;
var candidate = ORDERED_HASH_MAP_KEY_AT(table, entry, numBuckets); var candidate = ORDERED_HASH_MAP_KEY_AT(table, entry, numBuckets);
if (key === candidate) return entry; if (key === candidate) return entry;
var keyIsNaN = NumberIsNaN(key); var keyIsNaN = NUMBER_IS_NAN(key);
while (true) { while (true) {
if (keyIsNaN && NumberIsNaN(candidate)) { if (keyIsNaN && NUMBER_IS_NAN(candidate)) {
return entry; return entry;
} }
entry = ORDERED_HASH_MAP_CHAIN_AT(table, entry, numBuckets); entry = ORDERED_HASH_MAP_CHAIN_AT(table, entry, numBuckets);
......
...@@ -29,7 +29,6 @@ var InstallGetter = utils.InstallGetter; ...@@ -29,7 +29,6 @@ var InstallGetter = utils.InstallGetter;
var InternalArray = utils.InternalArray; var InternalArray = utils.InternalArray;
var InternalRegExpMatch; var InternalRegExpMatch;
var InternalRegExpReplace var InternalRegExpReplace
var IsNaN;
var ObjectHasOwnProperty = utils.ImportNow("ObjectHasOwnProperty"); var ObjectHasOwnProperty = utils.ImportNow("ObjectHasOwnProperty");
var OverrideFunction = utils.OverrideFunction; var OverrideFunction = utils.OverrideFunction;
var patternSymbol = utils.ImportNow("intl_pattern_symbol"); var patternSymbol = utils.ImportNow("intl_pattern_symbol");
...@@ -43,7 +42,6 @@ var StringSubstring; ...@@ -43,7 +42,6 @@ var StringSubstring;
utils.Import(function(from) { utils.Import(function(from) {
ArrayJoin = from.ArrayJoin; ArrayJoin = from.ArrayJoin;
ArrayPush = from.ArrayPush; ArrayPush = from.ArrayPush;
IsNaN = from.IsNaN;
InternalRegExpMatch = from.InternalRegExpMatch; InternalRegExpMatch = from.InternalRegExpMatch;
InternalRegExpReplace = from.InternalRegExpReplace; InternalRegExpReplace = from.InternalRegExpReplace;
StringIndexOf = from.StringIndexOf; StringIndexOf = from.StringIndexOf;
...@@ -2250,7 +2248,8 @@ function toLocaleDateTime(date, locales, options, required, defaults, service) { ...@@ -2250,7 +2248,8 @@ function toLocaleDateTime(date, locales, options, required, defaults, service) {
throw %make_type_error(kMethodInvokedOnWrongType, "Date"); throw %make_type_error(kMethodInvokedOnWrongType, "Date");
} }
if (IsNaN(date)) return 'Invalid Date'; var dateValue = TO_NUMBER(date);
if (NUMBER_IS_NAN(dateValue)) return 'Invalid Date';
var internalOptions = toDateTimeOptions(options, required, defaults); var internalOptions = toDateTimeOptions(options, required, defaults);
......
...@@ -191,14 +191,12 @@ function PostNatives(utils) { ...@@ -191,14 +191,12 @@ function PostNatives(utils) {
"GlobalPromise", "GlobalPromise",
"IntlParseDate", "IntlParseDate",
"IntlParseNumber", "IntlParseNumber",
"IsNaN",
"MapEntries", "MapEntries",
"MapIterator", "MapIterator",
"MapIteratorNext", "MapIteratorNext",
"MaxSimple", "MaxSimple",
"MinSimple", "MinSimple",
"NewPromiseCapability", "NewPromiseCapability",
"NumberIsInteger",
"PerformPromiseThen", "PerformPromiseThen",
"PromiseCastResolved", "PromiseCastResolved",
"PromiseThen", "PromiseThen",
......
...@@ -34,7 +34,6 @@ var InnerArraySome; ...@@ -34,7 +34,6 @@ var InnerArraySome;
var InnerArraySort; var InnerArraySort;
var InnerArrayToLocaleString; var InnerArrayToLocaleString;
var InternalArray = utils.InternalArray; var InternalArray = utils.InternalArray;
var IsNaN;
var MaxSimple; var MaxSimple;
var MinSimple; var MinSimple;
var PackedArrayReverse; var PackedArrayReverse;
...@@ -83,7 +82,6 @@ utils.Import(function(from) { ...@@ -83,7 +82,6 @@ utils.Import(function(from) {
InnerArraySome = from.InnerArraySome; InnerArraySome = from.InnerArraySome;
InnerArraySort = from.InnerArraySort; InnerArraySort = from.InnerArraySort;
InnerArrayToLocaleString = from.InnerArrayToLocaleString; InnerArrayToLocaleString = from.InnerArrayToLocaleString;
IsNaN = from.IsNaN;
MaxSimple = from.MaxSimple; MaxSimple = from.MaxSimple;
MinSimple = from.MinSimple; MinSimple = from.MinSimple;
PackedArrayReverse = from.PackedArrayReverse; PackedArrayReverse = from.PackedArrayReverse;
...@@ -544,9 +542,9 @@ function TypedArrayComparefn(x, y) { ...@@ -544,9 +542,9 @@ function TypedArrayComparefn(x, y) {
return -1; return -1;
} else if (x > y) { } else if (x > y) {
return 1; return 1;
} else if (IsNaN(x) && IsNaN(y)) { } else if (NUMBER_IS_NAN(x) && NUMBER_IS_NAN(y)) {
return IsNaN(y) ? 0 : 1; return NUMBER_IS_NAN(y) ? 0 : 1;
} else if (IsNaN(x)) { } else if (NUMBER_IS_NAN(x)) {
return 1; return 1;
} }
return 0; return 0;
......
...@@ -18,20 +18,6 @@ var ObjectToString = utils.ImportNow("object_to_string"); ...@@ -18,20 +18,6 @@ var ObjectToString = utils.ImportNow("object_to_string");
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// ES6 18.2.3 isNaN(number)
function GlobalIsNaN(number) {
number = TO_NUMBER(number);
return NUMBER_IS_NAN(number);
}
// ES6 18.2.2 isFinite(number)
function GlobalIsFinite(number) {
number = TO_NUMBER(number);
return NUMBER_IS_FINITE(number);
}
// ES6 18.2.5 parseInt(string, radix) // ES6 18.2.5 parseInt(string, radix)
function GlobalParseInt(string, radix) { function GlobalParseInt(string, radix) {
if (IS_UNDEFINED(radix) || radix === 10 || radix === 0) { if (IS_UNDEFINED(radix) || radix === 10 || radix === 0) {
...@@ -91,8 +77,6 @@ utils.InstallConstants(global, [ ...@@ -91,8 +77,6 @@ utils.InstallConstants(global, [
// Set up non-enumerable function on the global object. // Set up non-enumerable function on the global object.
utils.InstallFunctions(global, DONT_ENUM, [ utils.InstallFunctions(global, DONT_ENUM, [
"isNaN", GlobalIsNaN,
"isFinite", GlobalIsFinite,
"parseInt", GlobalParseInt, "parseInt", GlobalParseInt,
"parseFloat", GlobalParseFloat, "parseFloat", GlobalParseFloat,
]); ]);
...@@ -207,38 +191,6 @@ utils.InstallFunctions(GlobalObject, DONT_ENUM, [ ...@@ -207,38 +191,6 @@ utils.InstallFunctions(GlobalObject, DONT_ENUM, [
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Number // Number
// Harmony isFinite.
function NumberIsFinite(number) {
return IS_NUMBER(number) && NUMBER_IS_FINITE(number);
}
// Harmony isInteger
function NumberIsInteger(number) {
return NumberIsFinite(number) && TO_INTEGER(number) == number;
}
// Harmony isNaN.
function NumberIsNaN(number) {
return IS_NUMBER(number) && NUMBER_IS_NAN(number);
}
// Harmony isSafeInteger
function NumberIsSafeInteger(number) {
if (NumberIsFinite(number)) {
var integral = TO_INTEGER(number);
if (integral == number) {
return -kMaxSafeInteger <= integral && integral <= kMaxSafeInteger;
}
}
return false;
}
// ----------------------------------------------------------------------------
utils.InstallConstants(GlobalNumber, [ utils.InstallConstants(GlobalNumber, [
// ECMA-262 section 15.7.3.1. // ECMA-262 section 15.7.3.1.
"MAX_VALUE", 1.7976931348623157e+308, "MAX_VALUE", 1.7976931348623157e+308,
...@@ -260,15 +212,10 @@ utils.InstallConstants(GlobalNumber, [ ...@@ -260,15 +212,10 @@ utils.InstallConstants(GlobalNumber, [
// Harmony Number constructor additions // Harmony Number constructor additions
utils.InstallFunctions(GlobalNumber, DONT_ENUM, [ utils.InstallFunctions(GlobalNumber, DONT_ENUM, [
"isFinite", NumberIsFinite,
"isInteger", NumberIsInteger,
"isNaN", NumberIsNaN,
"isSafeInteger", NumberIsSafeInteger,
"parseInt", GlobalParseInt, "parseInt", GlobalParseInt,
"parseFloat", GlobalParseFloat "parseFloat", GlobalParseFloat
]); ]);
%SetForceInlineFlag(NumberIsNaN);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
...@@ -295,9 +242,6 @@ function GetIterator(obj, method) { ...@@ -295,9 +242,6 @@ function GetIterator(obj, method) {
utils.Export(function(to) { utils.Export(function(to) {
to.GetIterator = GetIterator; to.GetIterator = GetIterator;
to.GetMethod = GetMethod; to.GetMethod = GetMethod;
to.IsNaN = GlobalIsNaN;
to.NumberIsNaN = NumberIsNaN;
to.NumberIsInteger = NumberIsInteger;
to.ObjectHasOwnProperty = GlobalObject.prototype.hasOwnProperty; to.ObjectHasOwnProperty = GlobalObject.prototype.hasOwnProperty;
}); });
......
...@@ -6951,6 +6951,10 @@ class Script: public Struct { ...@@ -6951,6 +6951,10 @@ class Script: public Struct {
V(Math, clz32, MathClz32) \ V(Math, clz32, MathClz32) \
V(Math, fround, MathFround) \ V(Math, fround, MathFround) \
V(Math, trunc, MathTrunc) \ V(Math, trunc, MathTrunc) \
V(Number, isFinite, NumberIsFinite) \
V(Number, isInteger, NumberIsInteger) \
V(Number, isNaN, NumberIsNaN) \
V(Number, isSafeInteger, NumberIsSafeInteger) \
V(Number, parseInt, NumberParseInt) \ V(Number, parseInt, NumberParseInt) \
V(Number.prototype, toString, NumberToString) V(Number.prototype, toString, NumberToString)
...@@ -6979,6 +6983,8 @@ enum BuiltinFunctionId { ...@@ -6979,6 +6983,8 @@ enum BuiltinFunctionId {
kGlobalEncodeURIComponent, kGlobalEncodeURIComponent,
kGlobalEscape, kGlobalEscape,
kGlobalUnescape, kGlobalUnescape,
kGlobalIsFinite,
kGlobalIsNaN,
kTypedArrayByteLength, kTypedArrayByteLength,
kTypedArrayByteOffset, kTypedArrayByteOffset,
kTypedArrayLength, kTypedArrayLength,
......
...@@ -815,7 +815,7 @@ TEST(SnapshotDataBlobWithWarmup) { ...@@ -815,7 +815,7 @@ TEST(SnapshotDataBlobWithWarmup) {
// Running the warmup script has effect on whether functions are // Running the warmup script has effect on whether functions are
// pre-compiled, but does not pollute the context. // pre-compiled, but does not pollute the context.
CHECK(IsCompiled("Math.abs")); CHECK(IsCompiled("Math.abs"));
CHECK(!IsCompiled("Number.isFinite")); CHECK(!IsCompiled("Number.parseInt"));
CHECK(CompileRun("Math.random")->IsFunction()); CHECK(CompileRun("Math.random")->IsFunction());
} }
isolate->Dispose(); isolate->Dispose();
...@@ -825,8 +825,8 @@ TEST(CustomSnapshotDataBlobWithWarmup) { ...@@ -825,8 +825,8 @@ TEST(CustomSnapshotDataBlobWithWarmup) {
DisableTurbofan(); DisableTurbofan();
const char* source = const char* source =
"function f() { return Math.abs(1); }\n" "function f() { return Math.abs(1); }\n"
"function g() { return Number.isFinite(1); }\n" "function g() { return Number.parseInt(1); }\n"
"Number.isNaN(1);" "Number.parseFloat(1);"
"var a = 5"; "var a = 5";
const char* warmup = "a = f()"; const char* warmup = "a = f()";
...@@ -850,8 +850,8 @@ TEST(CustomSnapshotDataBlobWithWarmup) { ...@@ -850,8 +850,8 @@ TEST(CustomSnapshotDataBlobWithWarmup) {
CHECK(IsCompiled("f")); CHECK(IsCompiled("f"));
CHECK(IsCompiled("Math.abs")); CHECK(IsCompiled("Math.abs"));
CHECK(!IsCompiled("g")); CHECK(!IsCompiled("g"));
CHECK(!IsCompiled("Number.isFinite")); CHECK(!IsCompiled("Number.parseInt"));
CHECK(!IsCompiled("Number.isNaN")); CHECK(!IsCompiled("Number.parseFloat"));
CHECK_EQ(5, CompileRun("a")->Int32Value(context).FromJust()); CHECK_EQ(5, CompileRun("a")->Int32Value(context).FromJust());
} }
isolate->Dispose(); isolate->Dispose();
......
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax
function test(f) {
assertTrue(f(0));
assertTrue(f(Number.MIN_VALUE));
assertTrue(f(Number.MAX_VALUE));
assertTrue(f(Number.MIN_SAFE_INTEGER));
assertTrue(f(Number.MIN_SAFE_INTEGER - 13));
assertTrue(f(Number.MAX_SAFE_INTEGER));
assertTrue(f(Number.MAX_SAFE_INTEGER + 23));
assertFalse(f(Number.NaN));
assertFalse(f(Number.POSITIVE_INFINITY));
assertFalse(f(Number.NEGATIVE_INFINITY));
assertFalse(f(1 / 0));
assertFalse(f(-1 / 0));
}
function f(x) {
return Number.isFinite(+x);
}
test(f);
test(f);
%OptimizeFunctionOnNextCall(f);
test(f);
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax
function test(f) {
assertTrue(f(0));
assertFalse(f(Number.MIN_VALUE));
assertTrue(f(Number.MAX_VALUE));
assertTrue(f(Number.MIN_SAFE_INTEGER));
assertTrue(f(Number.MIN_SAFE_INTEGER - 13));
assertTrue(f(Number.MAX_SAFE_INTEGER));
assertTrue(f(Number.MAX_SAFE_INTEGER + 23));
assertFalse(f(Number.NaN));
assertFalse(f(Number.POSITIVE_INFINITY));
assertFalse(f(Number.NEGATIVE_INFINITY));
assertFalse(f(1 / 0));
assertFalse(f(-1 / 0));
assertFalse(f(Number.EPSILON));
}
function f(x) {
return Number.isInteger(+x);
}
test(f);
test(f);
%OptimizeFunctionOnNextCall(f);
test(f);
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax
function test(f) {
assertFalse(f(0));
assertFalse(f(Number.MIN_VALUE));
assertFalse(f(Number.MAX_VALUE));
assertFalse(f(Number.MIN_SAFE_INTEGER - 13));
assertFalse(f(Number.MAX_SAFE_INTEGER + 23));
assertTrue(f(Number.NaN));
assertFalse(f(Number.POSITIVE_INFINITY));
assertFalse(f(Number.NEGATIVE_INFINITY));
assertFalse(f(Number.EPSILON));
assertFalse(f(1 / 0));
assertFalse(f(-1 / 0));
}
function f(x) {
return Number.isNaN(+x);
}
test(f);
test(f);
%OptimizeFunctionOnNextCall(f);
test(f);
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax
function test(f) {
assertTrue(f(0));
assertTrue(f(Number.MIN_SAFE_INTEGER));
assertFalse(f(Number.MIN_SAFE_INTEGER - 13));
assertTrue(f(Number.MIN_SAFE_INTEGER + 13));
assertTrue(f(Number.MAX_SAFE_INTEGER));
assertFalse(f(Number.MAX_SAFE_INTEGER + 23));
assertTrue(f(Number.MAX_SAFE_INTEGER - 23));
assertFalse(f(Number.MIN_VALUE));
assertFalse(f(Number.MAX_VALUE));
assertFalse(f(Number.NaN));
assertFalse(f(Number.POSITIVE_INFINITY));
assertFalse(f(Number.NEGATIVE_INFINITY));
assertFalse(f(1 / 0));
assertFalse(f(-1 / 0));
assertFalse(f(Number.EPSILON));
var near_upper = Math.pow(2, 52);
assertTrue(f(near_upper));
assertFalse(f(2 * near_upper));
assertTrue(f(2 * near_upper - 1));
assertTrue(f(2 * near_upper - 2));
assertFalse(f(2 * near_upper + 1));
assertFalse(f(2 * near_upper + 2));
assertFalse(f(2 * near_upper + 7));
var near_lower = -near_upper;
assertTrue(f(near_lower));
assertFalse(f(2 * near_lower));
assertTrue(f(2 * near_lower + 1));
assertTrue(f(2 * near_lower + 2));
assertFalse(f(2 * near_lower - 1));
assertFalse(f(2 * near_lower - 2));
assertFalse(f(2 * near_lower - 7));
}
function f(x) {
return Number.isSafeInteger(+x);
}
test(f);
test(f);
%OptimizeFunctionOnNextCall(f);
test(f);
...@@ -38,6 +38,15 @@ class JSBuiltinReducerTest : public TypedGraphTest { ...@@ -38,6 +38,15 @@ class JSBuiltinReducerTest : public TypedGraphTest {
return reducer.Reduce(node); return reducer.Reduce(node);
} }
Node* GlobalFunction(const char* name) {
Handle<JSFunction> f = Handle<JSFunction>::cast(
Object::GetProperty(
isolate()->global_object(),
isolate()->factory()->NewStringFromAsciiChecked(name))
.ToHandleChecked());
return HeapConstant(f);
}
Node* MathFunction(const char* name) { Node* MathFunction(const char* name) {
Handle<Object> m = Handle<Object> m =
JSObject::GetProperty(isolate()->global_object(), JSObject::GetProperty(isolate()->global_object(),
...@@ -100,6 +109,91 @@ Type* const kNumberTypes[] = { ...@@ -100,6 +109,91 @@ Type* const kNumberTypes[] = {
} // namespace } // namespace
// -----------------------------------------------------------------------------
// isFinite
TEST_F(JSBuiltinReducerTest, GlobalIsFiniteWithNumber) {
Node* function = GlobalFunction("isFinite");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
TRACED_FOREACH(Type*, t0, kNumberTypes) {
Node* p0 = Parameter(t0, 0);
Node* call = graph()->NewNode(javascript()->CallFunction(3), function,
UndefinedConstant(), p0, context, frame_state,
effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberEqual(IsNumberSubtract(p0, p0),
IsNumberSubtract(p0, p0)));
}
}
TEST_F(JSBuiltinReducerTest, GlobalIsFiniteWithPlainPrimitive) {
Node* function = GlobalFunction("isFinite");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
Node* p0 = Parameter(Type::PlainPrimitive(), 0);
Node* call = graph()->NewNode(javascript()->CallFunction(3), function,
UndefinedConstant(), p0, context, frame_state,
effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsNumberEqual(IsNumberSubtract(IsPlainPrimitiveToNumber(p0),
IsPlainPrimitiveToNumber(p0)),
IsNumberSubtract(IsPlainPrimitiveToNumber(p0),
IsPlainPrimitiveToNumber(p0))));
}
// -----------------------------------------------------------------------------
// isNaN
TEST_F(JSBuiltinReducerTest, GlobalIsNaNWithNumber) {
Node* function = GlobalFunction("isNaN");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
TRACED_FOREACH(Type*, t0, kNumberTypes) {
Node* p0 = Parameter(t0, 0);
Node* call = graph()->NewNode(javascript()->CallFunction(3), function,
UndefinedConstant(), p0, context, frame_state,
effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsBooleanNot(IsNumberEqual(p0, p0)));
}
}
TEST_F(JSBuiltinReducerTest, GlobalIsNaNWithPlainPrimitive) {
Node* function = GlobalFunction("isNaN");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
Node* p0 = Parameter(Type::PlainPrimitive(), 0);
Node* call = graph()->NewNode(javascript()->CallFunction(3), function,
UndefinedConstant(), p0, context, frame_state,
effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsBooleanNot(IsNumberEqual(IsPlainPrimitiveToNumber(p0),
IsPlainPrimitiveToNumber(p0))));
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Math.abs // Math.abs
...@@ -1314,6 +1408,97 @@ TEST_F(JSBuiltinReducerTest, MathTruncWithPlainPrimitive) { ...@@ -1314,6 +1408,97 @@ TEST_F(JSBuiltinReducerTest, MathTruncWithPlainPrimitive) {
EXPECT_THAT(r.replacement(), IsNumberTrunc(IsPlainPrimitiveToNumber(p0))); EXPECT_THAT(r.replacement(), IsNumberTrunc(IsPlainPrimitiveToNumber(p0)));
} }
// -----------------------------------------------------------------------------
// Number.isFinite
TEST_F(JSBuiltinReducerTest, NumberIsFiniteWithNumber) {
Node* function = NumberFunction("isFinite");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
TRACED_FOREACH(Type*, t0, kNumberTypes) {
Node* p0 = Parameter(t0, 0);
Node* call = graph()->NewNode(javascript()->CallFunction(3), function,
UndefinedConstant(), p0, context, frame_state,
effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberEqual(IsNumberSubtract(p0, p0),
IsNumberSubtract(p0, p0)));
}
}
// -----------------------------------------------------------------------------
// Number.isInteger
TEST_F(JSBuiltinReducerTest, NumberIsIntegerWithNumber) {
Node* function = NumberFunction("isInteger");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
TRACED_FOREACH(Type*, t0, kNumberTypes) {
Node* p0 = Parameter(t0, 0);
Node* call = graph()->NewNode(javascript()->CallFunction(3), function,
UndefinedConstant(), p0, context, frame_state,
effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsNumberEqual(IsNumberSubtract(p0, IsNumberTrunc(p0)),
IsNumberConstant(0.0)));
}
}
// -----------------------------------------------------------------------------
// Number.isNaN
TEST_F(JSBuiltinReducerTest, NumberIsNaNWithNumber) {
Node* function = NumberFunction("isNaN");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
TRACED_FOREACH(Type*, t0, kNumberTypes) {
Node* p0 = Parameter(t0, 0);
Node* call = graph()->NewNode(javascript()->CallFunction(3), function,
UndefinedConstant(), p0, context, frame_state,
effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsBooleanNot(IsNumberEqual(p0, p0)));
}
}
// -----------------------------------------------------------------------------
// Number.isSafeInteger
TEST_F(JSBuiltinReducerTest, NumberIsSafeIntegerWithIntegral32) {
Node* function = NumberFunction("isSafeInteger");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
TRACED_FOREACH(Type*, t0, kIntegral32Types) {
Node* p0 = Parameter(t0, 0);
Node* call = graph()->NewNode(javascript()->CallFunction(3), function,
UndefinedConstant(), p0, context, frame_state,
effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsTrueConstant());
}
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Number.parseInt // Number.parseInt
......
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