diff options
Diffstat (limited to 'compiler/optimizing/inliner.h')
| -rw-r--r-- | compiler/optimizing/inliner.h | 177 |
1 files changed, 141 insertions, 36 deletions
diff --git a/compiler/optimizing/inliner.h b/compiler/optimizing/inliner.h index 7cf1424b6d..67476b6956 100644 --- a/compiler/optimizing/inliner.h +++ b/compiler/optimizing/inliner.h @@ -17,8 +17,10 @@ #ifndef ART_COMPILER_OPTIMIZING_INLINER_H_ #define ART_COMPILER_OPTIMIZING_INLINER_H_ +#include "dex_file_types.h" #include "invoke_type.h" #include "optimization.h" +#include "jit/profile_compilation_info.h" namespace art { @@ -27,7 +29,6 @@ class CompilerDriver; class DexCompilationUnit; class HGraph; class HInvoke; -class InlineCache; class OptimizingCompilerStats; class HInliner : public HOptimization { @@ -38,10 +39,12 @@ class HInliner : public HOptimization { const DexCompilationUnit& outer_compilation_unit, const DexCompilationUnit& caller_compilation_unit, CompilerDriver* compiler_driver, - StackHandleScopeCollection* handles, + VariableSizedHandleScope* handles, OptimizingCompilerStats* stats, size_t total_number_of_dex_registers, - size_t depth) + size_t total_number_of_instructions, + HInliner* parent, + size_t depth = 0) : HOptimization(outer_graph, kInlinerPassName, stats), outermost_graph_(outermost_graph), outer_compilation_unit_(outer_compilation_unit), @@ -49,54 +52,113 @@ class HInliner : public HOptimization { codegen_(codegen), compiler_driver_(compiler_driver), total_number_of_dex_registers_(total_number_of_dex_registers), + total_number_of_instructions_(total_number_of_instructions), + parent_(parent), depth_(depth), - number_of_inlined_instructions_(0), - handles_(handles) {} + inlining_budget_(0), + handles_(handles), + inline_stats_(nullptr) {} void Run() OVERRIDE; static constexpr const char* kInlinerPassName = "inliner"; private: + enum InlineCacheType { + kInlineCacheNoData = 0, + kInlineCacheUninitialized = 1, + kInlineCacheMonomorphic = 2, + kInlineCachePolymorphic = 3, + kInlineCacheMegamorphic = 4, + kInlineCacheMissingTypes = 5 + }; + bool TryInline(HInvoke* invoke_instruction); // Try to inline `resolved_method` in place of `invoke_instruction`. `do_rtp` is whether // reference type propagation can run after the inlining. If the inlining is successful, this - // method will replace and remove the `invoke_instruction`. - bool TryInlineAndReplace(HInvoke* invoke_instruction, ArtMethod* resolved_method, bool do_rtp) - SHARED_REQUIRES(Locks::mutator_lock_); + // method will replace and remove the `invoke_instruction`. If `cha_devirtualize` is true, + // a CHA guard needs to be added for the inlining. + bool TryInlineAndReplace(HInvoke* invoke_instruction, + ArtMethod* resolved_method, + ReferenceTypeInfo receiver_type, + bool do_rtp, + bool cha_devirtualize) + REQUIRES_SHARED(Locks::mutator_lock_); bool TryBuildAndInline(HInvoke* invoke_instruction, ArtMethod* resolved_method, + ReferenceTypeInfo receiver_type, HInstruction** return_replacement) - SHARED_REQUIRES(Locks::mutator_lock_); + REQUIRES_SHARED(Locks::mutator_lock_); bool TryBuildAndInlineHelper(HInvoke* invoke_instruction, ArtMethod* resolved_method, + ReferenceTypeInfo receiver_type, bool same_dex_file, HInstruction** return_replacement); // Run simple optimizations on `callee_graph`. - // Returns the number of inlined instructions. - size_t RunOptimizations(HGraph* callee_graph, - const DexFile::CodeItem* code_item, - const DexCompilationUnit& dex_compilation_unit); + void RunOptimizations(HGraph* callee_graph, + const DexFile::CodeItem* code_item, + const DexCompilationUnit& dex_compilation_unit) + REQUIRES_SHARED(Locks::mutator_lock_); // Try to recognize known simple patterns and replace invoke call with appropriate instructions. bool TryPatternSubstitution(HInvoke* invoke_instruction, ArtMethod* resolved_method, HInstruction** return_replacement) - SHARED_REQUIRES(Locks::mutator_lock_); + REQUIRES_SHARED(Locks::mutator_lock_); // Create a new HInstanceFieldGet. - HInstanceFieldGet* CreateInstanceFieldGet(Handle<mirror::DexCache> dex_cache, - uint32_t field_index, + HInstanceFieldGet* CreateInstanceFieldGet(uint32_t field_index, + ArtMethod* referrer, HInstruction* obj); // Create a new HInstanceFieldSet. - HInstanceFieldSet* CreateInstanceFieldSet(Handle<mirror::DexCache> dex_cache, - uint32_t field_index, + HInstanceFieldSet* CreateInstanceFieldSet(uint32_t field_index, + ArtMethod* referrer, HInstruction* obj, - HInstruction* value); + HInstruction* value, + bool* is_final = nullptr); + + // Try inlining the invoke instruction using inline caches. + bool TryInlineFromInlineCache( + const DexFile& caller_dex_file, + HInvoke* invoke_instruction, + ArtMethod* resolved_method) + REQUIRES_SHARED(Locks::mutator_lock_); + + // Try getting the inline cache from JIT code cache. + // Return true if the inline cache was successfully allocated and the + // invoke info was found in the profile info. + InlineCacheType GetInlineCacheJIT( + HInvoke* invoke_instruction, + StackHandleScope<1>* hs, + /*out*/Handle<mirror::ObjectArray<mirror::Class>>* inline_cache) + REQUIRES_SHARED(Locks::mutator_lock_); + + // Try getting the inline cache from AOT offline profile. + // Return true if the inline cache was successfully allocated and the + // invoke info was found in the profile info. + InlineCacheType GetInlineCacheAOT(const DexFile& caller_dex_file, + HInvoke* invoke_instruction, + StackHandleScope<1>* hs, + /*out*/Handle<mirror::ObjectArray<mirror::Class>>* inline_cache) + REQUIRES_SHARED(Locks::mutator_lock_); + + // Extract the mirror classes from the offline profile and add them to the `inline_cache`. + // Note that even if we have profile data for the invoke the inline_cache might contain + // only null entries if the types cannot be resolved. + InlineCacheType ExtractClassesFromOfflineProfile( + const HInvoke* invoke_instruction, + const ProfileCompilationInfo::OfflineProfileMethodInfo& offline_profile, + /*out*/Handle<mirror::ObjectArray<mirror::Class>> inline_cache) + REQUIRES_SHARED(Locks::mutator_lock_); + + // Compute the inline cache type. + InlineCacheType GetInlineCacheType( + const Handle<mirror::ObjectArray<mirror::Class>>& classes) + REQUIRES_SHARED(Locks::mutator_lock_); // Try to inline the target of a monomorphic call. If successful, the code // in the graph will look like: @@ -104,31 +166,54 @@ class HInliner : public HOptimization { // ... // inlined code bool TryInlineMonomorphicCall(HInvoke* invoke_instruction, ArtMethod* resolved_method, - const InlineCache& ic) - SHARED_REQUIRES(Locks::mutator_lock_); + Handle<mirror::ObjectArray<mirror::Class>> classes) + REQUIRES_SHARED(Locks::mutator_lock_); // Try to inline targets of a polymorphic call. bool TryInlinePolymorphicCall(HInvoke* invoke_instruction, ArtMethod* resolved_method, - const InlineCache& ic) - SHARED_REQUIRES(Locks::mutator_lock_); + Handle<mirror::ObjectArray<mirror::Class>> classes) + REQUIRES_SHARED(Locks::mutator_lock_); bool TryInlinePolymorphicCallToSameTarget(HInvoke* invoke_instruction, ArtMethod* resolved_method, - const InlineCache& ic) - SHARED_REQUIRES(Locks::mutator_lock_); + Handle<mirror::ObjectArray<mirror::Class>> classes) + REQUIRES_SHARED(Locks::mutator_lock_); + + // Returns whether or not we should use only polymorphic inlining with no deoptimizations. + bool UseOnlyPolymorphicInliningWithNoDeopt(); + // Try CHA-based devirtualization to change virtual method calls into + // direct calls. + // Returns the actual method that resolved_method can be devirtualized to. + ArtMethod* TryCHADevirtualization(ArtMethod* resolved_method) + REQUIRES_SHARED(Locks::mutator_lock_); + + // Add a CHA guard for a CHA-based devirtualized call. A CHA guard checks a + // should_deoptimize flag and if it's true, does deoptimization. + void AddCHAGuard(HInstruction* invoke_instruction, + uint32_t dex_pc, + HInstruction* cursor, + HBasicBlock* bb_cursor); HInstanceFieldGet* BuildGetReceiverClass(ClassLinker* class_linker, HInstruction* receiver, uint32_t dex_pc) const - SHARED_REQUIRES(Locks::mutator_lock_); + REQUIRES_SHARED(Locks::mutator_lock_); - void FixUpReturnReferenceType(HInvoke* invoke_instruction, - ArtMethod* resolved_method, - HInstruction* return_replacement, - bool do_rtp) - SHARED_REQUIRES(Locks::mutator_lock_); + void FixUpReturnReferenceType(ArtMethod* resolved_method, HInstruction* return_replacement) + REQUIRES_SHARED(Locks::mutator_lock_); + + // Creates an instance of ReferenceTypeInfo from `klass` if `klass` is + // admissible (see ReferenceTypePropagation::IsAdmissible for details). + // Otherwise returns inexact Object RTI. + ReferenceTypeInfo GetClassRTI(mirror::Class* klass) REQUIRES_SHARED(Locks::mutator_lock_); + + bool ArgumentTypesMoreSpecific(HInvoke* invoke_instruction, ArtMethod* resolved_method) + REQUIRES_SHARED(Locks::mutator_lock_); + + bool ReturnTypeMoreSpecific(HInvoke* invoke_instruction, HInstruction* return_replacement) + REQUIRES_SHARED(Locks::mutator_lock_); // Add a type guard on the given `receiver`. This will add to the graph: // i0 = HFieldGet(receiver, klass) @@ -142,11 +227,11 @@ class HInliner : public HOptimization { HInstruction* AddTypeGuard(HInstruction* receiver, HInstruction* cursor, HBasicBlock* bb_cursor, - uint32_t class_index, - bool is_referrer, + dex::TypeIndex class_index, + Handle<mirror::Class> klass, HInstruction* invoke_instruction, bool with_deoptimization) - SHARED_REQUIRES(Locks::mutator_lock_); + REQUIRES_SHARED(Locks::mutator_lock_); /* * Ad-hoc implementation for implementing a diamond pattern in the graph for @@ -181,15 +266,35 @@ class HInliner : public HOptimization { HInstruction* return_replacement, HInstruction* invoke_instruction); + // Update the inlining budget based on `total_number_of_instructions_`. + void UpdateInliningBudget(); + + // Count the number of calls of `method` being inlined recursively. + size_t CountRecursiveCallsOf(ArtMethod* method) const; + + // Pretty-print for spaces during logging. + std::string DepthString(int line) const; + HGraph* const outermost_graph_; const DexCompilationUnit& outer_compilation_unit_; const DexCompilationUnit& caller_compilation_unit_; CodeGenerator* const codegen_; CompilerDriver* const compiler_driver_; const size_t total_number_of_dex_registers_; + size_t total_number_of_instructions_; + + // The 'parent' inliner, that means the inlinigng optimization that requested + // `graph_` to be inlined. + const HInliner* const parent_; const size_t depth_; - size_t number_of_inlined_instructions_; - StackHandleScopeCollection* const handles_; + + // The budget left for inlining, in number of instructions. + size_t inlining_budget_; + VariableSizedHandleScope* const handles_; + + // Used to record stats about optimizations on the inlined graph. + // If the inlining is successful, these stats are merged to the caller graph's stats. + OptimizingCompilerStats* inline_stats_; DISALLOW_COPY_AND_ASSIGN(HInliner); }; |