blob: a032042c780b03726ac3b8f148c0bd406b98c339 [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
Andreas Gampea5b09a62016-11-17 15:21:22 -080020#include "dex_file_types.h"
Nicolas Geoffraye53798a2014-12-01 10:31:54 +000021#include "invoke_type.h"
22#include "optimization.h"
Calin Juravle13439f02017-02-21 01:17:21 -080023#include "jit/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,
45 size_t depth)
David Brazdil69ba7b72015-06-23 18:27:30 +010046 : HOptimization(outer_graph, kInlinerPassName, stats),
Nicolas Geoffray73be1e82015-09-17 15:22:56 +010047 outermost_graph_(outermost_graph),
Nicolas Geoffraye53798a2014-12-01 10:31:54 +000048 outer_compilation_unit_(outer_compilation_unit),
Nicolas Geoffray9437b782015-03-25 10:08:51 +000049 caller_compilation_unit_(caller_compilation_unit),
Vladimir Markodc151b22015-10-15 18:02:30 +010050 codegen_(codegen),
Nicolas Geoffraye53798a2014-12-01 10:31:54 +000051 compiler_driver_(compiler_driver),
Nicolas Geoffray5949fa02015-12-18 10:57:10 +000052 total_number_of_dex_registers_(total_number_of_dex_registers),
Nicolas Geoffray454a4812015-06-09 10:37:32 +010053 depth_(depth),
Nicolas Geoffraye418dda2015-08-11 20:03:09 -070054 number_of_inlined_instructions_(0),
Vladimir Marko438709f2017-02-23 18:56:13 +000055 handles_(handles),
56 inline_stats_(nullptr) {}
Nicolas Geoffraye53798a2014-12-01 10:31:54 +000057
58 void Run() OVERRIDE;
59
Andreas Gampe7c3952f2015-02-19 18:21:24 -080060 static constexpr const char* kInlinerPassName = "inliner";
61
Nicolas Geoffraye53798a2014-12-01 10:31:54 +000062 private:
Calin Juravle13439f02017-02-21 01:17:21 -080063 enum InlineCacheType {
64 kInlineCacheNoData = 0,
65 kInlineCacheUninitialized = 1,
66 kInlineCacheMonomorphic = 2,
67 kInlineCachePolymorphic = 3,
68 kInlineCacheMegamorphic = 4,
69 kInlineCacheMissingTypes = 5
70 };
71
Nicolas Geoffraye418dda2015-08-11 20:03:09 -070072 bool TryInline(HInvoke* invoke_instruction);
Nicolas Geoffray73be1e82015-09-17 15:22:56 +010073
74 // Try to inline `resolved_method` in place of `invoke_instruction`. `do_rtp` is whether
Nicolas Geoffray55bd7492016-02-16 15:37:12 +000075 // reference type propagation can run after the inlining. If the inlining is successful, this
Mingyao Yang063fc772016-08-02 11:02:54 -070076 // method will replace and remove the `invoke_instruction`. If `cha_devirtualize` is true,
77 // a CHA guard needs to be added for the inlining.
78 bool TryInlineAndReplace(HInvoke* invoke_instruction,
79 ArtMethod* resolved_method,
Nicolas Geoffray0f001b72017-01-04 16:46:23 +000080 ReferenceTypeInfo receiver_type,
Mingyao Yang063fc772016-08-02 11:02:54 -070081 bool do_rtp,
82 bool cha_devirtualize)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -070083 REQUIRES_SHARED(Locks::mutator_lock_);
Nicolas Geoffray73be1e82015-09-17 15:22:56 +010084
Nicolas Geoffray55bd7492016-02-16 15:37:12 +000085 bool TryBuildAndInline(HInvoke* invoke_instruction,
86 ArtMethod* resolved_method,
Nicolas Geoffray0f001b72017-01-04 16:46:23 +000087 ReferenceTypeInfo receiver_type,
Nicolas Geoffray55bd7492016-02-16 15:37:12 +000088 HInstruction** return_replacement)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -070089 REQUIRES_SHARED(Locks::mutator_lock_);
Nicolas Geoffray55bd7492016-02-16 15:37:12 +000090
91 bool TryBuildAndInlineHelper(HInvoke* invoke_instruction,
92 ArtMethod* resolved_method,
Nicolas Geoffray0f001b72017-01-04 16:46:23 +000093 ReferenceTypeInfo receiver_type,
Nicolas Geoffray55bd7492016-02-16 15:37:12 +000094 bool same_dex_file,
95 HInstruction** return_replacement);
96
Roland Levillaina3aef2e2016-04-06 17:45:58 +010097 // Run simple optimizations on `callee_graph`.
98 // Returns the number of inlined instructions.
99 size_t RunOptimizations(HGraph* callee_graph,
100 const DexFile::CodeItem* code_item,
101 const DexCompilationUnit& dex_compilation_unit);
102
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000103 // Try to recognize known simple patterns and replace invoke call with appropriate instructions.
Nicolas Geoffray55bd7492016-02-16 15:37:12 +0000104 bool TryPatternSubstitution(HInvoke* invoke_instruction,
105 ArtMethod* resolved_method,
106 HInstruction** return_replacement)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700107 REQUIRES_SHARED(Locks::mutator_lock_);
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000108
109 // Create a new HInstanceFieldGet.
Vladimir Markof44d36c2017-03-14 14:18:46 +0000110 HInstanceFieldGet* CreateInstanceFieldGet(uint32_t field_index,
111 ArtMethod* referrer,
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000112 HInstruction* obj);
113 // Create a new HInstanceFieldSet.
Vladimir Markof44d36c2017-03-14 14:18:46 +0000114 HInstanceFieldSet* CreateInstanceFieldSet(uint32_t field_index,
115 ArtMethod* referrer,
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000116 HInstruction* obj,
Vladimir Markof44d36c2017-03-14 14:18:46 +0000117 HInstruction* value,
118 bool* is_final = nullptr);
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000119
Calin Juravle13439f02017-02-21 01:17:21 -0800120 // Try inlining the invoke instruction using inline caches.
121 bool TryInlineFromInlineCache(
122 const DexFile& caller_dex_file,
123 HInvoke* invoke_instruction,
124 ArtMethod* resolved_method)
125 REQUIRES_SHARED(Locks::mutator_lock_);
126
127 // Try getting the inline cache from JIT code cache.
128 // Return true if the inline cache was successfully allocated and the
129 // invoke info was found in the profile info.
130 InlineCacheType GetInlineCacheJIT(
131 HInvoke* invoke_instruction,
132 StackHandleScope<1>* hs,
133 /*out*/Handle<mirror::ObjectArray<mirror::Class>>* inline_cache)
134 REQUIRES_SHARED(Locks::mutator_lock_);
135
136 // Try getting the inline cache from AOT offline profile.
137 // Return true if the inline cache was successfully allocated and the
138 // invoke info was found in the profile info.
139 InlineCacheType GetInlineCacheAOT(const DexFile& caller_dex_file,
140 HInvoke* invoke_instruction,
141 StackHandleScope<1>* hs,
142 /*out*/Handle<mirror::ObjectArray<mirror::Class>>* inline_cache)
143 REQUIRES_SHARED(Locks::mutator_lock_);
144
145 // Extract the mirror classes from the offline profile and add them to the `inline_cache`.
146 // Note that even if we have profile data for the invoke the inline_cache might contain
147 // only null entries if the types cannot be resolved.
148 InlineCacheType ExtractClassesFromOfflineProfile(
149 const HInvoke* invoke_instruction,
150 const ProfileCompilationInfo::OfflineProfileMethodInfo& offline_profile,
151 /*out*/Handle<mirror::ObjectArray<mirror::Class>> inline_cache)
152 REQUIRES_SHARED(Locks::mutator_lock_);
153
154 // Compute the inline cache type.
155 InlineCacheType GetInlineCacheType(
156 const Handle<mirror::ObjectArray<mirror::Class>>& classes)
157 REQUIRES_SHARED(Locks::mutator_lock_);
158
Nicolas Geoffray73be1e82015-09-17 15:22:56 +0100159 // Try to inline the target of a monomorphic call. If successful, the code
160 // in the graph will look like:
161 // if (receiver.getClass() != ic.GetMonomorphicType()) deopt
162 // ... // inlined code
163 bool TryInlineMonomorphicCall(HInvoke* invoke_instruction,
164 ArtMethod* resolved_method,
Nicolas Geoffraye51ca8b2016-11-22 14:49:31 +0000165 Handle<mirror::ObjectArray<mirror::Class>> classes)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700166 REQUIRES_SHARED(Locks::mutator_lock_);
Nicolas Geoffray73be1e82015-09-17 15:22:56 +0100167
Nicolas Geoffray916cc1d2016-02-18 11:12:31 +0000168 // Try to inline targets of a polymorphic call.
Nicolas Geoffray73be1e82015-09-17 15:22:56 +0100169 bool TryInlinePolymorphicCall(HInvoke* invoke_instruction,
170 ArtMethod* resolved_method,
Nicolas Geoffraye51ca8b2016-11-22 14:49:31 +0000171 Handle<mirror::ObjectArray<mirror::Class>> classes)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700172 REQUIRES_SHARED(Locks::mutator_lock_);
Nicolas Geoffray73be1e82015-09-17 15:22:56 +0100173
Nicolas Geoffray916cc1d2016-02-18 11:12:31 +0000174 bool TryInlinePolymorphicCallToSameTarget(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 Geoffray916cc1d2016-02-18 11:12:31 +0000178
Mingyao Yang063fc772016-08-02 11:02:54 -0700179 // Try CHA-based devirtualization to change virtual method calls into
180 // direct calls.
181 // Returns the actual method that resolved_method can be devirtualized to.
182 ArtMethod* TryCHADevirtualization(ArtMethod* resolved_method)
183 REQUIRES_SHARED(Locks::mutator_lock_);
184
185 // Add a CHA guard for a CHA-based devirtualized call. A CHA guard checks a
186 // should_deoptimize flag and if it's true, does deoptimization.
187 void AddCHAGuard(HInstruction* invoke_instruction,
188 uint32_t dex_pc,
189 HInstruction* cursor,
190 HBasicBlock* bb_cursor);
Nicolas Geoffray916cc1d2016-02-18 11:12:31 +0000191
Nicolas Geoffraya42363f2015-12-17 14:57:09 +0000192 HInstanceFieldGet* BuildGetReceiverClass(ClassLinker* class_linker,
193 HInstruction* receiver,
194 uint32_t dex_pc) const
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700195 REQUIRES_SHARED(Locks::mutator_lock_);
Nicolas Geoffraya42363f2015-12-17 14:57:09 +0000196
David Brazdil94ab38f2016-06-21 17:48:19 +0100197 void FixUpReturnReferenceType(ArtMethod* resolved_method, HInstruction* return_replacement)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700198 REQUIRES_SHARED(Locks::mutator_lock_);
David Brazdil94ab38f2016-06-21 17:48:19 +0100199
200 // Creates an instance of ReferenceTypeInfo from `klass` if `klass` is
201 // admissible (see ReferenceTypePropagation::IsAdmissible for details).
202 // Otherwise returns inexact Object RTI.
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700203 ReferenceTypeInfo GetClassRTI(mirror::Class* klass) REQUIRES_SHARED(Locks::mutator_lock_);
David Brazdil94ab38f2016-06-21 17:48:19 +0100204
205 bool ArgumentTypesMoreSpecific(HInvoke* invoke_instruction, ArtMethod* resolved_method)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700206 REQUIRES_SHARED(Locks::mutator_lock_);
David Brazdil94ab38f2016-06-21 17:48:19 +0100207
208 bool ReturnTypeMoreSpecific(HInvoke* invoke_instruction, HInstruction* return_replacement)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700209 REQUIRES_SHARED(Locks::mutator_lock_);
Vladimir Markobe10e8e2016-01-22 12:09:44 +0000210
Nicolas Geoffray916cc1d2016-02-18 11:12:31 +0000211 // Add a type guard on the given `receiver`. This will add to the graph:
212 // i0 = HFieldGet(receiver, klass)
213 // i1 = HLoadClass(class_index, is_referrer)
214 // i2 = HNotEqual(i0, i1)
215 //
216 // And if `with_deoptimization` is true:
217 // HDeoptimize(i2)
218 //
219 // The method returns the `HNotEqual`, that will be used for polymorphic inlining.
220 HInstruction* AddTypeGuard(HInstruction* receiver,
221 HInstruction* cursor,
222 HBasicBlock* bb_cursor,
Andreas Gampea5b09a62016-11-17 15:21:22 -0800223 dex::TypeIndex class_index,
Nicolas Geoffray5247c082017-01-13 14:17:29 +0000224 Handle<mirror::Class> klass,
Nicolas Geoffray916cc1d2016-02-18 11:12:31 +0000225 HInstruction* invoke_instruction,
226 bool with_deoptimization)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700227 REQUIRES_SHARED(Locks::mutator_lock_);
Nicolas Geoffray916cc1d2016-02-18 11:12:31 +0000228
229 /*
230 * Ad-hoc implementation for implementing a diamond pattern in the graph for
231 * polymorphic inlining:
232 * 1) `compare` becomes the input of the new `HIf`.
233 * 2) Everything up until `invoke_instruction` is in the then branch (could
234 * contain multiple blocks).
235 * 3) `invoke_instruction` is moved to the otherwise block.
236 * 4) If `return_replacement` is not null, the merge block will have
237 * a phi whose inputs are `return_replacement` and `invoke_instruction`.
238 *
239 * Before:
240 * Block1
241 * compare
242 * ...
243 * invoke_instruction
244 *
245 * After:
246 * Block1
247 * compare
248 * if
249 * / \
250 * / \
251 * Then block Otherwise block
252 * ... invoke_instruction
253 * \ /
254 * \ /
255 * Merge block
256 * phi(return_replacement, invoke_instruction)
257 */
258 void CreateDiamondPatternForPolymorphicInline(HInstruction* compare,
259 HInstruction* return_replacement,
260 HInstruction* invoke_instruction);
261
Nicolas Geoffray73be1e82015-09-17 15:22:56 +0100262 HGraph* const outermost_graph_;
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000263 const DexCompilationUnit& outer_compilation_unit_;
Nicolas Geoffray9437b782015-03-25 10:08:51 +0000264 const DexCompilationUnit& caller_compilation_unit_;
Vladimir Markodc151b22015-10-15 18:02:30 +0100265 CodeGenerator* const codegen_;
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000266 CompilerDriver* const compiler_driver_;
Nicolas Geoffray5949fa02015-12-18 10:57:10 +0000267 const size_t total_number_of_dex_registers_;
Nicolas Geoffrayef87c5d2015-01-30 12:41:14 +0000268 const size_t depth_;
Nicolas Geoffraye418dda2015-08-11 20:03:09 -0700269 size_t number_of_inlined_instructions_;
Mathieu Chartiere8a3c572016-10-11 16:52:17 -0700270 VariableSizedHandleScope* const handles_;
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000271
Vladimir Marko438709f2017-02-23 18:56:13 +0000272 // Used to record stats about optimizations on the inlined graph.
273 // If the inlining is successful, these stats are merged to the caller graph's stats.
274 OptimizingCompilerStats* inline_stats_;
275
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000276 DISALLOW_COPY_AND_ASSIGN(HInliner);
277};
278
279} // namespace art
280
281#endif // ART_COMPILER_OPTIMIZING_INLINER_H_