diff options
Diffstat (limited to 'compiler/optimizing/nodes.h')
-rw-r--r-- | compiler/optimizing/nodes.h | 232 |
1 files changed, 115 insertions, 117 deletions
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index cfb71791f4..7067aabaa1 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -44,7 +44,6 @@ class HBasicBlock; class HCurrentMethod; class HDoubleConstant; class HEnvironment; -class HFakeString; class HFloatConstant; class HGraphBuilder; class HGraphVisitor; @@ -98,11 +97,10 @@ enum IfCondition { kCondAE, // >= }; -enum BuildSsaResult { - kBuildSsaFailNonNaturalLoop, - kBuildSsaFailThrowCatchLoop, - kBuildSsaFailAmbiguousArrayOp, - kBuildSsaSuccess, +enum GraphAnalysisResult { + kAnalysisFailThrowCatchLoop, + kAnalysisFailAmbiguousArrayOp, + kAnalysisSuccess, }; class HInstructionList : public ValueObject { @@ -289,6 +287,7 @@ class HGraph : public ArenaObject<kArenaAllocGraph> { temporaries_vreg_slots_(0), has_bounds_checks_(false), has_try_catch_(false), + has_irreducible_loops_(false), debuggable_(debuggable), current_instruction_id_(start_instruction_id), dex_file_(dex_file), @@ -324,20 +323,20 @@ class HGraph : public ArenaObject<kArenaAllocGraph> { // Try building the SSA form of this graph, with dominance computation and // loop recognition. Returns a code specifying that it was successful or the // reason for failure. - BuildSsaResult TryBuildingSsa(StackHandleScopeCollection* handles); + GraphAnalysisResult TryBuildingSsa(StackHandleScopeCollection* handles); void ComputeDominanceInformation(); void ClearDominanceInformation(); - - void BuildDominatorTree(); + void ClearLoopInformation(); + void FindBackEdges(ArenaBitVector* visited); + GraphAnalysisResult BuildDominatorTree(); void SimplifyCFG(); void SimplifyCatchBlocks(); // Analyze all natural loops in this graph. Returns a code specifying that it // was successful or the reason for failure. The method will fail if a loop - // is not natural, that is the header does not dominate a back edge, or if it // is a throw-catch loop, i.e. the header is a catch block. - BuildSsaResult AnalyzeNaturalLoops() const; + GraphAnalysisResult AnalyzeLoops() const; // Iterate over blocks to compute try block membership. Needs reverse post // order and loop information. @@ -482,6 +481,9 @@ class HGraph : public ArenaObject<kArenaAllocGraph> { bool HasTryCatch() const { return has_try_catch_; } void SetHasTryCatch(bool value) { has_try_catch_ = value; } + bool HasIrreducibleLoops() const { return has_irreducible_loops_; } + void SetHasIrreducibleLoops(bool value) { has_irreducible_loops_ = value; } + ArtMethod* GetArtMethod() const { return art_method_; } void SetArtMethod(ArtMethod* method) { art_method_ = method; } @@ -491,7 +493,6 @@ class HGraph : public ArenaObject<kArenaAllocGraph> { HInstruction* InsertOppositeCondition(HInstruction* cond, HInstruction* cursor); private: - void FindBackEdges(ArenaBitVector* visited); void RemoveInstructionsAsUsersFromDeadBlocks(const ArenaBitVector& visited) const; void RemoveDeadBlocks(const ArenaBitVector& visited); @@ -558,6 +559,9 @@ class HGraph : public ArenaObject<kArenaAllocGraph> { // try/catch-related passes if false. bool has_try_catch_; + // Flag whether there are any irreducible loops in the graph. + bool has_irreducible_loops_; + // Indicates whether the graph should be compiled in a way that // ensures full debuggability. If false, we can apply more // aggressive optimizations that may limit the level of debugging. @@ -613,12 +617,17 @@ class HLoopInformation : public ArenaObject<kArenaAllocLoopInfo> { HLoopInformation(HBasicBlock* header, HGraph* graph) : header_(header), suspend_check_(nullptr), + irreducible_(false), back_edges_(graph->GetArena()->Adapter(kArenaAllocLoopInfoBackEdges)), // Make bit vector growable, as the number of blocks may change. blocks_(graph->GetArena(), graph->GetBlocks().size(), true) { back_edges_.reserve(kDefaultNumberOfBackEdges); } + bool IsIrreducible() const { return irreducible_; } + + void Dump(std::ostream& os); + HBasicBlock* GetHeader() const { return header_; } @@ -661,15 +670,8 @@ class HLoopInformation : public ArenaObject<kArenaAllocLoopInfo> { ReplaceElement(back_edges_, existing, new_back_edge); } - // Finds blocks that are part of this loop. Returns whether the loop is a natural loop, - // that is the header dominates the back edge. - bool Populate(); - - // Reanalyzes the loop by removing loop info from its blocks and re-running - // Populate(). If there are no back edges left, the loop info is completely - // removed as well as its SuspendCheck instruction. It must be run on nested - // inner loops first. - void Update(); + // Finds blocks that are part of this loop. + void Populate(); // Returns whether this loop information contains `block`. // Note that this loop information *must* be populated before entering this function. @@ -690,9 +692,11 @@ class HLoopInformation : public ArenaObject<kArenaAllocLoopInfo> { private: // Internal recursive implementation of `Populate`. void PopulateRecursive(HBasicBlock* block); + void PopulateIrreducibleRecursive(HBasicBlock* block); HBasicBlock* header_; HSuspendCheck* suspend_check_; + bool irreducible_; ArenaVector<HBasicBlock*> back_edges_; ArenaBitVector blocks_; @@ -856,6 +860,8 @@ class HBasicBlock : public ArenaObject<kArenaAllocBasicBlock> { HInstruction* GetLastPhi() const { return phis_.last_instruction_; } const HInstructionList& GetPhis() const { return phis_; } + HInstruction* GetFirstInstructionDisregardMoves() const; + void AddSuccessor(HBasicBlock* block) { successors_.push_back(block); block->predecessors_.push_back(this); @@ -1019,6 +1025,11 @@ class HBasicBlock : public ArenaObject<kArenaAllocBasicBlock> { return GetPredecessors()[0] == GetLoopInformation()->GetPreHeader(); } + bool IsFirstPredecessorBackEdge() const { + DCHECK(IsLoopHeader()); + return GetLoopInformation()->IsBackEdge(*GetPredecessors()[0]); + } + HLoopInformation* GetLoopInformation() const { return loop_information_; } @@ -1156,7 +1167,6 @@ class HLoopInformationOutwardIterator : public ValueObject { M(DoubleConstant, Constant) \ M(Equal, Condition) \ M(Exit, Instruction) \ - M(FakeString, Instruction) \ M(FloatConstant, Constant) \ M(Goto, Instruction) \ M(GreaterThan, Condition) \ @@ -1831,7 +1841,10 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> { void SetBlock(HBasicBlock* block) { block_ = block; } bool IsInBlock() const { return block_ != nullptr; } bool IsInLoop() const { return block_->IsInLoop(); } - bool IsLoopHeaderPhi() { return IsPhi() && block_->IsLoopHeader(); } + bool IsLoopHeaderPhi() const { return IsPhi() && block_->IsLoopHeader(); } + bool IsIrreducibleLoopHeaderPhi() const { + return IsLoopHeaderPhi() && GetBlock()->GetLoopInformation()->IsIrreducible(); + } virtual size_t InputCount() const = 0; HInstruction* InputAt(size_t i) const { return InputRecordAt(i).GetInstruction(); } @@ -1868,6 +1881,10 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> { return false; } + virtual bool IsActualObject() const { + return GetType() == Primitive::kPrimNot; + } + void SetReferenceTypeInfo(ReferenceTypeInfo rti); ReferenceTypeInfo GetReferenceTypeInfo() const { @@ -2487,8 +2504,10 @@ class HTryBoundary : public HTemplateInstruction<0> { // Deoptimize to interpreter, upon checking a condition. class HDeoptimize : public HTemplateInstruction<1> { public: + // We set CanTriggerGC to prevent any intermediate address to be live + // at the point of the `HDeoptimize`. HDeoptimize(HInstruction* cond, uint32_t dex_pc) - : HTemplateInstruction(SideEffects::None(), dex_pc) { + : HTemplateInstruction(SideEffects::CanTriggerGC(), dex_pc) { SetRawInputAt(0, cond); } @@ -3258,6 +3277,61 @@ class HDoubleConstant : public HConstant { DISALLOW_COPY_AND_ASSIGN(HDoubleConstant); }; +class HNewInstance : public HExpression<2> { + public: + HNewInstance(HInstruction* cls, + HCurrentMethod* current_method, + uint32_t dex_pc, + uint16_t type_index, + const DexFile& dex_file, + bool can_throw, + bool finalizable, + QuickEntrypointEnum entrypoint) + : HExpression(Primitive::kPrimNot, SideEffects::CanTriggerGC(), dex_pc), + type_index_(type_index), + dex_file_(dex_file), + can_throw_(can_throw), + finalizable_(finalizable), + entrypoint_(entrypoint) { + SetRawInputAt(0, cls); + SetRawInputAt(1, current_method); + } + + uint16_t GetTypeIndex() const { return type_index_; } + const DexFile& GetDexFile() const { return dex_file_; } + + // Calls runtime so needs an environment. + bool NeedsEnvironment() const OVERRIDE { return true; } + + // It may throw when called on type that's not instantiable/accessible. + // It can throw OOME. + // TODO: distinguish between the two cases so we can for example allow allocation elimination. + bool CanThrow() const OVERRIDE { return can_throw_ || true; } + + bool IsFinalizable() const { return finalizable_; } + + bool CanBeNull() const OVERRIDE { return false; } + + QuickEntrypointEnum GetEntrypoint() const { return entrypoint_; } + + void SetEntrypoint(QuickEntrypointEnum entrypoint) { + entrypoint_ = entrypoint; + } + + bool IsStringAlloc() const; + + DECLARE_INSTRUCTION(NewInstance); + + private: + const uint16_t type_index_; + const DexFile& dex_file_; + const bool can_throw_; + const bool finalizable_; + QuickEntrypointEnum entrypoint_; + + DISALLOW_COPY_AND_ASSIGN(HNewInstance); +}; + enum class Intrinsics { #define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \ k ## Name, @@ -3551,10 +3625,9 @@ class HInvokeStaticOrDirect : public HInvoke { // Get the index of the special input, if any. // - // If the invoke IsStringInit(), it initially has a HFakeString special argument - // which is removed by the instruction simplifier; if the invoke HasCurrentMethodInput(), - // the "special input" is the current method pointer; otherwise there may be one - // platform-specific special input, such as PC-relative addressing base. + // If the invoke HasCurrentMethodInput(), the "special input" is the current + // method pointer; otherwise there may be one platform-specific special input, + // such as PC-relative addressing base. uint32_t GetSpecialInputIndex() const { return GetNumberOfArguments(); } InvokeType GetOptimizedInvokeType() const { return optimized_invoke_type_; } @@ -3628,21 +3701,13 @@ class HInvokeStaticOrDirect : public HInvoke { DCHECK(!IsStaticWithExplicitClinitCheck()); } - bool IsStringFactoryFor(HFakeString* str) const { - if (!IsStringInit()) return false; - DCHECK(!HasCurrentMethodInput()); - if (InputCount() == (number_of_arguments_)) return false; - return InputAt(InputCount() - 1)->AsFakeString() == str; - } - - void RemoveFakeStringArgumentAsLastInput() { + HInstruction* GetAndRemoveThisArgumentOfStringInit() { DCHECK(IsStringInit()); - size_t last_input_index = InputCount() - 1; - HInstruction* last_input = InputAt(last_input_index); - DCHECK(last_input != nullptr); - DCHECK(last_input->IsFakeString()) << last_input->DebugName(); - RemoveAsUserOfInput(last_input_index); + size_t index = InputCount() - 1; + HInstruction* input = InputAt(index); + RemoveAsUserOfInput(index); inputs_.pop_back(); + return input; } // Is this a call to a static method whose declaring class has an @@ -3749,59 +3814,6 @@ class HInvokeInterface : public HInvoke { DISALLOW_COPY_AND_ASSIGN(HInvokeInterface); }; -class HNewInstance : public HExpression<2> { - public: - HNewInstance(HInstruction* cls, - HCurrentMethod* current_method, - uint32_t dex_pc, - uint16_t type_index, - const DexFile& dex_file, - bool can_throw, - bool finalizable, - QuickEntrypointEnum entrypoint) - : HExpression(Primitive::kPrimNot, SideEffects::CanTriggerGC(), dex_pc), - type_index_(type_index), - dex_file_(dex_file), - can_throw_(can_throw), - finalizable_(finalizable), - entrypoint_(entrypoint) { - SetRawInputAt(0, cls); - SetRawInputAt(1, current_method); - } - - uint16_t GetTypeIndex() const { return type_index_; } - const DexFile& GetDexFile() const { return dex_file_; } - - // Calls runtime so needs an environment. - bool NeedsEnvironment() const OVERRIDE { return true; } - - // It may throw when called on type that's not instantiable/accessible. - // It can throw OOME. - // TODO: distinguish between the two cases so we can for example allow allocation elimination. - bool CanThrow() const OVERRIDE { return can_throw_ || true; } - - bool IsFinalizable() const { return finalizable_; } - - bool CanBeNull() const OVERRIDE { return false; } - - QuickEntrypointEnum GetEntrypoint() const { return entrypoint_; } - - void SetEntrypoint(QuickEntrypointEnum entrypoint) { - entrypoint_ = entrypoint; - } - - DECLARE_INSTRUCTION(NewInstance); - - private: - const uint16_t type_index_; - const DexFile& dex_file_; - const bool can_throw_; - const bool finalizable_; - QuickEntrypointEnum entrypoint_; - - DISALLOW_COPY_AND_ASSIGN(HNewInstance); -}; - class HNeg : public HUnaryOperation { public: HNeg(Primitive::Type result_type, HInstruction* input, uint32_t dex_pc = kNoDexPc) @@ -4016,8 +4028,10 @@ class HRem : public HBinaryOperation { class HDivZeroCheck : public HExpression<1> { public: + // `HDivZeroCheck` can trigger GC, as it may call the `ArithmeticException` + // constructor. HDivZeroCheck(HInstruction* value, uint32_t dex_pc) - : HExpression(value->GetType(), SideEffects::None(), dex_pc) { + : HExpression(value->GetType(), SideEffects::CanTriggerGC(), dex_pc) { SetRawInputAt(0, value); } @@ -4538,8 +4552,10 @@ class HPhi : public HInstruction { class HNullCheck : public HExpression<1> { public: + // `HNullCheck` can trigger GC, as it may call the `NullPointerException` + // constructor. HNullCheck(HInstruction* value, uint32_t dex_pc) - : HExpression(value->GetType(), SideEffects::None(), dex_pc) { + : HExpression(value->GetType(), SideEffects::CanTriggerGC(), dex_pc) { SetRawInputAt(0, value); } @@ -4860,8 +4876,10 @@ class HArrayLength : public HExpression<1> { class HBoundsCheck : public HExpression<2> { public: + // `HBoundsCheck` can trigger GC, as it may call the `IndexOutOfBoundsException` + // constructor. HBoundsCheck(HInstruction* index, HInstruction* length, uint32_t dex_pc) - : HExpression(index->GetType(), SideEffects::None(), dex_pc) { + : HExpression(index->GetType(), SideEffects::CanTriggerGC(), dex_pc) { DCHECK(index->GetType() == Primitive::kPrimInt); SetRawInputAt(0, index); SetRawInputAt(1, length); @@ -5576,26 +5594,6 @@ class HMonitorOperation : public HTemplateInstruction<1> { DISALLOW_COPY_AND_ASSIGN(HMonitorOperation); }; -/** - * A HInstruction used as a marker for the replacement of new + <init> - * of a String to a call to a StringFactory. Only baseline will see - * the node at code generation, where it will be be treated as null. - * When compiling non-baseline, `HFakeString` instructions are being removed - * in the instruction simplifier. - */ -class HFakeString : public HTemplateInstruction<0> { - public: - explicit HFakeString(uint32_t dex_pc = kNoDexPc) - : HTemplateInstruction(SideEffects::None(), dex_pc) {} - - Primitive::Type GetType() const OVERRIDE { return Primitive::kPrimNot; } - - DECLARE_INSTRUCTION(FakeString); - - private: - DISALLOW_COPY_AND_ASSIGN(HFakeString); -}; - class MoveOperands : public ArenaObject<kArenaAllocMoveOperands> { public: MoveOperands(Location source, |