[turbofan] Also optimize instanceof with bound functions.
For bound functions on the right-hand side of instanceof we can constant-fold to the actual [[BoundTargetFunction]], actually instance OrdinaryHasInstance. Move the Function.prototype[@@hasInstance] reduction up to the JSCallReducer to allow this optimization to become effective (and also enable other optimizations). BUG=v8:5267 R=jarin@chromium.org Review-Url: https://codereview.chromium.org/2537763002 Cr-Commit-Position: refs/heads/master@{#41352}
This commit is contained in:
parent
95c0ecee66
commit
719d6c1d58
@ -964,34 +964,6 @@ Reduction JSBuiltinReducer::ReduceDateGetTime(Node* node) {
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
// ES6 section 19.2.3.6 Function.prototype [ @@hasInstance ] ( V )
|
||||
Reduction JSBuiltinReducer::ReduceFunctionHasInstance(Node* node) {
|
||||
Node* receiver = NodeProperties::GetValueInput(node, 1);
|
||||
Node* object = (node->op()->ValueInputCount() >= 3)
|
||||
? NodeProperties::GetValueInput(node, 2)
|
||||
: jsgraph()->UndefinedConstant();
|
||||
Node* context = NodeProperties::GetContextInput(node);
|
||||
Node* frame_state = NodeProperties::GetFrameStateInput(node);
|
||||
Node* effect = NodeProperties::GetEffectInput(node);
|
||||
Node* control = NodeProperties::GetControlInput(node);
|
||||
|
||||
// TODO(turbofan): If JSOrdinaryToInstance raises an exception, the
|
||||
// stack trace doesn't contain the @@hasInstance call; we have the
|
||||
// corresponding bug in the baseline case. Some massaging of the frame
|
||||
// state would be necessary here.
|
||||
|
||||
// Morph this {node} into a JSOrdinaryHasInstance node.
|
||||
node->ReplaceInput(0, receiver);
|
||||
node->ReplaceInput(1, object);
|
||||
node->ReplaceInput(2, context);
|
||||
node->ReplaceInput(3, frame_state);
|
||||
node->ReplaceInput(4, effect);
|
||||
node->ReplaceInput(5, control);
|
||||
node->TrimInputCount(6);
|
||||
NodeProperties::ChangeOp(node, javascript()->OrdinaryHasInstance());
|
||||
return Changed(node);
|
||||
}
|
||||
|
||||
// ES6 section 18.2.2 isFinite ( number )
|
||||
Reduction JSBuiltinReducer::ReduceGlobalIsFinite(Node* node) {
|
||||
JSCallReduction r(node);
|
||||
@ -1875,9 +1847,6 @@ Reduction JSBuiltinReducer::Reduce(Node* node) {
|
||||
return ReduceArrayPush(node);
|
||||
case kDateGetTime:
|
||||
return ReduceDateGetTime(node);
|
||||
case kFunctionHasInstance:
|
||||
return ReduceFunctionHasInstance(node);
|
||||
break;
|
||||
case kGlobalIsFinite:
|
||||
reduction = ReduceGlobalIsFinite(node);
|
||||
break;
|
||||
|
@ -58,7 +58,6 @@ class V8_EXPORT_PRIVATE JSBuiltinReducer final
|
||||
Reduction ReduceArrayPop(Node* node);
|
||||
Reduction ReduceArrayPush(Node* node);
|
||||
Reduction ReduceDateGetTime(Node* node);
|
||||
Reduction ReduceFunctionHasInstance(Node* node);
|
||||
Reduction ReduceGlobalIsFinite(Node* node);
|
||||
Reduction ReduceGlobalIsNaN(Node* node);
|
||||
Reduction ReduceMathAbs(Node* node);
|
||||
|
@ -189,6 +189,35 @@ Reduction JSCallReducer::ReduceFunctionPrototypeCall(Node* node) {
|
||||
return reduction.Changed() ? reduction : Changed(node);
|
||||
}
|
||||
|
||||
// ES6 section 19.2.3.6 Function.prototype [ @@hasInstance ] (V)
|
||||
Reduction JSCallReducer::ReduceFunctionPrototypeHasInstance(Node* node) {
|
||||
DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
|
||||
Node* receiver = NodeProperties::GetValueInput(node, 1);
|
||||
Node* object = (node->op()->ValueInputCount() >= 3)
|
||||
? NodeProperties::GetValueInput(node, 2)
|
||||
: jsgraph()->UndefinedConstant();
|
||||
Node* context = NodeProperties::GetContextInput(node);
|
||||
Node* frame_state = NodeProperties::GetFrameStateInput(node);
|
||||
Node* effect = NodeProperties::GetEffectInput(node);
|
||||
Node* control = NodeProperties::GetControlInput(node);
|
||||
|
||||
// TODO(turbofan): If JSOrdinaryToInstance raises an exception, the
|
||||
// stack trace doesn't contain the @@hasInstance call; we have the
|
||||
// corresponding bug in the baseline case. Some massaging of the frame
|
||||
// state would be necessary here.
|
||||
|
||||
// Morph this {node} into a JSOrdinaryHasInstance node.
|
||||
node->ReplaceInput(0, receiver);
|
||||
node->ReplaceInput(1, object);
|
||||
node->ReplaceInput(2, context);
|
||||
node->ReplaceInput(3, frame_state);
|
||||
node->ReplaceInput(4, effect);
|
||||
node->ReplaceInput(5, control);
|
||||
node->TrimInputCount(6);
|
||||
NodeProperties::ChangeOp(node, javascript()->OrdinaryHasInstance());
|
||||
return Changed(node);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// TODO(turbofan): Shall we move this to the NodeProperties? Or some (untyped)
|
||||
@ -280,6 +309,8 @@ Reduction JSCallReducer::ReduceJSCallFunction(Node* node) {
|
||||
return ReduceFunctionPrototypeApply(node);
|
||||
case Builtins::kFunctionPrototypeCall:
|
||||
return ReduceFunctionPrototypeCall(node);
|
||||
case Builtins::kFunctionPrototypeHasInstance:
|
||||
return ReduceFunctionPrototypeHasInstance(node);
|
||||
case Builtins::kNumberConstructor:
|
||||
return ReduceNumberConstructor(node);
|
||||
case Builtins::kObjectPrototypeGetProto:
|
||||
|
@ -44,6 +44,7 @@ class JSCallReducer final : public AdvancedReducer {
|
||||
Reduction ReduceNumberConstructor(Node* node);
|
||||
Reduction ReduceFunctionPrototypeApply(Node* node);
|
||||
Reduction ReduceFunctionPrototypeCall(Node* node);
|
||||
Reduction ReduceFunctionPrototypeHasInstance(Node* node);
|
||||
Reduction ReduceObjectPrototypeGetProto(Node* node);
|
||||
Reduction ReduceJSCallConstruct(Node* node);
|
||||
Reduction ReduceJSCallFunction(Node* node);
|
||||
|
@ -71,6 +71,8 @@ Reduction JSNativeContextSpecialization::Reduce(Node* node) {
|
||||
switch (node->opcode()) {
|
||||
case IrOpcode::kJSInstanceOf:
|
||||
return ReduceJSInstanceOf(node);
|
||||
case IrOpcode::kJSOrdinaryHasInstance:
|
||||
return ReduceJSOrdinaryHasInstance(node);
|
||||
case IrOpcode::kJSLoadContext:
|
||||
return ReduceJSLoadContext(node);
|
||||
case IrOpcode::kJSLoadNamed:
|
||||
@ -133,7 +135,8 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
|
||||
NodeProperties::ReplaceValueInput(node, object, 1);
|
||||
NodeProperties::ReplaceEffectInput(node, effect);
|
||||
NodeProperties::ChangeOp(node, javascript()->OrdinaryHasInstance());
|
||||
return Changed(node);
|
||||
Reduction const reduction = ReduceJSOrdinaryHasInstance(node);
|
||||
return reduction.Changed() ? reduction : Changed(node);
|
||||
}
|
||||
} else if (access_info.IsDataConstant()) {
|
||||
DCHECK(access_info.constant()->IsCallable());
|
||||
@ -174,6 +177,31 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
Reduction JSNativeContextSpecialization::ReduceJSOrdinaryHasInstance(
|
||||
Node* node) {
|
||||
DCHECK_EQ(IrOpcode::kJSOrdinaryHasInstance, node->opcode());
|
||||
Node* constructor = NodeProperties::GetValueInput(node, 0);
|
||||
Node* object = NodeProperties::GetValueInput(node, 1);
|
||||
|
||||
// Check if the {constructor} is a JSBoundFunction.
|
||||
HeapObjectMatcher m(constructor);
|
||||
if (m.HasValue() && m.Value()->IsJSBoundFunction()) {
|
||||
// OrdinaryHasInstance on bound functions turns into a recursive
|
||||
// invocation of the instanceof operator again.
|
||||
// ES6 section 7.3.19 OrdinaryHasInstance (C, O) step 2.
|
||||
Handle<JSBoundFunction> function = Handle<JSBoundFunction>::cast(m.Value());
|
||||
Handle<JSReceiver> bound_target_function(function->bound_target_function());
|
||||
NodeProperties::ReplaceValueInput(node, object, 0);
|
||||
NodeProperties::ReplaceValueInput(
|
||||
node, jsgraph()->HeapConstant(bound_target_function), 1);
|
||||
NodeProperties::ChangeOp(node, javascript()->InstanceOf());
|
||||
Reduction const reduction = ReduceJSInstanceOf(node);
|
||||
return reduction.Changed() ? reduction : Changed(node);
|
||||
}
|
||||
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
Reduction JSNativeContextSpecialization::ReduceJSLoadContext(Node* node) {
|
||||
DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
|
||||
ContextAccess const& access = ContextAccessOf(node->op());
|
||||
|
@ -54,6 +54,7 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
|
||||
|
||||
private:
|
||||
Reduction ReduceJSInstanceOf(Node* node);
|
||||
Reduction ReduceJSOrdinaryHasInstance(Node* node);
|
||||
Reduction ReduceJSLoadContext(Node* node);
|
||||
Reduction ReduceJSLoadNamed(Node* node);
|
||||
Reduction ReduceJSStoreNamed(Node* node);
|
||||
|
17
test/mjsunit/compiler/instanceof-opt3.js
Normal file
17
test/mjsunit/compiler/instanceof-opt3.js
Normal file
@ -0,0 +1,17 @@
|
||||
// Copyright 2016 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.
|
||||
|
||||
// Flags: --allow-natives-syntax
|
||||
|
||||
function Bar() {}
|
||||
var Foo = Bar.bind(null);
|
||||
|
||||
// TurboFan will optimize this to false via constant-folding the
|
||||
// OrdinaryHasInstance call inside Function.prototype[@@hasInstance].
|
||||
function foo() { return 1 instanceof Foo; }
|
||||
|
||||
assertEquals(false, foo());
|
||||
assertEquals(false, foo());
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
assertEquals(false, foo());
|
Loading…
Reference in New Issue
Block a user