Home | History | Annotate | Download | only in optimizing
      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:
     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