Commit 63b46569 authored by Sigurd Schneider's avatar Sigurd Schneider Committed by Commit Bot

[turbofan] Move Number.parseInt to JSCallReducer

This CL also removes the JSBuiltinReducer, which is no longer needed.

Bug: v8:7340, v8:7250
Change-Id: I28896f6ce0d352047ea1cb7ea6de490818840faf
Reviewed-on: https://chromium-review.googlesource.com/1027853
Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#52799}
parent 436faae0
......@@ -1610,8 +1610,6 @@ v8_source_set("v8_base") {
"src/compiler/instruction.h",
"src/compiler/int64-lowering.cc",
"src/compiler/int64-lowering.h",
"src/compiler/js-builtin-reducer.cc",
"src/compiler/js-builtin-reducer.h",
"src/compiler/js-call-reducer.cc",
"src/compiler/js-call-reducer.h",
"src/compiler/js-context-specialization.cc",
......
......@@ -731,6 +731,7 @@ namespace internal {
TFJ(NumberParseFloat, 1, kString) \
/* ES6 #sec-number.parseint */ \
TFJ(NumberParseInt, 2, kString, kRadix) \
TFS(ParseInt, kString, kRadix) \
CPP(NumberPrototypeToExponential) \
CPP(NumberPrototypeToFixed) \
CPP(NumberPrototypeToLocaleString) \
......
......@@ -280,7 +280,7 @@ TF_BUILTIN(NumberParseFloat, CodeStubAssembler) {
}
// ES6 #sec-number.parseint
TF_BUILTIN(NumberParseInt, CodeStubAssembler) {
TF_BUILTIN(ParseInt, CodeStubAssembler) {
Node* context = Parameter(Descriptor::kContext);
Node* input = Parameter(Descriptor::kString);
Node* radix = Parameter(Descriptor::kRadix);
......@@ -357,6 +357,14 @@ TF_BUILTIN(NumberParseInt, CodeStubAssembler) {
}
}
// ES6 #sec-number.parseint
TF_BUILTIN(NumberParseInt, CodeStubAssembler) {
Node* context = Parameter(Descriptor::kContext);
Node* input = Parameter(Descriptor::kString);
Node* radix = Parameter(Descriptor::kRadix);
Return(CallBuiltin(Builtins::kParseInt, context, input, radix));
}
// ES6 #sec-number.prototype.valueof
TF_BUILTIN(NumberPrototypeValueOf, CodeStubAssembler) {
Node* context = Parameter(Descriptor::kContext);
......
// Copyright 2014 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.
#include "src/compiler/js-builtin-reducer.h"
#include "src/base/bits.h"
#include "src/builtins/builtins-utils.h"
#include "src/code-factory.h"
#include "src/compilation-dependencies.h"
#include "src/compiler/access-builder.h"
#include "src/compiler/allocation-builder.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/linkage.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/node-properties.h"
#include "src/compiler/simplified-operator.h"
#include "src/compiler/type-cache.h"
#include "src/compiler/types.h"
#include "src/objects-inl.h"
namespace v8 {
namespace internal {
namespace compiler {
// Helper class to access JSCall nodes that are potential candidates
// for reduction when they have a BuiltinFunctionId associated with them.
class JSCallReduction {
public:
explicit JSCallReduction(Node* node) : node_(node) {}
// Determines whether the node is a JSCall operation that targets a
// constant callee being a well-known builtin with a BuiltinFunctionId.
bool HasBuiltinFunctionId() {
if (node_->opcode() != IrOpcode::kJSCall) return false;
HeapObjectMatcher m(NodeProperties::GetValueInput(node_, 0));
if (!m.HasValue() || !m.Value()->IsJSFunction()) return false;
Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
return function->shared()->HasBuiltinFunctionId();
}
bool BuiltinCanBeInlined() {
DCHECK_EQ(IrOpcode::kJSCall, node_->opcode());
HeapObjectMatcher m(NodeProperties::GetValueInput(node_, 0));
Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
// Do not inline if the builtin may have break points.
return !function->shared()->HasBreakInfo();
}
// Retrieves the BuiltinFunctionId as described above.
BuiltinFunctionId GetBuiltinFunctionId() {
DCHECK_EQ(IrOpcode::kJSCall, node_->opcode());
HeapObjectMatcher m(NodeProperties::GetValueInput(node_, 0));
Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
return function->shared()->builtin_function_id();
}
bool ReceiverMatches(Type* type) {
return NodeProperties::GetType(receiver())->Is(type);
}
// Determines whether the call takes zero inputs.
bool InputsMatchZero() { return GetJSCallArity() == 0; }
// Determines whether the call takes one input of the given type.
bool InputsMatchOne(Type* t1) {
return GetJSCallArity() == 1 &&
NodeProperties::GetType(GetJSCallInput(0))->Is(t1);
}
// Determines whether the call takes two inputs of the given types.
bool InputsMatchTwo(Type* t1, Type* t2) {
return GetJSCallArity() == 2 &&
NodeProperties::GetType(GetJSCallInput(0))->Is(t1) &&
NodeProperties::GetType(GetJSCallInput(1))->Is(t2);
}
// Determines whether the call takes inputs all of the given type.
bool InputsMatchAll(Type* t) {
for (int i = 0; i < GetJSCallArity(); i++) {
if (!NodeProperties::GetType(GetJSCallInput(i))->Is(t)) {
return false;
}
}
return true;
}
Node* receiver() { return NodeProperties::GetValueInput(node_, 1); }
Node* left() { return GetJSCallInput(0); }
Node* right() { return GetJSCallInput(1); }
int GetJSCallArity() {
DCHECK_EQ(IrOpcode::kJSCall, node_->opcode());
// Skip first (i.e. callee) and second (i.e. receiver) operand.
return node_->op()->ValueInputCount() - 2;
}
Node* GetJSCallInput(int index) {
DCHECK_EQ(IrOpcode::kJSCall, node_->opcode());
DCHECK_LT(index, GetJSCallArity());
// Skip first (i.e. callee) and second (i.e. receiver) operand.
return NodeProperties::GetValueInput(node_, index + 2);
}
private:
Node* node_;
};
JSBuiltinReducer::JSBuiltinReducer(Editor* editor, JSGraph* jsgraph,
CompilationDependencies* dependencies,
Handle<Context> native_context)
: AdvancedReducer(editor),
dependencies_(dependencies),
jsgraph_(jsgraph),
native_context_(native_context),
type_cache_(TypeCache::Get()) {}
// 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) -> a
// Number.parseInt(a:safe-integer,b:#0\/undefined) -> a
// Number.parseInt(a:safe-integer,b:#10\/undefined) -> a
Node* value = r.GetJSCallInput(0);
return Replace(value);
}
return NoChange();
}
Reduction JSBuiltinReducer::Reduce(Node* node) {
Reduction reduction = NoChange();
JSCallReduction r(node);
// Dispatch according to the BuiltinFunctionId if present.
if (!r.HasBuiltinFunctionId()) return NoChange();
if (!r.BuiltinCanBeInlined()) return NoChange();
switch (r.GetBuiltinFunctionId()) {
case kNumberParseInt:
reduction = ReduceNumberParseInt(node);
break;
default:
break;
}
// Replace builtin call assuming replacement nodes are pure values that don't
// produce an effect. Replaces {node} with {reduction} and relaxes effects.
if (reduction.Changed()) ReplaceWithValue(node, reduction.replacement());
return reduction;
}
Node* JSBuiltinReducer::ToNumber(Node* input) {
Type* input_type = NodeProperties::GetType(input);
if (input_type->Is(Type::Number())) return input;
return graph()->NewNode(simplified()->PlainPrimitiveToNumber(), input);
}
Node* JSBuiltinReducer::ToUint32(Node* input) {
input = ToNumber(input);
Type* input_type = NodeProperties::GetType(input);
if (input_type->Is(Type::Unsigned32())) return input;
return graph()->NewNode(simplified()->NumberToUint32(), input);
}
Graph* JSBuiltinReducer::graph() const { return jsgraph()->graph(); }
Factory* JSBuiltinReducer::factory() const { return isolate()->factory(); }
Isolate* JSBuiltinReducer::isolate() const { return jsgraph()->isolate(); }
CommonOperatorBuilder* JSBuiltinReducer::common() const {
return jsgraph()->common();
}
SimplifiedOperatorBuilder* JSBuiltinReducer::simplified() const {
return jsgraph()->simplified();
}
JSOperatorBuilder* JSBuiltinReducer::javascript() const {
return jsgraph()->javascript();
}
} // namespace compiler
} // namespace internal
} // namespace v8
// Copyright 2014 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.
#ifndef V8_COMPILER_JS_BUILTIN_REDUCER_H_
#define V8_COMPILER_JS_BUILTIN_REDUCER_H_
#include "src/base/compiler-specific.h"
#include "src/compiler/graph-reducer.h"
#include "src/globals.h"
namespace v8 {
namespace internal {
// Forward declarations.
class CompilationDependencies;
class Factory;
namespace compiler {
// Forward declarations.
class CommonOperatorBuilder;
struct FieldAccess;
class JSGraph;
class JSOperatorBuilder;
class SimplifiedOperatorBuilder;
class TypeCache;
class V8_EXPORT_PRIVATE JSBuiltinReducer final
: public NON_EXPORTED_BASE(AdvancedReducer) {
public:
JSBuiltinReducer(Editor* editor, JSGraph* jsgraph,
CompilationDependencies* dependencies,
Handle<Context> native_context);
~JSBuiltinReducer() final {}
const char* reducer_name() const override { return "JSBuiltinReducer"; }
Reduction Reduce(Node* node) final;
private:
Reduction ReduceNumberParseInt(Node* node);
Node* ToNumber(Node* value);
Node* ToUint32(Node* value);
Graph* graph() const;
Factory* factory() const;
JSGraph* jsgraph() const { return jsgraph_; }
Isolate* isolate() const;
Handle<Context> native_context() const { return native_context_; }
CommonOperatorBuilder* common() const;
SimplifiedOperatorBuilder* simplified() const;
JSOperatorBuilder* javascript() const;
CompilationDependencies* dependencies() const { return dependencies_; }
CompilationDependencies* const dependencies_;
JSGraph* const jsgraph_;
Handle<Context> const native_context_;
TypeCache const& type_cache_;
};
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_COMPILER_JS_BUILTIN_REDUCER_H_
......@@ -3485,6 +3485,8 @@ Reduction JSCallReducer::ReduceJSCall(Node* node,
return ReduceNumberIsSafeInteger(node);
case Builtins::kNumberIsNaN:
return ReduceNumberIsNaN(node);
case Builtins::kNumberParseInt:
return ReduceNumberParseInt(node);
case Builtins::kGlobalIsFinite:
return ReduceGlobalIsFinite(node);
case Builtins::kGlobalIsNaN:
......@@ -6698,6 +6700,34 @@ Reduction JSCallReducer::ReduceDateNow(Node* node) {
return Replace(value);
}
// ES6 section 20.1.2.13 Number.parseInt ( string, radix )
Reduction JSCallReducer::ReduceNumberParseInt(Node* node) {
// We certainly know that undefined is not an array.
if (node->op()->ValueInputCount() < 3) {
Node* value = jsgraph()->NaNConstant();
ReplaceWithValue(node, value);
return Replace(value);
}
int arg_count = node->op()->ValueInputCount();
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* context = NodeProperties::GetContextInput(node);
Node* frame_state = NodeProperties::GetFrameStateInput(node);
Node* object = NodeProperties::GetValueInput(node, 2);
Node* radix = arg_count >= 4 ? NodeProperties::GetValueInput(node, 3)
: jsgraph()->UndefinedConstant();
node->ReplaceInput(0, object);
node->ReplaceInput(1, radix);
node->ReplaceInput(2, context);
node->ReplaceInput(3, frame_state);
node->ReplaceInput(4, effect);
node->ReplaceInput(5, control);
node->TrimInputCount(6);
NodeProperties::ChangeOp(node, javascript()->ParseInt());
return Changed(node);
}
Graph* JSCallReducer::graph() const { return jsgraph()->graph(); }
Isolate* JSCallReducer::isolate() const { return jsgraph()->isolate(); }
......
......@@ -182,6 +182,7 @@ class V8_EXPORT_PRIVATE JSCallReducer final : public AdvancedReducer {
Reduction ReduceDatePrototypeGetTime(Node* node);
Reduction ReduceDateNow(Node* node);
Reduction ReduceNumberParseInt(Node* node);
// Returns the updated {to} node, and updates control and effect along the
// way.
......
......@@ -400,6 +400,12 @@ void JSGenericLowering::LowerJSCreateObject(Node* node) {
ReplaceWithStubCall(node, callable, flags);
}
void JSGenericLowering::LowerJSParseInt(Node* node) {
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
Callable callable = Builtins::CallableFor(isolate(), Builtins::kParseInt);
ReplaceWithStubCall(node, callable, flags);
}
void JSGenericLowering::LowerJSCreateClosure(Node* node) {
CreateClosureParameters const& p = CreateClosureParametersOf(node->op());
Handle<SharedFunctionInfo> const shared_info = p.shared_info();
......
......@@ -50,7 +50,7 @@ int CollectFunctions(Node* node, Handle<JSFunction>* functions,
}
bool CanInlineFunction(Handle<SharedFunctionInfo> shared) {
// Built-in functions are handled by the JSBuiltinReducer.
// Built-in functions are handled by the JSCallReducer.
if (shared->HasBuiltinFunctionId()) return false;
// Only choose user code for inlining.
......
......@@ -644,7 +644,8 @@ CompareOperationHint CompareOperationHintOf(const Operator* op) {
V(PromiseResolve, Operator::kNoProperties, 2, 1) \
V(RejectPromise, Operator::kNoDeopt | Operator::kNoThrow, 3, 1) \
V(ResolvePromise, Operator::kNoDeopt | Operator::kNoThrow, 2, 1) \
V(GetSuperConstructor, Operator::kNoWrite, 1, 1)
V(GetSuperConstructor, Operator::kNoWrite, 1, 1) \
V(ParseInt, Operator::kNoProperties, 2, 1)
#define BINARY_OP_LIST(V) V(Add)
......
......@@ -840,6 +840,7 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final
const Operator* CreateBlockContext(const Handle<ScopeInfo>& scpope_info);
const Operator* ObjectIsArray();
const Operator* ParseInt();
private:
Zone* zone() const { return zone_; }
......
......@@ -2220,6 +2220,22 @@ Reduction JSTypedLowering::ReduceObjectIsArray(Node* node) {
return Replace(value);
}
Reduction JSTypedLowering::ReduceJSParseInt(Node* node) {
Node* value = NodeProperties::GetValueInput(node, 0);
Type* value_type = NodeProperties::GetType(value);
Node* radix = NodeProperties::GetValueInput(node, 1);
Type* radix_type = NodeProperties::GetType(radix);
if (value_type->Is(type_cache_.kSafeInteger) &&
radix_type->Is(type_cache_.kZeroOrTenOrUndefined)) {
// Number.parseInt(a:safe-integer) -> a
// Number.parseInt(a:safe-integer,b:#0\/undefined) -> a
// Number.parseInt(a:safe-integer,b:#10\/undefined) -> a
ReplaceWithValue(node, value);
return Replace(value);
}
return NoChange();
}
Reduction JSTypedLowering::Reduce(Node* node) {
switch (node->opcode()) {
case IrOpcode::kJSEqual:
......@@ -2324,6 +2340,8 @@ Reduction JSTypedLowering::Reduce(Node* node) {
return ReduceSpeculativeNumberComparison(node);
case IrOpcode::kJSObjectIsArray:
return ReduceObjectIsArray(node);
case IrOpcode::kJSParseInt:
return ReduceJSParseInt(node);
default:
break;
}
......
......@@ -86,6 +86,7 @@ class V8_EXPORT_PRIVATE JSTypedLowering final
Reduction ReduceSpeculativeNumberBinop(Node* node);
Reduction ReduceSpeculativeNumberComparison(Node* node);
Reduction ReduceObjectIsArray(Node* node);
Reduction ReduceJSParseInt(Node* node);
// Helper for ReduceJSLoadModule and ReduceJSStoreModule.
Node* BuildGetModuleCell(Node* node);
......
......@@ -123,7 +123,8 @@
V(JSToNumber) \
V(JSToNumeric) \
V(JSToObject) \
V(JSToString)
V(JSToString) \
V(JSParseInt)
#define JS_SIMPLE_UNOP_LIST(V) \
JS_CONVERSION_UNOP_LIST(V) \
......
......@@ -96,6 +96,7 @@ bool OperatorProperties::HasFrameStateInput(const Operator* op) {
case IrOpcode::kJSToNumeric:
case IrOpcode::kJSToObject:
case IrOpcode::kJSToString:
case IrOpcode::kJSParseInt:
// Call operations
case IrOpcode::kJSConstructForwardVarargs:
......
......@@ -31,7 +31,6 @@
#include "src/compiler/graph-visualizer.h"
#include "src/compiler/instruction-selector.h"
#include "src/compiler/instruction.h"
#include "src/compiler/js-builtin-reducer.h"
#include "src/compiler/js-call-reducer.h"
#include "src/compiler/js-context-specialization.h"
#include "src/compiler/js-create-lowering.h"
......@@ -1196,9 +1195,6 @@ struct TypedLoweringPhase {
JSGraphReducer graph_reducer(data->jsgraph(), temp_zone);
DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(),
data->common(), temp_zone);
JSBuiltinReducer builtin_reducer(
&graph_reducer, data->jsgraph(),
data->info()->dependencies(), data->native_context());
JSCreateLowering create_lowering(
&graph_reducer, data->info()->dependencies(), data->jsgraph(),
data->native_context(), temp_zone);
......@@ -1211,7 +1207,6 @@ struct TypedLoweringPhase {
data->common(), data->machine(),
temp_zone);
AddReducer(data, &graph_reducer, &dead_code_elimination);
AddReducer(data, &graph_reducer, &builtin_reducer);
AddReducer(data, &graph_reducer, &create_lowering);
AddReducer(data, &graph_reducer, &typed_optimization);
AddReducer(data, &graph_reducer, &typed_lowering);
......
......@@ -3130,6 +3130,7 @@ class RepresentationSelector {
case IrOpcode::kJSToName:
case IrOpcode::kJSToObject:
case IrOpcode::kJSToString:
case IrOpcode::kJSParseInt:
VisitInputs(node);
// Assume the output is tagged.
return SetOutput(node, MachineRepresentation::kTagged);
......
......@@ -50,8 +50,8 @@ class TypeCache final {
Type::Union(kSingletonZero, Type::MinusZero(), zone());
Type* const kZeroOrUndefined =
Type::Union(kSingletonZero, Type::Undefined(), zone());
Type* const kTenOrUndefined =
Type::Union(kSingletonTen, Type::Undefined(), zone());
Type* const kZeroOrTenOrUndefined =
Type::Union(kZeroOrUndefined, kSingletonTen, zone());
Type* const kMinusOneOrZero = CreateRange(-1.0, 0.0);
Type* const kMinusOneToOneOrMinusZeroOrNaN = Type::Union(
Type::Union(CreateRange(-1.0, 1.0), Type::MinusZero(), zone()),
......
......@@ -1293,6 +1293,8 @@ Type* Typer::Visitor::TypeJSLoadGlobal(Node* node) {
return Type::NonInternal();
}
Type* Typer::Visitor::TypeJSParseInt(Node* node) { return Type::Number(); }
// Returns a somewhat larger range if we previously assigned
// a (smaller) range to this node. This is used to speed up
// the fixpoint calculation in case there appears to be a loop
......
......@@ -652,6 +652,12 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
// Type is Receiver.
CheckTypeIs(node, Type::Receiver());
break;
case IrOpcode::kJSParseInt:
// Type is Receiver.
CheckValueInputIs(node, 0, Type::Any());
CheckValueInputIs(node, 1, Type::Any());
CheckTypeIs(node, Type::Number());
break;
case IrOpcode::kJSCreate:
// Type is Object.
......
......@@ -107,7 +107,6 @@ v8_source_set("unittests_sources") {
"compiler/instruction-sequence-unittest.h",
"compiler/instruction-unittest.cc",
"compiler/int64-lowering-unittest.cc",
"compiler/js-builtin-reducer-unittest.cc",
"compiler/js-call-reducer-unittest.cc",
"compiler/js-create-lowering-unittest.cc",
"compiler/js-intrinsic-lowering-unittest.cc",
......
// Copyright 2014 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.
#include "src/compiler/js-builtin-reducer.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/node-properties.h"
#include "src/compiler/simplified-operator.h"
#include "src/compiler/typer.h"
#include "src/isolate-inl.h"
#include "test/unittests/compiler/graph-unittest.h"
#include "test/unittests/compiler/node-test-utils.h"
#include "testing/gmock-support.h"
using testing::BitEq;
using testing::Capture;
namespace v8 {
namespace internal {
namespace compiler {
class JSBuiltinReducerTest : public TypedGraphTest {
public:
JSBuiltinReducerTest() : javascript_(zone()) {}
protected:
Reduction Reduce(Node* node, MachineOperatorBuilder::Flags flags =
MachineOperatorBuilder::Flag::kNoFlags) {
MachineOperatorBuilder machine(zone(), MachineType::PointerRepresentation(),
flags);
SimplifiedOperatorBuilder simplified(zone());
JSGraph jsgraph(isolate(), graph(), common(), javascript(), &simplified,
&machine);
// TODO(titzer): mock the GraphReducer here for better unit testing.
GraphReducer graph_reducer(zone(), graph());
JSBuiltinReducer reducer(&graph_reducer, &jsgraph, nullptr,
native_context());
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) {
Handle<Object> m =
JSObject::GetProperty(isolate()->global_object(),
isolate()->factory()->NewStringFromAsciiChecked(
"Math")).ToHandleChecked();
Handle<JSFunction> f = Handle<JSFunction>::cast(
Object::GetProperty(
m, isolate()->factory()->NewStringFromAsciiChecked(name))
.ToHandleChecked());
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(
isolate()->global_object(),
isolate()->factory()->NewStringFromAsciiChecked("String"))
.ToHandleChecked();
Handle<JSFunction> f = Handle<JSFunction>::cast(
Object::GetProperty(
m, isolate()->factory()->NewStringFromAsciiChecked(name))
.ToHandleChecked());
return HeapConstant(f);
}
JSOperatorBuilder* javascript() { return &javascript_; }
private:
JSOperatorBuilder javascript_;
};
namespace {
Type* const kIntegral32Types[] = {Type::UnsignedSmall(), Type::Negative32(),
Type::Unsigned31(), Type::SignedSmall(),
Type::Signed32(), Type::Unsigned32(),
Type::Integral32()};
Type* const kNumberTypes[] = {
Type::UnsignedSmall(), Type::Negative32(), Type::Unsigned31(),
Type::SignedSmall(), Type::Signed32(), Type::Unsigned32(),
Type::Integral32(), Type::MinusZero(), Type::NaN(),
Type::OrderedNumber(), Type::PlainNumber(), Type::Number()};
} // namespace
// -----------------------------------------------------------------------------
// 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()->Call(3), function, UndefinedConstant(),
p0, context, frame_state, effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_EQ(p0, r.replacement());
}
}
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()->Call(4), function, UndefinedConstant(),
p0, p1, context, frame_state, effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_EQ(p0, r.replacement());
}
}
} // namespace compiler
} // namespace internal
} // namespace v8
......@@ -582,6 +582,26 @@ TEST_F(JSCallReducerTest, GlobalIsNaN) {
EXPECT_THAT(r.replacement(), IsNumberIsNaN(IsSpeculativeToNumber(p0)));
}
// -----------------------------------------------------------------------------
// Number.parseInt
TEST_F(JSCallReducerTest, NumberParseInt) {
Node* function = NumberFunction("parseInt");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
Node* p0 = Parameter(Type::Any(), 0);
Node* p1 = Parameter(Type::Any(), 1);
Node* call = graph()->NewNode(Call(4), function, UndefinedConstant(), p0, p1,
context, frame_state, effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsJSParseInt(p0, p1));
}
} // namespace compiler
} // namespace internal
} // namespace v8
......@@ -2115,6 +2115,7 @@ IS_BINOP_MATCHER(Int64Add)
IS_BINOP_MATCHER(Int64Sub)
IS_BINOP_MATCHER(Int64Mul)
IS_BINOP_MATCHER(JSAdd)
IS_BINOP_MATCHER(JSParseInt)
IS_BINOP_MATCHER(Float32Equal)
IS_BINOP_MATCHER(Float32LessThan)
IS_BINOP_MATCHER(Float32LessThanOrEqual)
......
......@@ -408,6 +408,8 @@ Matcher<Node*> IsInt64Mul(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsJSAdd(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsJSParseInt(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsBitcastTaggedToWord(const Matcher<Node*>& input_matcher);
Matcher<Node*> IsBitcastWordToTagged(const Matcher<Node*>& input_matcher);
Matcher<Node*> IsBitcastWordToTaggedSigned(const Matcher<Node*>& input_matcher);
......
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