diff options
Diffstat (limited to 'compiler/optimizing/nodes.h')
-rw-r--r-- | compiler/optimizing/nodes.h | 179 |
1 files changed, 166 insertions, 13 deletions
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index e9a42cb0ce..ba4242112b 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -1995,6 +1995,8 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> { environment_ = environment; } + void RemoveEnvironment(); + // Set the environment of this instruction, copying it from `environment`. While // copying, the uses lists are being updated. void CopyEnvironmentFrom(HEnvironment* environment) { @@ -5557,32 +5559,117 @@ class HLoadClass : public HExpression<1> { class HLoadString : public HExpression<1> { public: + // Determines how to load the String. + enum class LoadKind { + // Use boot image String* address that will be known at link time. + // Used for boot image strings referenced by boot image code in non-PIC mode. + kBootImageLinkTimeAddress, + + // Use PC-relative boot image String* address that will be known at link time. + // Used for boot image strings referenced by boot image code in PIC mode. + kBootImageLinkTimePcRelative, + + // Use a known boot image String* address, embedded in the code by the codegen. + // Used for boot image strings referenced by apps in AOT- and JIT-compiled code. + // Note: codegen needs to emit a linker patch if indicated by compiler options' + // 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 resolved strings array in the dex cache using a PC-relative load. + // Used for strings outside boot image when we know that we can access + // the dex cache arrays using a PC-relative load. + kDexCachePcRelative, + + // Load from resolved strings array accessed through the class loaded from + // the compiled method's own ArtMethod*. This is the default access type when + // all other types are unavailable. + kDexCacheViaMethod, + + kLast = kDexCacheViaMethod + }; + HLoadString(HCurrentMethod* current_method, uint32_t string_index, - uint32_t dex_pc, - bool is_in_dex_cache) + const DexFile& dex_file, + uint32_t dex_pc) : HExpression(Primitive::kPrimNot, SideEffectsForArchRuntimeCalls(), dex_pc), string_index_(string_index) { - SetPackedFlag<kFlagIsInDexCache>(is_in_dex_cache); + SetPackedFlag<kFlagIsInDexCache>(false); + SetPackedField<LoadKindField>(LoadKind::kDexCacheViaMethod); + load_data_.ref.dex_file = &dex_file; SetRawInputAt(0, current_method); } - bool CanBeMoved() const OVERRIDE { return true; } + void SetLoadKindWithAddress(LoadKind load_kind, uint64_t address) { + DCHECK(HasAddress(load_kind)); + load_data_.address = address; + SetLoadKindInternal(load_kind); + } - bool InstructionDataEquals(HInstruction* other) const OVERRIDE { - return other->AsLoadString()->string_index_ == string_index_; + void SetLoadKindWithStringReference(LoadKind load_kind, + const DexFile& dex_file, + uint32_t string_index) { + DCHECK(HasStringReference(load_kind)); + load_data_.ref.dex_file = &dex_file; + string_index_ = string_index; + SetLoadKindInternal(load_kind); } + void SetLoadKindWithDexCacheReference(LoadKind load_kind, + const DexFile& dex_file, + uint32_t element_index) { + DCHECK(HasDexCacheReference(load_kind)); + load_data_.ref.dex_file = &dex_file; + load_data_.ref.dex_cache_element_index = element_index; + SetLoadKindInternal(load_kind); + } + + LoadKind GetLoadKind() const { + return GetPackedField<LoadKindField>(); + } + + const DexFile& GetDexFile() const; + + uint32_t GetStringIndex() const { + DCHECK(HasStringReference(GetLoadKind()) || /* For slow paths. */ !IsInDexCache()); + return string_index_; + } + + uint32_t GetDexCacheElementOffset() const; + + uint64_t GetAddress() const { + DCHECK(HasAddress(GetLoadKind())); + return load_data_.address; + } + + bool CanBeMoved() const OVERRIDE { return true; } + + bool InstructionDataEquals(HInstruction* other) const OVERRIDE; + size_t ComputeHashCode() const OVERRIDE { return string_index_; } - uint32_t GetStringIndex() const { return string_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. + bool NeedsEnvironment() const OVERRIDE { + LoadKind load_kind = GetLoadKind(); + if (load_kind == LoadKind::kBootImageLinkTimeAddress || + load_kind == LoadKind::kBootImageLinkTimePcRelative || + load_kind == LoadKind::kBootImageAddress) { + return false; + } + return !IsInDexCache(); + } - // Will call the runtime if the string is not already in the dex cache. - bool NeedsEnvironment() const OVERRIDE { return !IsInDexCache(); } + bool NeedsDexCacheOfDeclaringClass() const OVERRIDE { + return GetLoadKind() == LoadKind::kDexCacheViaMethod; + } - bool NeedsDexCacheOfDeclaringClass() const OVERRIDE { return true; } bool CanBeNull() const OVERRIDE { return false; } - bool CanThrow() const OVERRIDE { return !IsInDexCache(); } + bool CanThrow() const OVERRIDE { return NeedsEnvironment(); } static SideEffects SideEffectsForArchRuntimeCalls() { return SideEffects::CanTriggerGC(); @@ -5590,17 +5677,83 @@ class HLoadString : public HExpression<1> { bool IsInDexCache() const { return GetPackedFlag<kFlagIsInDexCache>(); } + void MarkInDexCache() { + SetPackedFlag<kFlagIsInDexCache>(true); + DCHECK(!NeedsEnvironment()); + RemoveEnvironment(); + } + + size_t InputCount() const OVERRIDE { + return (InputAt(0) != nullptr) ? 1u : 0u; + } + + void AddSpecialInput(HInstruction* special_input); + DECLARE_INSTRUCTION(LoadString); private: static constexpr size_t kFlagIsInDexCache = kNumberOfExpressionPackedBits; - static constexpr size_t kNumberOfLoadStringPackedBits = kFlagIsInDexCache + 1; + static constexpr size_t kFieldLoadKind = kFlagIsInDexCache + 1; + static constexpr size_t kFieldLoadKindSize = + MinimumBitsToStore(static_cast<size_t>(LoadKind::kLast)); + static constexpr size_t kNumberOfLoadStringPackedBits = kFieldLoadKind + kFieldLoadKindSize; static_assert(kNumberOfLoadStringPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields."); + using LoadKindField = BitField<LoadKind, kFieldLoadKind, kFieldLoadKindSize>; + + static bool HasStringReference(LoadKind load_kind) { + return load_kind == LoadKind::kBootImageLinkTimeAddress || + load_kind == LoadKind::kBootImageLinkTimePcRelative || + load_kind == LoadKind::kDexCacheViaMethod; + } - const uint32_t string_index_; + static bool HasAddress(LoadKind load_kind) { + return load_kind == LoadKind::kBootImageAddress || load_kind == LoadKind::kDexCacheAddress; + } + + static bool HasDexCacheReference(LoadKind load_kind) { + return load_kind == LoadKind::kDexCachePcRelative; + } + + void SetLoadKindInternal(LoadKind load_kind); + + // 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_; + + union { + struct { + const DexFile* dex_file; // For string reference and dex cache reference. + uint32_t dex_cache_element_index; // Only for dex cache reference. + } ref; + uint64_t address; // Up to 64-bit, needed for kDexCacheAddress on 64-bit targets. + } load_data_; DISALLOW_COPY_AND_ASSIGN(HLoadString); }; +std::ostream& operator<<(std::ostream& os, HLoadString::LoadKind rhs); + +// Note: defined outside class to see operator<<(., HLoadString::LoadKind). +inline const DexFile& HLoadString::GetDexFile() const { + DCHECK(HasStringReference(GetLoadKind()) || HasDexCacheReference(GetLoadKind())) + << GetLoadKind(); + return *load_data_.ref.dex_file; +} + +// Note: defined outside class to see operator<<(., HLoadString::LoadKind). +inline uint32_t HLoadString::GetDexCacheElementOffset() const { + DCHECK(HasDexCacheReference(GetLoadKind())) << GetLoadKind(); + return load_data_.ref.dex_cache_element_index; +} + +// Note: defined outside class to see operator<<(., HLoadString::LoadKind). +inline void HLoadString::AddSpecialInput(HInstruction* special_input) { + // The special input is used for PC-relative loads on some architectures. + DCHECK(GetLoadKind() == LoadKind::kBootImageLinkTimePcRelative || + GetLoadKind() == LoadKind::kDexCachePcRelative) << GetLoadKind(); + DCHECK(InputAt(0) == nullptr); + SetRawInputAt(0u, special_input); + special_input->AddUseAt(this, 0); +} /** * Performs an initialization check on its Class object input. |