[turbofan] Recognize fast path for Number.parseInt.
The Number.parseInt (and therefore the parseInt function on the global object) are often used instead of Math.floor or just plain int32 truncation, and we can easily recognize those cases and provide a fast path in TurboFan. R=jarin@chromium.org Review-Url: https://codereview.chromium.org/2125583002 Cr-Commit-Position: refs/heads/master@{#37518}
This commit is contained in:
parent
277fac44ff
commit
f50721d56d
@ -521,6 +521,23 @@ Reduction JSBuiltinReducer::ReduceMathTrunc(Node* node) {
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
// ES6 section 20.1.2.13 Number.parseInt ( string, radix )
|
||||
Reduction JSBuiltinReducer::ReduceNumberParseInt(Node* node) {
|
||||
JSCallReduction r(node);
|
||||
if (r.InputsMatchOne(type_cache_.kSafeInteger) ||
|
||||
r.InputsMatchTwo(type_cache_.kSafeInteger,
|
||||
type_cache_.kZeroOrUndefined) ||
|
||||
r.InputsMatchTwo(type_cache_.kSafeInteger, type_cache_.kTenOrUndefined)) {
|
||||
// Number.parseInt(a:safe-integer) -> NumberToInt32(a)
|
||||
// Number.parseInt(a:safe-integer,b:#0\/undefined) -> NumberToInt32(a)
|
||||
// Number.parseInt(a:safe-integer,b:#10\/undefined) -> NumberToInt32(a)
|
||||
Node* input = r.GetJSCallInput(0);
|
||||
Node* value = graph()->NewNode(simplified()->NumberToInt32(), input);
|
||||
return Replace(value);
|
||||
}
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
// ES6 section 21.1.2.1 String.fromCharCode ( ...codeUnits )
|
||||
Reduction JSBuiltinReducer::ReduceStringFromCharCode(Node* node) {
|
||||
JSCallReduction r(node);
|
||||
@ -639,6 +656,9 @@ Reduction JSBuiltinReducer::Reduce(Node* node) {
|
||||
case kMathTrunc:
|
||||
reduction = ReduceMathTrunc(node);
|
||||
break;
|
||||
case kNumberParseInt:
|
||||
reduction = ReduceNumberParseInt(node);
|
||||
break;
|
||||
case kStringFromCharCode:
|
||||
reduction = ReduceStringFromCharCode(node);
|
||||
break;
|
||||
|
@ -62,6 +62,7 @@ class JSBuiltinReducer final : public AdvancedReducer {
|
||||
Reduction ReduceMathTan(Node* node);
|
||||
Reduction ReduceMathTanh(Node* node);
|
||||
Reduction ReduceMathTrunc(Node* node);
|
||||
Reduction ReduceNumberParseInt(Node* node);
|
||||
Reduction ReduceStringFromCharCode(Node* node);
|
||||
|
||||
Node* ToNumber(Node* value);
|
||||
|
@ -6756,7 +6756,8 @@ class Script: public Struct {
|
||||
V(Math, imul, MathImul) \
|
||||
V(Math, clz32, MathClz32) \
|
||||
V(Math, fround, MathFround) \
|
||||
V(Math, trunc, MathTrunc)
|
||||
V(Math, trunc, MathTrunc) \
|
||||
V(Number, parseInt, NumberParseInt)
|
||||
|
||||
#define ATOMIC_FUNCTIONS_WITH_ID_LIST(V) \
|
||||
V(Atomics, load, AtomicsLoad) \
|
||||
|
@ -42,7 +42,12 @@ class TypeCache final {
|
||||
|
||||
Type* const kSingletonZero = CreateRange(0.0, 0.0);
|
||||
Type* const kSingletonOne = CreateRange(1.0, 1.0);
|
||||
Type* const kSingletonTen = CreateRange(10.0, 10.0);
|
||||
Type* const kSingletonMinusOne = CreateRange(-1.0, -1.0);
|
||||
Type* const kZeroOrUndefined =
|
||||
Type::Union(kSingletonZero, Type::Undefined(), zone());
|
||||
Type* const kTenOrUndefined =
|
||||
Type::Union(kSingletonTen, Type::Undefined(), zone());
|
||||
Type* const kMinusOneOrZero = CreateRange(-1.0, 0.0);
|
||||
Type* const kZeroOrOne = CreateRange(0.0, 1.0);
|
||||
Type* const kZeroToThirtyOne = CreateRange(0.0, 31.0);
|
||||
|
@ -49,6 +49,19 @@ class JSBuiltinReducerTest : public TypedGraphTest {
|
||||
return HeapConstant(f);
|
||||
}
|
||||
|
||||
Node* NumberFunction(const char* name) {
|
||||
Handle<Object> m =
|
||||
JSObject::GetProperty(
|
||||
isolate()->global_object(),
|
||||
isolate()->factory()->NewStringFromAsciiChecked("Number"))
|
||||
.ToHandleChecked();
|
||||
Handle<JSFunction> f = Handle<JSFunction>::cast(
|
||||
Object::GetProperty(
|
||||
m, isolate()->factory()->NewStringFromAsciiChecked(name))
|
||||
.ToHandleChecked());
|
||||
return HeapConstant(f);
|
||||
}
|
||||
|
||||
Node* StringFunction(const char* name) {
|
||||
Handle<Object> m =
|
||||
JSObject::GetProperty(
|
||||
@ -1342,6 +1355,48 @@ TEST_F(JSBuiltinReducerTest, MathTruncWithPlainPrimitive) {
|
||||
EXPECT_THAT(r.replacement(), IsNumberTrunc(IsPlainPrimitiveToNumber(p0)));
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Number.parseInt
|
||||
|
||||
TEST_F(JSBuiltinReducerTest, NumberParseIntWithIntegral32) {
|
||||
Node* function = NumberFunction("parseInt");
|
||||
|
||||
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(), IsNumberToInt32(p0));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(JSBuiltinReducerTest, NumberParseIntWithIntegral32AndUndefined) {
|
||||
Node* function = NumberFunction("parseInt");
|
||||
|
||||
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* p1 = Parameter(Type::Undefined(), 1);
|
||||
Node* call = graph()->NewNode(javascript()->CallFunction(4), function,
|
||||
UndefinedConstant(), p0, p1, context,
|
||||
frame_state, effect, control);
|
||||
Reduction r = Reduce(call);
|
||||
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsNumberToInt32(p0));
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// String.fromCharCode
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user