blob: efd4c74079bef31d0d94bd310381d4a893d8e114 [file] [log] [blame]
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ART_COMPILER_OPTIMIZING_INLINER_H_
18#define ART_COMPILER_OPTIMIZING_INLINER_H_
19
David Sehr9e734c72018-01-04 17:56:19 -080020#include "dex/dex_file_types.h"
David Sehr8c0961f2018-01-23 16:11:38 -080021#include "dex/invoke_type.h"
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070022#include "optimization.h"
David Sehr82d046e2018-04-23 08:14:19 -070023#include "profile/profile_compilation_info.h"
Nicolas Geoffraye53798a2014-12-01 10:31:54 +000024
25namespace art {
26
Vladimir Markodc151b22015-10-15 18:02:30 +010027class CodeGenerator;
Nicolas Geoffraye53798a2014-12-01 10:31:54 +000028class CompilerDriver;
29class DexCompilationUnit;
30class HGraph;
31class HInvoke;
32class OptimizingCompilerStats;
33
34class HInliner : public HOptimization {
35 public:
36 HInliner(HGraph* outer_graph,
Nicolas Geoffray73be1e82015-09-17 15:22:56 +010037 HGraph* outermost_graph,
Vladimir Markodc151b22015-10-15 18:02:30 +010038 CodeGenerator* codegen,
Nicolas Geoffraye53798a2014-12-01 10:31:54 +000039 const DexCompilationUnit& outer_compilation_unit,
Nicolas Geoffray9437b782015-03-25 10:08:51 +000040 const DexCompilationUnit& caller_compilation_unit,
Mathieu Chartiere8a3c572016-10-11 16:52:17 -070041 VariableSizedHandleScope* handles,
Nicolas Geoffrayef87c5d2015-01-30 12:41:14 +000042 OptimizingCompilerStats* stats,
Nicolas Geoffray5949fa02015-12-18 10:57:10 +000043 size_t total_number_of_dex_registers,
Nicolas Geoffrayf6d46682017-02-28 17:41:45 +000044 size_t total_number_of_instructions,
45 HInliner* parent,
Aart Bik2ca10eb2017-11-15 15:17:53 -080046 size_t depth = 0,
47 const char* name = kInlinerPassName)
48 : HOptimization(outer_graph, name, stats),
Nicolas Geoffray73be1e82015-09-17 15:22:56 +010049 outermost_graph_(outermost_graph),
Nicolas Geoffraye53798a2014-12-01 10:31:54 +000050 outer_compilation_unit_(outer_compilation_unit),
Nicolas Geoffray9437b782015-03-25 10:08:51 +000051 caller_compilation_unit_(caller_compilation_unit),
Vladimir Markodc151b22015-10-15 18:02:30 +010052 codegen_(codegen),
Nicolas Geoffray5949fa02015-12-18 10:57:10 +000053 total_number_of_dex_registers_(total_number_of_dex_registers),
Nicolas Geoffrayf6d46682017-02-28 17:41:45 +000054 total_number_of_instructions_(total_number_of_instructions),
55 parent_(parent),
Nicolas Geoffray454a4812015-06-09 10:37:32 +010056 depth_(depth),
Nicolas Geoffrayf6d46682017-02-28 17:41:45 +000057 inlining_budget_(0),
Vladimir Marko438709f2017-02-23 18:56:13 +000058 handles_(handles),
59 inline_stats_(nullptr) {}
Nicolas Geoffraye53798a2014-12-01 10:31:54 +000060
Roland Levillainbbc6e7e2018-08-24 16:58:47 +010061 bool Run() override;
Nicolas Geoffraye53798a2014-12-01 10:31:54 +000062
Andreas Gampe7c3952f2015-02-19 18:21:24 -080063 static constexpr const char* kInlinerPassName = "inliner";
64
Nicolas Geoffraye53798a2014-12-01 10:31:54 +000065 private:
Calin Juravle13439f02017-02-21 01:17:21 -080066 enum InlineCacheType {
67 kInlineCacheNoData = 0,
68 kInlineCacheUninitialized = 1,
69 kInlineCacheMonomorphic = 2,
70 kInlineCachePolymorphic = 3,
71 kInlineCacheMegamorphic = 4,
72 kInlineCacheMissingTypes = 5
73 };
74
Nicolas Geoffraye418dda2015-08-11 20:03:09 -070075 bool TryInline(HInvoke* invoke_instruction);
Nicolas Geoffray73be1e82015-09-17 15:22:56 +010076
77 // Try to inline `resolved_method` in place of `invoke_instruction`. `do_rtp` is whether
Nicolas Geoffray55bd7492016-02-16 15:37:12 +000078 // reference type propagation can run after the inlining. If the inlining is successful, this
Mingyao Yang063fc772016-08-02 11:02:54 -070079 // method will replace and remove the `invoke_instruction`. If `cha_devirtualize` is true,
80 // a CHA guard needs to be added for the inlining.
81 bool TryInlineAndReplace(HInvoke* invoke_instruction,
82 ArtMethod* resolved_method,
Nicolas Geoffray0f001b72017-01-04 16:46:23 +000083 ReferenceTypeInfo receiver_type,
Mingyao Yang063fc772016-08-02 11:02:54 -070084 bool do_rtp,
85 bool cha_devirtualize)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -070086 REQUIRES_SHARED(Locks::mutator_lock_);
Nicolas Geoffray73be1e82015-09-17 15:22:56 +010087
Nicolas Geoffray55bd7492016-02-16 15:37:12 +000088 bool TryBuildAndInline(HInvoke* invoke_instruction,
89 ArtMethod* resolved_method,
Nicolas Geoffray0f001b72017-01-04 16:46:23 +000090 ReferenceTypeInfo receiver_type,
Nicolas Geoffray55bd7492016-02-16 15:37:12 +000091 HInstruction** return_replacement)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -070092 REQUIRES_SHARED(Locks::mutator_lock_);
Nicolas Geoffray55bd7492016-02-16 15:37:12 +000093
94 bool TryBuildAndInlineHelper(HInvoke* invoke_instruction,
95 ArtMethod* resolved_method,
Nicolas Geoffray0f001b72017-01-04 16:46:23 +000096 ReferenceTypeInfo receiver_type,
Nicolas Geoffray55bd7492016-02-16 15:37:12 +000097 bool same_dex_file,
98 HInstruction** return_replacement);
99
Roland Levillaina3aef2e2016-04-06 17:45:58 +0100100 // Run simple optimizations on `callee_graph`.
Nicolas Geoffrayf6d46682017-02-28 17:41:45 +0000101 void RunOptimizations(HGraph* callee_graph,
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800102 const dex::CodeItem* code_item,
Nicolas Geoffrayf6d46682017-02-28 17:41:45 +0000103 const DexCompilationUnit& dex_compilation_unit)
104 REQUIRES_SHARED(Locks::mutator_lock_);
Roland Levillaina3aef2e2016-04-06 17:45:58 +0100105
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000106 // Try to recognize known simple patterns and replace invoke call with appropriate instructions.
Nicolas Geoffray55bd7492016-02-16 15:37:12 +0000107 bool TryPatternSubstitution(HInvoke* invoke_instruction,
108 ArtMethod* resolved_method,
109 HInstruction** return_replacement)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700110 REQUIRES_SHARED(Locks::mutator_lock_);
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000111
112 // Create a new HInstanceFieldGet.
Vladimir Markof44d36c2017-03-14 14:18:46 +0000113 HInstanceFieldGet* CreateInstanceFieldGet(uint32_t field_index,
114 ArtMethod* referrer,
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000115 HInstruction* obj);
116 // Create a new HInstanceFieldSet.
Vladimir Markof44d36c2017-03-14 14:18:46 +0000117 HInstanceFieldSet* CreateInstanceFieldSet(uint32_t field_index,
118 ArtMethod* referrer,
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000119 HInstruction* obj,
Vladimir Markof44d36c2017-03-14 14:18:46 +0000120 HInstruction* value,
121 bool* is_final = nullptr);
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000122
Calin Juravle13439f02017-02-21 01:17:21 -0800123 // Try inlining the invoke instruction using inline caches.
124 bool TryInlineFromInlineCache(
125 const DexFile& caller_dex_file,
126 HInvoke* invoke_instruction,
127 ArtMethod* resolved_method)
128 REQUIRES_SHARED(Locks::mutator_lock_);
129
130 // Try getting the inline cache from JIT code cache.
131 // Return true if the inline cache was successfully allocated and the
132 // invoke info was found in the profile info.
133 InlineCacheType GetInlineCacheJIT(
134 HInvoke* invoke_instruction,
135 StackHandleScope<1>* hs,
136 /*out*/Handle<mirror::ObjectArray<mirror::Class>>* inline_cache)
137 REQUIRES_SHARED(Locks::mutator_lock_);
138
139 // Try getting the inline cache from AOT offline profile.
140 // Return true if the inline cache was successfully allocated and the
141 // invoke info was found in the profile info.
142 InlineCacheType GetInlineCacheAOT(const DexFile& caller_dex_file,
143 HInvoke* invoke_instruction,
144 StackHandleScope<1>* hs,
145 /*out*/Handle<mirror::ObjectArray<mirror::Class>>* inline_cache)
146 REQUIRES_SHARED(Locks::mutator_lock_);
147
148 // Extract the mirror classes from the offline profile and add them to the `inline_cache`.
149 // Note that even if we have profile data for the invoke the inline_cache might contain
150 // only null entries if the types cannot be resolved.
151 InlineCacheType ExtractClassesFromOfflineProfile(
152 const HInvoke* invoke_instruction,
153 const ProfileCompilationInfo::OfflineProfileMethodInfo& offline_profile,
154 /*out*/Handle<mirror::ObjectArray<mirror::Class>> inline_cache)
155 REQUIRES_SHARED(Locks::mutator_lock_);
156
157 // Compute the inline cache type.
158 InlineCacheType GetInlineCacheType(
159 const Handle<mirror::ObjectArray<mirror::Class>>& classes)
160 REQUIRES_SHARED(Locks::mutator_lock_);
161
Nicolas Geoffray73be1e82015-09-17 15:22:56 +0100162 // Try to inline the target of a monomorphic call. If successful, the code
163 // in the graph will look like:
164 // if (receiver.getClass() != ic.GetMonomorphicType()) deopt
165 // ... // inlined code
166 bool TryInlineMonomorphicCall(HInvoke* invoke_instruction,
167 ArtMethod* resolved_method,
Nicolas Geoffraye51ca8b2016-11-22 14:49:31 +0000168 Handle<mirror::ObjectArray<mirror::Class>> classes)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700169 REQUIRES_SHARED(Locks::mutator_lock_);
Nicolas Geoffray73be1e82015-09-17 15:22:56 +0100170
Nicolas Geoffray916cc1d2016-02-18 11:12:31 +0000171 // Try to inline targets of a polymorphic call.
Nicolas Geoffray73be1e82015-09-17 15:22:56 +0100172 bool TryInlinePolymorphicCall(HInvoke* invoke_instruction,
173 ArtMethod* resolved_method,
Nicolas Geoffraye51ca8b2016-11-22 14:49:31 +0000174 Handle<mirror::ObjectArray<mirror::Class>> classes)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700175 REQUIRES_SHARED(Locks::mutator_lock_);
Nicolas Geoffray73be1e82015-09-17 15:22:56 +0100176
Nicolas Geoffray916cc1d2016-02-18 11:12:31 +0000177 bool TryInlinePolymorphicCallToSameTarget(HInvoke* invoke_instruction,
178 ArtMethod* resolved_method,
Nicolas Geoffraye51ca8b2016-11-22 14:49:31 +0000179 Handle<mirror::ObjectArray<mirror::Class>> classes)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700180 REQUIRES_SHARED(Locks::mutator_lock_);
Nicolas Geoffray916cc1d2016-02-18 11:12:31 +0000181
Calin Juravleaf44e6c2017-05-23 14:24:55 -0700182 // Returns whether or not we should use only polymorphic inlining with no deoptimizations.
183 bool UseOnlyPolymorphicInliningWithNoDeopt();
184
Mingyao Yang063fc772016-08-02 11:02:54 -0700185 // Try CHA-based devirtualization to change virtual method calls into
186 // direct calls.
187 // Returns the actual method that resolved_method can be devirtualized to.
188 ArtMethod* TryCHADevirtualization(ArtMethod* resolved_method)
189 REQUIRES_SHARED(Locks::mutator_lock_);
190
191 // Add a CHA guard for a CHA-based devirtualized call. A CHA guard checks a
192 // should_deoptimize flag and if it's true, does deoptimization.
193 void AddCHAGuard(HInstruction* invoke_instruction,
194 uint32_t dex_pc,
195 HInstruction* cursor,
196 HBasicBlock* bb_cursor);
Nicolas Geoffray916cc1d2016-02-18 11:12:31 +0000197
Nicolas Geoffraya42363f2015-12-17 14:57:09 +0000198 HInstanceFieldGet* BuildGetReceiverClass(ClassLinker* class_linker,
199 HInstruction* receiver,
200 uint32_t dex_pc) const
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700201 REQUIRES_SHARED(Locks::mutator_lock_);
Nicolas Geoffraya42363f2015-12-17 14:57:09 +0000202
David Brazdil94ab38f2016-06-21 17:48:19 +0100203 void FixUpReturnReferenceType(ArtMethod* resolved_method, HInstruction* return_replacement)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700204 REQUIRES_SHARED(Locks::mutator_lock_);
David Brazdil94ab38f2016-06-21 17:48:19 +0100205
206 // Creates an instance of ReferenceTypeInfo from `klass` if `klass` is
207 // admissible (see ReferenceTypePropagation::IsAdmissible for details).
208 // Otherwise returns inexact Object RTI.
Vladimir Markob45528c2017-07-27 14:14:28 +0100209 ReferenceTypeInfo GetClassRTI(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_);
David Brazdil94ab38f2016-06-21 17:48:19 +0100210
211 bool ArgumentTypesMoreSpecific(HInvoke* invoke_instruction, ArtMethod* resolved_method)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700212 REQUIRES_SHARED(Locks::mutator_lock_);
David Brazdil94ab38f2016-06-21 17:48:19 +0100213
214 bool ReturnTypeMoreSpecific(HInvoke* invoke_instruction, HInstruction* return_replacement)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700215 REQUIRES_SHARED(Locks::mutator_lock_);
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000216
Nicolas Geoffray916cc1d2016-02-18 11:12:31 +0000217 // Add a type guard on the given `receiver`. This will add to the graph:
218 // i0 = HFieldGet(receiver, klass)
219 // i1 = HLoadClass(class_index, is_referrer)
220 // i2 = HNotEqual(i0, i1)
221 //
222 // And if `with_deoptimization` is true:
223 // HDeoptimize(i2)
224 //
225 // The method returns the `HNotEqual`, that will be used for polymorphic inlining.
226 HInstruction* AddTypeGuard(HInstruction* receiver,
227 HInstruction* cursor,
228 HBasicBlock* bb_cursor,
Andreas Gampea5b09a62016-11-17 15:21:22 -0800229 dex::TypeIndex class_index,
Nicolas Geoffray5247c082017-01-13 14:17:29 +0000230 Handle<mirror::Class> klass,
Nicolas Geoffray916cc1d2016-02-18 11:12:31 +0000231 HInstruction* invoke_instruction,
232 bool with_deoptimization)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700233 REQUIRES_SHARED(Locks::mutator_lock_);
Nicolas Geoffray916cc1d2016-02-18 11:12:31 +0000234
235 /*
236 * Ad-hoc implementation for implementing a diamond pattern in the graph for
237 * polymorphic inlining:
238 * 1) `compare` becomes the input of the new `HIf`.
239 * 2) Everything up until `invoke_instruction` is in the then branch (could
240 * contain multiple blocks).
241 * 3) `invoke_instruction` is moved to the otherwise block.
242 * 4) If `return_replacement` is not null, the merge block will have
243 * a phi whose inputs are `return_replacement` and `invoke_instruction`.
244 *
245 * Before:
246 * Block1
247 * compare
248 * ...
249 * invoke_instruction
250 *
251 * After:
252 * Block1
253 * compare
254 * if
255 * / \
256 * / \
257 * Then block Otherwise block
258 * ... invoke_instruction
259 * \ /
260 * \ /
261 * Merge block
262 * phi(return_replacement, invoke_instruction)
263 */
264 void CreateDiamondPatternForPolymorphicInline(HInstruction* compare,
265 HInstruction* return_replacement,
266 HInstruction* invoke_instruction);
267
Nicolas Geoffrayf6d46682017-02-28 17:41:45 +0000268 // Update the inlining budget based on `total_number_of_instructions_`.
269 void UpdateInliningBudget();
270
271 // Count the number of calls of `method` being inlined recursively.
272 size_t CountRecursiveCallsOf(ArtMethod* method) const;
273
274 // Pretty-print for spaces during logging.
275 std::string DepthString(int line) const;
276
Nicolas Geoffray73be1e82015-09-17 15:22:56 +0100277 HGraph* const outermost_graph_;
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000278 const DexCompilationUnit& outer_compilation_unit_;
Nicolas Geoffray9437b782015-03-25 10:08:51 +0000279 const DexCompilationUnit& caller_compilation_unit_;
Vladimir Markodc151b22015-10-15 18:02:30 +0100280 CodeGenerator* const codegen_;
Nicolas Geoffray5949fa02015-12-18 10:57:10 +0000281 const size_t total_number_of_dex_registers_;
Nicolas Geoffrayf6d46682017-02-28 17:41:45 +0000282 size_t total_number_of_instructions_;
283
284 // The 'parent' inliner, that means the inlinigng optimization that requested
285 // `graph_` to be inlined.
286 const HInliner* const parent_;
Nicolas Geoffrayef87c5d2015-01-30 12:41:14 +0000287 const size_t depth_;
Nicolas Geoffrayf6d46682017-02-28 17:41:45 +0000288
289 // The budget left for inlining, in number of instructions.
290 size_t inlining_budget_;
Mathieu Chartiere8a3c572016-10-11 16:52:17 -0700291 VariableSizedHandleScope* const handles_;
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000292
Vladimir Marko438709f2017-02-23 18:56:13 +0000293 // Used to record stats about optimizations on the inlined graph.
294 // If the inlining is successful, these stats are merged to the caller graph's stats.
295 OptimizingCompilerStats* inline_stats_;
296
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000297 DISALLOW_COPY_AND_ASSIGN(HInliner);
298};
299
300} // namespace art
301
302#endif // ART_COMPILER_OPTIMIZING_INLINER_H_