diff options
Diffstat (limited to 'compiler/optimizing/nodes.h')
-rw-r--r-- | compiler/optimizing/nodes.h | 373 |
1 files changed, 256 insertions, 117 deletions
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 849f876f36..939e62c6dd 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -81,12 +81,19 @@ static constexpr InvokeType kInvalidInvokeType = static_cast<InvokeType>(-1); static constexpr uint32_t kNoDexPc = -1; enum IfCondition { - kCondEQ, - kCondNE, - kCondLT, - kCondLE, - kCondGT, - kCondGE, + // All types. + kCondEQ, // == + kCondNE, // != + // Signed integers and floating-point numbers. + kCondLT, // < + kCondLE, // <= + kCondGT, // > + kCondGE, // >= + // Unsigned integers. + kCondB, // < + kCondBE, // <= + kCondA, // > + kCondAE, // >= }; class HInstructionList : public ValueObject { @@ -177,11 +184,6 @@ class HGraph : public ArenaObject<kArenaAllocGraph> { ArenaAllocator* GetArena() const { return arena_; } const ArenaVector<HBasicBlock*>& GetBlocks() const { return blocks_; } - HBasicBlock* GetBlock(size_t id) const { - DCHECK_LT(id, blocks_.size()); - return blocks_[id]; - } - bool IsInSsaForm() const { return in_ssa_form_; } HBasicBlock* GetEntryBlock() const { return entry_block_; } @@ -648,20 +650,10 @@ class HBasicBlock : public ArenaObject<kArenaAllocBasicBlock> { return predecessors_; } - HBasicBlock* GetPredecessor(size_t pred_idx) const { - DCHECK_LT(pred_idx, predecessors_.size()); - return predecessors_[pred_idx]; - } - const ArenaVector<HBasicBlock*>& GetSuccessors() const { return successors_; } - HBasicBlock* GetSuccessor(size_t succ_idx) const { - DCHECK_LT(succ_idx, successors_.size()); - return successors_[succ_idx]; - } - bool HasSuccessor(const HBasicBlock* block, size_t start_from = 0u) { return ContainsElement(successors_, block, start_from); } @@ -797,18 +789,18 @@ class HBasicBlock : public ArenaObject<kArenaAllocBasicBlock> { HBasicBlock* GetSinglePredecessor() const { DCHECK_EQ(GetPredecessors().size(), 1u); - return GetPredecessor(0); + return GetPredecessors()[0]; } HBasicBlock* GetSingleSuccessor() const { DCHECK_EQ(GetSuccessors().size(), 1u); - return GetSuccessor(0); + return GetSuccessors()[0]; } // Returns whether the first occurrence of `predecessor` in the list of // predecessors is at index `idx`. bool IsFirstIndexOfPredecessor(HBasicBlock* predecessor, size_t idx) const { - DCHECK_EQ(GetPredecessor(idx), predecessor); + DCHECK_EQ(GetPredecessors()[idx], predecessor); return GetPredecessorIndexOf(predecessor) == idx; } @@ -886,7 +878,7 @@ class HBasicBlock : public ArenaObject<kArenaAllocBasicBlock> { bool IsLoopPreHeaderFirstPredecessor() const { DCHECK(IsLoopHeader()); - return GetPredecessor(0) == GetLoopInformation()->GetPreHeader(); + return GetPredecessors()[0] == GetLoopInformation()->GetPreHeader(); } HLoopInformation* GetLoopInformation() const { @@ -1003,11 +995,15 @@ class HLoopInformationOutwardIterator : public ValueObject { }; #define FOR_EACH_CONCRETE_INSTRUCTION_COMMON(M) \ + M(Above, Condition) \ + M(AboveOrEqual, Condition) \ M(Add, BinaryOperation) \ M(And, BinaryOperation) \ M(ArrayGet, Instruction) \ M(ArrayLength, Instruction) \ M(ArraySet, Instruction) \ + M(Below, Condition) \ + M(BelowOrEqual, Condition) \ M(BooleanNot, UnaryOperation) \ M(BoundsCheck, Instruction) \ M(BoundType, Instruction) \ @@ -1089,7 +1085,8 @@ class HLoopInformationOutwardIterator : public ValueObject { #define FOR_EACH_CONCRETE_INSTRUCTION_X86(M) \ M(X86ComputeBaseMethodAddress, Instruction) \ - M(X86LoadFromConstantTable, Instruction) + M(X86LoadFromConstantTable, Instruction) \ + M(X86PackedSwitch, Instruction) #define FOR_EACH_CONCRETE_INSTRUCTION_X86_64(M) @@ -1559,12 +1556,10 @@ class HEnvironment : public ArenaObject<kArenaAllocEnvironment> { void CopyFromWithLoopPhiAdjustment(HEnvironment* env, HBasicBlock* loop_header); void SetRawEnvAt(size_t index, HInstruction* instruction) { - DCHECK_LT(index, Size()); vregs_[index] = HUserRecord<HEnvironment*>(instruction); } HInstruction* GetInstructionAt(size_t index) const { - DCHECK_LT(index, Size()); return vregs_[index].GetInstruction(); } @@ -1575,12 +1570,10 @@ class HEnvironment : public ArenaObject<kArenaAllocEnvironment> { HEnvironment* GetParent() const { return parent_; } void SetLocationAt(size_t index, Location location) { - DCHECK_LT(index, Size()); locations_[index] = location; } Location GetLocationAt(size_t index) const { - DCHECK_LT(index, Size()); return locations_[index]; } @@ -1610,7 +1603,6 @@ class HEnvironment : public ArenaObject<kArenaAllocEnvironment> { void RecordEnvUse(HUseListNode<HEnvironment*>* env_use) { DCHECK(env_use->GetUser() == this); size_t index = env_use->GetIndex(); - DCHECK_LT(index, Size()); vregs_[index] = HUserRecord<HEnvironment*>(vregs_[index], env_use); } @@ -1656,6 +1648,11 @@ class ReferenceTypeInfo : ValueObject { return GetTypeHandle()->IsObjectClass(); } + bool IsStringClass() const SHARED_REQUIRES(Locks::mutator_lock_) { + DCHECK(IsValid()); + return GetTypeHandle()->IsStringClass(); + } + bool IsObjectArray() const SHARED_REQUIRES(Locks::mutator_lock_) { DCHECK(IsValid()); return IsArrayClass() && GetTypeHandle()->GetComponentType()->IsObjectClass(); @@ -1667,15 +1664,36 @@ class ReferenceTypeInfo : ValueObject { } bool IsArrayClass() const SHARED_REQUIRES(Locks::mutator_lock_) { + DCHECK(IsValid()); return GetTypeHandle()->IsArrayClass(); } + bool IsPrimitiveArrayClass() const SHARED_REQUIRES(Locks::mutator_lock_) { + DCHECK(IsValid()); + return GetTypeHandle()->IsPrimitiveArray(); + } + + bool IsNonPrimitiveArrayClass() const SHARED_REQUIRES(Locks::mutator_lock_) { + DCHECK(IsValid()); + return GetTypeHandle()->IsArrayClass() && !GetTypeHandle()->IsPrimitiveArray(); + } + bool CanArrayHold(ReferenceTypeInfo rti) const SHARED_REQUIRES(Locks::mutator_lock_) { + DCHECK(IsValid()); if (!IsExact()) return false; if (!IsArrayClass()) return false; return GetTypeHandle()->GetComponentType()->IsAssignableFrom(rti.GetTypeHandle().Get()); } + bool CanArrayHoldValuesOf(ReferenceTypeInfo rti) const SHARED_REQUIRES(Locks::mutator_lock_) { + DCHECK(IsValid()); + if (!IsExact()) return false; + if (!IsArrayClass()) return false; + if (!rti.IsArrayClass()) return false; + return GetTypeHandle()->GetComponentType()->IsAssignableFrom( + rti.GetTypeHandle()->GetComponentType()); + } + Handle<mirror::Class> GetTypeHandle() const { return type_handle_; } bool IsSupertypeOf(ReferenceTypeInfo rti) const SHARED_REQUIRES(Locks::mutator_lock_) { @@ -1715,7 +1733,7 @@ std::ostream& operator<<(std::ostream& os, const ReferenceTypeInfo& rhs); class HInstruction : public ArenaObject<kArenaAllocInstruction> { public: - HInstruction(SideEffects side_effects, uint32_t dex_pc = kNoDexPc) + HInstruction(SideEffects side_effects, uint32_t dex_pc) : previous_(nullptr), next_(nullptr), block_(nullptr), @@ -1781,8 +1799,7 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> { return true; } - virtual bool CanDoImplicitNullCheckOn(HInstruction* obj) const { - UNUSED(obj); + virtual bool CanDoImplicitNullCheckOn(HInstruction* obj ATTRIBUTE_UNUSED) const { return false; } @@ -1899,16 +1916,14 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> { virtual bool CanBeMoved() const { return false; } // Returns whether the two instructions are of the same kind. - virtual bool InstructionTypeEquals(HInstruction* other) const { - UNUSED(other); + virtual bool InstructionTypeEquals(HInstruction* other ATTRIBUTE_UNUSED) const { return false; } // Returns whether any data encoded in the two instructions is equal. // This method does not look at the inputs. Both instructions must be // of the same type, otherwise the method has undefined behavior. - virtual bool InstructionDataEquals(HInstruction* other) const { - UNUSED(other); + virtual bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const { return false; } @@ -2072,7 +2087,7 @@ class HBackwardInstructionIterator : public ValueObject { template<size_t N> class HTemplateInstruction: public HInstruction { public: - HTemplateInstruction<N>(SideEffects side_effects, uint32_t dex_pc = kNoDexPc) + HTemplateInstruction<N>(SideEffects side_effects, uint32_t dex_pc) : HInstruction(side_effects, dex_pc), inputs_() {} virtual ~HTemplateInstruction() {} @@ -2099,7 +2114,7 @@ class HTemplateInstruction: public HInstruction { template<> class HTemplateInstruction<0>: public HInstruction { public: - explicit HTemplateInstruction<0>(SideEffects side_effects, uint32_t dex_pc = kNoDexPc) + explicit HTemplateInstruction<0>(SideEffects side_effects, uint32_t dex_pc) : HInstruction(side_effects, dex_pc) {} virtual ~HTemplateInstruction() {} @@ -2125,7 +2140,7 @@ class HTemplateInstruction<0>: public HInstruction { template<intptr_t N> class HExpression : public HTemplateInstruction<N> { public: - HExpression<N>(Primitive::Type type, SideEffects side_effects, uint32_t dex_pc = kNoDexPc) + HExpression<N>(Primitive::Type type, SideEffects side_effects, uint32_t dex_pc) : HTemplateInstruction<N>(side_effects, dex_pc), type_(type) {} virtual ~HExpression() {} @@ -2315,11 +2330,11 @@ class HIf : public HTemplateInstruction<1> { bool IsControlFlow() const OVERRIDE { return true; } HBasicBlock* IfTrueSuccessor() const { - return GetBlock()->GetSuccessor(0); + return GetBlock()->GetSuccessors()[0]; } HBasicBlock* IfFalseSuccessor() const { - return GetBlock()->GetSuccessor(1); + return GetBlock()->GetSuccessors()[1]; } DECLARE_INSTRUCTION(If); @@ -2347,7 +2362,7 @@ class HTryBoundary : public HTemplateInstruction<0> { bool IsControlFlow() const OVERRIDE { return true; } // Returns the block's non-exceptional successor (index zero). - HBasicBlock* GetNormalFlowSuccessor() const { return GetBlock()->GetSuccessor(0); } + HBasicBlock* GetNormalFlowSuccessor() const { return GetBlock()->GetSuccessors()[0]; } // Returns whether `handler` is among its exception handlers (non-zero index // successors). @@ -2384,7 +2399,7 @@ class HExceptionHandlerIterator : public ValueObject { : block_(*try_boundary.GetBlock()), index_(block_.NumberOfNormalSuccessors()) {} bool Done() const { return index_ == block_.GetSuccessors().size(); } - HBasicBlock* Current() const { return block_.GetSuccessor(index_); } + HBasicBlock* Current() const { return block_.GetSuccessors()[index_]; } size_t CurrentSuccessorIndex() const { return index_; } void Advance() { ++index_; } @@ -2449,7 +2464,7 @@ class HPackedSwitch : public HTemplateInstruction<1> { HBasicBlock* GetDefaultBlock() const { // Last entry is the default block. - return GetBlock()->GetSuccessor(num_entries_); + return GetBlock()->GetSuccessors()[num_entries_]; } DECLARE_INSTRUCTION(PackedSwitch); @@ -2471,8 +2486,7 @@ class HUnaryOperation : public HExpression<1> { Primitive::Type GetResultType() const { return GetType(); } bool CanBeMoved() const OVERRIDE { return true; } - bool InstructionDataEquals(HInstruction* other) const OVERRIDE { - UNUSED(other); + bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE { return true; } @@ -2542,8 +2556,7 @@ class HBinaryOperation : public HExpression<2> { } bool CanBeMoved() const OVERRIDE { return true; } - bool InstructionDataEquals(HInstruction* other) const OVERRIDE { - UNUSED(other); + bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE { return true; } @@ -2647,8 +2660,6 @@ class HEqual : public HCondition { bool IsCommutative() const OVERRIDE { return true; } - template <typename T> bool Compute(T x, T y) const { return x == y; } - HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { return GetBlock()->GetGraph()->GetIntConstant( Compute(x->GetValue(), y->GetValue()), GetDexPc()); @@ -2669,6 +2680,8 @@ class HEqual : public HCondition { } private: + template <typename T> bool Compute(T x, T y) const { return x == y; } + DISALLOW_COPY_AND_ASSIGN(HEqual); }; @@ -2679,8 +2692,6 @@ class HNotEqual : public HCondition { bool IsCommutative() const OVERRIDE { return true; } - template <typename T> bool Compute(T x, T y) const { return x != y; } - HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { return GetBlock()->GetGraph()->GetIntConstant( Compute(x->GetValue(), y->GetValue()), GetDexPc()); @@ -2701,6 +2712,8 @@ class HNotEqual : public HCondition { } private: + template <typename T> bool Compute(T x, T y) const { return x != y; } + DISALLOW_COPY_AND_ASSIGN(HNotEqual); }; @@ -2709,8 +2722,6 @@ class HLessThan : public HCondition { HLessThan(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc) : HCondition(first, second, dex_pc) {} - template <typename T> bool Compute(T x, T y) const { return x < y; } - HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { return GetBlock()->GetGraph()->GetIntConstant( Compute(x->GetValue(), y->GetValue()), GetDexPc()); @@ -2731,6 +2742,8 @@ class HLessThan : public HCondition { } private: + template <typename T> bool Compute(T x, T y) const { return x < y; } + DISALLOW_COPY_AND_ASSIGN(HLessThan); }; @@ -2739,8 +2752,6 @@ class HLessThanOrEqual : public HCondition { HLessThanOrEqual(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc) : HCondition(first, second, dex_pc) {} - template <typename T> bool Compute(T x, T y) const { return x <= y; } - HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { return GetBlock()->GetGraph()->GetIntConstant( Compute(x->GetValue(), y->GetValue()), GetDexPc()); @@ -2761,6 +2772,8 @@ class HLessThanOrEqual : public HCondition { } private: + template <typename T> bool Compute(T x, T y) const { return x <= y; } + DISALLOW_COPY_AND_ASSIGN(HLessThanOrEqual); }; @@ -2769,8 +2782,6 @@ class HGreaterThan : public HCondition { HGreaterThan(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc) : HCondition(first, second, dex_pc) {} - template <typename T> bool Compute(T x, T y) const { return x > y; } - HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { return GetBlock()->GetGraph()->GetIntConstant( Compute(x->GetValue(), y->GetValue()), GetDexPc()); @@ -2791,6 +2802,8 @@ class HGreaterThan : public HCondition { } private: + template <typename T> bool Compute(T x, T y) const { return x > y; } + DISALLOW_COPY_AND_ASSIGN(HGreaterThan); }; @@ -2799,8 +2812,6 @@ class HGreaterThanOrEqual : public HCondition { HGreaterThanOrEqual(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc) : HCondition(first, second, dex_pc) {} - template <typename T> bool Compute(T x, T y) const { return x >= y; } - HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { return GetBlock()->GetGraph()->GetIntConstant( Compute(x->GetValue(), y->GetValue()), GetDexPc()); @@ -2821,9 +2832,138 @@ class HGreaterThanOrEqual : public HCondition { } private: + template <typename T> bool Compute(T x, T y) const { return x >= y; } + DISALLOW_COPY_AND_ASSIGN(HGreaterThanOrEqual); }; +class HBelow : public HCondition { + public: + HBelow(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc) + : HCondition(first, second, dex_pc) {} + + HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { + return GetBlock()->GetGraph()->GetIntConstant( + Compute(static_cast<uint32_t>(x->GetValue()), + static_cast<uint32_t>(y->GetValue())), GetDexPc()); + } + HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE { + return GetBlock()->GetGraph()->GetIntConstant( + Compute(static_cast<uint64_t>(x->GetValue()), + static_cast<uint64_t>(y->GetValue())), GetDexPc()); + } + + DECLARE_INSTRUCTION(Below); + + IfCondition GetCondition() const OVERRIDE { + return kCondB; + } + + IfCondition GetOppositeCondition() const OVERRIDE { + return kCondAE; + } + + private: + template <typename T> bool Compute(T x, T y) const { return x < y; } + + DISALLOW_COPY_AND_ASSIGN(HBelow); +}; + +class HBelowOrEqual : public HCondition { + public: + HBelowOrEqual(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc) + : HCondition(first, second, dex_pc) {} + + HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { + return GetBlock()->GetGraph()->GetIntConstant( + Compute(static_cast<uint32_t>(x->GetValue()), + static_cast<uint32_t>(y->GetValue())), GetDexPc()); + } + HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE { + return GetBlock()->GetGraph()->GetIntConstant( + Compute(static_cast<uint64_t>(x->GetValue()), + static_cast<uint64_t>(y->GetValue())), GetDexPc()); + } + + DECLARE_INSTRUCTION(BelowOrEqual); + + IfCondition GetCondition() const OVERRIDE { + return kCondBE; + } + + IfCondition GetOppositeCondition() const OVERRIDE { + return kCondA; + } + + private: + template <typename T> bool Compute(T x, T y) const { return x <= y; } + + DISALLOW_COPY_AND_ASSIGN(HBelowOrEqual); +}; + +class HAbove : public HCondition { + public: + HAbove(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc) + : HCondition(first, second, dex_pc) {} + + HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { + return GetBlock()->GetGraph()->GetIntConstant( + Compute(static_cast<uint32_t>(x->GetValue()), + static_cast<uint32_t>(y->GetValue())), GetDexPc()); + } + HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE { + return GetBlock()->GetGraph()->GetIntConstant( + Compute(static_cast<uint64_t>(x->GetValue()), + static_cast<uint64_t>(y->GetValue())), GetDexPc()); + } + + DECLARE_INSTRUCTION(Above); + + IfCondition GetCondition() const OVERRIDE { + return kCondA; + } + + IfCondition GetOppositeCondition() const OVERRIDE { + return kCondBE; + } + + private: + template <typename T> bool Compute(T x, T y) const { return x > y; } + + DISALLOW_COPY_AND_ASSIGN(HAbove); +}; + +class HAboveOrEqual : public HCondition { + public: + HAboveOrEqual(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc) + : HCondition(first, second, dex_pc) {} + + HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { + return GetBlock()->GetGraph()->GetIntConstant( + Compute(static_cast<uint32_t>(x->GetValue()), + static_cast<uint32_t>(y->GetValue())), GetDexPc()); + } + HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE { + return GetBlock()->GetGraph()->GetIntConstant( + Compute(static_cast<uint64_t>(x->GetValue()), + static_cast<uint64_t>(y->GetValue())), GetDexPc()); + } + + DECLARE_INSTRUCTION(AboveOrEqual); + + IfCondition GetCondition() const OVERRIDE { + return kCondAE; + } + + IfCondition GetOppositeCondition() const OVERRIDE { + return kCondB; + } + + private: + template <typename T> bool Compute(T x, T y) const { return x >= y; } + + DISALLOW_COPY_AND_ASSIGN(HAboveOrEqual); +}; // Instruction to check how two inputs compare to each other. // Result is 0 if input0 == input1, 1 if input0 > input1, or -1 if input0 < input1. @@ -3034,11 +3174,7 @@ class HInvoke : public HInstruction { public: size_t InputCount() const OVERRIDE { return inputs_.size(); } - // Runtime needs to walk the stack, so Dex -> Dex calls need to - // know their environment. - bool NeedsEnvironment() const OVERRIDE { - return needs_environment_or_cache_ == kNeedsEnvironmentOrCache; - } + bool NeedsEnvironment() const OVERRIDE; void SetArgumentAt(size_t index, HInstruction* argument) { SetRawInputAt(index, argument); @@ -3062,10 +3198,7 @@ class HInvoke : public HInstruction { return intrinsic_; } - void SetIntrinsic(Intrinsics intrinsic, IntrinsicNeedsEnvironmentOrCache needs_env_or_cache) { - intrinsic_ = intrinsic; - needs_environment_or_cache_ = needs_env_or_cache; - } + void SetIntrinsic(Intrinsics intrinsic, IntrinsicNeedsEnvironmentOrCache needs_env_or_cache); bool IsFromInlinedInvoke() const { return GetEnvironment()->GetParent() != nullptr; @@ -3073,6 +3206,16 @@ class HInvoke : public HInstruction { bool CanThrow() const OVERRIDE { return true; } + uint32_t* GetIntrinsicOptimizations() { + return &intrinsic_optimizations_; + } + + const uint32_t* GetIntrinsicOptimizations() const { + return &intrinsic_optimizations_; + } + + bool IsIntrinsic() const { return intrinsic_ != Intrinsics::kNone; } + DECLARE_INSTRUCTION(Invoke); protected: @@ -3092,16 +3235,14 @@ class HInvoke : public HInstruction { dex_method_index_(dex_method_index), original_invoke_type_(original_invoke_type), intrinsic_(Intrinsics::kNone), - needs_environment_or_cache_(kNeedsEnvironmentOrCache) { + intrinsic_optimizations_(0) { } const HUserRecord<HInstruction*> InputRecordAt(size_t index) const OVERRIDE { - DCHECK_LT(index, InputCount()); return inputs_[index]; } void SetRawInputRecordAt(size_t index, const HUserRecord<HInstruction*>& input) OVERRIDE { - DCHECK_LT(index, InputCount()); inputs_[index] = input; } @@ -3111,7 +3252,9 @@ class HInvoke : public HInstruction { const uint32_t dex_method_index_; const InvokeType original_invoke_type_; Intrinsics intrinsic_; - IntrinsicNeedsEnvironmentOrCache needs_environment_or_cache_; + + // A magic word holding optimizations for intrinsics. See intrinsics.h. + uint32_t intrinsic_optimizations_; private: DISALLOW_COPY_AND_ASSIGN(HInvoke); @@ -3244,8 +3387,7 @@ class HInvokeStaticOrDirect : public HInvoke { target_method_(target_method), dispatch_info_(dispatch_info) {} - bool CanDoImplicitNullCheckOn(HInstruction* obj) const OVERRIDE { - UNUSED(obj); + bool CanDoImplicitNullCheckOn(HInstruction* obj ATTRIBUTE_UNUSED) const OVERRIDE { // We access the method via the dex cache so we can't do an implicit null check. // TODO: for intrinsics we can generate implicit null checks. return false; @@ -3259,10 +3401,7 @@ class HInvokeStaticOrDirect : public HInvoke { MethodLoadKind GetMethodLoadKind() const { return dispatch_info_.method_load_kind; } CodePtrLocation GetCodePtrLocation() const { return dispatch_info_.code_ptr_location; } bool IsRecursive() const { return GetMethodLoadKind() == MethodLoadKind::kRecursive; } - bool NeedsDexCache() const OVERRIDE { - if (intrinsic_ != Intrinsics::kNone) { return needs_environment_or_cache_; } - return !IsRecursive() && !IsStringInit(); - } + bool NeedsDexCache() const OVERRIDE; bool IsStringInit() const { return GetMethodLoadKind() == MethodLoadKind::kStringInit; } uint32_t GetCurrentMethodInputIndex() const { return GetNumberOfArguments(); } bool HasMethodAddress() const { return GetMethodLoadKind() == MethodLoadKind::kDirectAddress; } @@ -3686,8 +3825,7 @@ class HDivZeroCheck : public HExpression<1> { bool CanBeMoved() const OVERRIDE { return true; } - bool InstructionDataEquals(HInstruction* other) const OVERRIDE { - UNUSED(other); + bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE { return true; } @@ -3957,8 +4095,7 @@ class HNot : public HUnaryOperation { : HUnaryOperation(result_type, input, dex_pc) {} bool CanBeMoved() const OVERRIDE { return true; } - bool InstructionDataEquals(HInstruction* other) const OVERRIDE { - UNUSED(other); + bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE { return true; } @@ -3983,8 +4120,7 @@ class HBooleanNot : public HUnaryOperation { : HUnaryOperation(Primitive::Type::kPrimBoolean, input, dex_pc) {} bool CanBeMoved() const OVERRIDE { return true; } - bool InstructionDataEquals(HInstruction* other) const OVERRIDE { - UNUSED(other); + bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE { return true; } @@ -4125,12 +4261,10 @@ class HPhi : public HInstruction { protected: const HUserRecord<HInstruction*> InputRecordAt(size_t index) const OVERRIDE { - DCHECK_LE(index, InputCount()); return inputs_[index]; } void SetRawInputRecordAt(size_t index, const HUserRecord<HInstruction*>& input) OVERRIDE { - DCHECK_LE(index, InputCount()); inputs_[index] = input; } @@ -4152,8 +4286,7 @@ class HNullCheck : public HExpression<1> { } bool CanBeMoved() const OVERRIDE { return true; } - bool InstructionDataEquals(HInstruction* other) const OVERRIDE { - UNUSED(other); + bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE { return true; } @@ -4210,7 +4343,7 @@ class HInstanceFieldGet : public HExpression<1> { uint32_t field_idx, const DexFile& dex_file, Handle<mirror::DexCache> dex_cache, - uint32_t dex_pc = kNoDexPc) + uint32_t dex_pc) : HExpression( field_type, SideEffects::FieldReadOfType(field_type, is_volatile), dex_pc), @@ -4256,7 +4389,7 @@ class HInstanceFieldSet : public HTemplateInstruction<2> { uint32_t field_idx, const DexFile& dex_file, Handle<mirror::DexCache> dex_cache, - uint32_t dex_pc = kNoDexPc) + uint32_t dex_pc) : HTemplateInstruction( SideEffects::FieldWriteOfType(field_type, is_volatile), dex_pc), field_info_(field_offset, field_type, is_volatile, field_idx, dex_file, dex_cache), @@ -4291,19 +4424,17 @@ class HArrayGet : public HExpression<2> { HArrayGet(HInstruction* array, HInstruction* index, Primitive::Type type, - uint32_t dex_pc = kNoDexPc) + uint32_t dex_pc) : HExpression(type, SideEffects::ArrayReadOfType(type), dex_pc) { SetRawInputAt(0, array); SetRawInputAt(1, index); } bool CanBeMoved() const OVERRIDE { return true; } - bool InstructionDataEquals(HInstruction* other) const OVERRIDE { - UNUSED(other); + bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE { return true; } - bool CanDoImplicitNullCheckOn(HInstruction* obj) const OVERRIDE { - UNUSED(obj); + bool CanDoImplicitNullCheckOn(HInstruction* obj ATTRIBUTE_UNUSED) const OVERRIDE { // TODO: We can be smarter here. // Currently, the array access is always preceded by an ArrayLength or a NullCheck // which generates the implicit null check. There are cases when these can be removed @@ -4351,8 +4482,7 @@ class HArraySet : public HTemplateInstruction<3> { // Can throw ArrayStoreException. bool CanThrow() const OVERRIDE { return needs_type_check_; } - bool CanDoImplicitNullCheckOn(HInstruction* obj) const OVERRIDE { - UNUSED(obj); + bool CanDoImplicitNullCheckOn(HInstruction* obj ATTRIBUTE_UNUSED) const OVERRIDE { // TODO: Same as for ArrayGet. return false; } @@ -4407,7 +4537,7 @@ class HArraySet : public HTemplateInstruction<3> { class HArrayLength : public HExpression<1> { public: - explicit HArrayLength(HInstruction* array, uint32_t dex_pc = kNoDexPc) + HArrayLength(HInstruction* array, uint32_t dex_pc) : HExpression(Primitive::kPrimInt, SideEffects::None(), dex_pc) { // Note that arrays do not change length, so the instruction does not // depend on any write. @@ -4415,8 +4545,7 @@ class HArrayLength : public HExpression<1> { } bool CanBeMoved() const OVERRIDE { return true; } - bool InstructionDataEquals(HInstruction* other) const OVERRIDE { - UNUSED(other); + bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE { return true; } bool CanDoImplicitNullCheckOn(HInstruction* obj) const OVERRIDE { @@ -4439,8 +4568,7 @@ class HBoundsCheck : public HExpression<2> { } bool CanBeMoved() const OVERRIDE { return true; } - bool InstructionDataEquals(HInstruction* other) const OVERRIDE { - UNUSED(other); + bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE { return true; } @@ -4513,20 +4641,29 @@ class HLoadClass : public HExpression<1> { uint16_t type_index, const DexFile& dex_file, bool is_referrers_class, - uint32_t dex_pc) + uint32_t dex_pc, + bool needs_access_check) : HExpression(Primitive::kPrimNot, SideEffectsForArchRuntimeCalls(), dex_pc), type_index_(type_index), dex_file_(dex_file), is_referrers_class_(is_referrers_class), generate_clinit_check_(false), + needs_access_check_(needs_access_check), loaded_class_rti_(ReferenceTypeInfo::CreateInvalid()) { + // Referrers class should not need access check. We never inline unverified + // methods so we can't possibly end up in this situation. + DCHECK(!is_referrers_class_ || !needs_access_check_); SetRawInputAt(0, current_method); } bool CanBeMoved() const OVERRIDE { return true; } bool InstructionDataEquals(HInstruction* other) const OVERRIDE { - return other->AsLoadClass()->type_index_ == type_index_; + // Note that we don't need to test for generate_clinit_check_. + // Whether or not we need to generate the clinit check is processed in + // prepare_for_register_allocator based on existing HInvokes and HClinitChecks. + return other->AsLoadClass()->type_index_ == type_index_ && + other->AsLoadClass()->needs_access_check_ == needs_access_check_; } size_t ComputeHashCode() const OVERRIDE { return type_index_; } @@ -4544,13 +4681,16 @@ class HLoadClass : public HExpression<1> { bool MustGenerateClinitCheck() const { return generate_clinit_check_; } - void SetMustGenerateClinitCheck(bool generate_clinit_check) { generate_clinit_check_ = generate_clinit_check; } bool CanCallRuntime() const { - return MustGenerateClinitCheck() || !is_referrers_class_; + return MustGenerateClinitCheck() || !is_referrers_class_ || needs_access_check_; + } + + bool NeedsAccessCheck() const { + return needs_access_check_; } bool CanThrow() const OVERRIDE { @@ -4586,6 +4726,7 @@ class HLoadClass : public HExpression<1> { // Whether this instruction must generate the initialization check. // Used for code generation. bool generate_clinit_check_; + bool needs_access_check_; ReferenceTypeInfo loaded_class_rti_; @@ -4641,8 +4782,7 @@ class HClinitCheck : public HExpression<1> { } bool CanBeMoved() const OVERRIDE { return true; } - bool InstructionDataEquals(HInstruction* other) const OVERRIDE { - UNUSED(other); + bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE { return true; } @@ -4669,7 +4809,7 @@ class HStaticFieldGet : public HExpression<1> { uint32_t field_idx, const DexFile& dex_file, Handle<mirror::DexCache> dex_cache, - uint32_t dex_pc = kNoDexPc) + uint32_t dex_pc) : HExpression( field_type, SideEffects::FieldReadOfType(field_type, is_volatile), dex_pc), @@ -4712,7 +4852,7 @@ class HStaticFieldSet : public HTemplateInstruction<2> { uint32_t field_idx, const DexFile& dex_file, Handle<mirror::DexCache> dex_cache, - uint32_t dex_pc = kNoDexPc) + uint32_t dex_pc) : HTemplateInstruction( SideEffects::FieldWriteOfType(field_type, is_volatile), dex_pc), field_info_(field_offset, field_type, is_volatile, field_idx, dex_file, dex_cache), @@ -4897,6 +5037,7 @@ class HThrow : public HTemplateInstruction<1> { * or `HCheckCast`. */ enum class TypeCheckKind { + kUnresolvedCheck, // Check against an unresolved type. kExactCheck, // Can do a single class compare. kClassHierarchyCheck, // Can just walk the super class chain. kAbstractClassCheck, // Can just walk the super class chain, starting one up. @@ -5233,7 +5374,6 @@ class HParallelMove : public HTemplateInstruction<0> { } MoveOperands* MoveOperandsAt(size_t index) { - DCHECK_LT(index, moves_.size()); return &moves_[index]; } @@ -5260,7 +5400,7 @@ class HGraphVisitor : public ValueObject { explicit HGraphVisitor(HGraph* graph) : graph_(graph) {} virtual ~HGraphVisitor() {} - virtual void VisitInstruction(HInstruction* instruction) { UNUSED(instruction); } + virtual void VisitInstruction(HInstruction* instruction ATTRIBUTE_UNUSED) {} virtual void VisitBasicBlock(HBasicBlock* block); // Visit the graph following basic block insertion order. @@ -5307,7 +5447,7 @@ class HInsertionOrderIterator : public ValueObject { explicit HInsertionOrderIterator(const HGraph& graph) : graph_(graph), index_(0) {} bool Done() const { return index_ == graph_.GetBlocks().size(); } - HBasicBlock* Current() const { return graph_.GetBlock(index_); } + HBasicBlock* Current() const { return graph_.GetBlocks()[index_]; } void Advance() { ++index_; } private: @@ -5433,7 +5573,6 @@ class HBlocksInLoopReversePostOrderIterator : public ValueObject { : blocks_in_loop_(info.GetBlocks()), blocks_(info.GetHeader()->GetGraph()->GetReversePostOrder()), index_(0) { - DCHECK(!blocks_.empty()); if (!blocks_in_loop_.IsBitSet(blocks_[index_]->GetBlockId())) { Advance(); } |