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
23namespace art {
24
25class CodeGenerator;
26class CompilerDriver;
27class DexCompilationUnit;
28class HGraph;
29class HInvoke;
30class InlineCache;
31class OptimizingCompilerStats;
32
33class HInliner : public HOptimization {
34 public:
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