1// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#ifndef RUNTIME_VM_COMPILER_BACKEND_INLINER_H_
6#define RUNTIME_VM_COMPILER_BACKEND_INLINER_H_
7
8#if defined(DART_PRECOMPILED_RUNTIME)
9#error "AOT runtime should not use compiler sources (including header files)"
10#endif // defined(DART_PRECOMPILED_RUNTIME)
11
12#include "vm/allocation.h"
13#include "vm/growable_array.h"
14#include "vm/token_position.h"
15
16namespace dart {
17
18class Definition;
19class Field;
20class FlowGraph;
21class ForwardInstructionIterator;
22class Function;
23class FunctionEntryInstr;
24class GraphEntryInstr;
25class ICData;
26class InstanceCallInstr;
27class Instruction;
28struct InstructionSource;
29class Precompiler;
30class StaticCallInstr;
31class TargetEntryInstr;
32
33class SpeculativeInliningPolicy {
34 public:
35 explicit SpeculativeInliningPolicy(bool enable_suppression,
36 intptr_t limit = -1)
37 : enable_suppression_(enable_suppression), remaining_(limit) {}
38
39 bool AllowsSpeculativeInlining() const {
40 return !enable_suppression_ || remaining_ > 0;
41 }
42
43 bool IsAllowedForInlining(intptr_t call_deopt_id) const {
44 // If we are not suppressing, we always enable optimistic inlining.
45 if (!enable_suppression_) {
46 return true;
47 }
48
49 // If we have already suppressed the deopt-id we don't allow inlining it.
50 if (IsSuppressed(id: call_deopt_id)) {
51 return false;
52 }
53
54 // Allow it if we can bailout at least one more time.
55 return remaining_ > 0;
56 }
57
58 bool AddBlockedDeoptId(intptr_t id) {
59 ASSERT(enable_suppression_);
60#if defined(DEBUG)
61 ASSERT(!IsSuppressed(id));
62#endif
63
64 // If we exhausted the number of suppression entries there is no point
65 // in adding entries to the list.
66 if (remaining_ <= 0) return false;
67
68 inlining_suppressions_.Add(id);
69 remaining_ -= 1;
70 return true;
71 }
72
73 intptr_t length() const { return inlining_suppressions_.length(); }
74
75 private:
76 bool IsSuppressed(intptr_t id) const {
77 for (intptr_t i = 0; i < inlining_suppressions_.length(); ++i) {
78 if (inlining_suppressions_[i] == id) return true;
79 }
80 return false;
81 }
82
83 // Whether we enable suppressing inlining at specific deopt-ids.
84 const bool enable_suppression_;
85
86 // After we reach [remaining_] number of deopt-ids in [inlining_suppressions_]
87 // list, we'll disable speculative inlining entirely.
88 intptr_t remaining_;
89 GrowableArray<intptr_t> inlining_suppressions_;
90};
91
92class FlowGraphInliner : ValueObject {
93 public:
94 FlowGraphInliner(FlowGraph* flow_graph,
95 GrowableArray<const Function*>* inline_id_to_function,
96 GrowableArray<TokenPosition>* inline_id_to_token_pos,
97 GrowableArray<intptr_t>* caller_inline_id,
98 SpeculativeInliningPolicy* speculative_policy,
99 Precompiler* precompiler);
100
101 // The flow graph is destructively updated upon inlining. Returns the max
102 // depth that we inlined.
103 int Inline();
104
105 // Computes graph information (instruction and call site count).
106 // For the non-specialized cases (num_constants_args == 0), the
107 // method uses a cache to avoid recomputing the counts (the cached
108 // value may still be approximate but close). The 'force' flag is
109 // used to update the cached value at the end of running the full pipeline
110 // on non-specialized cases. Specialized cases (num_constants_args > 0)
111 // always recompute the counts without caching.
112 //
113 // TODO(ajcbik): cache for specific constant argument combinations too?
114 static void CollectGraphInfo(FlowGraph* flow_graph,
115 intptr_t num_constant_args,
116 bool force,
117 intptr_t* instruction_count,
118 intptr_t* call_site_count);
119
120 static void SetInliningId(FlowGraph* flow_graph, intptr_t inlining_id);
121
122 bool AlwaysInline(const Function& function);
123
124 static bool FunctionHasPreferInlinePragma(const Function& function);
125 static bool FunctionHasNeverInlinePragma(const Function& function);
126 static bool FunctionHasAlwaysConsiderInliningPragma(const Function& function);
127
128 FlowGraph* flow_graph() const { return flow_graph_; }
129 intptr_t NextInlineId(const Function& function,
130 const InstructionSource& source);
131
132 bool trace_inlining() const { return trace_inlining_; }
133
134 SpeculativeInliningPolicy* speculative_policy() {
135 return speculative_policy_;
136 }
137
138 struct ExactnessInfo {
139 const bool is_exact;
140 bool emit_exactness_guard;
141 };
142
143 static bool TryReplaceInstanceCallWithInline(
144 FlowGraph* flow_graph,
145 ForwardInstructionIterator* iterator,
146 InstanceCallInstr* call,
147 SpeculativeInliningPolicy* policy);
148
149 static bool TryReplaceStaticCallWithInline(
150 FlowGraph* flow_graph,
151 ForwardInstructionIterator* iterator,
152 StaticCallInstr* call,
153 SpeculativeInliningPolicy* policy);
154
155 static bool TryInlineRecognizedMethod(FlowGraph* flow_graph,
156 intptr_t receiver_cid,
157 const Function& target,
158 Definition* call,
159 Definition* receiver,
160 const InstructionSource& source,
161 const ICData* ic_data,
162 GraphEntryInstr* graph_entry,
163 FunctionEntryInstr** entry,
164 Instruction** last,
165 Definition** result,
166 SpeculativeInliningPolicy* policy,
167 ExactnessInfo* exactness = nullptr);
168
169 private:
170 friend class CallSiteInliner;
171
172 FlowGraph* flow_graph_;
173 GrowableArray<const Function*>* inline_id_to_function_;
174 GrowableArray<TokenPosition>* inline_id_to_token_pos_;
175 GrowableArray<intptr_t>* caller_inline_id_;
176 const bool trace_inlining_;
177 SpeculativeInliningPolicy* speculative_policy_;
178 Precompiler* precompiler_;
179
180 DISALLOW_COPY_AND_ASSIGN(FlowGraphInliner);
181};
182
183} // namespace dart
184
185#endif // RUNTIME_VM_COMPILER_BACKEND_INLINER_H_
186

source code of dart_sdk/runtime/vm/compiler/backend/inliner.h