[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:
parent
d0b30d0276
commit
ddb9f461f1
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user