diff options
Diffstat (limited to 'compiler/optimizing/nodes.h')
| -rw-r--r-- | compiler/optimizing/nodes.h | 140 |
1 files changed, 104 insertions, 36 deletions
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 6a45149509..e3f4d8f035 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -29,6 +29,7 @@ #include "base/stl_util.h" #include "base/transform_array_ref.h" #include "dex_file.h" +#include "dex_file_types.h" #include "entrypoints/quick/quick_entrypoints_enum.h" #include "handle.h" #include "handle_scope.h" @@ -332,7 +333,8 @@ class HGraph : public ArenaObject<kArenaAllocGraph> { cached_double_constants_(std::less<int64_t>(), arena->Adapter(kArenaAllocConstantsMap)), cached_current_method_(nullptr), inexact_object_rti_(ReferenceTypeInfo::CreateInvalid()), - osr_(osr) { + osr_(osr), + cha_single_implementation_list_(arena->Adapter(kArenaAllocCHA)) { blocks_.reserve(kDefaultNumberOfBlocks); } @@ -535,6 +537,20 @@ class HGraph : public ArenaObject<kArenaAllocGraph> { bool IsCompilingOsr() const { return osr_; } + ArenaSet<ArtMethod*>& GetCHASingleImplementationList() { + return cha_single_implementation_list_; + } + + void AddCHASingleImplementationDependency(ArtMethod* method) { + cha_single_implementation_list_.insert(method); + } + + bool HasShouldDeoptimizeFlag() const { + // TODO: if all CHA guards can be eliminated, there is no need for the flag + // even if cha_single_implementation_list_ is not empty. + return !cha_single_implementation_list_.empty(); + } + bool HasTryCatch() const { return has_try_catch_; } void SetHasTryCatch(bool value) { has_try_catch_ = value; } @@ -671,6 +687,9 @@ class HGraph : public ArenaObject<kArenaAllocGraph> { // compiled code entries which the interpreter can directly jump to. const bool osr_; + // List of methods that are assumed to have single implementation. + ArenaSet<ArtMethod*> cha_single_implementation_list_; + friend class SsaBuilder; // For caching constants. friend class SsaLivenessAnalysis; // For the linear order. friend class HInliner; // For the reverse post order. @@ -769,6 +788,8 @@ class HLoopInformation : public ArenaObject<kArenaAllocLoopInfo> { bool DominatesAllBackEdges(HBasicBlock* block); + bool HasExitEdge() const; + private: // Internal recursive implementation of `Populate`. void PopulateRecursive(HBasicBlock* block); @@ -798,7 +819,7 @@ class TryCatchInformation : public ArenaObject<kArenaAllocTryCatchInfo> { } // Catch block information constructor. - TryCatchInformation(uint16_t catch_type_index, const DexFile& dex_file) + TryCatchInformation(dex::TypeIndex catch_type_index, const DexFile& dex_file) : try_entry_(nullptr), catch_dex_file_(&dex_file), catch_type_index_(catch_type_index) {} @@ -814,10 +835,10 @@ class TryCatchInformation : public ArenaObject<kArenaAllocTryCatchInfo> { bool IsCatchAllTypeIndex() const { DCHECK(IsCatchBlock()); - return catch_type_index_ == DexFile::kDexNoIndex16; + return !catch_type_index_.IsValid(); } - uint16_t GetCatchTypeIndex() const { + dex::TypeIndex GetCatchTypeIndex() const { DCHECK(IsCatchBlock()); return catch_type_index_; } @@ -834,7 +855,7 @@ class TryCatchInformation : public ArenaObject<kArenaAllocTryCatchInfo> { // Exception type information. Only set for catch blocks. const DexFile* catch_dex_file_; - const uint16_t catch_type_index_; + const dex::TypeIndex catch_type_index_; }; static constexpr size_t kNoLifetime = -1; @@ -1237,6 +1258,7 @@ class HLoopInformationOutwardIterator : public ValueObject { M(ClinitCheck, Instruction) \ M(Compare, BinaryOperation) \ M(CurrentMethod, Instruction) \ + M(ShouldDeoptimizeFlag, Instruction) \ M(Deoptimize, Instruction) \ M(Div, BinaryOperation) \ M(DivZeroCheck, Instruction) \ @@ -1855,6 +1877,15 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> { size_t InputCount() const { return GetInputRecords().size(); } HInstruction* InputAt(size_t i) const { return InputRecordAt(i).GetInstruction(); } + bool HasInput(HInstruction* input) const { + for (const HInstruction* i : GetInputs()) { + if (i == input) { + return true; + } + } + return false; + } + void SetRawInputAt(size_t index, HInstruction* input) { SetRawInputRecordAt(index, HUserRecord<HInstruction*>(input)); } @@ -1947,7 +1978,7 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> { bool IsRemovable() const { return - !HasSideEffects() && + !DoesAnyWrite() && !CanThrow() && !IsSuspendCheck() && !IsControlFlow() && @@ -2060,6 +2091,8 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> { #undef INSTRUCTION_TYPE_CHECK // Returns whether the instruction can be moved within the graph. + // TODO: this method is used by LICM and GVN with possibly different + // meanings? split and rename? virtual bool CanBeMoved() const { return false; } // Returns whether the two instructions are of the same kind. @@ -2861,6 +2894,27 @@ class HDeoptimize FINAL : public HTemplateInstruction<1> { DISALLOW_COPY_AND_ASSIGN(HDeoptimize); }; +// Represents a should_deoptimize flag. Currently used for CHA-based devirtualization. +// The compiled code checks this flag value in a guard before devirtualized call and +// if it's true, starts to do deoptimization. +// It has a 4-byte slot on stack. +// TODO: allocate a register for this flag. +class HShouldDeoptimizeFlag FINAL : public HExpression<0> { + public: + // TODO: use SideEffects to aid eliminating some CHA guards. + explicit HShouldDeoptimizeFlag(uint32_t dex_pc) + : HExpression(Primitive::kPrimInt, SideEffects::None(), dex_pc) { + } + + // We don't eliminate CHA guards yet. + bool CanBeMoved() const OVERRIDE { return false; } + + DECLARE_INSTRUCTION(ShouldDeoptimizeFlag); + + private: + DISALLOW_COPY_AND_ASSIGN(HShouldDeoptimizeFlag); +}; + // Represents the ArtMethod that was passed as a first argument to // the method. It is used by instructions that depend on it, like // instructions that work with the dex cache. @@ -3660,7 +3714,7 @@ class HNewInstance FINAL : public HExpression<2> { HNewInstance(HInstruction* cls, HCurrentMethod* current_method, uint32_t dex_pc, - uint16_t type_index, + dex::TypeIndex type_index, const DexFile& dex_file, bool needs_access_check, bool finalizable, @@ -3675,7 +3729,7 @@ class HNewInstance FINAL : public HExpression<2> { SetRawInputAt(1, current_method); } - uint16_t GetTypeIndex() const { return type_index_; } + dex::TypeIndex GetTypeIndex() const { return type_index_; } const DexFile& GetDexFile() const { return dex_file_; } // Calls runtime so needs an environment. @@ -3708,7 +3762,7 @@ class HNewInstance FINAL : public HExpression<2> { static_assert(kNumberOfNewInstancePackedBits <= kMaxNumberOfPackedBits, "Too many packed fields."); - const uint16_t type_index_; + const dex::TypeIndex type_index_; const DexFile& dex_file_; QuickEntrypointEnum entrypoint_; @@ -3773,9 +3827,11 @@ class HInvoke : public HInstruction { return GetEnvironment()->IsFromInlinedInvoke(); } + void SetCanThrow(bool can_throw) { SetPackedFlag<kFlagCanThrow>(can_throw); } + bool CanThrow() const OVERRIDE { return GetPackedFlag<kFlagCanThrow>(); } - bool CanBeMoved() const OVERRIDE { return IsIntrinsic(); } + bool CanBeMoved() const OVERRIDE { return IsIntrinsic() && !DoesAnyWrite(); } bool InstructionDataEquals(const HInstruction* other) const OVERRIDE { return intrinsic_ != Intrinsics::kNone && intrinsic_ == other->AsInvoke()->intrinsic_; @@ -3831,8 +3887,6 @@ class HInvoke : public HInstruction { SetPackedFlag<kFlagCanThrow>(true); } - void SetCanThrow(bool can_throw) { SetPackedFlag<kFlagCanThrow>(can_throw); } - uint32_t number_of_arguments_; ArtMethod* const resolved_method_; ArenaVector<HUserRecord<HInstruction*>> inputs_; @@ -4169,6 +4223,19 @@ class HInvokeVirtual FINAL : public HInvoke { kVirtual), vtable_index_(vtable_index) {} + bool CanBeNull() const OVERRIDE { + switch (GetIntrinsic()) { + case Intrinsics::kThreadCurrentThread: + case Intrinsics::kStringBufferAppend: + case Intrinsics::kStringBufferToString: + case Intrinsics::kStringBuilderAppend: + case Intrinsics::kStringBuilderToString: + return false; + default: + return HInvoke::CanBeNull(); + } + } + bool CanDoImplicitNullCheckOn(HInstruction* obj) const OVERRIDE { // TODO: Add implicit null checks in intrinsics. return (obj == InputAt(0)) && !GetLocations()->Intrinsified(); @@ -4254,7 +4321,7 @@ class HNewArray FINAL : public HExpression<2> { HNewArray(HInstruction* length, HCurrentMethod* current_method, uint32_t dex_pc, - uint16_t type_index, + dex::TypeIndex type_index, const DexFile& dex_file, QuickEntrypointEnum entrypoint) : HExpression(Primitive::kPrimNot, SideEffects::CanTriggerGC(), dex_pc), @@ -4265,7 +4332,7 @@ class HNewArray FINAL : public HExpression<2> { SetRawInputAt(1, current_method); } - uint16_t GetTypeIndex() const { return type_index_; } + dex::TypeIndex GetTypeIndex() const { return type_index_; } const DexFile& GetDexFile() const { return dex_file_; } // Calls runtime so needs an environment. @@ -4281,7 +4348,7 @@ class HNewArray FINAL : public HExpression<2> { DECLARE_INSTRUCTION(NewArray); private: - const uint16_t type_index_; + const dex::TypeIndex type_index_; const DexFile& dex_file_; const QuickEntrypointEnum entrypoint_; @@ -4818,7 +4885,7 @@ class HRor FINAL : public HBinaryOperation { class HParameterValue FINAL : public HExpression<0> { public: HParameterValue(const DexFile& dex_file, - uint16_t type_index, + dex::TypeIndex type_index, uint8_t index, Primitive::Type parameter_type, bool is_this = false) @@ -4831,7 +4898,7 @@ class HParameterValue FINAL : public HExpression<0> { } const DexFile& GetDexFile() const { return dex_file_; } - uint16_t GetTypeIndex() const { return type_index_; } + dex::TypeIndex GetTypeIndex() const { return type_index_; } uint8_t GetIndex() const { return index_; } bool IsThis() const { return GetPackedFlag<kFlagIsThis>(); } @@ -4849,7 +4916,7 @@ class HParameterValue FINAL : public HExpression<0> { "Too many packed fields."); const DexFile& dex_file_; - const uint16_t type_index_; + const dex::TypeIndex type_index_; // The index of this parameter in the parameters list. Must be less // than HGraph::number_of_in_vregs_. const uint8_t index_; @@ -5444,7 +5511,7 @@ class HLoadClass FINAL : public HInstruction { }; HLoadClass(HCurrentMethod* current_method, - uint16_t type_index, + dex::TypeIndex type_index, const DexFile& dex_file, bool is_referrers_class, uint32_t dex_pc, @@ -5476,7 +5543,7 @@ class HLoadClass FINAL : public HInstruction { void SetLoadKindWithTypeReference(LoadKind load_kind, const DexFile& dex_file, - uint32_t type_index) { + dex::TypeIndex type_index) { DCHECK(HasTypeReference(load_kind)); DCHECK(IsSameDexFile(dex_file_, dex_file)); DCHECK_EQ(type_index_, type_index); @@ -5500,7 +5567,7 @@ class HLoadClass FINAL : public HInstruction { bool InstructionDataEquals(const HInstruction* other) const; - size_t ComputeHashCode() const OVERRIDE { return type_index_; } + size_t ComputeHashCode() const OVERRIDE { return type_index_.index_; } bool CanBeNull() const OVERRIDE { return false; } @@ -5536,7 +5603,7 @@ class HLoadClass FINAL : public HInstruction { loaded_class_rti_ = rti; } - uint32_t GetTypeIndex() const { return type_index_; } + dex::TypeIndex GetTypeIndex() const { return type_index_; } const DexFile& GetDexFile() const { return dex_file_; } uint32_t GetDexCacheElementOffset() const; @@ -5619,7 +5686,7 @@ class HLoadClass FINAL : public HInstruction { // for PC-relative loads, i.e. kDexCachePcRelative or kBootImageLinkTimePcRelative. HUserRecord<HInstruction*> special_input_; - const uint16_t type_index_; + const dex::TypeIndex type_index_; const DexFile& dex_file_; union { @@ -5670,10 +5737,6 @@ class HLoadString FINAL : public HInstruction { // GetIncludePatchInformation(). kBootImageAddress, - // Load from the resolved strings array at an absolute address. - // Used for strings outside the boot image referenced by JIT-compiled code. - kDexCacheAddress, - // Load from an entry in the .bss section using a PC-relative load. // Used for strings outside boot image when .bss is accessible with a PC-relative load. kBssEntry, @@ -5683,11 +5746,14 @@ class HLoadString FINAL : public HInstruction { // all other types are unavailable. kDexCacheViaMethod, - kLast = kDexCacheViaMethod + // Load from the root table associated with the JIT compiled method. + kJitTableAddress, + + kLast = kJitTableAddress, }; HLoadString(HCurrentMethod* current_method, - uint32_t string_index, + dex::StringIndex string_index, const DexFile& dex_file, uint32_t dex_pc) : HInstruction(SideEffectsForArchRuntimeCalls(), dex_pc), @@ -5706,7 +5772,7 @@ class HLoadString FINAL : public HInstruction { void SetLoadKindWithStringReference(LoadKind load_kind, const DexFile& dex_file, - uint32_t string_index) { + dex::StringIndex string_index) { DCHECK(HasStringReference(load_kind)); load_data_.dex_file_ = &dex_file; string_index_ = string_index; @@ -5719,7 +5785,7 @@ class HLoadString FINAL : public HInstruction { const DexFile& GetDexFile() const; - uint32_t GetStringIndex() const { + dex::StringIndex GetStringIndex() const { DCHECK(HasStringReference(GetLoadKind()) || /* For slow paths. */ !IsInDexCache()); return string_index_; } @@ -5733,7 +5799,7 @@ class HLoadString FINAL : public HInstruction { bool InstructionDataEquals(const HInstruction* other) const OVERRIDE; - size_t ComputeHashCode() const OVERRIDE { return string_index_; } + size_t ComputeHashCode() const OVERRIDE { return string_index_.index_; } // Will call the runtime if we need to load the string through // the dex cache and the string is not guaranteed to be there yet. @@ -5741,7 +5807,8 @@ class HLoadString FINAL : public HInstruction { LoadKind load_kind = GetLoadKind(); if (load_kind == LoadKind::kBootImageLinkTimeAddress || load_kind == LoadKind::kBootImageLinkTimePcRelative || - load_kind == LoadKind::kBootImageAddress) { + load_kind == LoadKind::kBootImageAddress || + load_kind == LoadKind::kJitTableAddress) { return false; } return !IsInDexCache(); @@ -5794,11 +5861,12 @@ class HLoadString FINAL : public HInstruction { return load_kind == LoadKind::kBootImageLinkTimeAddress || load_kind == LoadKind::kBootImageLinkTimePcRelative || load_kind == LoadKind::kBssEntry || - load_kind == LoadKind::kDexCacheViaMethod; + load_kind == LoadKind::kDexCacheViaMethod || + load_kind == LoadKind::kJitTableAddress; } static bool HasAddress(LoadKind load_kind) { - return load_kind == LoadKind::kBootImageAddress || load_kind == LoadKind::kDexCacheAddress; + return load_kind == LoadKind::kBootImageAddress; } void SetLoadKindInternal(LoadKind load_kind); @@ -5810,7 +5878,7 @@ class HLoadString FINAL : public HInstruction { // String index serves also as the hash code and it's also needed for slow-paths, // so it must not be overwritten with other load data. - uint32_t string_index_; + dex::StringIndex string_index_; union { const DexFile* dex_file_; // For string reference. |