Commit 961fef2d authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Specialize JSCallFunction based on CallIC feedback.

If the CallIC collected a known target function for a callsite, add
a runtime check to ensure that the feedback remains the same and
specialize the JSCallFunction node to the known target function so that
inlining and typed lowering can pick up the feedback.

R=mstarzinger@chromium.org
BUG=v8:4470, v8:4493
LOG=n

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

Cr-Commit-Position: refs/heads/master@{#31689}
parent 4c05639e
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "src/compiler/access-builder.h" #include "src/compiler/access-builder.h"
#include "src/compiler/js-graph.h" #include "src/compiler/js-graph.h"
#include "src/compiler/js-operator.h" #include "src/compiler/js-operator.h"
#include "src/compiler/node-matchers.h"
#include "src/contexts.h" #include "src/contexts.h"
#include "src/field-index-inl.h" #include "src/field-index-inl.h"
#include "src/lookup.h" #include "src/lookup.h"
...@@ -43,6 +44,8 @@ JSNativeContextSpecialization::JSNativeContextSpecialization( ...@@ -43,6 +44,8 @@ JSNativeContextSpecialization::JSNativeContextSpecialization(
Reduction JSNativeContextSpecialization::Reduce(Node* node) { Reduction JSNativeContextSpecialization::Reduce(Node* node) {
switch (node->opcode()) { switch (node->opcode()) {
case IrOpcode::kJSCallFunction:
return ReduceJSCallFunction(node);
case IrOpcode::kJSLoadGlobal: case IrOpcode::kJSLoadGlobal:
return ReduceJSLoadGlobal(node); return ReduceJSLoadGlobal(node);
case IrOpcode::kJSStoreGlobal: case IrOpcode::kJSStoreGlobal:
...@@ -58,6 +61,57 @@ Reduction JSNativeContextSpecialization::Reduce(Node* node) { ...@@ -58,6 +61,57 @@ Reduction JSNativeContextSpecialization::Reduce(Node* node) {
} }
Reduction JSNativeContextSpecialization::ReduceJSCallFunction(Node* node) {
DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
Node* target = NodeProperties::GetValueInput(node, 0);
Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
Node* control = NodeProperties::GetControlInput(node);
Node* effect = NodeProperties::GetEffectInput(node);
// Not much we can do if deoptimization support is disabled.
if (!(flags() & kDeoptimizationEnabled)) return NoChange();
// Don't mess with JSCallFunction nodes that have a constant {target}.
if (HeapObjectMatcher(target).HasValue()) return NoChange();
if (!p.feedback().IsValid()) return NoChange();
CallICNexus nexus(p.feedback().vector(), p.feedback().slot());
Handle<Object> feedback(nexus.GetFeedback(), isolate());
if (feedback->IsWeakCell()) {
Handle<WeakCell> cell = Handle<WeakCell>::cast(feedback);
if (cell->value()->IsJSFunction()) {
// Avoid cross-context leaks, meaning don't embed references to functions
// in other native contexts.
Handle<JSFunction> function(JSFunction::cast(cell->value()), isolate());
if (function->context()->native_context() !=
global_object()->native_context()) {
return NoChange();
}
// Check that the {target} is still the {target_function}.
Node* target_function = jsgraph()->HeapConstant(function);
Node* check = graph()->NewNode(simplified()->ReferenceEqual(Type::Any()),
target, target_function);
Node* branch =
graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* deoptimize = graph()->NewNode(common()->Deoptimize(), frame_state,
effect, if_false);
// TODO(bmeurer): This should be on the AdvancedReducer somehow.
NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
control = graph()->NewNode(common()->IfTrue(), branch);
// Specialize the JSCallFunction node to the {target_function}.
NodeProperties::ReplaceValueInput(node, target_function, 0);
NodeProperties::ReplaceControlInput(node, control);
return Changed(node);
}
// TODO(bmeurer): Also support optimizing bound functions and proxies here.
}
return NoChange();
}
Reduction JSNativeContextSpecialization::ReduceJSLoadGlobal(Node* node) { Reduction JSNativeContextSpecialization::ReduceJSLoadGlobal(Node* node) {
DCHECK_EQ(IrOpcode::kJSLoadGlobal, node->opcode()); DCHECK_EQ(IrOpcode::kJSLoadGlobal, node->opcode());
Handle<Name> name = LoadGlobalParametersOf(node->op()).name(); Handle<Name> name = LoadGlobalParametersOf(node->op()).name();
......
...@@ -48,6 +48,7 @@ class JSNativeContextSpecialization final : public AdvancedReducer { ...@@ -48,6 +48,7 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
Reduction Reduce(Node* node) final; Reduction Reduce(Node* node) final;
private: private:
Reduction ReduceJSCallFunction(Node* node);
Reduction ReduceJSLoadGlobal(Node* node); Reduction ReduceJSLoadGlobal(Node* node);
Reduction ReduceJSStoreGlobal(Node* node); Reduction ReduceJSStoreGlobal(Node* node);
Reduction ReduceJSLoadNamed(Node* node); Reduction ReduceJSLoadNamed(Node* node);
......
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