[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}
This commit is contained in:
bmeurer 2015-12-02 06:35:44 -08:00 committed by Commit bot
parent d0b30d0276
commit ddb9f461f1
3 changed files with 66 additions and 35 deletions

View File

@ -243,43 +243,46 @@ Reduction JSIntrinsicLowering::ReduceIsInstanceType(
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);
Type* value_type = NodeProperties::GetType(value);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
if (value_type->Is(Type::Receiver())) {
value = jsgraph()->TrueConstant();
} else if (!value_type->Maybe(Type::Receiver())) {
value = jsgraph()->FalseConstant();
} else {
// if (%_IsSmi(value)) {
// return false;
// } else {
// return FIRST_JS_RECEIVER_TYPE <= %_GetInstanceType(%_GetMap(value))
// }
STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
Node* branch = graph()->NewNode(common()->Branch(), check, control);
Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
Node* branch = graph()->NewNode(common()->Branch(), check, control);
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* etrue = effect;
Node* vtrue = jsgraph()->FalseConstant();
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* etrue = effect;
Node* vtrue = jsgraph()->FalseConstant();
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* efalse = graph()->NewNode(
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);
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* efalse = graph()->NewNode(
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);
// Replace all effect uses of {node} with the {ephi}.
effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
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);
// Turn the {node} into a Phi.
return Change(node, common()->Phi(type, 2), vtrue, vfalse, control);
return Replace(value);
}

View File

@ -1558,6 +1558,7 @@ Type* Typer::Visitor::TypeJSCallRuntime(Node* node) {
case Runtime::kInlineIsMinusZero:
case Runtime::kInlineIsFunction:
case Runtime::kInlineIsRegExp:
case Runtime::kInlineIsJSReceiver:
return Type::Boolean(zone());
case Runtime::kInlineDoubleLo:
case Runtime::kInlineDoubleHi:

View File

@ -7,6 +7,7 @@
#include "src/compiler/js-graph.h"
#include "src/compiler/js-intrinsic-lowering.h"
#include "src/compiler/js-operator.h"
#include "src/types-inl.h"
#include "test/unittests/compiler/graph-unittest.h"
#include "test/unittests/compiler/node-test-utils.h"
#include "testing/gmock-support.h"
@ -23,9 +24,9 @@ namespace v8 {
namespace internal {
namespace compiler {
class JSIntrinsicLoweringTest : public GraphTest {
class JSIntrinsicLoweringTest : public TypedGraphTest {
public:
JSIntrinsicLoweringTest() : GraphTest(3), javascript_(zone()) {}
JSIntrinsicLoweringTest() : TypedGraphTest(3), javascript_(zone()) {}
~JSIntrinsicLoweringTest() override {}
protected:
@ -287,9 +288,9 @@ TEST_F(JSIntrinsicLoweringTest, InlineIsRegExp) {
// %_IsJSReceiver
TEST_F(JSIntrinsicLoweringTest, InlineIsJSReceiver) {
Node* const input = Parameter(0);
Node* const context = Parameter(1);
TEST_F(JSIntrinsicLoweringTest, InlineIsJSReceiverWithAny) {
Node* const input = Parameter(Type::Any());
Node* const context = Parameter(Type::Any());
Node* const effect = graph()->start();
Node* const control = graph()->start();
Reduction const r = Reduce(graph()->NewNode(
@ -302,7 +303,7 @@ TEST_F(JSIntrinsicLoweringTest, InlineIsJSReceiver) {
EXPECT_THAT(
phi,
IsPhi(
static_cast<MachineType>(kTypeBool | kRepTagged), IsFalseConstant(),
kMachAnyTagged, IsFalseConstant(),
IsUint32LessThanOrEqual(
IsInt32Constant(FIRST_JS_RECEIVER_TYPE),
IsLoadField(AccessBuilder::ForMapInstanceType(),
@ -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