Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(127)

Unified Diff: src/compiler/js-inlining.cc

Issue 2626783003: [turbofan] Enable inlining based on SharedFunctionInfo. (Closed)
Patch Set: Rebased. Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/compiler/js-inlining.h ('k') | src/compiler/js-inlining-heuristic.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/compiler/js-inlining.cc
diff --git a/src/compiler/js-inlining.cc b/src/compiler/js-inlining.cc
index 782c5adafdc17a7443b37415c913b8ae362b96e8..65fce825b4af089287e6e4bd408a4c01ec278c8d 100644
--- a/src/compiler/js-inlining.cc
+++ b/src/compiler/js-inlining.cc
@@ -347,29 +347,120 @@ bool IsNonConstructible(Handle<SharedFunctionInfo> shared_info) {
} // namespace
-
-Reduction JSInliner::Reduce(Node* node) {
- if (!IrOpcode::IsInlineeOpcode(node->opcode())) return NoChange();
+// Determines whether the call target of the given call {node} is statically
+// known and can be used as an inlining candidate. The {SharedFunctionInfo} of
+// the call target is provided (the exact closure might be unknown).
+bool JSInliner::DetermineCallTarget(
+ Node* node, Handle<SharedFunctionInfo>& shared_info_out) {
+ DCHECK(IrOpcode::IsInlineeOpcode(node->opcode()));
+ HeapObjectMatcher match(node->InputAt(0));
// This reducer can handle both normal function calls as well a constructor
// calls whenever the target is a constant function object, as follows:
// - JSCall(target:constant, receiver, args...)
// - JSConstruct(target:constant, args..., new.target)
+ if (match.HasValue() && match.Value()->IsJSFunction()) {
+ Handle<JSFunction> function = Handle<JSFunction>::cast(match.Value());
+
+ // Disallow cross native-context inlining for now. This means that all parts
+ // of the resulting code will operate on the same global object. This also
+ // prevents cross context leaks, where we could inline functions from a
+ // different context and hold on to that context (and closure) from the code
+ // object.
+ // TODO(turbofan): We might want to revisit this restriction later when we
+ // have a need for this, and we know how to model different native contexts
+ // in the same graph in a compositional way.
+ if (function->context()->native_context() !=
+ info_->context()->native_context()) {
+ return false;
+ }
+
+ shared_info_out = handle(function->shared());
+ return true;
+ }
+
+ // This reducer can also handle calls where the target is statically known to
+ // be the result of a closure instantiation operation, as follows:
+ // - JSCall(JSCreateClosure[shared](context), receiver, args...)
+ // - JSConstruct(JSCreateClosure[shared](context), args..., new.target)
+ if (match.IsJSCreateClosure()) {
+ CreateClosureParameters const& p = CreateClosureParametersOf(match.op());
+
+ // Disallow inlining in case the instantiation site was never run and hence
+ // the vector cell does not contain a valid feedback vector for the call
+ // target.
+ // TODO(turbofan): We might consider to eagerly create the feedback vector
+ // in such a case (in {DetermineCallContext} below) eventually.
+ FeedbackVectorSlot slot = p.feedback().slot();
+ Handle<Cell> cell(Cell::cast(p.feedback().vector()->Get(slot)));
+ if (!cell->value()->IsTypeFeedbackVector()) return false;
+
+ shared_info_out = p.shared_info();
+ return true;
+ }
+
+ return false;
+}
+
+// Determines statically known information about the call target (assuming that
+// the call target is known according to {DetermineCallTarget} above). The
+// following static information is provided:
+// - context : The context (as SSA value) bound by the call target.
+// - feedback_vector : The target is guaranteed to use this feedback vector.
+void JSInliner::DetermineCallContext(
+ Node* node, Node*& context_out,
+ Handle<TypeFeedbackVector>& feedback_vector_out) {
+ DCHECK(IrOpcode::IsInlineeOpcode(node->opcode()));
HeapObjectMatcher match(node->InputAt(0));
- if (!match.HasValue() || !match.Value()->IsJSFunction()) return NoChange();
- Handle<JSFunction> function = Handle<JSFunction>::cast(match.Value());
- return ReduceJSCall(node, function);
+ if (match.HasValue() && match.Value()->IsJSFunction()) {
+ Handle<JSFunction> function = Handle<JSFunction>::cast(match.Value());
+
+ // If the target function was never invoked, its literals array might not
+ // contain a feedback vector. We ensure at this point that it is created.
+ JSFunction::EnsureLiterals(function);
+
+ // The inlinee specializes to the context from the JSFunction object.
+ context_out = jsgraph()->Constant(handle(function->context()));
+ feedback_vector_out = handle(function->feedback_vector());
+ return;
+ }
+
+ if (match.IsJSCreateClosure()) {
+ CreateClosureParameters const& p = CreateClosureParametersOf(match.op());
+
+ // Load the feedback vector of the target by looking up its vector cell at
+ // the instantiation site (we only decide to inline if it's populated).
+ FeedbackVectorSlot slot = p.feedback().slot();
+ Handle<Cell> cell(Cell::cast(p.feedback().vector()->Get(slot)));
+ DCHECK(cell->value()->IsTypeFeedbackVector());
+
+ // The inlinee uses the locally provided context at instantiation.
+ context_out = NodeProperties::GetContextInput(match.node());
+ feedback_vector_out = handle(TypeFeedbackVector::cast(cell->value()));
+ return;
+ }
+
+ // Must succeed.
+ UNREACHABLE();
}
-Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) {
+Reduction JSInliner::Reduce(Node* node) {
+ if (!IrOpcode::IsInlineeOpcode(node->opcode())) return NoChange();
+ return ReduceJSCall(node);
+}
+
+Reduction JSInliner::ReduceJSCall(Node* node) {
DCHECK(IrOpcode::IsInlineeOpcode(node->opcode()));
+ Handle<SharedFunctionInfo> shared_info;
JSCallAccessor call(node);
- Handle<SharedFunctionInfo> shared_info(function->shared());
+
+ // Determine the call target.
+ if (!DetermineCallTarget(node, shared_info)) return NoChange();
// Inlining is only supported in the bytecode pipeline.
if (!info_->is_optimizing_from_bytecode()) {
- TRACE("Inlining %s into %s is not supported in the deprecated pipeline\n",
+ TRACE("Not inlining %s into %s due to use of the deprecated pipeline\n",
shared_info->DebugName()->ToCString().get(),
info_->shared_info()->DebugName()->ToCString().get());
return NoChange();
@@ -410,22 +501,6 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) {
return NoChange();
}
- // Disallow cross native-context inlining for now. This means that all parts
- // of the resulting code will operate on the same global object.
- // This also prevents cross context leaks for asm.js code, where we could
- // inline functions from a different context and hold on to that context (and
- // closure) from the code object.
- // TODO(turbofan): We might want to revisit this restriction later when we
- // have a need for this, and we know how to model different native contexts
- // in the same graph in a compositional way.
- if (function->context()->native_context() !=
- info_->context()->native_context()) {
- TRACE("Not inlining %s into %s because of different native contexts\n",
- shared_info->DebugName()->ToCString().get(),
- info_->shared_info()->DebugName()->ToCString().get());
- return NoChange();
- }
-
// TODO(turbofan): TranslatedState::GetAdaptedArguments() currently relies on
// not inlining recursive functions. We might want to relax that at some
// point.
@@ -504,8 +579,10 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) {
shared_info->DebugName()->ToCString().get(),
info_->shared_info()->DebugName()->ToCString().get());
- // If function was lazily compiled, its literals array may not yet be set up.
- JSFunction::EnsureLiterals(function);
+ // Determine the targets feedback vector and its context.
+ Node* context;
+ Handle<TypeFeedbackVector> feedback_vector;
+ DetermineCallContext(node, context, feedback_vector);
// Create the subgraph for the inlinee.
Node* start;
@@ -514,9 +591,8 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) {
// Run the BytecodeGraphBuilder to create the subgraph.
Graph::SubgraphScope scope(graph());
BytecodeGraphBuilder graph_builder(
- &zone, shared_info, handle(function->feedback_vector()),
- BailoutId::None(), jsgraph(), call.frequency(), source_positions_,
- inlining_id);
+ &zone, shared_info, feedback_vector, BailoutId::None(), jsgraph(),
+ call.frequency(), source_positions_, inlining_id);
graph_builder.CreateGraph(false);
// Extract the inlinee start/end nodes.
@@ -593,12 +669,6 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) {
FrameStateType::kConstructStub, info.shared_info());
}
- // The inlinee specializes to the context from the JSFunction object.
- // TODO(turbofan): We might want to load the context from the JSFunction at
- // runtime in case we only know the SharedFunctionInfo once we have dynamic
- // type feedback in the compiler.
- Node* context = jsgraph()->Constant(handle(function->context()));
-
// Insert a JSConvertReceiver node for sloppy callees. Note that the context
// passed into this node has to be the callees context (loaded above).
if (node->opcode() == IrOpcode::kJSCall &&
« no previous file with comments | « src/compiler/js-inlining.h ('k') | src/compiler/js-inlining-heuristic.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698