blob: 2fdf6a1306716aad339140d2d38fd4a9f5043678 [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,
Nicolas Geoffraye53798a2014-12-01 10:31:54 +000041 CompilerDriver* compiler_driver,
Mathieu Chartiere8a3c572016-10-11 16:52:17 -070042 VariableSizedHandleScope* handles,
Nicolas Geoffrayef87c5d2015-01-30 12:41:14 +000043 OptimizingCompilerStats* stats,
Nicolas Geoffray5949fa02015-12-18 10:57:10 +000044 size_t total_number_of_dex_registers,
Nicolas Geoffrayf6d46682017-02-28 17:41:45 +000045 size_t total_number_of_instructions,
46 HInliner* parent,
Aart Bik2ca10eb2017-11-15 15:17:53 -080047 size_t depth = 0,
48 const char* name = kInlinerPassName)
49 : HOptimization(outer_graph, name, stats),
Nicolas Geoffray73be1e82015-09-17 15:22:56 +010050 outermost_graph_(outermost_graph),
Nicolas Geoffraye53798a2014-12-01 10:31:54 +000051 outer_compilation_unit_(outer_compilation_unit),
Nicolas Geoffray9437b782015-03-25 10:08:51 +000052 caller_compilation_unit_(caller_compilation_unit),
Vladimir Markodc151b22015-10-15 18:02:30 +010053 codegen_(codegen),
Nicolas Geoffraye53798a2014-12-01 10:31:54 +000054 compiler_driver_(compiler_driver),
Nicolas Geoffray5949fa02015-12-18 10:57:10 +000055 total_number_of_dex_registers_(total_number_of_dex_registers),
Nicolas Geoffrayf6d46682017-02-28 17:41:45 +000056 total_number_of_instructions_(total_number_of_instructions),
57 parent_(parent),
Nicolas Geoffray454a4812015-06-09 10:37:32 +010058 depth_(depth),
Nicolas Geoffrayf6d46682017-02-28 17:41:45 +000059 inlining_budget_(0),
Vladimir Marko438709f2017-02-23 18:56:13 +000060 handles_(handles),
61 inline_stats_(nullptr) {}
Nicolas Geoffraye53798a2014-12-01 10:31:54 +000062
Aart Bik24773202018-04-26 10:28:51 -070063 bool Run() OVERRIDE;
Nicolas Geoffraye53798a2014-12-01 10:31:54 +000064
Andreas Gampe7c3952f2015-02-19 18:21:24 -080065 static constexpr const char* kInlinerPassName = "inliner";
66
Nicolas Geoffraye53798a2014-12-01 10:31:54 +000067 private:
Calin Juravle13439f02017-02-21 01:17:21 -080068 enum InlineCacheType {
69 kInlineCacheNoData = 0,
70 kInlineCacheUninitialized = 1,
71 kInlineCacheMonomorphic = 2,
72 kInlineCachePolymorphic = 3,
73 kInlineCacheMegamorphic = 4,
74 kInlineCacheMissingTypes = 5
75 };
76
Nicolas Geoffraye418dda2015-08-11 20:03:09 -070077 bool TryInline(HInvoke* invoke_instruction);
Nicolas Geoffray73be1e82015-09-17 15:22:56 +010078
79 // Try to inline `resolved_method` in place of `invoke_instruction`. `do_rtp` is whether
Nicolas Geoffray55bd7492016-02-16 15:37:12 +000080 // reference type propagation can run after the inlining. If the inlining is successful, this
Mingyao Yang063fc772016-08-02 11:02:54 -070081 // method will replace and remove the `invoke_instruction`. If `cha_devirtualize` is true,
82 // a CHA guard needs to be added for the inlining.
83 bool TryInlineAndReplace(HInvoke* invoke_instruction,
84 ArtMethod* resolved_method,
Nicolas Geoffray0f001b72017-01-04 16:46:23 +000085 ReferenceTypeInfo receiver_type,
Mingyao Yang063fc772016-08-02 11:02:54 -070086 bool do_rtp,
87 bool cha_devirtualize)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -070088 REQUIRES_SHARED(Locks::mutator_lock_);
Nicolas Geoffray73be1e82015-09-17 15:22:56 +010089
Nicolas Geoffray55bd7492016-02-16 15:37:12 +000090 bool TryBuildAndInline(HInvoke* invoke_instruction,
91 ArtMethod* resolved_method,
Nicolas Geoffray0f001b72017-01-04 16:46:23 +000092 ReferenceTypeInfo receiver_type,
Nicolas Geoffray55bd7492016-02-16 15:37:12 +000093 HInstruction** return_replacement)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -070094 REQUIRES_SHARED(Locks::mutator_lock_);
Nicolas Geoffray55bd7492016-02-16 15:37:12 +000095
96 bool TryBuildAndInlineHelper(HInvoke* invoke_instruction,
97 ArtMethod* resolved_method,
Nicolas Geoffray0f001b72017-01-04 16:46:23 +000098 ReferenceTypeInfo receiver_type,
Nicolas Geoffray55bd7492016-02-16 15:37:12 +000099 bool same_dex_file,
100 HInstruction** return_replacement);
101
Roland Levillaina3aef2e2016-04-06 17:45:58 +0100102 // Run simple optimizations on `callee_graph`.
Nicolas Geoffrayf6d46682017-02-28 17:41:45 +0000103 void RunOptimizations(HGraph* callee_graph,
104 const DexFile::CodeItem* code_item,
105 const DexCompilationUnit& dex_compilation_unit)
106 REQUIRES_SHARED(Locks::mutator_lock_);
Roland Levillaina3aef2e2016-04-06 17:45:58 +0100107
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000108 // Try to recognize known simple patterns and replace invoke call with appropriate instructions.
Nicolas Geoffray55bd7492016-02-16 15:37:12 +0000109 bool TryPatternSubstitution(HInvoke* invoke_instruction,
110 ArtMethod* resolved_method,
111 HInstruction** return_replacement)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700112 REQUIRES_SHARED(Locks::mutator_lock_);
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000113
114 // Create a new HInstanceFieldGet.
Vladimir Markof44d36c2017-03-14 14:18:46 +0000115 HInstanceFieldGet* CreateInstanceFieldGet(uint32_t field_index,
116 ArtMethod* referrer,
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000117 HInstruction* obj);
118 // Create a new HInstanceFieldSet.
Vladimir Markof44d36c2017-03-14 14:18:46 +0000119 HInstanceFieldSet* CreateInstanceFieldSet(uint32_t field_index,
120 ArtMethod* referrer,
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000121 HInstruction* obj,
Vladimir Markof44d36c2017-03-14 14:18:46 +0000122 HInstruction* value,
123 bool* is_final = nullptr);
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000124
Calin Juravle13439f02017-02-21 01:17:21 -0800125 // Try inlining the invoke instruction using inline caches.
126 bool TryInlineFromInlineCache(
127 const DexFile& caller_dex_file,
128 HInvoke* invoke_instruction,
129 ArtMethod* resolved_method)
130 REQUIRES_SHARED(Locks::mutator_lock_);
131
132 // Try getting the inline cache from JIT code cache.
133 // Return true if the inline cache was successfully allocated and the
134 // invoke info was found in the profile info.
135 InlineCacheType GetInlineCacheJIT(
136 HInvoke* invoke_instruction,
137 StackHandleScope<1>* hs,
138 /*out*/Handle<mirror::ObjectArray<mirror::Class>>* inline_cache)
139 REQUIRES_SHARED(Locks::mutator_lock_);
140
141 // Try getting the inline cache from AOT offline profile.
142 // Return true if the inline cache was successfully allocated and the
143 // invoke info was found in the profile info.
144 InlineCacheType GetInlineCacheAOT(const DexFile& caller_dex_file,
145 HInvoke* invoke_instruction,
146 StackHandleScope<1>* hs,
147 /*out*/Handle<mirror::ObjectArray<mirror::Class>>* inline_cache)
148 REQUIRES_SHARED(Locks::mutator_lock_);
149
150 // Extract the mirror classes from the offline profile and add them to the `inline_cache`.
151 // Note that even if we have profile data for the invoke the inline_cache might contain
152 // only null entries if the types cannot be resolved.
153 InlineCacheType ExtractClassesFromOfflineProfile(
154 const HInvoke* invoke_instruction,
155 const ProfileCompilationInfo::OfflineProfileMethodInfo& offline_profile,
156 /*out*/Handle<mirror::ObjectArray<mirror::Class>> inline_cache)
157 REQUIRES_SHARED(Locks::mutator_lock_);
158
159 // Compute the inline cache type.
160 InlineCacheType GetInlineCacheType(
161 const Handle<mirror::ObjectArray<mirror::Class>>& classes)
162 REQUIRES_SHARED(Locks::mutator_lock_);
163
Nicolas Geoffray73be1e82015-09-17 15:22:56 +0100164 // Try to inline the target of a monomorphic call. If successful, the code
165 // in the graph will look like:
166 // if (receiver.getClass() != ic.GetMonomorphicType()) deopt
167 // ... // inlined code
168 bool TryInlineMonomorphicCall(HInvoke* invoke_instruction,
169 ArtMethod* resolved_method,
Nicolas Geoffraye51ca8b2016-11-22 14:49:31 +0000170 Handle<mirror::ObjectArray<mirror::Class>> classes)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700171 REQUIRES_SHARED(Locks::mutator_lock_);
Nicolas Geoffray73be1e82015-09-17 15:22:56 +0100172
Nicolas Geoffray916cc1d2016-02-18 11:12:31 +0000173 // Try to inline targets of a polymorphic call.
Nicolas Geoffray73be1e82015-09-17 15:22:56 +0100174 bool TryInlinePolymorphicCall(HInvoke* invoke_instruction,
175 ArtMethod* resolved_method,
Nicolas Geoffraye51ca8b2016-11-22 14:49:31 +0000176 Handle<mirror::ObjectArray<mirror::Class>> classes)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700177 REQUIRES_SHARED(Locks::mutator_lock_);
Nicolas Geoffray73be1e82015-09-17 15:22:56 +0100178
Nicolas Geoffray916cc1d2016-02-18 11:12:31 +0000179 bool TryInlinePolymorphicCallToSameTarget(HInvoke* invoke_instruction,
180 ArtMethod* resolved_method,
Nicolas Geoffraye51ca8b2016-11-22 14:49:31 +0000181 Handle<mirror::ObjectArray<mirror::Class>> classes)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700182 REQUIRES_SHARED(Locks::mutator_lock_);
Nicolas Geoffray916cc1d2016-02-18 11:12:31 +0000183
Calin Juravleaf44e6c2017-05-23 14:24:55 -0700184 // Returns whether or not we should use only polymorphic inlining with no deoptimizations.
185 bool UseOnlyPolymorphicInliningWithNoDeopt();
186
Mingyao Yang063fc772016-08-02 11:02:54 -0700187 // Try CHA-based devirtualization to change virtual method calls into
188 // direct calls.
189 // Returns the actual method that resolved_method can be devirtualized to.
190 ArtMethod* TryCHADevirtualization(ArtMethod* resolved_method)
191 REQUIRES_SHARED(Locks::mutator_lock_);
192
193 // Add a CHA guard for a CHA-based devirtualized call. A CHA guard checks a
194 // should_deoptimize flag and if it's true, does deoptimization.
195 void AddCHAGuard(HInstruction* invoke_instruction,
196 uint32_t dex_pc,
197 HInstruction* cursor,
198 HBasicBlock* bb_cursor);
Nicolas Geoffray916cc1d2016-02-18 11:12:31 +0000199
Nicolas Geoffraya42363f2015-12-17 14:57:09 +0000200 HInstanceFieldGet* BuildGetReceiverClass(ClassLinker* class_linker,
201 HInstruction* receiver,
202 uint32_t dex_pc) const
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700203 REQUIRES_SHARED(Locks::mutator_lock_);
Nicolas Geoffraya42363f2015-12-17 14:57:09 +0000204
David Brazdil94ab38f2016-06-21 17:48:19 +0100205 void FixUpReturnReferenceType(ArtMethod* resolved_method, HInstruction* return_replacement)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700206 REQUIRES_SHARED(Locks::mutator_lock_);
David Brazdil94ab38f2016-06-21 17:48:19 +0100207
208 // Creates an instance of ReferenceTypeInfo from `klass` if `klass` is
209 // admissible (see ReferenceTypePropagation::IsAdmissible for details).
210 // Otherwise returns inexact Object RTI.
Vladimir Markob45528c2017-07-27 14:14:28 +0100211 ReferenceTypeInfo GetClassRTI(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_);
David Brazdil94ab38f2016-06-21 17:48:19 +0100212
213 bool ArgumentTypesMoreSpecific(HInvoke* invoke_instruction, ArtMethod* resolved_method)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700214 REQUIRES_SHARED(Locks::mutator_lock_);
David Brazdil94ab38f2016-06-21 17:48:19 +0100215
216 bool ReturnTypeMoreSpecific(HInvoke* invoke_instruction, HInstruction* return_replacement)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700217 REQUIRES_SHARED(Locks::mutator_lock_);
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000218
Nicolas Geoffray916cc1d2016-02-18 11:12:31 +0000219 // Add a type guard on the given `receiver`. This will add to the graph:
220 // i0 = HFieldGet(receiver, klass)
221 // i1 = HLoadClass(class_index, is_referrer)
222 // i2 = HNotEqual(i0, i1)
223 //
224 // And if `with_deoptimization` is true:
225 // HDeoptimize(i2)
226 //
227 // The method returns the `HNotEqual`, that will be used for polymorphic inlining.
228 HInstruction* AddTypeGuard(HInstruction* receiver,
229 HInstruction* cursor,
230 HBasicBlock* bb_cursor,
Andreas Gampea5b09a62016-11-17 15:21:22 -0800231 dex::TypeIndex class_index,
Nicolas Geoffray5247c082017-01-13 14:17:29 +0000232 Handle<mirror::Class> klass,
Nicolas Geoffray916cc1d2016-02-18 11:12:31 +0000233 HInstruction* invoke_instruction,
234 bool with_deoptimization)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700235 REQUIRES_SHARED(Locks::mutator_lock_);
Nicolas Geoffray916cc1d2016-02-18 11:12:31 +0000236
237 /*
238 * Ad-hoc implementation for implementing a diamond pattern in the graph for
239 * polymorphic inlining:
240 * 1) `compare` becomes the input of the new `HIf`.
241 * 2) Everything up until `invoke_instruction` is in the then branch (could
242 * contain multiple blocks).
243 * 3) `invoke_instruction` is moved to the otherwise block.
244 * 4) If `return_replacement` is not null, the merge block will have
245 * a phi whose inputs are `return_replacement` and `invoke_instruction`.
246 *
247 * Before:
248 * Block1
249 * compare
250 * ...
251 * invoke_instruction
252 *
253 * After:
254 * Block1
255 * compare
256 * if
257 * / \
258 * / \
259 * Then block Otherwise block
260 * ... invoke_instruction
261 * \ /
262 * \ /
263 * Merge block
264 * phi(return_replacement, invoke_instruction)
265 */
266 void CreateDiamondPatternForPolymorphicInline(HInstruction* compare,
267 HInstruction* return_replacement,
268 HInstruction* invoke_instruction);
269
Nicolas Geoffrayf6d46682017-02-28 17:41:45 +0000270 // Update the inlining budget based on `total_number_of_instructions_`.
271 void UpdateInliningBudget();
272
273 // Count the number of calls of `method` being inlined recursively.
274 size_t CountRecursiveCallsOf(ArtMethod* method) const;
275
276 // Pretty-print for spaces during logging.
277 std::string DepthString(int line) const;
278
Nicolas Geoffray73be1e82015-09-17 15:22:56 +0100279 HGraph* const outermost_graph_;
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000280 const DexCompilationUnit& outer_compilation_unit_;
Nicolas Geoffray9437b782015-03-25 10:08:51 +0000281 const DexCompilationUnit& caller_compilation_unit_;
Vladimir Markodc151b22015-10-15 18:02:30 +0100282 CodeGenerator* const codegen_;
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000283 CompilerDriver* const compiler_driver_;
Nicolas Geoffray5949fa02015-12-18 10:57:10 +0000284 const size_t total_number_of_dex_registers_;
Nicolas Geoffrayf6d46682017-02-28 17:41:45 +0000285 size_t total_number_of_instructions_;
286
287 // The 'parent' inliner, that means the inlinigng optimization that requested
288 // `graph_` to be inlined.
289 const HInliner* const parent_;
Nicolas Geoffrayef87c5d2015-01-30 12:41:14 +0000290 const size_t depth_;
Nicolas Geoffrayf6d46682017-02-28 17:41:45 +0000291
292 // The budget left for inlining, in number of instructions.
293 size_t inlining_budget_;
Mathieu Chartiere8a3c572016-10-11 16:52:17 -0700294 VariableSizedHandleScope* const handles_;
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000295
Vladimir Marko438709f2017-02-23 18:56:13 +0000296 // Used to record stats about optimizations on the inlined graph.
297 // If the inlining is successful, these stats are merged to the caller graph's stats.
298 OptimizingCompilerStats* inline_stats_;
299
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000300 DISALLOW_COPY_AND_ASSIGN(HInliner);
301};
302
303} // namespace art
304
305#endif // ART_COMPILER_OPTIMIZING_INLINER_H_