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 "invoke_type.h" 21 #include "optimization.h" 22 23 namespace art { 24 25 class CodeGenerator; 26 class CompilerDriver; 27 class DexCompilationUnit; 28 class HGraph; 29 class HInvoke; 30 class InlineCache; 31 class OptimizingCompilerStats; 32 33 class HInliner : public HOptimization { 34 public: HInliner(HGraph * outer_graph,HGraph * outermost_graph,CodeGenerator * codegen,const DexCompilationUnit & outer_compilation_unit,const DexCompilationUnit & caller_compilation_unit,CompilerDriver * compiler_driver,StackHandleScopeCollection * handles,OptimizingCompilerStats * stats,size_t total_number_of_dex_registers,size_t depth)35 HInliner(HGraph* outer_graph, 36 HGraph* outermost_graph, 37 CodeGenerator* codegen, 38 const DexCompilationUnit& outer_compilation_unit, 39 const DexCompilationUnit& caller_compilation_unit, 40 CompilerDriver* compiler_driver, 41 StackHandleScopeCollection* handles, 42 OptimizingCompilerStats* stats, 43 size_t total_number_of_dex_registers, 44 size_t depth) 45 : HOptimization(outer_graph, kInlinerPassName, stats), 46 outermost_graph_(outermost_graph), 47 outer_compilation_unit_(outer_compilation_unit), 48 caller_compilation_unit_(caller_compilation_unit), 49 codegen_(codegen), 50 compiler_driver_(compiler_driver), 51 total_number_of_dex_registers_(total_number_of_dex_registers), 52 depth_(depth), 53 number_of_inlined_instructions_(0), 54 handles_(handles) {} 55 56 void Run() OVERRIDE; 57 58 static constexpr const char* kInlinerPassName = "inliner"; 59 60 private: 61 bool TryInline(HInvoke* invoke_instruction); 62 63 // Try to inline `resolved_method` in place of `invoke_instruction`. `do_rtp` is whether 64 // reference type propagation can run after the inlining. If the inlining is successful, this 65 // method will replace and remove the `invoke_instruction`. 66 bool TryInlineAndReplace(HInvoke* invoke_instruction, ArtMethod* resolved_method, bool do_rtp) 67 SHARED_REQUIRES(Locks::mutator_lock_); 68 69 bool TryBuildAndInline(HInvoke* invoke_instruction, 70 ArtMethod* resolved_method, 71 HInstruction** return_replacement) 72 SHARED_REQUIRES(Locks::mutator_lock_); 73 74 bool TryBuildAndInlineHelper(HInvoke* invoke_instruction, 75 ArtMethod* resolved_method, 76 bool same_dex_file, 77 HInstruction** return_replacement); 78 79 // Run simple optimizations on `callee_graph`. 80 // Returns the number of inlined instructions. 81 size_t RunOptimizations(HGraph* callee_graph, 82 const DexFile::CodeItem* code_item, 83 const DexCompilationUnit& dex_compilation_unit); 84 85 // Try to recognize known simple patterns and replace invoke call with appropriate instructions. 86 bool TryPatternSubstitution(HInvoke* invoke_instruction, 87 ArtMethod* resolved_method, 88 HInstruction** return_replacement) 89 SHARED_REQUIRES(Locks::mutator_lock_); 90 91 // Create a new HInstanceFieldGet. 92 HInstanceFieldGet* CreateInstanceFieldGet(Handle<mirror::DexCache> dex_cache, 93 uint32_t field_index, 94 HInstruction* obj); 95 // Create a new HInstanceFieldSet. 96 HInstanceFieldSet* CreateInstanceFieldSet(Handle<mirror::DexCache> dex_cache, 97 uint32_t field_index, 98 HInstruction* obj, 99 HInstruction* value); 100 101 // Try to inline the target of a monomorphic call. If successful, the code 102 // in the graph will look like: 103 // if (receiver.getClass() != ic.GetMonomorphicType()) deopt 104 // ... // inlined code 105 bool TryInlineMonomorphicCall(HInvoke* invoke_instruction, 106 ArtMethod* resolved_method, 107 const InlineCache& ic) 108 SHARED_REQUIRES(Locks::mutator_lock_); 109 110 // Try to inline targets of a polymorphic call. 111 bool TryInlinePolymorphicCall(HInvoke* invoke_instruction, 112 ArtMethod* resolved_method, 113 const InlineCache& ic) 114 SHARED_REQUIRES(Locks::mutator_lock_); 115 116 bool TryInlinePolymorphicCallToSameTarget(HInvoke* invoke_instruction, 117 ArtMethod* resolved_method, 118 const InlineCache& ic) 119 SHARED_REQUIRES(Locks::mutator_lock_); 120 121 122 HInstanceFieldGet* BuildGetReceiverClass(ClassLinker* class_linker, 123 HInstruction* receiver, 124 uint32_t dex_pc) const 125 SHARED_REQUIRES(Locks::mutator_lock_); 126 127 void FixUpReturnReferenceType(HInvoke* invoke_instruction, 128 ArtMethod* resolved_method, 129 HInstruction* return_replacement, 130 bool do_rtp) 131 SHARED_REQUIRES(Locks::mutator_lock_); 132 133 // Add a type guard on the given `receiver`. This will add to the graph: 134 // i0 = HFieldGet(receiver, klass) 135 // i1 = HLoadClass(class_index, is_referrer) 136 // i2 = HNotEqual(i0, i1) 137 // 138 // And if `with_deoptimization` is true: 139 // HDeoptimize(i2) 140 // 141 // The method returns the `HNotEqual`, that will be used for polymorphic inlining. 142 HInstruction* AddTypeGuard(HInstruction* receiver, 143 HInstruction* cursor, 144 HBasicBlock* bb_cursor, 145 uint32_t class_index, 146 bool is_referrer, 147 HInstruction* invoke_instruction, 148 bool with_deoptimization) 149 SHARED_REQUIRES(Locks::mutator_lock_); 150 151 /* 152 * Ad-hoc implementation for implementing a diamond pattern in the graph for 153 * polymorphic inlining: 154 * 1) `compare` becomes the input of the new `HIf`. 155 * 2) Everything up until `invoke_instruction` is in the then branch (could 156 * contain multiple blocks). 157 * 3) `invoke_instruction` is moved to the otherwise block. 158 * 4) If `return_replacement` is not null, the merge block will have 159 * a phi whose inputs are `return_replacement` and `invoke_instruction`. 160 * 161 * Before: 162 * Block1 163 * compare 164 * ... 165 * invoke_instruction 166 * 167 * After: 168 * Block1 169 * compare 170 * if 171 * / \ 172 * / \ 173 * Then block Otherwise block 174 * ... invoke_instruction 175 * \ / 176 * \ / 177 * Merge block 178 * phi(return_replacement, invoke_instruction) 179 */ 180 void CreateDiamondPatternForPolymorphicInline(HInstruction* compare, 181 HInstruction* return_replacement, 182 HInstruction* invoke_instruction); 183 184 HGraph* const outermost_graph_; 185 const DexCompilationUnit& outer_compilation_unit_; 186 const DexCompilationUnit& caller_compilation_unit_; 187 CodeGenerator* const codegen_; 188 CompilerDriver* const compiler_driver_; 189 const size_t total_number_of_dex_registers_; 190 const size_t depth_; 191 size_t number_of_inlined_instructions_; 192 StackHandleScopeCollection* const handles_; 193 194 DISALLOW_COPY_AND_ASSIGN(HInliner); 195 }; 196 197 } // namespace art 198 199 #endif // ART_COMPILER_OPTIMIZING_INLINER_H_ 200