1 /* 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 20 #include "dex_file_types.h" 21 #include "invoke_type.h" 22 #include "optimization.h" 23 #include "jit/profile_compilation_info.h" 24 25 namespace art { 26 27 class CodeGenerator; 28 class CompilerDriver; 29 class DexCompilationUnit; 30 class HGraph; 31 class HInvoke; 32 class OptimizingCompilerStats; 33 34 class HInliner : public HOptimization { 35 public: 36 HInliner(HGraph* outer_graph, 37 HGraph* outermost_graph, 38 CodeGenerator* codegen, 39 const DexCompilationUnit& outer_compilation_unit, 40 const DexCompilationUnit& caller_compilation_unit, 41 CompilerDriver* compiler_driver, 42 VariableSizedHandleScope* handles, 43 OptimizingCompilerStats* stats, 44 size_t total_number_of_dex_registers, 45 size_t total_number_of_instructions, 46 HInliner* parent, 47 size_t depth = 0) HOptimization(outer_graph,kInlinerPassName,stats)48 : HOptimization(outer_graph, kInlinerPassName, stats), 49 outermost_graph_(outermost_graph), 50 outer_compilation_unit_(outer_compilation_unit), 51 caller_compilation_unit_(caller_compilation_unit), 52 codegen_(codegen), 53 compiler_driver_(compiler_driver), 54 total_number_of_dex_registers_(total_number_of_dex_registers), 55 total_number_of_instructions_(total_number_of_instructions), 56 parent_(parent), 57 depth_(depth), 58 inlining_budget_(0), 59 handles_(handles), 60 inline_stats_(nullptr) {} 61 62 void Run() OVERRIDE; 63 64 static constexpr const char* kInlinerPassName = "inliner"; 65 66 private: 67 enum InlineCacheType { 68 kInlineCacheNoData = 0, 69 kInlineCacheUninitialized = 1, 70 kInlineCacheMonomorphic = 2, 71 kInlineCachePolymorphic = 3, 72 kInlineCacheMegamorphic = 4, 73 kInlineCacheMissingTypes = 5 74 }; 75 76 bool TryInline(HInvoke* invoke_instruction); 77 78 // Try to inline `resolved_method` in place of `invoke_instruction`. `do_rtp` is whether 79 // reference type propagation can run after the inlining. If the inlining is successful, this 80 // method will replace and remove the `invoke_instruction`. If `cha_devirtualize` is true, 81 // a CHA guard needs to be added for the inlining. 82 bool TryInlineAndReplace(HInvoke* invoke_instruction, 83 ArtMethod* resolved_method, 84 ReferenceTypeInfo receiver_type, 85 bool do_rtp, 86 bool cha_devirtualize) 87 REQUIRES_SHARED(Locks::mutator_lock_); 88 89 bool TryBuildAndInline(HInvoke* invoke_instruction, 90 ArtMethod* resolved_method, 91 ReferenceTypeInfo receiver_type, 92 HInstruction** return_replacement) 93 REQUIRES_SHARED(Locks::mutator_lock_); 94 95 bool TryBuildAndInlineHelper(HInvoke* invoke_instruction, 96 ArtMethod* resolved_method, 97 ReferenceTypeInfo receiver_type, 98 bool same_dex_file, 99 HInstruction** return_replacement); 100 101 // Run simple optimizations on `callee_graph`. 102 void RunOptimizations(HGraph* callee_graph, 103 const DexFile::CodeItem* code_item, 104 const DexCompilationUnit& dex_compilation_unit) 105 REQUIRES_SHARED(Locks::mutator_lock_); 106 107 // Try to recognize known simple patterns and replace invoke call with appropriate instructions. 108 bool TryPatternSubstitution(HInvoke* invoke_instruction, 109 ArtMethod* resolved_method, 110 HInstruction** return_replacement) 111 REQUIRES_SHARED(Locks::mutator_lock_); 112 113 // Create a new HInstanceFieldGet. 114 HInstanceFieldGet* CreateInstanceFieldGet(uint32_t field_index, 115 ArtMethod* referrer, 116 HInstruction* obj); 117 // Create a new HInstanceFieldSet. 118 HInstanceFieldSet* CreateInstanceFieldSet(uint32_t field_index, 119 ArtMethod* referrer, 120 HInstruction* obj, 121 HInstruction* value, 122 bool* is_final = nullptr); 123 124 // Try inlining the invoke instruction using inline caches. 125 bool TryInlineFromInlineCache( 126 const DexFile& caller_dex_file, 127 HInvoke* invoke_instruction, 128 ArtMethod* resolved_method) 129 REQUIRES_SHARED(Locks::mutator_lock_); 130 131 // Try getting the inline cache from JIT code cache. 132 // Return true if the inline cache was successfully allocated and the 133 // invoke info was found in the profile info. 134 InlineCacheType GetInlineCacheJIT( 135 HInvoke* invoke_instruction, 136 StackHandleScope<1>* hs, 137 /*out*/Handle<mirror::ObjectArray<mirror::Class>>* inline_cache) 138 REQUIRES_SHARED(Locks::mutator_lock_); 139 140 // Try getting the inline cache from AOT offline profile. 141 // Return true if the inline cache was successfully allocated and the 142 // invoke info was found in the profile info. 143 InlineCacheType GetInlineCacheAOT(const DexFile& caller_dex_file, 144 HInvoke* invoke_instruction, 145 StackHandleScope<1>* hs, 146 /*out*/Handle<mirror::ObjectArray<mirror::Class>>* inline_cache) 147 REQUIRES_SHARED(Locks::mutator_lock_); 148 149 // Extract the mirror classes from the offline profile and add them to the `inline_cache`. 150 // Note that even if we have profile data for the invoke the inline_cache might contain 151 // only null entries if the types cannot be resolved. 152 InlineCacheType ExtractClassesFromOfflineProfile( 153 const HInvoke* invoke_instruction, 154 const ProfileCompilationInfo::OfflineProfileMethodInfo& offline_profile, 155 /*out*/Handle<mirror::ObjectArray<mirror::Class>> inline_cache) 156 REQUIRES_SHARED(Locks::mutator_lock_); 157 158 // Compute the inline cache type. 159 InlineCacheType GetInlineCacheType( 160 const Handle<mirror::ObjectArray<mirror::Class>>& classes) 161 REQUIRES_SHARED(Locks::mutator_lock_); 162 163 // Try to inline the target of a monomorphic call. If successful, the code 164 // in the graph will look like: 165 // if (receiver.getClass() != ic.GetMonomorphicType()) deopt 166 // ... // inlined code 167 bool TryInlineMonomorphicCall(HInvoke* invoke_instruction, 168 ArtMethod* resolved_method, 169 Handle<mirror::ObjectArray<mirror::Class>> classes) 170 REQUIRES_SHARED(Locks::mutator_lock_); 171 172 // Try to inline targets of a polymorphic call. 173 bool TryInlinePolymorphicCall(HInvoke* invoke_instruction, 174 ArtMethod* resolved_method, 175 Handle<mirror::ObjectArray<mirror::Class>> classes) 176 REQUIRES_SHARED(Locks::mutator_lock_); 177 178 bool TryInlinePolymorphicCallToSameTarget(HInvoke* invoke_instruction, 179 ArtMethod* resolved_method, 180 Handle<mirror::ObjectArray<mirror::Class>> classes) 181 REQUIRES_SHARED(Locks::mutator_lock_); 182 183 // Returns whether or not we should use only polymorphic inlining with no deoptimizations. 184 bool UseOnlyPolymorphicInliningWithNoDeopt(); 185 186 // Try CHA-based devirtualization to change virtual method calls into 187 // direct calls. 188 // Returns the actual method that resolved_method can be devirtualized to. 189 ArtMethod* TryCHADevirtualization(ArtMethod* resolved_method) 190 REQUIRES_SHARED(Locks::mutator_lock_); 191 192 // Add a CHA guard for a CHA-based devirtualized call. A CHA guard checks a 193 // should_deoptimize flag and if it's true, does deoptimization. 194 void AddCHAGuard(HInstruction* invoke_instruction, 195 uint32_t dex_pc, 196 HInstruction* cursor, 197 HBasicBlock* bb_cursor); 198 199 HInstanceFieldGet* BuildGetReceiverClass(ClassLinker* class_linker, 200 HInstruction* receiver, 201 uint32_t dex_pc) const 202 REQUIRES_SHARED(Locks::mutator_lock_); 203 204 void FixUpReturnReferenceType(ArtMethod* resolved_method, HInstruction* return_replacement) 205 REQUIRES_SHARED(Locks::mutator_lock_); 206 207 // Creates an instance of ReferenceTypeInfo from `klass` if `klass` is 208 // admissible (see ReferenceTypePropagation::IsAdmissible for details). 209 // Otherwise returns inexact Object RTI. 210 ReferenceTypeInfo GetClassRTI(mirror::Class* klass) REQUIRES_SHARED(Locks::mutator_lock_); 211 212 bool ArgumentTypesMoreSpecific(HInvoke* invoke_instruction, ArtMethod* resolved_method) 213 REQUIRES_SHARED(Locks::mutator_lock_); 214 215 bool ReturnTypeMoreSpecific(HInvoke* invoke_instruction, HInstruction* return_replacement) 216 REQUIRES_SHARED(Locks::mutator_lock_); 217 218 // Add a type guard on the given `receiver`. This will add to the graph: 219 // i0 = HFieldGet(receiver, klass) 220 // i1 = HLoadClass(class_index, is_referrer) 221 // i2 = HNotEqual(i0, i1) 222 // 223 // And if `with_deoptimization` is true: 224 // HDeoptimize(i2) 225 // 226 // The method returns the `HNotEqual`, that will be used for polymorphic inlining. 227 HInstruction* AddTypeGuard(HInstruction* receiver, 228 HInstruction* cursor, 229 HBasicBlock* bb_cursor, 230 dex::TypeIndex class_index, 231 Handle<mirror::Class> klass, 232 HInstruction* invoke_instruction, 233 bool with_deoptimization) 234 REQUIRES_SHARED(Locks::mutator_lock_); 235 236 /* 237 * Ad-hoc implementation for implementing a diamond pattern in the graph for 238 * polymorphic inlining: 239 * 1) `compare` becomes the input of the new `HIf`. 240 * 2) Everything up until `invoke_instruction` is in the then branch (could 241 * contain multiple blocks). 242 * 3) `invoke_instruction` is moved to the otherwise block. 243 * 4) If `return_replacement` is not null, the merge block will have 244 * a phi whose inputs are `return_replacement` and `invoke_instruction`. 245 * 246 * Before: 247 * Block1 248 * compare 249 * ... 250 * invoke_instruction 251 * 252 * After: 253 * Block1 254 * compare 255 * if 256 * / \ 257 * / \ 258 * Then block Otherwise block 259 * ... invoke_instruction 260 * \ / 261 * \ / 262 * Merge block 263 * phi(return_replacement, invoke_instruction) 264 */ 265 void CreateDiamondPatternForPolymorphicInline(HInstruction* compare, 266 HInstruction* return_replacement, 267 HInstruction* invoke_instruction); 268 269 // Update the inlining budget based on `total_number_of_instructions_`. 270 void UpdateInliningBudget(); 271 272 // Count the number of calls of `method` being inlined recursively. 273 size_t CountRecursiveCallsOf(ArtMethod* method) const; 274 275 // Pretty-print for spaces during logging. 276 std::string DepthString(int line) const; 277 278 HGraph* const outermost_graph_; 279 const DexCompilationUnit& outer_compilation_unit_; 280 const DexCompilationUnit& caller_compilation_unit_; 281 CodeGenerator* const codegen_; 282 CompilerDriver* const compiler_driver_; 283 const size_t total_number_of_dex_registers_; 284 size_t total_number_of_instructions_; 285 286 // The 'parent' inliner, that means the inlinigng optimization that requested 287 // `graph_` to be inlined. 288 const HInliner* const parent_; 289 const size_t depth_; 290 291 // The budget left for inlining, in number of instructions. 292 size_t inlining_budget_; 293 VariableSizedHandleScope* const handles_; 294 295 // Used to record stats about optimizations on the inlined graph. 296 // If the inlining is successful, these stats are merged to the caller graph's stats. 297 OptimizingCompilerStats* inline_stats_; 298 299 DISALLOW_COPY_AND_ASSIGN(HInliner); 300 }; 301 302 } // namespace art 303 304 #endif // ART_COMPILER_OPTIMIZING_INLINER_H_ 305