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