Commit ddb9f461 authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Optimize %_IsJSReceiver based on input type.

We can constant fold %_IsJSReceiver(x) based on whether x is always a
receiver or can never be a receiver.  This is important as
%_IsJSReceiver is inserted by the JSInliner.

R=jarin@chromium.org
BUG=v8:4544
LOG=n

Review URL: https://codereview.chromium.org/1486383003

Cr-Commit-Position: refs/heads/master@{#32519}
parent d0b30d02
...@@ -243,43 +243,46 @@ Reduction JSIntrinsicLowering::ReduceIsInstanceType( ...@@ -243,43 +243,46 @@ Reduction JSIntrinsicLowering::ReduceIsInstanceType(
Reduction JSIntrinsicLowering::ReduceIsJSReceiver(Node* node) { Reduction JSIntrinsicLowering::ReduceIsJSReceiver(Node* node) {
// if (%_IsSmi(value)) {
// return false;
// } else {
// return FIRST_JS_RECEIVER_TYPE <= %_GetInstanceType(%_GetMap(value))
// }
STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
MachineType const type = static_cast<MachineType>(kTypeBool | kRepTagged);
Node* value = NodeProperties::GetValueInput(node, 0); Node* value = NodeProperties::GetValueInput(node, 0);
Type* value_type = NodeProperties::GetType(value);
Node* effect = NodeProperties::GetEffectInput(node); Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node); Node* control = NodeProperties::GetControlInput(node);
if (value_type->Is(Type::Receiver())) {
Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value); value = jsgraph()->TrueConstant();
Node* branch = graph()->NewNode(common()->Branch(), check, control); } else if (!value_type->Maybe(Type::Receiver())) {
value = jsgraph()->FalseConstant();
Node* if_true = graph()->NewNode(common()->IfTrue(), branch); } else {
Node* etrue = effect; // if (%_IsSmi(value)) {
Node* vtrue = jsgraph()->FalseConstant(); // return false;
// } else {
Node* if_false = graph()->NewNode(common()->IfFalse(), branch); // return FIRST_JS_RECEIVER_TYPE <= %_GetInstanceType(%_GetMap(value))
Node* efalse = graph()->NewNode( // }
simplified()->LoadField(AccessBuilder::ForMapInstanceType()), STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), value,
effect, if_false), Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
effect, if_false); Node* branch = graph()->NewNode(common()->Branch(), check, control);
Node* vfalse = graph()->NewNode(
machine()->Uint32LessThanOrEqual(), Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
jsgraph()->Int32Constant(FIRST_JS_RECEIVER_TYPE), efalse); Node* etrue = effect;
Node* vtrue = jsgraph()->FalseConstant();
control = graph()->NewNode(common()->Merge(2), if_true, if_false);
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
// Replace all effect uses of {node} with the {ephi}. Node* efalse = graph()->NewNode(
effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control); simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
value, effect, if_false),
effect, if_false);
Node* vfalse = graph()->NewNode(
machine()->Uint32LessThanOrEqual(),
jsgraph()->Int32Constant(FIRST_JS_RECEIVER_TYPE), efalse);
control = graph()->NewNode(common()->Merge(2), if_true, if_false);
effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
value = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), vtrue, vfalse,
control);
}
ReplaceWithValue(node, node, effect, control); ReplaceWithValue(node, node, effect, control);
return Replace(value);
// Turn the {node} into a Phi.
return Change(node, common()->Phi(type, 2), vtrue, vfalse, control);
} }
......
...@@ -1558,6 +1558,7 @@ Type* Typer::Visitor::TypeJSCallRuntime(Node* node) { ...@@ -1558,6 +1558,7 @@ Type* Typer::Visitor::TypeJSCallRuntime(Node* node) {
case Runtime::kInlineIsMinusZero: case Runtime::kInlineIsMinusZero:
case Runtime::kInlineIsFunction: case Runtime::kInlineIsFunction:
case Runtime::kInlineIsRegExp: case Runtime::kInlineIsRegExp:
case Runtime::kInlineIsJSReceiver:
return Type::Boolean(zone()); return Type::Boolean(zone());
case Runtime::kInlineDoubleLo: case Runtime::kInlineDoubleLo:
case Runtime::kInlineDoubleHi: case Runtime::kInlineDoubleHi:
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "src/compiler/js-graph.h" #include "src/compiler/js-graph.h"
#include "src/compiler/js-intrinsic-lowering.h" #include "src/compiler/js-intrinsic-lowering.h"
#include "src/compiler/js-operator.h" #include "src/compiler/js-operator.h"
#include "src/types-inl.h"
#include "test/unittests/compiler/graph-unittest.h" #include "test/unittests/compiler/graph-unittest.h"
#include "test/unittests/compiler/node-test-utils.h" #include "test/unittests/compiler/node-test-utils.h"
#include "testing/gmock-support.h" #include "testing/gmock-support.h"
...@@ -23,9 +24,9 @@ namespace v8 { ...@@ -23,9 +24,9 @@ namespace v8 {
namespace internal { namespace internal {
namespace compiler { namespace compiler {
class JSIntrinsicLoweringTest : public GraphTest { class JSIntrinsicLoweringTest : public TypedGraphTest {
public: public:
JSIntrinsicLoweringTest() : GraphTest(3), javascript_(zone()) {} JSIntrinsicLoweringTest() : TypedGraphTest(3), javascript_(zone()) {}
~JSIntrinsicLoweringTest() override {} ~JSIntrinsicLoweringTest() override {}
protected: protected:
...@@ -287,9 +288,9 @@ TEST_F(JSIntrinsicLoweringTest, InlineIsRegExp) { ...@@ -287,9 +288,9 @@ TEST_F(JSIntrinsicLoweringTest, InlineIsRegExp) {
// %_IsJSReceiver // %_IsJSReceiver
TEST_F(JSIntrinsicLoweringTest, InlineIsJSReceiver) { TEST_F(JSIntrinsicLoweringTest, InlineIsJSReceiverWithAny) {
Node* const input = Parameter(0); Node* const input = Parameter(Type::Any());
Node* const context = Parameter(1); Node* const context = Parameter(Type::Any());
Node* const effect = graph()->start(); Node* const effect = graph()->start();
Node* const control = graph()->start(); Node* const control = graph()->start();
Reduction const r = Reduce(graph()->NewNode( Reduction const r = Reduce(graph()->NewNode(
...@@ -302,7 +303,7 @@ TEST_F(JSIntrinsicLoweringTest, InlineIsJSReceiver) { ...@@ -302,7 +303,7 @@ TEST_F(JSIntrinsicLoweringTest, InlineIsJSReceiver) {
EXPECT_THAT( EXPECT_THAT(
phi, phi,
IsPhi( IsPhi(
static_cast<MachineType>(kTypeBool | kRepTagged), IsFalseConstant(), kMachAnyTagged, IsFalseConstant(),
IsUint32LessThanOrEqual( IsUint32LessThanOrEqual(
IsInt32Constant(FIRST_JS_RECEIVER_TYPE), IsInt32Constant(FIRST_JS_RECEIVER_TYPE),
IsLoadField(AccessBuilder::ForMapInstanceType(), IsLoadField(AccessBuilder::ForMapInstanceType(),
...@@ -315,6 +316,32 @@ TEST_F(JSIntrinsicLoweringTest, InlineIsJSReceiver) { ...@@ -315,6 +316,32 @@ TEST_F(JSIntrinsicLoweringTest, InlineIsJSReceiver) {
} }
TEST_F(JSIntrinsicLoweringTest, InlineIsJSReceiverWithReceiver) {
Node* const input = Parameter(Type::Receiver());
Node* const context = Parameter(Type::Any());
Node* const effect = graph()->start();
Node* const control = graph()->start();
Reduction const r = Reduce(graph()->NewNode(
javascript()->CallRuntime(Runtime::kInlineIsJSReceiver, 1), input,
context, effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsTrueConstant());
}
TEST_F(JSIntrinsicLoweringTest, InlineIsJSReceiverWithUndefined) {
Node* const input = Parameter(Type::Undefined());
Node* const context = Parameter(Type::Any());
Node* const effect = graph()->start();
Node* const control = graph()->start();
Reduction const r = Reduce(graph()->NewNode(
javascript()->CallRuntime(Runtime::kInlineIsJSReceiver, 1), input,
context, effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsFalseConstant());
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// %_JSValueGetValue // %_JSValueGetValue
......
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