From af6925b7fe5dc5a3c8d52ee3370e86e75400f873 Mon Sep 17 00:00:00 2001 From: Vladimir Marko Date: Fri, 31 Oct 2014 16:37:32 +0000 Subject: [PATCH] Rewrite GVN's field id and field type handling. Create a helper unit for dex insn classification and cache dex field type (as encoded in the insn) in the MirFieldInfo. Use this for cleanup and a few additional DCHECKs. Change the GVN's field id to match the field lowering info index (MIR::meta::{i,s}field_lowering_info), except where multiple indexes refer to the same field and we use the lowest of the applicable indexes. Use the MirMethodInfo from MIRGraph to retrieve field type for GVN using this index. This slightly reduces GVN compilation time and prepares for further compilation time improvements. Change-Id: I1b1247cdb8e8b6897254e2180f3230f10159bed5 --- compiler/Android.mk | 3 +- compiler/dex/global_value_numbering.cc | 16 --- compiler/dex/global_value_numbering.h | 74 ++++++---- compiler/dex/global_value_numbering_test.cc | 203 +++++++++++++++------------- compiler/dex/local_value_numbering.cc | 33 +++-- compiler/dex/local_value_numbering_test.cc | 95 +++++++------ compiler/dex/mir_analysis.cc | 83 ++++++------ compiler/dex/mir_field_info.cc | 6 +- compiler/dex/mir_field_info.h | 24 +++- compiler/dex/mir_graph.h | 41 +++++- compiler/dex/mir_optimization.cc | 39 ++++-- compiler/dex/mir_optimization_test.cc | 112 +++++++-------- compiler/dex/quick/gen_common.cc | 4 + compiler/utils/dex_instruction_utils.h | 188 ++++++++++++++++++++++++++ runtime/quick/inline_method_analyser.h | 4 +- 15 files changed, 599 insertions(+), 326 deletions(-) create mode 100644 compiler/utils/dex_instruction_utils.h diff --git a/compiler/Android.mk b/compiler/Android.mk index eb9ad475b..84176a177 100644 --- a/compiler/Android.mk +++ b/compiler/Android.mk @@ -180,7 +180,8 @@ LIBART_COMPILER_ENUM_OPERATOR_OUT_HEADER_FILES := \ driver/compiler_options.h \ image_writer.h \ optimizing/locations.h \ - utils/arm/constants_arm.h + utils/arm/constants_arm.h \ + utils/dex_instruction_utils.h # $(1): target or host # $(2): ndebug or debug diff --git a/compiler/dex/global_value_numbering.cc b/compiler/dex/global_value_numbering.cc index d311bc76f..dbe98506b 100644 --- a/compiler/dex/global_value_numbering.cc +++ b/compiler/dex/global_value_numbering.cc @@ -15,7 +15,6 @@ */ #include "global_value_numbering.h" - #include "local_value_numbering.h" namespace art { @@ -31,8 +30,6 @@ GlobalValueNumbering::GlobalValueNumbering(CompilationUnit* cu, ScopedArenaAlloc modifications_allowed_(true), mode_(mode), global_value_map_(std::less(), allocator->Adapter()), - field_index_map_(FieldReferenceComparator(), allocator->Adapter()), - field_index_reverse_map_(allocator->Adapter()), array_location_map_(ArrayLocationComparator(), allocator->Adapter()), array_location_reverse_map_(allocator->Adapter()), ref_set_map_(std::less(), allocator->Adapter()), @@ -145,19 +142,6 @@ bool GlobalValueNumbering::FinishBasicBlock(BasicBlock* bb) { return change; } -uint16_t GlobalValueNumbering::GetFieldId(const MirFieldInfo& field_info, uint16_t type) { - FieldReference key = { field_info.DeclaringDexFile(), field_info.DeclaringFieldIndex(), type }; - auto lb = field_index_map_.lower_bound(key); - if (lb != field_index_map_.end() && !field_index_map_.key_comp()(key, lb->first)) { - return lb->second; - } - DCHECK_LT(field_index_map_.size(), kNoValue); - uint16_t id = field_index_map_.size(); - auto it = field_index_map_.PutBefore(lb, key, id); - field_index_reverse_map_.push_back(&*it); - return id; -} - uint16_t GlobalValueNumbering::GetArrayLocation(uint16_t base, uint16_t index) { auto cmp = array_location_map_.key_comp(); ArrayLocation key = { base, index }; diff --git a/compiler/dex/global_value_numbering.h b/compiler/dex/global_value_numbering.h index 72d111244..8a93afb87 100644 --- a/compiler/dex/global_value_numbering.h +++ b/compiler/dex/global_value_numbering.h @@ -39,6 +39,12 @@ class GlobalValueNumbering : public DeletableArenaObject { cu->mir_graph->GetMaxNestedLoops() > kMaxAllowedNestedLoops; } + // Instance and static field id map is held by MIRGraph to avoid multiple recalculations + // when doing LVN. + template // Container of MirIFieldLoweringInfo or MirSFieldLoweringInfo. + static uint16_t* PrepareGvnFieldIds(ScopedArenaAllocator* allocator, + const Container& field_infos); + GlobalValueNumbering(CompilationUnit* cu, ScopedArenaAllocator* allocator, Mode mode); ~GlobalValueNumbering(); @@ -114,34 +120,24 @@ class GlobalValueNumbering : public DeletableArenaObject { return (it != global_value_map_.end() && it->second == value); } - // FieldReference represents a unique resolved field. - struct FieldReference { - const DexFile* dex_file; - uint16_t field_idx; - uint16_t type; // See comments for LocalValueNumbering::kFieldTypeCount. - }; - - struct FieldReferenceComparator { - bool operator()(const FieldReference& lhs, const FieldReference& rhs) const { - if (lhs.field_idx != rhs.field_idx) { - return lhs.field_idx < rhs.field_idx; - } - // If the field_idx and dex_file match, the type must also match. - DCHECK(lhs.dex_file != rhs.dex_file || lhs.type == rhs.type); - return lhs.dex_file < rhs.dex_file; - } - }; + // Get an instance field id. + uint16_t GetIFieldId(MIR* mir) { + return GetMirGraph()->GetGvnIFieldId(mir); + } - // Maps field key to field id for resolved fields. - typedef ScopedArenaSafeMap FieldIndexMap; + // Get a static field id. + uint16_t GetSFieldId(MIR* mir) { + return GetMirGraph()->GetGvnSFieldId(mir); + } - // Get a field id. - uint16_t GetFieldId(const MirFieldInfo& field_info, uint16_t type); + // Get an instance field type based on field id. + uint16_t GetIFieldType(uint16_t field_id) { + return static_cast(GetMirGraph()->GetIFieldLoweringInfo(field_id).MemAccessType()); + } - // Get a field type based on field id. - uint16_t GetFieldType(uint16_t field_id) { - DCHECK_LT(field_id, field_index_reverse_map_.size()); - return field_index_reverse_map_[field_id]->first.type; + // Get a static field type based on field id. + uint16_t GetSFieldType(uint16_t field_id) { + return static_cast(GetMirGraph()->GetSFieldLoweringInfo(field_id).MemAccessType()); } struct ArrayLocation { @@ -239,8 +235,6 @@ class GlobalValueNumbering : public DeletableArenaObject { Mode mode_; ValueMap global_value_map_; - FieldIndexMap field_index_map_; - ScopedArenaVector field_index_reverse_map_; ArrayLocationMap array_location_map_; ScopedArenaVector array_location_reverse_map_; RefSetIdMap ref_set_map_; @@ -268,6 +262,32 @@ inline uint16_t GlobalValueNumbering::NewValueName() { return last_value_; } +template // Container of MirIFieldLoweringInfo or MirSFieldLoweringInfo. +uint16_t* GlobalValueNumbering::PrepareGvnFieldIds(ScopedArenaAllocator* allocator, + const Container& field_infos) { + size_t size = field_infos.size(); + uint16_t* field_ids = reinterpret_cast(allocator->Alloc(size * sizeof(uint16_t), + kArenaAllocMisc)); + for (size_t i = 0u; i != size; ++i) { + size_t idx = i; + const MirFieldInfo& cur_info = field_infos[i]; + if (cur_info.IsResolved()) { + for (size_t j = 0; j != i; ++j) { + const MirFieldInfo& prev_info = field_infos[j]; + if (prev_info.IsResolved() && + prev_info.DeclaringDexFile() == cur_info.DeclaringDexFile() && + prev_info.DeclaringFieldIndex() == cur_info.DeclaringFieldIndex()) { + DCHECK_EQ(cur_info.MemAccessType(), prev_info.MemAccessType()); + idx = j; + break; + } + } + } + field_ids[i] = idx; + } + return field_ids; +} + } // namespace art #endif // ART_COMPILER_DEX_GLOBAL_VALUE_NUMBERING_H_ diff --git a/compiler/dex/global_value_numbering_test.cc b/compiler/dex/global_value_numbering_test.cc index 35d5b995c..a78812979 100644 --- a/compiler/dex/global_value_numbering_test.cc +++ b/compiler/dex/global_value_numbering_test.cc @@ -17,6 +17,7 @@ #include "compiler_internals.h" #include "dataflow_iterator.h" #include "dataflow_iterator-inl.h" +#include "dex/mir_field_info.h" #include "global_value_numbering.h" #include "local_value_numbering.h" #include "gtest/gtest.h" @@ -32,6 +33,7 @@ class GlobalValueNumberingTest : public testing::Test { uintptr_t declaring_dex_file; uint16_t declaring_field_idx; bool is_volatile; + DexMemAccessType type; }; struct SFieldDef { @@ -39,6 +41,7 @@ class GlobalValueNumberingTest : public testing::Test { uintptr_t declaring_dex_file; uint16_t declaring_field_idx; bool is_volatile; + DexMemAccessType type; }; struct BBDef { @@ -137,12 +140,11 @@ class GlobalValueNumberingTest : public testing::Test { cu_.mir_graph->ifield_lowering_infos_.reserve(count); for (size_t i = 0u; i != count; ++i) { const IFieldDef* def = &defs[i]; - MirIFieldLoweringInfo field_info(def->field_idx); + MirIFieldLoweringInfo field_info(def->field_idx, def->type); if (def->declaring_dex_file != 0u) { field_info.declaring_dex_file_ = reinterpret_cast(def->declaring_dex_file); field_info.declaring_field_idx_ = def->declaring_field_idx; - field_info.flags_ = 0u | // Without kFlagIsStatic. - (def->is_volatile ? MirIFieldLoweringInfo::kFlagIsVolatile : 0u); + field_info.flags_ &= ~(def->is_volatile ? 0u : MirSFieldLoweringInfo::kFlagIsVolatile); } cu_.mir_graph->ifield_lowering_infos_.push_back(field_info); } @@ -158,15 +160,14 @@ class GlobalValueNumberingTest : public testing::Test { cu_.mir_graph->sfield_lowering_infos_.reserve(count); for (size_t i = 0u; i != count; ++i) { const SFieldDef* def = &defs[i]; - MirSFieldLoweringInfo field_info(def->field_idx); + MirSFieldLoweringInfo field_info(def->field_idx, def->type); // Mark even unresolved fields as initialized. - field_info.flags_ = MirSFieldLoweringInfo::kFlagIsStatic | - MirSFieldLoweringInfo::kFlagClassIsInitialized; + field_info.flags_ |= MirSFieldLoweringInfo::kFlagClassIsInitialized; // NOTE: MirSFieldLoweringInfo::kFlagClassIsInDexCache isn't used by GVN. if (def->declaring_dex_file != 0u) { field_info.declaring_dex_file_ = reinterpret_cast(def->declaring_dex_file); field_info.declaring_field_idx_ = def->declaring_field_idx; - field_info.flags_ |= (def->is_volatile ? MirSFieldLoweringInfo::kFlagIsVolatile : 0u); + field_info.flags_ &= ~(def->is_volatile ? 0u : MirSFieldLoweringInfo::kFlagIsVolatile); } cu_.mir_graph->sfield_lowering_infos_.push_back(field_info); } @@ -238,12 +239,16 @@ class GlobalValueNumberingTest : public testing::Test { mir->dalvikInsn.opcode = def->opcode; mir->dalvikInsn.vB = static_cast(def->value); mir->dalvikInsn.vB_wide = def->value; - if (def->opcode >= Instruction::IGET && def->opcode <= Instruction::IPUT_SHORT) { + if (IsInstructionIGetOrIPut(def->opcode)) { ASSERT_LT(def->field_info, cu_.mir_graph->ifield_lowering_infos_.size()); mir->meta.ifield_lowering_info = def->field_info; - } else if (def->opcode >= Instruction::SGET && def->opcode <= Instruction::SPUT_SHORT) { + ASSERT_EQ(cu_.mir_graph->ifield_lowering_infos_[def->field_info].MemAccessType(), + IGetOrIPutMemAccessType(def->opcode)); + } else if (IsInstructionSGetOrSPut(def->opcode)) { ASSERT_LT(def->field_info, cu_.mir_graph->sfield_lowering_infos_.size()); mir->meta.sfield_lowering_info = def->field_info; + ASSERT_EQ(cu_.mir_graph->sfield_lowering_infos_[def->field_info].MemAccessType(), + SGetOrSPutMemAccessType(def->opcode)); } else if (def->opcode == static_cast(kMirOpPhi)) { mir->meta.phi_incoming = static_cast( allocator_->Alloc(def->num_uses * sizeof(BasicBlockId), kArenaAllocDFInfo)); @@ -288,6 +293,10 @@ class GlobalValueNumberingTest : public testing::Test { cu_.mir_graph->ComputeDominators(); cu_.mir_graph->ComputeTopologicalSortOrder(); cu_.mir_graph->SSATransformationEnd(); + cu_.mir_graph->temp_.gvn.ifield_ids_ = GlobalValueNumbering::PrepareGvnFieldIds( + allocator_.get(), cu_.mir_graph->ifield_lowering_infos_); + cu_.mir_graph->temp_.gvn.sfield_ids_ = GlobalValueNumbering::PrepareGvnFieldIds( + allocator_.get(), cu_.mir_graph->sfield_lowering_infos_); ASSERT_TRUE(gvn_ == nullptr); gvn_.reset(new (allocator_.get()) GlobalValueNumbering(&cu_, allocator_.get(), GlobalValueNumbering::kModeGvn)); @@ -498,18 +507,18 @@ GlobalValueNumberingTestTwoNestedLoops::GlobalValueNumberingTestTwoNestedLoops() TEST_F(GlobalValueNumberingTestDiamond, NonAliasingIFields) { static const IFieldDef ifields[] = { - { 0u, 1u, 0u, false }, // Int. - { 1u, 1u, 1u, false }, // Int. - { 2u, 1u, 2u, false }, // Int. - { 3u, 1u, 3u, false }, // Int. - { 4u, 1u, 4u, false }, // Short. - { 5u, 1u, 5u, false }, // Char. - { 6u, 0u, 0u, false }, // Unresolved, Short. - { 7u, 1u, 7u, false }, // Int. - { 8u, 0u, 0u, false }, // Unresolved, Int. - { 9u, 1u, 9u, false }, // Int. - { 10u, 1u, 10u, false }, // Int. - { 11u, 1u, 11u, false }, // Int. + { 0u, 1u, 0u, false, kDexMemAccessWord }, + { 1u, 1u, 1u, false, kDexMemAccessWord }, + { 2u, 1u, 2u, false, kDexMemAccessWord }, + { 3u, 1u, 3u, false, kDexMemAccessWord }, + { 4u, 1u, 4u, false, kDexMemAccessShort }, + { 5u, 1u, 5u, false, kDexMemAccessChar }, + { 6u, 0u, 0u, false, kDexMemAccessShort }, // Unresolved. + { 7u, 1u, 7u, false, kDexMemAccessWord }, + { 8u, 0u, 0u, false, kDexMemAccessWord }, // Unresolved. + { 9u, 1u, 9u, false, kDexMemAccessWord }, + { 10u, 1u, 10u, false, kDexMemAccessWord }, + { 11u, 1u, 11u, false, kDexMemAccessWord }, }; static const MIRDef mirs[] = { // NOTE: MIRs here are ordered by unique tests. They will be put into appropriate blocks. @@ -604,15 +613,15 @@ TEST_F(GlobalValueNumberingTestDiamond, NonAliasingIFields) { TEST_F(GlobalValueNumberingTestDiamond, AliasingIFieldsSingleObject) { static const IFieldDef ifields[] = { - { 0u, 1u, 0u, false }, // Int. - { 1u, 1u, 1u, false }, // Int. - { 2u, 1u, 2u, false }, // Int. - { 3u, 1u, 3u, false }, // Int. - { 4u, 1u, 4u, false }, // Short. - { 5u, 1u, 5u, false }, // Char. - { 6u, 0u, 0u, false }, // Unresolved, Short. - { 7u, 1u, 7u, false }, // Int. - { 8u, 1u, 8u, false }, // Int. + { 0u, 1u, 0u, false, kDexMemAccessWord }, + { 1u, 1u, 1u, false, kDexMemAccessWord }, + { 2u, 1u, 2u, false, kDexMemAccessWord }, + { 3u, 1u, 3u, false, kDexMemAccessWord }, + { 4u, 1u, 4u, false, kDexMemAccessShort }, + { 5u, 1u, 5u, false, kDexMemAccessChar }, + { 6u, 0u, 0u, false, kDexMemAccessShort }, // Unresolved. + { 7u, 1u, 7u, false, kDexMemAccessWord }, + { 8u, 1u, 8u, false, kDexMemAccessWord }, }; static const MIRDef mirs[] = { // NOTE: MIRs here are ordered by unique tests. They will be put into appropriate blocks. @@ -671,15 +680,15 @@ TEST_F(GlobalValueNumberingTestDiamond, AliasingIFieldsSingleObject) { TEST_F(GlobalValueNumberingTestDiamond, AliasingIFieldsTwoObjects) { static const IFieldDef ifields[] = { - { 0u, 1u, 0u, false }, // Int. - { 1u, 1u, 1u, false }, // Int. - { 2u, 1u, 2u, false }, // Int. - { 3u, 1u, 3u, false }, // Int. - { 4u, 1u, 4u, false }, // Short. - { 5u, 1u, 5u, false }, // Char. - { 6u, 0u, 0u, false }, // Unresolved, Short. - { 7u, 1u, 7u, false }, // Int. - { 8u, 1u, 8u, false }, // Int. + { 0u, 1u, 0u, false, kDexMemAccessWord }, + { 1u, 1u, 1u, false, kDexMemAccessWord }, + { 2u, 1u, 2u, false, kDexMemAccessWord }, + { 3u, 1u, 3u, false, kDexMemAccessWord }, + { 4u, 1u, 4u, false, kDexMemAccessShort }, + { 5u, 1u, 5u, false, kDexMemAccessChar }, + { 6u, 0u, 0u, false, kDexMemAccessShort }, // Unresolved. + { 7u, 1u, 7u, false, kDexMemAccessWord }, + { 8u, 1u, 8u, false, kDexMemAccessWord }, }; static const MIRDef mirs[] = { // NOTE: MIRs here are ordered by unique tests. They will be put into appropriate blocks. @@ -740,15 +749,15 @@ TEST_F(GlobalValueNumberingTestDiamond, AliasingIFieldsTwoObjects) { TEST_F(GlobalValueNumberingTestDiamond, SFields) { static const SFieldDef sfields[] = { - { 0u, 1u, 0u, false }, // Int. - { 1u, 1u, 1u, false }, // Int. - { 2u, 1u, 2u, false }, // Int. - { 3u, 1u, 3u, false }, // Int. - { 4u, 1u, 4u, false }, // Short. - { 5u, 1u, 5u, false }, // Char. - { 6u, 0u, 0u, false }, // Unresolved, Short. - { 7u, 1u, 7u, false }, // Int. - { 8u, 1u, 8u, false }, // Int. + { 0u, 1u, 0u, false, kDexMemAccessWord }, + { 1u, 1u, 1u, false, kDexMemAccessWord }, + { 2u, 1u, 2u, false, kDexMemAccessWord }, + { 3u, 1u, 3u, false, kDexMemAccessWord }, + { 4u, 1u, 4u, false, kDexMemAccessShort }, + { 5u, 1u, 5u, false, kDexMemAccessChar }, + { 6u, 0u, 0u, false, kDexMemAccessShort }, // Unresolved. + { 7u, 1u, 7u, false, kDexMemAccessWord }, + { 8u, 1u, 8u, false, kDexMemAccessWord }, }; static const MIRDef mirs[] = { // NOTE: MIRs here are ordered by unique tests. They will be put into appropriate blocks. @@ -1078,18 +1087,18 @@ TEST_F(GlobalValueNumberingTestDiamond, PhiWide) { TEST_F(GlobalValueNumberingTestLoop, NonAliasingIFields) { static const IFieldDef ifields[] = { - { 0u, 1u, 0u, false }, // Int. - { 1u, 1u, 1u, false }, // Int. - { 2u, 1u, 2u, false }, // Int. - { 3u, 1u, 3u, false }, // Int. - { 4u, 1u, 4u, false }, // Int. - { 5u, 1u, 5u, false }, // Short. - { 6u, 1u, 6u, false }, // Char. - { 7u, 0u, 0u, false }, // Unresolved, Short. - { 8u, 1u, 8u, false }, // Int. - { 9u, 0u, 0u, false }, // Unresolved, Int. - { 10u, 1u, 10u, false }, // Int. - { 11u, 1u, 11u, false }, // Int. + { 0u, 1u, 0u, false, kDexMemAccessWord }, + { 1u, 1u, 1u, false, kDexMemAccessWord }, + { 2u, 1u, 2u, false, kDexMemAccessWord }, + { 3u, 1u, 3u, false, kDexMemAccessWord }, + { 4u, 1u, 4u, false, kDexMemAccessWord }, + { 5u, 1u, 5u, false, kDexMemAccessShort }, + { 6u, 1u, 6u, false, kDexMemAccessChar }, + { 7u, 0u, 0u, false, kDexMemAccessShort }, // Unresolved. + { 8u, 1u, 8u, false, kDexMemAccessWord }, + { 9u, 0u, 0u, false, kDexMemAccessWord }, // Unresolved. + { 10u, 1u, 10u, false, kDexMemAccessWord }, + { 11u, 1u, 11u, false, kDexMemAccessWord }, }; static const MIRDef mirs[] = { // NOTE: MIRs here are ordered by unique tests. They will be put into appropriate blocks. @@ -1201,14 +1210,14 @@ TEST_F(GlobalValueNumberingTestLoop, NonAliasingIFields) { TEST_F(GlobalValueNumberingTestLoop, AliasingIFieldsSingleObject) { static const IFieldDef ifields[] = { - { 0u, 1u, 0u, false }, // Int. - { 1u, 1u, 1u, false }, // Int. - { 2u, 1u, 2u, false }, // Int. - { 3u, 1u, 3u, false }, // Int. - { 4u, 1u, 4u, false }, // Int. - { 5u, 1u, 5u, false }, // Short. - { 6u, 1u, 6u, false }, // Char. - { 7u, 0u, 0u, false }, // Unresolved, Short. + { 0u, 1u, 0u, false, kDexMemAccessWord }, + { 1u, 1u, 1u, false, kDexMemAccessWord }, + { 2u, 1u, 2u, false, kDexMemAccessWord }, + { 3u, 1u, 3u, false, kDexMemAccessWord }, + { 4u, 1u, 4u, false, kDexMemAccessWord }, + { 5u, 1u, 5u, false, kDexMemAccessShort }, + { 6u, 1u, 6u, false, kDexMemAccessChar }, + { 7u, 0u, 0u, false, kDexMemAccessShort }, // Unresolved. }; static const MIRDef mirs[] = { // NOTE: MIRs here are ordered by unique tests. They will be put into appropriate blocks. @@ -1272,14 +1281,14 @@ TEST_F(GlobalValueNumberingTestLoop, AliasingIFieldsSingleObject) { TEST_F(GlobalValueNumberingTestLoop, AliasingIFieldsTwoObjects) { static const IFieldDef ifields[] = { - { 0u, 1u, 0u, false }, // Int. - { 1u, 1u, 1u, false }, // Int. - { 2u, 1u, 2u, false }, // Int. - { 3u, 1u, 3u, false }, // Short. - { 4u, 1u, 4u, false }, // Char. - { 5u, 0u, 0u, false }, // Unresolved, Short. - { 6u, 1u, 6u, false }, // Int. - { 7u, 1u, 7u, false }, // Int. + { 0u, 1u, 0u, false, kDexMemAccessWord }, + { 1u, 1u, 1u, false, kDexMemAccessWord }, + { 2u, 1u, 2u, false, kDexMemAccessWord }, + { 3u, 1u, 3u, false, kDexMemAccessShort }, + { 4u, 1u, 4u, false, kDexMemAccessChar }, + { 5u, 0u, 0u, false, kDexMemAccessShort }, // Unresolved. + { 6u, 1u, 6u, false, kDexMemAccessWord }, + { 7u, 1u, 7u, false, kDexMemAccessWord }, }; static const MIRDef mirs[] = { // NOTE: MIRs here are ordered by unique tests. They will be put into appropriate blocks. @@ -1341,7 +1350,7 @@ TEST_F(GlobalValueNumberingTestLoop, AliasingIFieldsTwoObjects) { TEST_F(GlobalValueNumberingTestLoop, IFieldToBaseDependency) { static const IFieldDef ifields[] = { - { 0u, 1u, 0u, false }, // Int. + { 0u, 1u, 0u, false, kDexMemAccessWord }, }; static const MIRDef mirs[] = { // For the IGET that loads sreg 3u using base 2u, the following IPUT creates a dependency @@ -1366,9 +1375,9 @@ TEST_F(GlobalValueNumberingTestLoop, IFieldToBaseDependency) { TEST_F(GlobalValueNumberingTestLoop, SFields) { static const SFieldDef sfields[] = { - { 0u, 1u, 0u, false }, // Int. - { 1u, 1u, 1u, false }, // Int. - { 2u, 1u, 2u, false }, // Int. + { 0u, 1u, 0u, false, kDexMemAccessWord }, + { 1u, 1u, 1u, false, kDexMemAccessWord }, + { 2u, 1u, 2u, false, kDexMemAccessWord }, }; static const MIRDef mirs[] = { // NOTE: MIRs here are ordered by unique tests. They will be put into appropriate blocks. @@ -1562,8 +1571,8 @@ TEST_F(GlobalValueNumberingTestLoop, Phi) { TEST_F(GlobalValueNumberingTestCatch, IFields) { static const IFieldDef ifields[] = { - { 0u, 1u, 0u, false }, - { 1u, 1u, 1u, false }, + { 0u, 1u, 0u, false, kDexMemAccessWord }, + { 1u, 1u, 1u, false, kDexMemAccessWord }, }; static const MIRDef mirs[] = { DEF_UNIQUE_REF(3, Instruction::NEW_INSTANCE, 200u), @@ -1608,8 +1617,8 @@ TEST_F(GlobalValueNumberingTestCatch, IFields) { TEST_F(GlobalValueNumberingTestCatch, SFields) { static const SFieldDef sfields[] = { - { 0u, 1u, 0u, false }, - { 1u, 1u, 1u, false }, + { 0u, 1u, 0u, false, kDexMemAccessWord }, + { 1u, 1u, 1u, false, kDexMemAccessWord }, }; static const MIRDef mirs[] = { DEF_SGET(3, Instruction::SGET, 0u, 0u), @@ -1731,8 +1740,8 @@ TEST_F(GlobalValueNumberingTestCatch, Phi) { TEST_F(GlobalValueNumberingTest, NullCheckIFields) { static const IFieldDef ifields[] = { - { 0u, 1u, 0u, false }, // Object. - { 1u, 1u, 1u, false }, // Object. + { 0u, 1u, 0u, false, kDexMemAccessObject }, // Object. + { 1u, 1u, 1u, false, kDexMemAccessObject }, // Object. }; static const BBDef bbs[] = { DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()), @@ -1780,8 +1789,8 @@ TEST_F(GlobalValueNumberingTest, NullCheckIFields) { TEST_F(GlobalValueNumberingTest, NullCheckSFields) { static const SFieldDef sfields[] = { - { 0u, 1u, 0u, false }, // Object. - { 1u, 1u, 1u, false }, // Object. + { 0u, 1u, 0u, false, kDexMemAccessObject }, + { 1u, 1u, 1u, false, kDexMemAccessObject }, }; static const BBDef bbs[] = { DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()), @@ -1907,12 +1916,12 @@ TEST_F(GlobalValueNumberingTestDiamond, RangeCheckArrays) { TEST_F(GlobalValueNumberingTestDiamond, MergeSameValueInDifferentMemoryLocations) { static const IFieldDef ifields[] = { - { 0u, 1u, 0u, false }, // Int. - { 1u, 1u, 1u, false }, // Int. + { 0u, 1u, 0u, false, kDexMemAccessWord }, + { 1u, 1u, 1u, false, kDexMemAccessWord }, }; static const SFieldDef sfields[] = { - { 0u, 1u, 0u, false }, // Int. - { 1u, 1u, 1u, false }, // Int. + { 0u, 1u, 0u, false, kDexMemAccessWord }, + { 1u, 1u, 1u, false, kDexMemAccessWord }, }; static const MIRDef mirs[] = { DEF_UNIQUE_REF(3, Instruction::NEW_INSTANCE, 100u), @@ -1977,7 +1986,7 @@ TEST_F(GlobalValueNumberingTest, InfiniteLocationLoop) { // LVN's aliasing_array_value_map_'s load_value_map for BBs #9, #4, #5, #7 because of the // DFS ordering of LVN evaluation. static const IFieldDef ifields[] = { - { 0u, 1u, 0u, false }, // Object. + { 0u, 1u, 0u, false, kDexMemAccessObject }, }; static const BBDef bbs[] = { DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()), @@ -2015,7 +2024,7 @@ TEST_F(GlobalValueNumberingTest, InfiniteLocationLoop) { TEST_F(GlobalValueNumberingTestTwoConsecutiveLoops, IFieldAndPhi) { static const IFieldDef ifields[] = { - { 0u, 1u, 0u, false }, // Int. + { 0u, 1u, 0u, false, kDexMemAccessObject }, }; static const MIRDef mirs[] = { DEF_MOVE(3, Instruction::MOVE_OBJECT, 0u, 100u), @@ -2052,10 +2061,10 @@ TEST_F(GlobalValueNumberingTestTwoConsecutiveLoops, IFieldAndPhi) { TEST_F(GlobalValueNumberingTestTwoConsecutiveLoops, NullCheck) { static const IFieldDef ifields[] = { - { 0u, 1u, 0u, false }, // Int. + { 0u, 1u, 0u, false, kDexMemAccessObject }, }; static const SFieldDef sfields[] = { - { 0u, 1u, 0u, false }, // Int. + { 0u, 1u, 0u, false, kDexMemAccessObject }, }; static const MIRDef mirs[] = { DEF_MOVE(3, Instruction::MOVE_OBJECT, 0u, 100u), @@ -2143,7 +2152,7 @@ TEST_F(GlobalValueNumberingTestTwoConsecutiveLoops, NullCheck) { TEST_F(GlobalValueNumberingTestTwoNestedLoops, IFieldAndPhi) { static const IFieldDef ifields[] = { - { 0u, 1u, 0u, false }, // Int. + { 0u, 1u, 0u, false, kDexMemAccessObject }, }; static const MIRDef mirs[] = { DEF_MOVE(3, Instruction::MOVE_OBJECT, 0u, 100u), diff --git a/compiler/dex/local_value_numbering.cc b/compiler/dex/local_value_numbering.cc index c1ce2ac01..90b91bc95 100644 --- a/compiler/dex/local_value_numbering.cc +++ b/compiler/dex/local_value_numbering.cc @@ -56,7 +56,7 @@ class LocalValueNumbering::AliasingIFieldVersions { public: static uint16_t StartMemoryVersion(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn, uint16_t field_id) { - uint16_t type = gvn->GetFieldType(field_id); + uint16_t type = gvn->GetIFieldType(field_id); return gvn->LookupValue(kAliasingIFieldStartVersionOp, field_id, lvn->global_memory_version_, lvn->unresolved_ifield_version_[type]); } @@ -75,7 +75,7 @@ class LocalValueNumbering::AliasingIFieldVersions { static uint16_t LookupMergeValue(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn, uint16_t field_id, uint16_t base) { // If the base/field_id is non-aliasing in lvn, use the non-aliasing value. - uint16_t type = gvn->GetFieldType(field_id); + uint16_t type = gvn->GetIFieldType(field_id); if (lvn->IsNonAliasingIField(base, field_id, type)) { uint16_t loc = gvn->LookupValue(kNonAliasingIFieldLocOp, base, field_id, type); auto lb = lvn->non_aliasing_ifield_value_map_.find(loc); @@ -89,7 +89,7 @@ class LocalValueNumbering::AliasingIFieldVersions { static bool HasNewBaseVersion(GlobalValueNumbering* gvn, const LocalValueNumbering* lvn, uint16_t field_id) { - uint16_t type = gvn->GetFieldType(field_id); + uint16_t type = gvn->GetIFieldType(field_id); return lvn->unresolved_ifield_version_[type] == lvn->merge_new_memory_version_ || lvn->global_memory_version_ == lvn->merge_new_memory_version_; } @@ -711,7 +711,7 @@ void LocalValueNumbering::MergeSFieldValues(const SFieldToValueMap::value_type& if (it != lvn->sfield_value_map_.end()) { value_name = it->second; } else { - uint16_t type = gvn_->GetFieldType(field_id); + uint16_t type = gvn_->GetSFieldType(field_id); value_name = gvn_->LookupValue(kResolvedSFieldOp, field_id, lvn->unresolved_sfield_version_[type], lvn->global_memory_version_); @@ -1150,12 +1150,11 @@ uint16_t LocalValueNumbering::HandlePhi(MIR* mir) { } uint16_t LocalValueNumbering::HandleAGet(MIR* mir, uint16_t opcode) { - // uint16_t type = opcode - Instruction::AGET; uint16_t array = GetOperandValue(mir->ssa_rep->uses[0]); HandleNullCheck(mir, array); uint16_t index = GetOperandValue(mir->ssa_rep->uses[1]); HandleRangeCheck(mir, array, index); - uint16_t type = opcode - Instruction::AGET; + uint16_t type = AGetMemAccessType(static_cast(opcode)); // Establish value number for loaded register. uint16_t res; if (IsNonAliasingArray(array, type)) { @@ -1182,7 +1181,7 @@ void LocalValueNumbering::HandleAPut(MIR* mir, uint16_t opcode) { uint16_t index = GetOperandValue(mir->ssa_rep->uses[index_idx]); HandleRangeCheck(mir, array, index); - uint16_t type = opcode - Instruction::APUT; + uint16_t type = APutMemAccessType(static_cast(opcode)); uint16_t value = (opcode == Instruction::APUT_WIDE) ? GetOperandValueWide(mir->ssa_rep->uses[0]) : GetOperandValue(mir->ssa_rep->uses[0]); @@ -1224,8 +1223,8 @@ uint16_t LocalValueNumbering::HandleIGet(MIR* mir, uint16_t opcode) { // Use result s_reg - will be unique. res = gvn_->LookupValue(kNoValue, mir->ssa_rep->defs[0], kNoValue, kNoValue); } else { - uint16_t type = opcode - Instruction::IGET; - uint16_t field_id = gvn_->GetFieldId(field_info, type); + uint16_t type = IGetMemAccessType(static_cast(opcode)); + uint16_t field_id = gvn_->GetIFieldId(mir); if (IsNonAliasingIField(base, field_id, type)) { uint16_t loc = gvn_->LookupValue(kNonAliasingIFieldLocOp, base, field_id, type); auto lb = non_aliasing_ifield_value_map_.lower_bound(loc); @@ -1249,10 +1248,10 @@ uint16_t LocalValueNumbering::HandleIGet(MIR* mir, uint16_t opcode) { } void LocalValueNumbering::HandleIPut(MIR* mir, uint16_t opcode) { - uint16_t type = opcode - Instruction::IPUT; int base_reg = (opcode == Instruction::IPUT_WIDE) ? 2 : 1; uint16_t base = GetOperandValue(mir->ssa_rep->uses[base_reg]); HandleNullCheck(mir, base); + uint16_t type = IPutMemAccessType(static_cast(opcode)); const MirFieldInfo& field_info = gvn_->GetMirGraph()->GetIFieldLoweringInfo(mir); if (!field_info.IsResolved()) { // Unresolved fields always alias with everything of the same type. @@ -1272,7 +1271,7 @@ void LocalValueNumbering::HandleIPut(MIR* mir, uint16_t opcode) { // Aliasing fields of the same type may have been overwritten. auto it = aliasing_ifield_value_map_.begin(), end = aliasing_ifield_value_map_.end(); while (it != end) { - if (gvn_->GetFieldType(it->first) != type) { + if (gvn_->GetIFieldType(it->first) != type) { ++it; } else { it = aliasing_ifield_value_map_.erase(it); @@ -1282,7 +1281,7 @@ void LocalValueNumbering::HandleIPut(MIR* mir, uint16_t opcode) { // Nothing to do, resolved volatile fields always get a new memory version anyway and // can't alias with resolved non-volatile fields. } else { - uint16_t field_id = gvn_->GetFieldId(field_info, type); + uint16_t field_id = gvn_->GetIFieldId(mir); uint16_t value = (opcode == Instruction::IPUT_WIDE) ? GetOperandValueWide(mir->ssa_rep->uses[0]) : GetOperandValue(mir->ssa_rep->uses[0]); @@ -1333,8 +1332,8 @@ uint16_t LocalValueNumbering::HandleSGet(MIR* mir, uint16_t opcode) { // Use result s_reg - will be unique. res = gvn_->LookupValue(kNoValue, mir->ssa_rep->defs[0], kNoValue, kNoValue); } else { - uint16_t type = opcode - Instruction::SGET; - uint16_t field_id = gvn_->GetFieldId(field_info, type); + uint16_t type = SGetMemAccessType(static_cast(opcode)); + uint16_t field_id = gvn_->GetSFieldId(mir); auto lb = sfield_value_map_.lower_bound(field_id); if (lb != sfield_value_map_.end() && lb->first == field_id) { res = lb->second; @@ -1362,7 +1361,7 @@ void LocalValueNumbering::HandleSPut(MIR* mir, uint16_t opcode) { // Class initialization can call arbitrary functions, we need to wipe aliasing values. HandleInvokeOrClInitOrAcquireOp(mir); } - uint16_t type = opcode - Instruction::SPUT; + uint16_t type = SPutMemAccessType(static_cast(opcode)); if (!field_info.IsResolved()) { // Unresolved fields always alias with everything of the same type. // Use mir->offset as modifier; without elaborate inlining, it will be unique. @@ -1373,7 +1372,7 @@ void LocalValueNumbering::HandleSPut(MIR* mir, uint16_t opcode) { // Nothing to do, resolved volatile fields always get a new memory version anyway and // can't alias with resolved non-volatile fields. } else { - uint16_t field_id = gvn_->GetFieldId(field_info, type); + uint16_t field_id = gvn_->GetSFieldId(mir); uint16_t value = (opcode == Instruction::SPUT_WIDE) ? GetOperandValueWide(mir->ssa_rep->uses[0]) : GetOperandValue(mir->ssa_rep->uses[0]); @@ -1397,7 +1396,7 @@ void LocalValueNumbering::HandleSPut(MIR* mir, uint16_t opcode) { void LocalValueNumbering::RemoveSFieldsForType(uint16_t type) { // Erase all static fields of this type from the sfield_value_map_. for (auto it = sfield_value_map_.begin(), end = sfield_value_map_.end(); it != end; ) { - if (gvn_->GetFieldType(it->first) == type) { + if (gvn_->GetSFieldType(it->first) == type) { it = sfield_value_map_.erase(it); } else { ++it; diff --git a/compiler/dex/local_value_numbering_test.cc b/compiler/dex/local_value_numbering_test.cc index 824c323b4..51aa9d98c 100644 --- a/compiler/dex/local_value_numbering_test.cc +++ b/compiler/dex/local_value_numbering_test.cc @@ -15,6 +15,7 @@ */ #include "compiler_internals.h" +#include "dex/mir_field_info.h" #include "global_value_numbering.h" #include "local_value_numbering.h" #include "gtest/gtest.h" @@ -28,6 +29,7 @@ class LocalValueNumberingTest : public testing::Test { uintptr_t declaring_dex_file; uint16_t declaring_field_idx; bool is_volatile; + DexMemAccessType type; }; struct SFieldDef { @@ -35,6 +37,7 @@ class LocalValueNumberingTest : public testing::Test { uintptr_t declaring_dex_file; uint16_t declaring_field_idx; bool is_volatile; + DexMemAccessType type; }; struct MIRDef { @@ -90,12 +93,11 @@ class LocalValueNumberingTest : public testing::Test { cu_.mir_graph->ifield_lowering_infos_.reserve(count); for (size_t i = 0u; i != count; ++i) { const IFieldDef* def = &defs[i]; - MirIFieldLoweringInfo field_info(def->field_idx); + MirIFieldLoweringInfo field_info(def->field_idx, def->type); if (def->declaring_dex_file != 0u) { field_info.declaring_dex_file_ = reinterpret_cast(def->declaring_dex_file); field_info.declaring_field_idx_ = def->declaring_field_idx; - field_info.flags_ = 0u | // Without kFlagIsStatic. - (def->is_volatile ? MirIFieldLoweringInfo::kFlagIsVolatile : 0u); + field_info.flags_ &= ~(def->is_volatile ? 0u : MirSFieldLoweringInfo::kFlagIsVolatile); } cu_.mir_graph->ifield_lowering_infos_.push_back(field_info); } @@ -111,15 +113,14 @@ class LocalValueNumberingTest : public testing::Test { cu_.mir_graph->sfield_lowering_infos_.reserve(count); for (size_t i = 0u; i != count; ++i) { const SFieldDef* def = &defs[i]; - MirSFieldLoweringInfo field_info(def->field_idx); + MirSFieldLoweringInfo field_info(def->field_idx, def->type); // Mark even unresolved fields as initialized. - field_info.flags_ = MirSFieldLoweringInfo::kFlagIsStatic | - MirSFieldLoweringInfo::kFlagClassIsInitialized; + field_info.flags_ |= MirSFieldLoweringInfo::kFlagClassIsInitialized; // NOTE: MirSFieldLoweringInfo::kFlagClassIsInDexCache isn't used by LVN. if (def->declaring_dex_file != 0u) { field_info.declaring_dex_file_ = reinterpret_cast(def->declaring_dex_file); field_info.declaring_field_idx_ = def->declaring_field_idx; - field_info.flags_ |= (def->is_volatile ? MirSFieldLoweringInfo::kFlagIsVolatile : 0u); + field_info.flags_ &= ~(def->is_volatile ? 0u : MirSFieldLoweringInfo::kFlagIsVolatile); } cu_.mir_graph->sfield_lowering_infos_.push_back(field_info); } @@ -140,12 +141,16 @@ class LocalValueNumberingTest : public testing::Test { mir->dalvikInsn.opcode = def->opcode; mir->dalvikInsn.vB = static_cast(def->value); mir->dalvikInsn.vB_wide = def->value; - if (def->opcode >= Instruction::IGET && def->opcode <= Instruction::IPUT_SHORT) { + if (IsInstructionIGetOrIPut(def->opcode)) { ASSERT_LT(def->field_info, cu_.mir_graph->ifield_lowering_infos_.size()); mir->meta.ifield_lowering_info = def->field_info; - } else if (def->opcode >= Instruction::SGET && def->opcode <= Instruction::SPUT_SHORT) { + ASSERT_EQ(cu_.mir_graph->ifield_lowering_infos_[def->field_info].MemAccessType(), + IGetOrIPutMemAccessType(def->opcode)); + } else if (IsInstructionSGetOrSPut(def->opcode)) { ASSERT_LT(def->field_info, cu_.mir_graph->sfield_lowering_infos_.size()); mir->meta.sfield_lowering_info = def->field_info; + ASSERT_EQ(cu_.mir_graph->sfield_lowering_infos_[def->field_info].MemAccessType(), + SGetOrSPutMemAccessType(def->opcode)); } mir->ssa_rep = &ssa_reps_[i]; mir->ssa_rep->num_uses = def->num_uses; @@ -177,6 +182,13 @@ class LocalValueNumberingTest : public testing::Test { } void PerformLVN() { + cu_.mir_graph->temp_.gvn.ifield_ids_ = GlobalValueNumbering::PrepareGvnFieldIds( + allocator_.get(), cu_.mir_graph->ifield_lowering_infos_); + cu_.mir_graph->temp_.gvn.sfield_ids_ = GlobalValueNumbering::PrepareGvnFieldIds( + allocator_.get(), cu_.mir_graph->sfield_lowering_infos_); + gvn_.reset(new (allocator_.get()) GlobalValueNumbering(&cu_, allocator_.get(), + GlobalValueNumbering::kModeLvn)); + lvn_.reset(new (allocator_.get()) LocalValueNumbering(gvn_.get(), 0u, allocator_.get())); value_names_.resize(mir_count_); for (size_t i = 0; i != mir_count_; ++i) { value_names_[i] = lvn_->GetValueNumber(&mirs_[i]); @@ -196,9 +208,6 @@ class LocalValueNumberingTest : public testing::Test { value_names_() { cu_.mir_graph.reset(new MIRGraph(&cu_, &cu_.arena)); allocator_.reset(ScopedArenaAllocator::Create(&cu_.arena_stack)); - gvn_.reset(new (allocator_.get()) GlobalValueNumbering(&cu_, allocator_.get(), - GlobalValueNumbering::kModeLvn)); - lvn_.reset(new (allocator_.get()) LocalValueNumbering(gvn_.get(), 0u, allocator_.get())); } ArenaPool pool_; @@ -214,7 +223,7 @@ class LocalValueNumberingTest : public testing::Test { TEST_F(LocalValueNumberingTest, IGetIGetInvokeIGet) { static const IFieldDef ifields[] = { - { 1u, 1u, 1u, false }, + { 1u, 1u, 1u, false, kDexMemAccessWord }, }; static const MIRDef mirs[] = { DEF_IGET(Instruction::IGET, 0u, 10u, 0u), @@ -237,8 +246,8 @@ TEST_F(LocalValueNumberingTest, IGetIGetInvokeIGet) { TEST_F(LocalValueNumberingTest, IGetIPutIGetIGetIGet) { static const IFieldDef ifields[] = { - { 1u, 1u, 1u, false }, - { 2u, 1u, 2u, false }, + { 1u, 1u, 1u, false, kDexMemAccessObject }, + { 2u, 1u, 2u, false, kDexMemAccessWord }, }; static const MIRDef mirs[] = { DEF_IGET(Instruction::IGET_OBJECT, 0u, 10u, 0u), @@ -262,7 +271,7 @@ TEST_F(LocalValueNumberingTest, IGetIPutIGetIGetIGet) { TEST_F(LocalValueNumberingTest, UniquePreserve1) { static const IFieldDef ifields[] = { - { 1u, 1u, 1u, false }, + { 1u, 1u, 1u, false, kDexMemAccessWord }, }; static const MIRDef mirs[] = { DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 10u), @@ -284,7 +293,7 @@ TEST_F(LocalValueNumberingTest, UniquePreserve1) { TEST_F(LocalValueNumberingTest, UniquePreserve2) { static const IFieldDef ifields[] = { - { 1u, 1u, 1u, false }, + { 1u, 1u, 1u, false, kDexMemAccessWord }, }; static const MIRDef mirs[] = { DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 11u), @@ -306,7 +315,7 @@ TEST_F(LocalValueNumberingTest, UniquePreserve2) { TEST_F(LocalValueNumberingTest, UniquePreserveAndEscape) { static const IFieldDef ifields[] = { - { 1u, 1u, 1u, false }, + { 1u, 1u, 1u, false, kDexMemAccessWord }, }; static const MIRDef mirs[] = { DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 10u), @@ -331,8 +340,8 @@ TEST_F(LocalValueNumberingTest, UniquePreserveAndEscape) { TEST_F(LocalValueNumberingTest, Volatile) { static const IFieldDef ifields[] = { - { 1u, 1u, 1u, false }, - { 2u, 1u, 2u, true }, + { 1u, 1u, 1u, false, kDexMemAccessWord }, + { 2u, 1u, 2u, true, kDexMemAccessWord }, }; static const MIRDef mirs[] = { DEF_IGET(Instruction::IGET, 0u, 10u, 1u), // Volatile. @@ -358,9 +367,9 @@ TEST_F(LocalValueNumberingTest, Volatile) { TEST_F(LocalValueNumberingTest, UnresolvedIField) { static const IFieldDef ifields[] = { - { 1u, 1u, 1u, false }, // Resolved field #1. - { 2u, 1u, 2u, false }, // Resolved field #2. - { 3u, 0u, 0u, false }, // Unresolved field. + { 1u, 1u, 1u, false, kDexMemAccessWord }, // Resolved field #1. + { 2u, 1u, 2u, false, kDexMemAccessWide }, // Resolved field #2. + { 3u, 0u, 0u, false, kDexMemAccessWord }, // Unresolved field. }; static const MIRDef mirs[] = { DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 20u), @@ -407,9 +416,9 @@ TEST_F(LocalValueNumberingTest, UnresolvedIField) { TEST_F(LocalValueNumberingTest, UnresolvedSField) { static const SFieldDef sfields[] = { - { 1u, 1u, 1u, false }, // Resolved field #1. - { 2u, 1u, 2u, false }, // Resolved field #2. - { 3u, 0u, 0u, false }, // Unresolved field. + { 1u, 1u, 1u, false, kDexMemAccessWord }, // Resolved field #1. + { 2u, 1u, 2u, false, kDexMemAccessWide }, // Resolved field #2. + { 3u, 0u, 0u, false, kDexMemAccessWord }, // Unresolved field. }; static const MIRDef mirs[] = { DEF_SGET(Instruction::SGET, 0u, 0u), // Resolved field #1. @@ -438,11 +447,11 @@ TEST_F(LocalValueNumberingTest, UnresolvedSField) { TEST_F(LocalValueNumberingTest, UninitializedSField) { static const IFieldDef ifields[] = { - { 1u, 1u, 1u, false }, // Resolved field #1. + { 1u, 1u, 1u, false, kDexMemAccessWord }, // Resolved field #1. }; static const SFieldDef sfields[] = { - { 1u, 1u, 1u, false }, // Resolved field #1. - { 2u, 1u, 2u, false }, // Resolved field #2; uninitialized. + { 1u, 1u, 1u, false, kDexMemAccessWord }, // Resolved field #1. + { 2u, 1u, 2u, false, kDexMemAccessWord }, // Resolved field #2; uninitialized. }; static const MIRDef mirs[] = { DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 200u), @@ -487,11 +496,11 @@ TEST_F(LocalValueNumberingTest, ConstString) { TEST_F(LocalValueNumberingTest, SameValueInDifferentMemoryLocations) { static const IFieldDef ifields[] = { - { 1u, 1u, 1u, false }, - { 2u, 1u, 2u, false }, + { 1u, 1u, 1u, false, kDexMemAccessWord }, + { 2u, 1u, 2u, false, kDexMemAccessWord }, }; static const SFieldDef sfields[] = { - { 3u, 1u, 3u, false }, + { 3u, 1u, 3u, false, kDexMemAccessWord }, }; static const MIRDef mirs[] = { DEF_UNIQUE_REF(Instruction::NEW_ARRAY, 201u), @@ -551,12 +560,12 @@ TEST_F(LocalValueNumberingTest, UniqueArrayAliasing) { TEST_F(LocalValueNumberingTest, EscapingRefs) { static const IFieldDef ifields[] = { - { 1u, 1u, 1u, false }, // Field #1. - { 2u, 1u, 2u, false }, // Field #2. - { 3u, 1u, 3u, false }, // Reference field for storing escaping refs. - { 4u, 1u, 4u, false }, // Wide. - { 5u, 0u, 0u, false }, // Unresolved field, int. - { 6u, 0u, 0u, false }, // Unresolved field, wide. + { 1u, 1u, 1u, false, kDexMemAccessWord }, // Field #1. + { 2u, 1u, 2u, false, kDexMemAccessWord }, // Field #2. + { 3u, 1u, 3u, false, kDexMemAccessObject }, // For storing escaping refs. + { 4u, 1u, 4u, false, kDexMemAccessWide }, // Wide. + { 5u, 0u, 0u, false, kDexMemAccessWord }, // Unresolved field, int. + { 6u, 0u, 0u, false, kDexMemAccessWide }, // Unresolved field, wide. }; static const MIRDef mirs[] = { DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 20u), @@ -634,11 +643,11 @@ TEST_F(LocalValueNumberingTest, EscapingArrayRefs) { TEST_F(LocalValueNumberingTest, StoringSameValueKeepsMemoryVersion) { static const IFieldDef ifields[] = { - { 1u, 1u, 1u, false }, - { 2u, 1u, 2u, false }, + { 1u, 1u, 1u, false, kDexMemAccessWord }, + { 2u, 1u, 2u, false, kDexMemAccessWord }, }; static const SFieldDef sfields[] = { - { 2u, 1u, 2u, false }, + { 2u, 1u, 2u, false, kDexMemAccessWord }, }; static const MIRDef mirs[] = { DEF_IGET(Instruction::IGET, 0u, 30u, 0u), @@ -716,8 +725,8 @@ TEST_F(LocalValueNumberingTest, FilledNewArrayTracking) { TEST_F(LocalValueNumberingTest, ClInitOnSget) { static const SFieldDef sfields[] = { - { 0u, 1u, 0u, false }, - { 1u, 2u, 1u, false }, + { 0u, 1u, 0u, false, kDexMemAccessObject }, + { 1u, 2u, 1u, false, kDexMemAccessObject }, }; static const MIRDef mirs[] = { DEF_SGET(Instruction::SGET_OBJECT, 0u, 0u), diff --git a/compiler/dex/mir_analysis.cc b/compiler/dex/mir_analysis.cc index 44f69ba67..7b53b1490 100644 --- a/compiler/dex/mir_analysis.cc +++ b/compiler/dex/mir_analysis.cc @@ -21,6 +21,7 @@ #include "dataflow_iterator-inl.h" #include "dex_instruction.h" #include "dex_instruction-inl.h" +#include "dex/mir_field_info.h" #include "dex/verified_method.h" #include "dex/quick/dex_file_method_inliner.h" #include "dex/quick/dex_file_to_method_inliner_map.h" @@ -1204,6 +1205,8 @@ void MIRGraph::DoCacheFieldLoweringInfo() { ScopedArenaAllocator allocator(&cu_->arena_stack); uint16_t* field_idxs = reinterpret_cast(allocator.Alloc(max_refs * sizeof(uint16_t), kArenaAllocMisc)); + DexMemAccessType* field_types = reinterpret_cast( + allocator.Alloc(max_refs * sizeof(DexMemAccessType), kArenaAllocMisc)); // Find IGET/IPUT/SGET/SPUT insns, store IGET/IPUT fields at the beginning, SGET/SPUT at the end. size_t ifield_pos = 0u; @@ -1214,38 +1217,41 @@ void MIRGraph::DoCacheFieldLoweringInfo() { continue; } for (MIR* mir = bb->first_mir_insn; mir != nullptr; mir = mir->next) { - if (mir->dalvikInsn.opcode >= Instruction::IGET && - mir->dalvikInsn.opcode <= Instruction::SPUT_SHORT) { - // Get field index and try to find it among existing indexes. If found, it's usually among - // the last few added, so we'll start the search from ifield_pos/sfield_pos. Though this - // is a linear search, it actually performs much better than map based approach. - if (mir->dalvikInsn.opcode <= Instruction::IPUT_SHORT) { - uint16_t field_idx = mir->dalvikInsn.vC; - size_t i = ifield_pos; - while (i != 0u && field_idxs[i - 1] != field_idx) { - --i; - } - if (i != 0u) { - mir->meta.ifield_lowering_info = i - 1; - } else { - mir->meta.ifield_lowering_info = ifield_pos; - field_idxs[ifield_pos++] = field_idx; - } + // Get field index and try to find it among existing indexes. If found, it's usually among + // the last few added, so we'll start the search from ifield_pos/sfield_pos. Though this + // is a linear search, it actually performs much better than map based approach. + if (IsInstructionIGetOrIPut(mir->dalvikInsn.opcode)) { + uint16_t field_idx = mir->dalvikInsn.vC; + size_t i = ifield_pos; + while (i != 0u && field_idxs[i - 1] != field_idx) { + --i; + } + if (i != 0u) { + mir->meta.ifield_lowering_info = i - 1; + DCHECK_EQ(field_types[i - 1], IGetOrIPutMemAccessType(mir->dalvikInsn.opcode)); + } else { + mir->meta.ifield_lowering_info = ifield_pos; + field_idxs[ifield_pos] = field_idx; + field_types[ifield_pos] = IGetOrIPutMemAccessType(mir->dalvikInsn.opcode); + ++ifield_pos; + } + } else if (IsInstructionSGetOrSPut(mir->dalvikInsn.opcode)) { + uint16_t field_idx = mir->dalvikInsn.vB; + size_t i = sfield_pos; + while (i != max_refs && field_idxs[i] != field_idx) { + ++i; + } + if (i != max_refs) { + mir->meta.sfield_lowering_info = max_refs - i - 1u; + DCHECK_EQ(field_types[i], SGetOrSPutMemAccessType(mir->dalvikInsn.opcode)); } else { - uint16_t field_idx = mir->dalvikInsn.vB; - size_t i = sfield_pos; - while (i != max_refs && field_idxs[i] != field_idx) { - ++i; - } - if (i != max_refs) { - mir->meta.sfield_lowering_info = max_refs - i - 1u; - } else { - mir->meta.sfield_lowering_info = max_refs - sfield_pos; - field_idxs[--sfield_pos] = field_idx; - } + mir->meta.sfield_lowering_info = max_refs - sfield_pos; + --sfield_pos; + field_idxs[sfield_pos] = field_idx; + field_types[sfield_pos] = SGetOrSPutMemAccessType(mir->dalvikInsn.opcode); } - DCHECK_LE(ifield_pos, sfield_pos); } + DCHECK_LE(ifield_pos, sfield_pos); } } @@ -1254,7 +1260,7 @@ void MIRGraph::DoCacheFieldLoweringInfo() { DCHECK_EQ(ifield_lowering_infos_.size(), 0u); ifield_lowering_infos_.reserve(ifield_pos); for (size_t pos = 0u; pos != ifield_pos; ++pos) { - ifield_lowering_infos_.push_back(MirIFieldLoweringInfo(field_idxs[pos])); + ifield_lowering_infos_.push_back(MirIFieldLoweringInfo(field_idxs[pos], field_types[pos])); } MirIFieldLoweringInfo::Resolve(cu_->compiler_driver, GetCurrentDexCompilationUnit(), ifield_lowering_infos_.data(), ifield_pos); @@ -1266,7 +1272,7 @@ void MIRGraph::DoCacheFieldLoweringInfo() { sfield_lowering_infos_.reserve(max_refs - sfield_pos); for (size_t pos = max_refs; pos != sfield_pos;) { --pos; - sfield_lowering_infos_.push_back(MirSFieldLoweringInfo(field_idxs[pos])); + sfield_lowering_infos_.push_back(MirSFieldLoweringInfo(field_idxs[pos], field_types[pos])); } MirSFieldLoweringInfo::Resolve(cu_->compiler_driver, GetCurrentDexCompilationUnit(), sfield_lowering_infos_.data(), max_refs - sfield_pos); @@ -1329,19 +1335,10 @@ void MIRGraph::DoCacheMethodLoweringInfo() { continue; } for (MIR* mir = bb->first_mir_insn; mir != nullptr; mir = mir->next) { - if (mir->dalvikInsn.opcode >= Instruction::INVOKE_VIRTUAL && - mir->dalvikInsn.opcode <= Instruction::INVOKE_INTERFACE_RANGE && - mir->dalvikInsn.opcode != Instruction::RETURN_VOID_BARRIER) { + if (IsInstructionInvoke(mir->dalvikInsn.opcode)) { // Decode target method index and invoke type. - uint16_t target_method_idx; - uint16_t invoke_type_idx; - if (mir->dalvikInsn.opcode <= Instruction::INVOKE_INTERFACE) { - target_method_idx = mir->dalvikInsn.vB; - invoke_type_idx = mir->dalvikInsn.opcode - Instruction::INVOKE_VIRTUAL; - } else { - target_method_idx = mir->dalvikInsn.vB; - invoke_type_idx = mir->dalvikInsn.opcode - Instruction::INVOKE_VIRTUAL_RANGE; - } + uint16_t target_method_idx = mir->dalvikInsn.vB; + DexInvokeType invoke_type_idx = InvokeInstructionType(mir->dalvikInsn.opcode); // Find devirtualization target. // TODO: The devirt map is ordered by the dex pc here. Is there a way to get INVOKEs diff --git a/compiler/dex/mir_field_info.cc b/compiler/dex/mir_field_info.cc index 1db3b5b91..53afcad87 100644 --- a/compiler/dex/mir_field_info.cc +++ b/compiler/dex/mir_field_info.cc @@ -35,7 +35,7 @@ void MirIFieldLoweringInfo::Resolve(CompilerDriver* compiler_driver, DCHECK(field_infos != nullptr); DCHECK_NE(count, 0u); for (auto it = field_infos, end = field_infos + count; it != end; ++it) { - MirIFieldLoweringInfo unresolved(it->field_idx_); + MirIFieldLoweringInfo unresolved(it->field_idx_, it->MemAccessType()); DCHECK_EQ(memcmp(&unresolved, &*it, sizeof(*it)), 0); } } @@ -66,6 +66,7 @@ void MirIFieldLoweringInfo::Resolve(CompilerDriver* compiler_driver, std::pair fast_path = compiler_driver->IsFastInstanceField( dex_cache.Get(), referrer_class.Get(), resolved_field, field_idx); it->flags_ = 0u | // Without kFlagIsStatic. + (it->flags_ & (kMemAccessTypeMask << kBitMemAccessTypeBegin)) | (is_volatile ? kFlagIsVolatile : 0u) | (fast_path.first ? kFlagFastGet : 0u) | (fast_path.second ? kFlagFastPut : 0u); @@ -79,7 +80,7 @@ void MirSFieldLoweringInfo::Resolve(CompilerDriver* compiler_driver, DCHECK(field_infos != nullptr); DCHECK_NE(count, 0u); for (auto it = field_infos, end = field_infos + count; it != end; ++it) { - MirSFieldLoweringInfo unresolved(it->field_idx_); + MirSFieldLoweringInfo unresolved(it->field_idx_, it->MemAccessType()); // In 64-bit builds, there's padding after storage_index_, don't include it in memcmp. size_t size = OFFSETOF_MEMBER(MirSFieldLoweringInfo, storage_index_) + sizeof(it->storage_index_); @@ -114,6 +115,7 @@ void MirSFieldLoweringInfo::Resolve(CompilerDriver* compiler_driver, std::pair fast_path = compiler_driver->IsFastStaticField( dex_cache.Get(), referrer_class, resolved_field, field_idx, &it->storage_index_); uint16_t flags = kFlagIsStatic | + (it->flags_ & (kMemAccessTypeMask << kBitMemAccessTypeBegin)) | (is_volatile ? kFlagIsVolatile : 0u) | (fast_path.first ? kFlagFastGet : 0u) | (fast_path.second ? kFlagFastPut : 0u); diff --git a/compiler/dex/mir_field_info.h b/compiler/dex/mir_field_info.h index e97f7a00f..ff427f88d 100644 --- a/compiler/dex/mir_field_info.h +++ b/compiler/dex/mir_field_info.h @@ -20,6 +20,7 @@ #include "base/macros.h" #include "dex_file.h" #include "offsets.h" +#include "utils/dex_instruction_utils.h" namespace art { @@ -63,18 +64,27 @@ class MirFieldInfo { return (flags_ & kFlagIsVolatile) != 0u; } + DexMemAccessType MemAccessType() const { + return static_cast((flags_ >> kBitMemAccessTypeBegin) & kMemAccessTypeMask); + } + protected: enum { kBitIsStatic = 0, kBitIsVolatile, - kFieldInfoBitEnd + kBitMemAccessTypeBegin, + kBitMemAccessTypeEnd = kBitMemAccessTypeBegin + 3, // 3 bits for raw type. + kFieldInfoBitEnd = kBitMemAccessTypeEnd }; static constexpr uint16_t kFlagIsVolatile = 1u << kBitIsVolatile; static constexpr uint16_t kFlagIsStatic = 1u << kBitIsStatic; + static constexpr uint16_t kMemAccessTypeMask = 7u; + static_assert((1u << (kBitMemAccessTypeEnd - kBitMemAccessTypeBegin)) - 1u == kMemAccessTypeMask, + "Invalid raw type mask"); - MirFieldInfo(uint16_t field_idx, uint16_t flags) + MirFieldInfo(uint16_t field_idx, uint16_t flags, DexMemAccessType type) : field_idx_(field_idx), - flags_(flags), + flags_(flags | static_cast(type) << kBitMemAccessTypeBegin), declaring_field_idx_(0u), declaring_class_idx_(0u), declaring_dex_file_(nullptr) { @@ -107,8 +117,8 @@ class MirIFieldLoweringInfo : public MirFieldInfo { LOCKS_EXCLUDED(Locks::mutator_lock_); // Construct an unresolved instance field lowering info. - explicit MirIFieldLoweringInfo(uint16_t field_idx) - : MirFieldInfo(field_idx, kFlagIsVolatile), // Without kFlagIsStatic. + explicit MirIFieldLoweringInfo(uint16_t field_idx, DexMemAccessType type) + : MirFieldInfo(field_idx, kFlagIsVolatile, type), // Without kFlagIsStatic. field_offset_(0u) { } @@ -155,8 +165,8 @@ class MirSFieldLoweringInfo : public MirFieldInfo { LOCKS_EXCLUDED(Locks::mutator_lock_); // Construct an unresolved static field lowering info. - explicit MirSFieldLoweringInfo(uint16_t field_idx) - : MirFieldInfo(field_idx, kFlagIsVolatile | kFlagIsStatic), + explicit MirSFieldLoweringInfo(uint16_t field_idx, DexMemAccessType type) + : MirFieldInfo(field_idx, kFlagIsVolatile | kFlagIsStatic, type), field_offset_(0u), storage_index_(DexFile::kDexNoIndex) { } diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h index d77ad6f76..63b1f2d95 100644 --- a/compiler/dex/mir_graph.h +++ b/compiler/dex/mir_graph.h @@ -661,13 +661,29 @@ class MIRGraph { void DoCacheFieldLoweringInfo(); const MirIFieldLoweringInfo& GetIFieldLoweringInfo(MIR* mir) const { - DCHECK_LT(mir->meta.ifield_lowering_info, ifield_lowering_infos_.size()); - return ifield_lowering_infos_[mir->meta.ifield_lowering_info]; + return GetIFieldLoweringInfo(mir->meta.ifield_lowering_info); + } + + const MirIFieldLoweringInfo& GetIFieldLoweringInfo(uint32_t lowering_info) const { + DCHECK_LT(lowering_info, ifield_lowering_infos_.size()); + return ifield_lowering_infos_[lowering_info]; + } + + size_t GetIFieldLoweringInfoCount() const { + return ifield_lowering_infos_.size(); } const MirSFieldLoweringInfo& GetSFieldLoweringInfo(MIR* mir) const { - DCHECK_LT(mir->meta.sfield_lowering_info, sfield_lowering_infos_.size()); - return sfield_lowering_infos_[mir->meta.sfield_lowering_info]; + return GetSFieldLoweringInfo(mir->meta.sfield_lowering_info); + } + + const MirSFieldLoweringInfo& GetSFieldLoweringInfo(uint32_t lowering_info) const { + DCHECK_LT(lowering_info, sfield_lowering_infos_.size()); + return sfield_lowering_infos_[lowering_info]; + } + + size_t GetSFieldLoweringInfoCount() const { + return sfield_lowering_infos_.size(); } void DoCacheMethodLoweringInfo(); @@ -1035,6 +1051,21 @@ class MIRGraph { bool ApplyGlobalValueNumberingGate(); bool ApplyGlobalValueNumbering(BasicBlock* bb); void ApplyGlobalValueNumberingEnd(); + + uint16_t GetGvnIFieldId(MIR* mir) const { + DCHECK(IsInstructionIGetOrIPut(mir->dalvikInsn.opcode)); + DCHECK_LT(mir->meta.ifield_lowering_info, ifield_lowering_infos_.size()); + DCHECK(temp_.gvn.ifield_ids_ != nullptr); + return temp_.gvn.ifield_ids_[mir->meta.ifield_lowering_info]; + } + + uint16_t GetGvnSFieldId(MIR* mir) const { + DCHECK(IsInstructionSGetOrSPut(mir->dalvikInsn.opcode)); + DCHECK_LT(mir->meta.sfield_lowering_info, sfield_lowering_infos_.size()); + DCHECK(temp_.gvn.sfield_ids_ != nullptr); + return temp_.gvn.sfield_ids_[mir->meta.sfield_lowering_info]; + } + /* * Type inference handling helpers. Because Dalvik's bytecode is not fully typed, * we have to do some work to figure out the sreg type. For some operations it is @@ -1300,6 +1331,8 @@ class MIRGraph { // Global value numbering. struct { GlobalValueNumbering* gvn; + uint16_t* ifield_ids_; // Part of GVN/LVN but cached here for LVN to avoid recalculation. + uint16_t* sfield_ids_; // Ditto. } gvn; } temp_; static const int kInvalidEntry = -1; diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc index d025d0816..fd564ed1d 100644 --- a/compiler/dex/mir_optimization.cc +++ b/compiler/dex/mir_optimization.cc @@ -19,6 +19,7 @@ #include "dataflow_iterator-inl.h" #include "global_value_numbering.h" #include "local_value_numbering.h" +#include "mir_field_info.h" #include "quick/dex_file_method_inliner.h" #include "quick/dex_file_to_method_inliner_map.h" #include "stack.h" @@ -217,10 +218,6 @@ static constexpr ConditionCode kIfCcZConditionCodes[] = { static_assert(arraysize(kIfCcZConditionCodes) == Instruction::IF_LEZ - Instruction::IF_EQZ + 1, "if_ccz_ccodes_size1"); -static constexpr bool IsInstructionIfCcZ(Instruction::Code opcode) { - return Instruction::IF_EQZ <= opcode && opcode <= Instruction::IF_LEZ; -} - static constexpr ConditionCode ConditionCodeForIfCcZ(Instruction::Code opcode) { return kIfCcZConditionCodes[opcode - Instruction::IF_EQZ]; } @@ -1159,8 +1156,7 @@ bool MIRGraph::EliminateClassInitChecksGate() { for (BasicBlock* bb = iter.Next(); bb != nullptr; bb = iter.Next()) { if (bb->block_type == kDalvikByteCode) { for (MIR* mir = bb->first_mir_insn; mir != nullptr; mir = mir->next) { - if (mir->dalvikInsn.opcode >= Instruction::SGET && - mir->dalvikInsn.opcode <= Instruction::SPUT_SHORT) { + if (IsInstructionSGetOrSPut(mir->dalvikInsn.opcode)) { const MirSFieldLoweringInfo& field_info = GetSFieldLoweringInfo(mir); if (!field_info.IsReferrersClass()) { DCHECK_LT(class_to_index_map.size(), 0xffffu); @@ -1176,8 +1172,7 @@ bool MIRGraph::EliminateClassInitChecksGate() { // Using offset/2 for index into temp_.cice.indexes. temp_.cice.indexes[mir->offset / 2u] = index; } - } else if (mir->dalvikInsn.opcode == Instruction::INVOKE_STATIC || - mir->dalvikInsn.opcode == Instruction::INVOKE_STATIC_RANGE) { + } else if (IsInstructionInvokeStatic(mir->dalvikInsn.opcode)) { const MirMethodLoweringInfo& method_info = GetMethodLoweringInfo(mir); DCHECK(method_info.IsStatic()); if (method_info.FastPath() && !method_info.IsReferrersClass()) { @@ -1261,12 +1256,10 @@ bool MIRGraph::EliminateClassInitChecks(BasicBlock* bb) { // NOTE: index != 0xffff does not guarantee that this is an SGET/SPUT/INVOKE_STATIC. // Dex instructions with width 1 can have the same offset/2. - if (mir->dalvikInsn.opcode >= Instruction::SGET && - mir->dalvikInsn.opcode <= Instruction::SPUT_SHORT) { + if (IsInstructionSGetOrSPut(mir->dalvikInsn.opcode)) { check_initialization = true; check_dex_cache = true; - } else if (mir->dalvikInsn.opcode == Instruction::INVOKE_STATIC || - mir->dalvikInsn.opcode == Instruction::INVOKE_STATIC_RANGE) { + } else if (IsInstructionInvokeStatic(mir->dalvikInsn.opcode)) { check_initialization = true; // NOTE: INVOKE_STATIC doesn't guarantee that the type will be in the dex cache. } @@ -1333,6 +1326,10 @@ bool MIRGraph::ApplyGlobalValueNumberingGate() { DCHECK(temp_scoped_alloc_ == nullptr); temp_scoped_alloc_.reset(ScopedArenaAllocator::Create(&cu_->arena_stack)); + temp_.gvn.ifield_ids_ = + GlobalValueNumbering::PrepareGvnFieldIds(temp_scoped_alloc_.get(), ifield_lowering_infos_); + temp_.gvn.sfield_ids_ = + GlobalValueNumbering::PrepareGvnFieldIds(temp_scoped_alloc_.get(), sfield_lowering_infos_); DCHECK(temp_.gvn.gvn == nullptr); temp_.gvn.gvn = new (temp_scoped_alloc_.get()) GlobalValueNumbering( cu_, temp_scoped_alloc_.get(), GlobalValueNumbering::kModeGvn); @@ -1378,6 +1375,8 @@ void MIRGraph::ApplyGlobalValueNumberingEnd() { delete temp_.gvn.gvn; temp_.gvn.gvn = nullptr; + temp_.gvn.ifield_ids_ = nullptr; + temp_.gvn.sfield_ids_ = nullptr; DCHECK(temp_scoped_alloc_ != nullptr); temp_scoped_alloc_.reset(); } @@ -1396,7 +1395,8 @@ void MIRGraph::ComputeInlineIFieldLoweringInfo(uint16_t field_idx, MIR* invoke, cu_, cu_->class_loader, cu_->class_linker, *target.dex_file, nullptr /* code_item not used */, 0u /* class_def_idx not used */, target.dex_method_index, 0u /* access_flags not used */, nullptr /* verified_method not used */); - MirIFieldLoweringInfo inlined_field_info(field_idx); + DexMemAccessType type = IGetOrIPutMemAccessType(iget_or_iput->dalvikInsn.opcode); + MirIFieldLoweringInfo inlined_field_info(field_idx, type); MirIFieldLoweringInfo::Resolve(cu_->compiler_driver, &inlined_unit, &inlined_field_info, 1u); DCHECK(inlined_field_info.IsResolved()); @@ -1544,6 +1544,14 @@ bool MIRGraph::BuildExtendedBBList(class BasicBlock* bb) { } void MIRGraph::BasicBlockOptimization() { + if ((cu_->disable_opt & (1 << kLocalValueNumbering)) == 0) { + temp_scoped_alloc_.reset(ScopedArenaAllocator::Create(&cu_->arena_stack)); + temp_.gvn.ifield_ids_ = + GlobalValueNumbering::PrepareGvnFieldIds(temp_scoped_alloc_.get(), ifield_lowering_infos_); + temp_.gvn.sfield_ids_ = + GlobalValueNumbering::PrepareGvnFieldIds(temp_scoped_alloc_.get(), sfield_lowering_infos_); + } + if ((cu_->disable_opt & (1 << kSuppressExceptionEdges)) != 0) { ClearAllVisitedFlags(); PreOrderDfsIterator iter2(this); @@ -1560,6 +1568,11 @@ void MIRGraph::BasicBlockOptimization() { BasicBlockOpt(bb); } } + + // Clean up after LVN. + temp_.gvn.ifield_ids_ = nullptr; + temp_.gvn.sfield_ids_ = nullptr; + temp_scoped_alloc_.reset(); } } // namespace art diff --git a/compiler/dex/mir_optimization_test.cc b/compiler/dex/mir_optimization_test.cc index 8874fafa0..c794cc61f 100644 --- a/compiler/dex/mir_optimization_test.cc +++ b/compiler/dex/mir_optimization_test.cc @@ -19,6 +19,7 @@ #include "compiler_internals.h" #include "dataflow_iterator.h" #include "dataflow_iterator-inl.h" +#include "dex/mir_field_info.h" #include "gtest/gtest.h" namespace art { @@ -236,15 +237,17 @@ class MirOptimizationTest : public testing::Test { ASSERT_LT(def->bbid, cu_.mir_graph->block_list_.size()); BasicBlock* bb = cu_.mir_graph->block_list_[def->bbid]; bb->AppendMIR(mir); - if (def->opcode >= Instruction::SGET && def->opcode <= Instruction::SPUT_SHORT) { - ASSERT_LT(def->field_or_method_info, cu_.mir_graph->sfield_lowering_infos_.size()); - mir->meta.sfield_lowering_info = def->field_or_method_info; - } else if (def->opcode >= Instruction::IGET && def->opcode <= Instruction::IPUT_SHORT) { + if (IsInstructionIGetOrIPut(def->opcode)) { ASSERT_LT(def->field_or_method_info, cu_.mir_graph->ifield_lowering_infos_.size()); mir->meta.ifield_lowering_info = def->field_or_method_info; - } else if (def->opcode >= Instruction::INVOKE_VIRTUAL && - def->opcode < Instruction::INVOKE_INTERFACE_RANGE && - def->opcode != Instruction::RETURN_VOID_BARRIER) { + ASSERT_EQ(cu_.mir_graph->ifield_lowering_infos_[def->field_or_method_info].MemAccessType(), + IGetOrIPutMemAccessType(def->opcode)); + } else if (IsInstructionSGetOrSPut(def->opcode)) { + ASSERT_LT(def->field_or_method_info, cu_.mir_graph->sfield_lowering_infos_.size()); + mir->meta.sfield_lowering_info = def->field_or_method_info; + ASSERT_EQ(cu_.mir_graph->sfield_lowering_infos_[def->field_or_method_info].MemAccessType(), + SGetOrSPutMemAccessType(def->opcode)); + } else if (IsInstructionInvoke(def->opcode)) { ASSERT_LT(def->field_or_method_info, cu_.mir_graph->method_lowering_infos_.size()); mir->meta.method_lowering_info = def->field_or_method_info; } @@ -294,6 +297,7 @@ class ClassInitCheckEliminationTest : public MirOptimizationTest { uintptr_t declaring_dex_file; uint16_t declaring_class_idx; uint16_t declaring_field_idx; + DexMemAccessType type; }; void DoPrepareSFields(const SFieldDef* defs, size_t count) { @@ -301,12 +305,12 @@ class ClassInitCheckEliminationTest : public MirOptimizationTest { cu_.mir_graph->sfield_lowering_infos_.reserve(count); for (size_t i = 0u; i != count; ++i) { const SFieldDef* def = &defs[i]; - MirSFieldLoweringInfo field_info(def->field_idx); + MirSFieldLoweringInfo field_info(def->field_idx, def->type); if (def->declaring_dex_file != 0u) { field_info.declaring_dex_file_ = reinterpret_cast(def->declaring_dex_file); field_info.declaring_class_idx_ = def->declaring_class_idx; field_info.declaring_field_idx_ = def->declaring_field_idx; - field_info.flags_ = MirSFieldLoweringInfo::kFlagIsStatic; + // We don't care about the volatile flag in these tests. } ASSERT_EQ(def->declaring_dex_file != 0u, field_info.IsResolved()); ASSERT_FALSE(field_info.IsClassInitialized()); @@ -343,6 +347,7 @@ class NullCheckEliminationTest : public MirOptimizationTest { uintptr_t declaring_dex_file; uint16_t declaring_class_idx; uint16_t declaring_field_idx; + DexMemAccessType type; }; void DoPrepareIFields(const IFieldDef* defs, size_t count) { @@ -350,11 +355,12 @@ class NullCheckEliminationTest : public MirOptimizationTest { cu_.mir_graph->ifield_lowering_infos_.reserve(count); for (size_t i = 0u; i != count; ++i) { const IFieldDef* def = &defs[i]; - MirIFieldLoweringInfo field_info(def->field_idx); + MirIFieldLoweringInfo field_info(def->field_idx, def->type); if (def->declaring_dex_file != 0u) { field_info.declaring_dex_file_ = reinterpret_cast(def->declaring_dex_file); field_info.declaring_class_idx_ = def->declaring_class_idx; field_info.declaring_field_idx_ = def->declaring_field_idx; + // We don't care about the volatile flag in these tests. } ASSERT_EQ(def->declaring_dex_file != 0u, field_info.IsResolved()); cu_.mir_graph->ifield_lowering_infos_.push_back(field_info); @@ -393,12 +399,12 @@ class NullCheckEliminationTest : public MirOptimizationTest { TEST_F(ClassInitCheckEliminationTest, SingleBlock) { static const SFieldDef sfields[] = { - { 0u, 1u, 0u, 0u }, - { 1u, 1u, 1u, 1u }, - { 2u, 1u, 2u, 2u }, - { 3u, 1u, 3u, 3u }, // Same declaring class as sfield[4]. - { 4u, 1u, 3u, 4u }, // Same declaring class as sfield[3]. - { 5u, 0u, 0u, 0u }, // Unresolved. + { 0u, 1u, 0u, 0u, kDexMemAccessWord }, + { 1u, 1u, 1u, 1u, kDexMemAccessWord }, + { 2u, 1u, 2u, 2u, kDexMemAccessWord }, + { 3u, 1u, 3u, 3u, kDexMemAccessWord }, // Same declaring class as sfield[4]. + { 4u, 1u, 3u, 4u, kDexMemAccessWord }, // Same declaring class as sfield[3]. + { 5u, 0u, 0u, 0u, kDexMemAccessWord }, // Unresolved. }; static const MIRDef mirs[] = { DEF_SGET_SPUT(3u, Instruction::SPUT, 0u, 5u), // Unresolved. @@ -432,9 +438,9 @@ TEST_F(ClassInitCheckEliminationTest, SingleBlock) { TEST_F(ClassInitCheckEliminationTest, SingleBlockWithInvokes) { static const SFieldDef sfields[] = { - { 0u, 1u, 0u, 0u }, - { 1u, 1u, 1u, 1u }, - { 2u, 1u, 2u, 2u }, + { 0u, 1u, 0u, 0u, kDexMemAccessWord }, + { 1u, 1u, 1u, 1u, kDexMemAccessWord }, + { 2u, 1u, 2u, 2u, kDexMemAccessWord }, }; static const MethodDef methods[] = { { 0u, 1u, 0u, 0u, kStatic, kStatic, false, false }, @@ -473,17 +479,17 @@ TEST_F(ClassInitCheckEliminationTest, SingleBlockWithInvokes) { TEST_F(ClassInitCheckEliminationTest, Diamond) { static const SFieldDef sfields[] = { - { 0u, 1u, 0u, 0u }, - { 1u, 1u, 1u, 1u }, - { 2u, 1u, 2u, 2u }, - { 3u, 1u, 3u, 3u }, - { 4u, 1u, 4u, 4u }, - { 5u, 1u, 5u, 5u }, - { 6u, 1u, 6u, 6u }, - { 7u, 1u, 7u, 7u }, - { 8u, 1u, 8u, 8u }, // Same declaring class as sfield[9]. - { 9u, 1u, 8u, 9u }, // Same declaring class as sfield[8]. - { 10u, 0u, 0u, 0u }, // Unresolved. + { 0u, 1u, 0u, 0u, kDexMemAccessWord }, + { 1u, 1u, 1u, 1u, kDexMemAccessWord }, + { 2u, 1u, 2u, 2u, kDexMemAccessWord }, + { 3u, 1u, 3u, 3u, kDexMemAccessWord }, + { 4u, 1u, 4u, 4u, kDexMemAccessWord }, + { 5u, 1u, 5u, 5u, kDexMemAccessWord }, + { 6u, 1u, 6u, 6u, kDexMemAccessWord }, + { 7u, 1u, 7u, 7u, kDexMemAccessWord }, + { 8u, 1u, 8u, 8u, kDexMemAccessWord }, // Same declaring class as sfield[9]. + { 9u, 1u, 8u, 9u, kDexMemAccessWord }, // Same declaring class as sfield[8]. + { 10u, 0u, 0u, 0u, kDexMemAccessWord }, // Unresolved. }; static const MIRDef mirs[] = { // NOTE: MIRs here are ordered by unique tests. They will be put into appropriate blocks. @@ -539,11 +545,11 @@ TEST_F(ClassInitCheckEliminationTest, Diamond) { TEST_F(ClassInitCheckEliminationTest, DiamondWithInvokes) { static const SFieldDef sfields[] = { - { 0u, 1u, 0u, 0u }, - { 1u, 1u, 1u, 1u }, - { 2u, 1u, 2u, 2u }, - { 3u, 1u, 3u, 3u }, - { 4u, 1u, 4u, 4u }, + { 0u, 1u, 0u, 0u, kDexMemAccessWord }, + { 1u, 1u, 1u, 1u, kDexMemAccessWord }, + { 2u, 1u, 2u, 2u, kDexMemAccessWord }, + { 3u, 1u, 3u, 3u, kDexMemAccessWord }, + { 4u, 1u, 4u, 4u, kDexMemAccessWord }, }; static const MethodDef methods[] = { { 0u, 1u, 0u, 0u, kStatic, kStatic, false, false }, @@ -600,9 +606,9 @@ TEST_F(ClassInitCheckEliminationTest, DiamondWithInvokes) { TEST_F(ClassInitCheckEliminationTest, Loop) { static const SFieldDef sfields[] = { - { 0u, 1u, 0u, 0u }, - { 1u, 1u, 1u, 1u }, - { 2u, 1u, 2u, 2u }, + { 0u, 1u, 0u, 0u, kDexMemAccessWord }, + { 1u, 1u, 1u, 1u, kDexMemAccessWord }, + { 2u, 1u, 2u, 2u, kDexMemAccessWord }, }; static const MIRDef mirs[] = { DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 0u), @@ -631,7 +637,7 @@ TEST_F(ClassInitCheckEliminationTest, Loop) { TEST_F(ClassInitCheckEliminationTest, LoopWithInvokes) { static const SFieldDef sfields[] = { - { 0u, 1u, 0u, 0u }, + { 0u, 1u, 0u, 0u, kDexMemAccessWord }, }; static const MethodDef methods[] = { { 0u, 1u, 0u, 0u, kStatic, kStatic, false, false }, @@ -671,10 +677,10 @@ TEST_F(ClassInitCheckEliminationTest, LoopWithInvokes) { TEST_F(ClassInitCheckEliminationTest, Catch) { static const SFieldDef sfields[] = { - { 0u, 1u, 0u, 0u }, - { 1u, 1u, 1u, 1u }, - { 2u, 1u, 2u, 2u }, - { 3u, 1u, 3u, 3u }, + { 0u, 1u, 0u, 0u, kDexMemAccessWord }, + { 1u, 1u, 1u, 1u, kDexMemAccessWord }, + { 2u, 1u, 2u, 2u, kDexMemAccessWord }, + { 3u, 1u, 3u, 3u, kDexMemAccessWord }, }; static const MIRDef mirs[] = { DEF_SGET_SPUT(3u, Instruction::SGET, 0u, 0u), // Before the exception edge. @@ -707,9 +713,9 @@ TEST_F(ClassInitCheckEliminationTest, Catch) { TEST_F(NullCheckEliminationTest, SingleBlock) { static const IFieldDef ifields[] = { - { 0u, 1u, 0u, 0u }, - { 1u, 1u, 0u, 1u }, - { 2u, 1u, 0u, 2u }, // Object. + { 0u, 1u, 0u, 0u, kDexMemAccessWord }, + { 1u, 1u, 0u, 1u, kDexMemAccessWord }, + { 2u, 1u, 0u, 2u, kDexMemAccessObject }, }; static const MIRDef mirs[] = { DEF_IGET_IPUT(3u, Instruction::IGET_OBJECT, 0u, 100u, 2u), @@ -768,9 +774,9 @@ TEST_F(NullCheckEliminationTest, SingleBlock) { TEST_F(NullCheckEliminationTest, Diamond) { static const IFieldDef ifields[] = { - { 0u, 1u, 0u, 0u }, - { 1u, 1u, 0u, 1u }, - { 2u, 1u, 0u, 2u }, // int[]. + { 0u, 1u, 0u, 0u, kDexMemAccessWord }, + { 1u, 1u, 0u, 1u, kDexMemAccessWord }, + { 2u, 1u, 0u, 2u, kDexMemAccessObject }, // int[]. }; static const MIRDef mirs[] = { // NOTE: MIRs here are ordered by unique tests. They will be put into appropriate blocks. @@ -816,8 +822,8 @@ TEST_F(NullCheckEliminationTest, Diamond) { TEST_F(NullCheckEliminationTest, Loop) { static const IFieldDef ifields[] = { - { 0u, 1u, 0u, 0u }, - { 1u, 1u, 1u, 1u }, + { 0u, 1u, 0u, 0u, kDexMemAccessWord }, + { 1u, 1u, 1u, 1u, kDexMemAccessWord }, }; static const MIRDef mirs[] = { DEF_IGET_IPUT(3u, Instruction::IGET, 0u, 100u, 0u), @@ -846,8 +852,8 @@ TEST_F(NullCheckEliminationTest, Loop) { TEST_F(NullCheckEliminationTest, Catch) { static const IFieldDef ifields[] = { - { 0u, 1u, 0u, 0u }, - { 1u, 1u, 1u, 1u }, + { 0u, 1u, 0u, 0u, kDexMemAccessWord }, + { 1u, 1u, 1u, 1u, kDexMemAccessWord }, }; static const MIRDef mirs[] = { DEF_IGET_IPUT(3u, Instruction::IGET, 0u, 100u, 0u), // Before the exception edge. diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc index c00f90b6e..4dd24cb9f 100644 --- a/compiler/dex/quick/gen_common.cc +++ b/compiler/dex/quick/gen_common.cc @@ -583,6 +583,7 @@ class StaticFieldSlowPath : public Mir2Lir::LIRSlowPath { void Mir2Lir::GenSput(MIR* mir, RegLocation rl_src, OpSize size) { const MirSFieldLoweringInfo& field_info = mir_graph_->GetSFieldLoweringInfo(mir); + DCHECK_EQ(SPutMemAccessType(mir->dalvikInsn.opcode), field_info.MemAccessType()); cu_->compiler_driver->ProcessedStaticField(field_info.FastPut(), field_info.IsReferrersClass()); if (!SLOW_FIELD_PATH && field_info.FastPut()) { DCHECK_GE(field_info.FieldOffset().Int32Value(), 0); @@ -701,6 +702,7 @@ void Mir2Lir::GenSput(MIR* mir, RegLocation rl_src, OpSize size) { void Mir2Lir::GenSget(MIR* mir, RegLocation rl_dest, OpSize size, Primitive::Type type) { const MirSFieldLoweringInfo& field_info = mir_graph_->GetSFieldLoweringInfo(mir); + DCHECK_EQ(SGetMemAccessType(mir->dalvikInsn.opcode), field_info.MemAccessType()); cu_->compiler_driver->ProcessedStaticField(field_info.FastGet(), field_info.IsReferrersClass()); if (!SLOW_FIELD_PATH && field_info.FastGet()) { @@ -839,6 +841,7 @@ void Mir2Lir::HandleSlowPaths() { void Mir2Lir::GenIGet(MIR* mir, int opt_flags, OpSize size, Primitive::Type type, RegLocation rl_dest, RegLocation rl_obj) { const MirIFieldLoweringInfo& field_info = mir_graph_->GetIFieldLoweringInfo(mir); + DCHECK_EQ(IGetMemAccessType(mir->dalvikInsn.opcode), field_info.MemAccessType()); cu_->compiler_driver->ProcessedInstanceField(field_info.FastGet()); if (!SLOW_FIELD_PATH && field_info.FastGet()) { RegisterClass reg_class = RegClassForFieldLoadStore(size, field_info.IsVolatile()); @@ -912,6 +915,7 @@ void Mir2Lir::GenIGet(MIR* mir, int opt_flags, OpSize size, Primitive::Type type void Mir2Lir::GenIPut(MIR* mir, int opt_flags, OpSize size, RegLocation rl_src, RegLocation rl_obj) { const MirIFieldLoweringInfo& field_info = mir_graph_->GetIFieldLoweringInfo(mir); + DCHECK_EQ(IPutMemAccessType(mir->dalvikInsn.opcode), field_info.MemAccessType()); cu_->compiler_driver->ProcessedInstanceField(field_info.FastPut()); if (!SLOW_FIELD_PATH && field_info.FastPut()) { RegisterClass reg_class = RegClassForFieldLoadStore(size, field_info.IsVolatile()); diff --git a/compiler/utils/dex_instruction_utils.h b/compiler/utils/dex_instruction_utils.h new file mode 100644 index 000000000..09d9419c0 --- /dev/null +++ b/compiler/utils/dex_instruction_utils.h @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_COMPILER_UTILS_DEX_INSTRUCTION_UTILS_H_ +#define ART_COMPILER_UTILS_DEX_INSTRUCTION_UTILS_H_ + +#include "dex_instruction.h" + +namespace art { + +// Dex invoke type corresponds to the ordering of INVOKE instructions; +// this order is the same for range and non-range invokes. +enum DexInvokeType : uint8_t { + kDexInvokeVirtual = 0, // invoke-virtual, invoke-virtual-range + kDexInvokeSuper, // invoke-super, invoke-super-range + kDexInvokeDirect, // invoke-direct, invoke-direct-range + kDexInvokeStatic, // invoke-static, invoke-static-range + kDexInvokeInterface, // invoke-interface, invoke-interface-range + kDexInvokeTypeCount +}; + +// Dex instruction memory access types correspond to the ordering of GET/PUT instructions; +// this order is the same for IGET, IPUT, SGET, SPUT, AGET and APUT. +enum DexMemAccessType : uint8_t { + kDexMemAccessWord = 0, // op 0; int or float, the actual type is not encoded. + kDexMemAccessWide, // op_WIDE 1; long or double, the actual type is not encoded. + kDexMemAccessObject, // op_OBJECT 2; the actual reference type is not encoded. + kDexMemAccessBoolean, // op_BOOLEAN 3 + kDexMemAccessByte, // op_BYTE 4 + kDexMemAccessChar, // op_CHAR 5 + kDexMemAccessShort, // op_SHORT 6 + kDexMemAccessTypeCount +}; + +std::ostream& operator<<(std::ostream& os, const DexMemAccessType& type); + +// NOTE: The following functions disregard quickened instructions. + +constexpr bool IsInstructionInvoke(Instruction::Code opcode) { + return Instruction::INVOKE_VIRTUAL <= opcode && opcode <= Instruction::INVOKE_INTERFACE_RANGE && + opcode != Instruction::RETURN_VOID_BARRIER; +} + +constexpr bool IsInstructionInvokeStatic(Instruction::Code opcode) { + return opcode == Instruction::INVOKE_STATIC || opcode == Instruction::INVOKE_STATIC_RANGE; +} + +constexpr bool IsInstructionIfCc(Instruction::Code opcode) { + return Instruction::IF_EQ <= opcode && opcode <= Instruction::IF_LE; +} + +constexpr bool IsInstructionIfCcZ(Instruction::Code opcode) { + return Instruction::IF_EQZ <= opcode && opcode <= Instruction::IF_LEZ; +} + +constexpr bool IsInstructionIGet(Instruction::Code code) { + return Instruction::IGET <= code && code <= Instruction::IGET_SHORT; +} + +constexpr bool IsInstructionIPut(Instruction::Code code) { + return Instruction::IPUT <= code && code <= Instruction::IPUT_SHORT; +} + +constexpr bool IsInstructionSGet(Instruction::Code code) { + return Instruction::SGET <= code && code <= Instruction::SGET_SHORT; +} + +constexpr bool IsInstructionSPut(Instruction::Code code) { + return Instruction::SPUT <= code && code <= Instruction::SPUT_SHORT; +} + +constexpr bool IsInstructionAGet(Instruction::Code code) { + return Instruction::AGET <= code && code <= Instruction::AGET_SHORT; +} + +constexpr bool IsInstructionAPut(Instruction::Code code) { + return Instruction::APUT <= code && code <= Instruction::APUT_SHORT; +} + +constexpr bool IsInstructionIGetOrIPut(Instruction::Code code) { + return Instruction::IGET <= code && code <= Instruction::IPUT_SHORT; +} + +constexpr bool IsInstructionSGetOrSPut(Instruction::Code code) { + return Instruction::SGET <= code && code <= Instruction::SPUT_SHORT; +} + +constexpr bool IsInstructionAGetOrAPut(Instruction::Code code) { + return Instruction::AGET <= code && code <= Instruction::APUT_SHORT; +} + +// TODO: Remove the #if guards below when we fully migrate to C++14. + +constexpr bool IsInvokeInstructionRange(Instruction::Code opcode) { +#if __cplusplus >= 201402 // C++14 allows the DCHECK() in constexpr functions. + DCHECK(IsInstructionInvoke(opcode)); +#endif + return opcode >= Instruction::INVOKE_VIRTUAL_RANGE; +} + +constexpr DexInvokeType InvokeInstructionType(Instruction::Code opcode) { +#if __cplusplus >= 201402 // C++14 allows the DCHECK() in constexpr functions. + DCHECK(IsInstructionInvoke(opcode)); +#endif + return static_cast(IsInvokeInstructionRange(opcode) + ? (opcode - Instruction::INVOKE_VIRTUAL_RANGE) + : (opcode - Instruction::INVOKE_VIRTUAL)); +} + +constexpr DexMemAccessType IGetMemAccessType(Instruction::Code code) { +#if __cplusplus >= 201402 // C++14 allows the DCHECK() in constexpr functions. + DCHECK(IsInstructionIGet(opcode)); +#endif + return static_cast(code - Instruction::IGET); +} + +constexpr DexMemAccessType IPutMemAccessType(Instruction::Code code) { +#if __cplusplus >= 201402 // C++14 allows the DCHECK() in constexpr functions. + DCHECK(IsInstructionIPut(opcode)); +#endif + return static_cast(code - Instruction::IPUT); +} + +constexpr DexMemAccessType SGetMemAccessType(Instruction::Code code) { +#if __cplusplus >= 201402 // C++14 allows the DCHECK() in constexpr functions. + DCHECK(IsInstructionSGet(opcode)); +#endif + return static_cast(code - Instruction::SGET); +} + +constexpr DexMemAccessType SPutMemAccessType(Instruction::Code code) { +#if __cplusplus >= 201402 // C++14 allows the DCHECK() in constexpr functions. + DCHECK(IsInstructionSPut(opcode)); +#endif + return static_cast(code - Instruction::SPUT); +} + +constexpr DexMemAccessType AGetMemAccessType(Instruction::Code code) { +#if __cplusplus >= 201402 // C++14 allows the DCHECK() in constexpr functions. + DCHECK(IsInstructionAGet(opcode)); +#endif + return static_cast(code - Instruction::AGET); +} + +constexpr DexMemAccessType APutMemAccessType(Instruction::Code code) { +#if __cplusplus >= 201402 // C++14 allows the DCHECK() in constexpr functions. + DCHECK(IsInstructionAPut(opcode)); +#endif + return static_cast(code - Instruction::APUT); +} + +constexpr DexMemAccessType IGetOrIPutMemAccessType(Instruction::Code code) { +#if __cplusplus >= 201402 // C++14 allows the DCHECK() in constexpr functions. + DCHECK(IsInstructionIGetOrIPut(opcode)); +#endif + return (code >= Instruction::IPUT) ? IPutMemAccessType(code) : IGetMemAccessType(code); +} + +constexpr DexMemAccessType SGetOrSPutMemAccessType(Instruction::Code code) { +#if __cplusplus >= 201402 // C++14 allows the DCHECK() in constexpr functions. + DCHECK(IsInstructionSGetOrSPut(opcode)); +#endif + return (code >= Instruction::SPUT) ? SPutMemAccessType(code) : SGetMemAccessType(code); +} + +constexpr DexMemAccessType AGetOrAPutMemAccessType(Instruction::Code code) { +#if __cplusplus >= 201402 // C++14 allows the DCHECK() in constexpr functions. + DCHECK(IsInstructionAGetOrAPut(opcode)); +#endif + return (code >= Instruction::APUT) ? APutMemAccessType(code) : AGetMemAccessType(code); +} + +} // namespace art + +#endif // ART_COMPILER_UTILS_DEX_INSTRUCTION_UTILS_H_ diff --git a/runtime/quick/inline_method_analyser.h b/runtime/quick/inline_method_analyser.h index a8d430895..72b696b2d 100644 --- a/runtime/quick/inline_method_analyser.h +++ b/runtime/quick/inline_method_analyser.h @@ -106,9 +106,7 @@ enum IntrinsicFlags { }; struct InlineIGetIPutData { - // The op_variant below is opcode-Instruction::IGET for IGETs and - // opcode-Instruction::IPUT for IPUTs. This is because the runtime - // doesn't know the OpSize enumeration. + // The op_variant below is DexMemAccessType but the runtime doesn't know that enumeration. uint16_t op_variant : 3; uint16_t method_is_static : 1; uint16_t object_arg : 4; -- 2.11.0