OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler/js-inlining-heuristic.h" | 5 #include "src/compiler/js-inlining-heuristic.h" |
6 | 6 |
| 7 #include "src/compiler/dead-code-elimination.h" // TODO(mstarzinger): Remove! |
7 #include "src/compiler/node-matchers.h" | 8 #include "src/compiler/node-matchers.h" |
8 #include "src/objects-inl.h" | 9 #include "src/objects-inl.h" |
9 | 10 |
10 namespace v8 { | 11 namespace v8 { |
11 namespace internal { | 12 namespace internal { |
12 namespace compiler { | 13 namespace compiler { |
13 | 14 |
14 Reduction JSInliningHeuristic::Reduce(Node* node) { | 15 Reduction JSInliningHeuristic::Reduce(Node* node) { |
15 if (node->opcode() != IrOpcode::kJSCallFunction) return NoChange(); | 16 if (node->opcode() != IrOpcode::kJSCallFunction) return NoChange(); |
16 | 17 |
17 Node* callee = node->InputAt(0); | 18 Node* callee = node->InputAt(0); |
18 HeapObjectMatcher match(callee); | 19 HeapObjectMatcher match(callee); |
19 if (!match.HasValue() || !match.Value()->IsJSFunction()) return NoChange(); | 20 if (!match.HasValue() || !match.Value()->IsJSFunction()) return NoChange(); |
20 Handle<JSFunction> function = Handle<JSFunction>::cast(match.Value()); | 21 Handle<JSFunction> function = Handle<JSFunction>::cast(match.Value()); |
21 | 22 |
22 // Functions marked with %SetForceInlineFlag are immediately inlined. | 23 // Functions marked with %SetForceInlineFlag are immediately inlined. |
23 if (function->shared()->force_inline()) { | 24 if (function->shared()->force_inline()) { |
24 return inliner_.ReduceJSCallFunction(node, function); | 25 return inliner_.ReduceJSCallFunction(node, function); |
25 } | 26 } |
26 | 27 |
27 // All other functions are only handled with general inlining. | 28 // Handling of special inlining modes right away: |
28 if (mode_ == kRestrictedInlining) return NoChange(); | 29 // - For restricted inlining: stop all handling at this point. |
29 return inliner_.ReduceJSCallFunction(node, function); | 30 // - For stressing inlining: immediately handle all functions. |
| 31 switch (mode_) { |
| 32 case kRestrictedInlining: |
| 33 return NoChange(); |
| 34 case kStressInlining: |
| 35 return inliner_.ReduceJSCallFunction(node, function); |
| 36 case kGeneralInlining: |
| 37 break; |
| 38 } |
| 39 |
| 40 // --------------------------------------------------------------------------- |
| 41 // Everything below this line is part of the inlining heuristic. |
| 42 // --------------------------------------------------------------------------- |
| 43 |
| 44 // Built-in functions are handled by the JSBuiltinReducer. |
| 45 if (function->shared()->HasBuiltinFunctionId()) return NoChange(); |
| 46 |
| 47 // Quick check on source code length to avoid parsing large candidate. |
| 48 if (function->shared()->SourceSize() > FLAG_max_inlined_source_size) { |
| 49 return NoChange(); |
| 50 } |
| 51 |
| 52 // Quick check on the size of the AST to avoid parsing large candidate. |
| 53 if (function->shared()->ast_node_count() > FLAG_max_inlined_nodes) { |
| 54 return NoChange(); |
| 55 } |
| 56 |
| 57 // Gather feedback on how often this call site has been hit before. |
| 58 CallFunctionParameters p = CallFunctionParametersOf(node->op()); |
| 59 CallICNexus nexus(p.feedback().vector(), p.feedback().slot()); |
| 60 int calls = nexus.ExtractCallCount(); |
| 61 |
| 62 // --------------------------------------------------------------------------- |
| 63 // Everything above this line is part of the inlining heuristic. |
| 64 // --------------------------------------------------------------------------- |
| 65 |
| 66 // In the general case we remember the candidate for later. |
| 67 candidates_.push_back({function, node, calls}); |
| 68 return NoChange(); |
| 69 } |
| 70 |
| 71 |
| 72 void JSInliningHeuristic::ProcessCandidates() { |
| 73 if (candidates_.empty()) return; // Nothing to do without candidates. |
| 74 std::sort(candidates_.begin(), candidates_.end(), Compare); |
| 75 if (FLAG_trace_turbo_inlining) PrintCandidates(); |
| 76 |
| 77 int cumulative_count = 0; |
| 78 for (const Candidate& candidate : candidates_) { |
| 79 if (cumulative_count > FLAG_max_inlined_nodes_cumulative) break; |
| 80 inliner_.ReduceJSCallFunction(candidate.node, candidate.function); |
| 81 cumulative_count += candidate.function->shared()->ast_node_count(); |
| 82 } |
| 83 |
| 84 // TODO(mstarzinger): Temporary workaround to eliminate dead control from the |
| 85 // graph being introduced by the inliner. Make this part of the pipeline. |
| 86 GraphReducer graph_reducer(local_zone_, jsgraph_->graph(), jsgraph_->Dead()); |
| 87 DeadCodeElimination dead_code_elimination(&graph_reducer, jsgraph_->graph(), |
| 88 jsgraph_->common()); |
| 89 graph_reducer.AddReducer(&dead_code_elimination); |
| 90 graph_reducer.ReduceGraph(); |
| 91 } |
| 92 |
| 93 |
| 94 // static |
| 95 bool JSInliningHeuristic::Compare(const Candidate& left, |
| 96 const Candidate& right) { |
| 97 return left.calls > right.calls; |
| 98 } |
| 99 |
| 100 |
| 101 void JSInliningHeuristic::PrintCandidates() { |
| 102 PrintF("Candidates for inlining (size=%zu):\n", candidates_.size()); |
| 103 for (const Candidate& candidate : candidates_) { |
| 104 PrintF(" id:%d, calls:%d, size[source]:%d, size[ast]:%d / %s\n", |
| 105 candidate.node->id(), candidate.calls, |
| 106 candidate.function->shared()->SourceSize(), |
| 107 candidate.function->shared()->ast_node_count(), |
| 108 candidate.function->shared()->DebugName()->ToCString().get()); |
| 109 } |
30 } | 110 } |
31 | 111 |
32 } // namespace compiler | 112 } // namespace compiler |
33 } // namespace internal | 113 } // namespace internal |
34 } // namespace v8 | 114 } // namespace v8 |
OLD | NEW |