diff options
Diffstat (limited to 'compiler')
35 files changed, 476 insertions, 986 deletions
diff --git a/compiler/Android.mk b/compiler/Android.mk index 86a27c1..beb34dc 100644 --- a/compiler/Android.mk +++ b/compiler/Android.mk @@ -79,7 +79,6 @@ LIBART_COMPILER_SRC_FILES := \ driver/compiler_driver.cc \ driver/compiler_options.cc \ driver/dex_compilation_unit.cc \ - jit/jit_compiler.cc \ jni/quick/arm/calling_convention_arm.cc \ jni/quick/arm64/calling_convention_arm64.cc \ jni/quick/mips/calling_convention_mips.cc \ @@ -162,7 +161,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/common_compiler_test.cc b/compiler/common_compiler_test.cc index e8354b2..1cd78f8 100644 --- a/compiler/common_compiler_test.cc +++ b/compiler/common_compiler_test.cc @@ -52,19 +52,19 @@ void CommonCompilerTest::MakeExecutable(mirror::ArtMethod* method) { const SwapVector<uint8_t>* code = compiled_method->GetQuickCode(); uint32_t code_size = code->size(); CHECK_NE(0u, code_size); - const SwapVector<uint8_t>* vmap_table = compiled_method->GetVmapTable(); - uint32_t vmap_table_offset = vmap_table->empty() ? 0u - : sizeof(OatQuickMethodHeader) + vmap_table->size(); + const SwapVector<uint8_t>& vmap_table = compiled_method->GetVmapTable(); + uint32_t vmap_table_offset = vmap_table.empty() ? 0u + : sizeof(OatQuickMethodHeader) + vmap_table.size(); const SwapVector<uint8_t>* mapping_table = compiled_method->GetMappingTable(); bool mapping_table_used = mapping_table != nullptr && !mapping_table->empty(); size_t mapping_table_size = mapping_table_used ? mapping_table->size() : 0U; uint32_t mapping_table_offset = !mapping_table_used ? 0u - : sizeof(OatQuickMethodHeader) + vmap_table->size() + mapping_table_size; + : sizeof(OatQuickMethodHeader) + vmap_table.size() + mapping_table_size; const SwapVector<uint8_t>* gc_map = compiled_method->GetGcMap(); bool gc_map_used = gc_map != nullptr && !gc_map->empty(); size_t gc_map_size = gc_map_used ? gc_map->size() : 0U; uint32_t gc_map_offset = !gc_map_used ? 0u - : sizeof(OatQuickMethodHeader) + vmap_table->size() + mapping_table_size + gc_map_size; + : sizeof(OatQuickMethodHeader) + vmap_table.size() + mapping_table_size + gc_map_size; OatQuickMethodHeader method_header(mapping_table_offset, vmap_table_offset, gc_map_offset, compiled_method->GetFrameSizeInBytes(), compiled_method->GetCoreSpillMask(), @@ -72,14 +72,14 @@ void CommonCompilerTest::MakeExecutable(mirror::ArtMethod* method) { header_code_and_maps_chunks_.push_back(std::vector<uint8_t>()); std::vector<uint8_t>* chunk = &header_code_and_maps_chunks_.back(); - size_t size = sizeof(method_header) + code_size + vmap_table->size() + mapping_table_size + + size_t size = sizeof(method_header) + code_size + vmap_table.size() + mapping_table_size + gc_map_size; size_t code_offset = compiled_method->AlignCode(size - code_size); size_t padding = code_offset - (size - code_size); chunk->reserve(padding + size); chunk->resize(sizeof(method_header)); memcpy(&(*chunk)[0], &method_header, sizeof(method_header)); - chunk->insert(chunk->begin(), vmap_table->begin(), vmap_table->end()); + chunk->insert(chunk->begin(), vmap_table.begin(), vmap_table.end()); if (mapping_table_used) { chunk->insert(chunk->begin(), mapping_table->begin(), mapping_table->end()); } @@ -212,7 +212,7 @@ void CommonCompilerTest::CompileMethod(mirror::ArtMethod* method) { CHECK(method != nullptr); TimingLogger timings("CommonTest::CompileMethod", false, false); TimingLogger::ScopedTiming t(__FUNCTION__, &timings); - compiler_driver_->CompileOne(Thread::Current(), method, &timings); + compiler_driver_->CompileOne(method, &timings); TimingLogger::ScopedTiming t2("MakeExecutable", &timings); MakeExecutable(method); } diff --git a/compiler/compiled_method.cc b/compiler/compiled_method.cc index 1849e7e..22be28c 100644 --- a/compiler/compiled_method.cc +++ b/compiler/compiled_method.cc @@ -20,29 +20,16 @@ namespace art { CompiledCode::CompiledCode(CompilerDriver* compiler_driver, InstructionSet instruction_set, - const ArrayRef<const uint8_t>& quick_code, bool owns_code_array) + const ArrayRef<const uint8_t>& quick_code) : compiler_driver_(compiler_driver), instruction_set_(instruction_set), - owns_code_array_(owns_code_array), quick_code_(nullptr) { + quick_code_(nullptr) { SetCode(&quick_code); } void CompiledCode::SetCode(const ArrayRef<const uint8_t>* quick_code) { if (quick_code != nullptr) { CHECK(!quick_code->empty()); - if (owns_code_array_) { - // If we are supposed to own the code, don't deduplicate it. - CHECK(quick_code_ == nullptr); - quick_code_ = new SwapVector<uint8_t>(quick_code->begin(), quick_code->end(), - compiler_driver_->GetSwapSpaceAllocator()); - } else { - quick_code_ = compiler_driver_->DeduplicateCode(*quick_code); - } - } -} - -CompiledCode::~CompiledCode() { - if (owns_code_array_) { - delete quick_code_; + quick_code_ = compiler_driver_->DeduplicateCode(*quick_code); } } @@ -59,11 +46,11 @@ bool CompiledCode::operator==(const CompiledCode& rhs) const { return (rhs.quick_code_ == nullptr); } -size_t CompiledCode::AlignCode(size_t offset) const { +uint32_t CompiledCode::AlignCode(uint32_t offset) const { return AlignCode(offset, instruction_set_); } -size_t CompiledCode::AlignCode(size_t offset, InstructionSet instruction_set) { +uint32_t CompiledCode::AlignCode(uint32_t offset, InstructionSet instruction_set) { return RoundUp(offset, GetInstructionSetAlignment(instruction_set)); } @@ -133,39 +120,17 @@ CompiledMethod::CompiledMethod(CompilerDriver* driver, const ArrayRef<const uint8_t>& native_gc_map, const ArrayRef<const uint8_t>& cfi_info, const ArrayRef<LinkerPatch>& patches) - : CompiledCode(driver, instruction_set, quick_code, !driver->DedupeEnabled()), - owns_arrays_(!driver->DedupeEnabled()), - frame_size_in_bytes_(frame_size_in_bytes), core_spill_mask_(core_spill_mask), - fp_spill_mask_(fp_spill_mask), + : CompiledCode(driver, instruction_set, quick_code), frame_size_in_bytes_(frame_size_in_bytes), + core_spill_mask_(core_spill_mask), fp_spill_mask_(fp_spill_mask), + src_mapping_table_(src_mapping_table == nullptr ? + driver->DeduplicateSrcMappingTable(ArrayRef<SrcMapElem>()) : + driver->DeduplicateSrcMappingTable(ArrayRef<SrcMapElem>(src_mapping_table->Arrange()))), + mapping_table_(mapping_table.data() == nullptr ? + nullptr : driver->DeduplicateMappingTable(mapping_table)), + vmap_table_(driver->DeduplicateVMapTable(vmap_table)), + gc_map_(native_gc_map.data() == nullptr ? nullptr : driver->DeduplicateGCMap(native_gc_map)), + cfi_info_(cfi_info.data() == nullptr ? nullptr : driver->DeduplicateCFIInfo(cfi_info)), patches_(patches.begin(), patches.end(), driver->GetSwapSpaceAllocator()) { - if (owns_arrays_) { - if (src_mapping_table == nullptr) { - src_mapping_table_ = new SwapSrcMap(driver->GetSwapSpaceAllocator()); - } else { - src_mapping_table->Arrange(); - src_mapping_table_ = new SwapSrcMap(src_mapping_table->begin(), src_mapping_table->end(), - driver->GetSwapSpaceAllocator()); - } - mapping_table_ = mapping_table.empty() ? - nullptr : new SwapVector<uint8_t>(mapping_table.begin(), mapping_table.end(), - driver->GetSwapSpaceAllocator()); - vmap_table_ = new SwapVector<uint8_t>(vmap_table.begin(), vmap_table.end(), - driver->GetSwapSpaceAllocator()); - gc_map_ = native_gc_map.empty() ? nullptr : - new SwapVector<uint8_t>(native_gc_map.begin(), native_gc_map.end(), - driver->GetSwapSpaceAllocator()); - cfi_info_ = cfi_info.empty() ? nullptr : - new SwapVector<uint8_t>(cfi_info.begin(), cfi_info.end(), driver->GetSwapSpaceAllocator()); - } else { - src_mapping_table_ = src_mapping_table == nullptr ? - driver->DeduplicateSrcMappingTable(ArrayRef<SrcMapElem>()) : - driver->DeduplicateSrcMappingTable(ArrayRef<SrcMapElem>(src_mapping_table->Arrange())); - mapping_table_ = mapping_table.empty() ? - nullptr : driver->DeduplicateMappingTable(mapping_table); - vmap_table_ = driver->DeduplicateVMapTable(vmap_table); - gc_map_ = native_gc_map.empty() ? nullptr : driver->DeduplicateGCMap(native_gc_map); - cfi_info_ = cfi_info.empty() ? nullptr : driver->DeduplicateCFIInfo(cfi_info); - } } CompiledMethod* CompiledMethod::SwapAllocCompiledMethod( @@ -229,14 +194,4 @@ void CompiledMethod::ReleaseSwapAllocatedCompiledMethod(CompilerDriver* driver, alloc.deallocate(m, 1); } -CompiledMethod::~CompiledMethod() { - if (owns_arrays_) { - delete src_mapping_table_; - delete mapping_table_; - delete vmap_table_; - delete gc_map_; - delete cfi_info_; - } -} - } // namespace art diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h index d6a07f6..6013507 100644 --- a/compiler/compiled_method.h +++ b/compiler/compiled_method.h @@ -27,6 +27,10 @@ #include "utils/array_ref.h" #include "utils/swap_space.h" +namespace llvm { + class Function; +} // namespace llvm + namespace art { class CompilerDriver; @@ -35,9 +39,7 @@ class CompiledCode { public: // For Quick to supply an code blob CompiledCode(CompilerDriver* compiler_driver, InstructionSet instruction_set, - const ArrayRef<const uint8_t>& quick_code, bool owns_code_array); - - virtual ~CompiledCode(); + const ArrayRef<const uint8_t>& quick_code); InstructionSet GetInstructionSet() const { return instruction_set_; @@ -54,8 +56,8 @@ class CompiledCode { // To align an offset from a page-aligned value to make it suitable // for code storage. For example on ARM, to ensure that PC relative // valu computations work out as expected. - size_t AlignCode(size_t offset) const; - static size_t AlignCode(size_t offset, InstructionSet instruction_set); + uint32_t AlignCode(uint32_t offset) const; + static uint32_t AlignCode(uint32_t offset, InstructionSet instruction_set); // returns the difference between the code address and a usable PC. // mainly to cope with kThumb2 where the lower bit must be set. @@ -76,9 +78,6 @@ class CompiledCode { const InstructionSet instruction_set_; - // If we own the code array (means that we free in destructor). - const bool owns_code_array_; - // Used to store the PIC code for Quick. SwapVector<uint8_t>* quick_code_; @@ -123,7 +122,6 @@ class SrcMap FINAL : public std::vector<SrcMapElem, Allocator> { using std::vector<SrcMapElem, Allocator>::size; explicit SrcMap() {} - explicit SrcMap(const Allocator& alloc) : std::vector<SrcMapElem, Allocator>(alloc) {} template <class InputIt> SrcMap(InputIt first, InputIt last, const Allocator& alloc) @@ -293,7 +291,7 @@ class CompiledMethod FINAL : public CompiledCode { const ArrayRef<const uint8_t>& cfi_info, const ArrayRef<LinkerPatch>& patches = ArrayRef<LinkerPatch>()); - virtual ~CompiledMethod(); + ~CompiledMethod() {} static CompiledMethod* SwapAllocCompiledMethod( CompilerDriver* driver, @@ -349,9 +347,9 @@ class CompiledMethod FINAL : public CompiledCode { return mapping_table_; } - const SwapVector<uint8_t>* GetVmapTable() const { + const SwapVector<uint8_t>& GetVmapTable() const { DCHECK(vmap_table_ != nullptr); - return vmap_table_; + return *vmap_table_; } SwapVector<uint8_t> const* GetGcMap() const { @@ -367,8 +365,6 @@ class CompiledMethod FINAL : public CompiledCode { } private: - // Whether or not the arrays are owned by the compiled method or dedupe sets. - const bool owns_arrays_; // For quick code, the size of the activation used by the code. const size_t frame_size_in_bytes_; // For quick code, a bit mask describing spilled GPR callee-save registers. diff --git a/compiler/dex/global_value_numbering_test.cc b/compiler/dex/global_value_numbering_test.cc index b91c3ca..54e34ea 100644 --- a/compiler/dex/global_value_numbering_test.cc +++ b/compiler/dex/global_value_numbering_test.cc @@ -142,7 +142,7 @@ 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, def->type, false); + MirIFieldLoweringInfo field_info(def->field_idx, def->type); if (def->declaring_dex_file != 0u) { field_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file); field_info.declaring_field_idx_ = def->declaring_field_idx; diff --git a/compiler/dex/gvn_dead_code_elimination_test.cc b/compiler/dex/gvn_dead_code_elimination_test.cc index 4d2b8b3..954e9f1 100644 --- a/compiler/dex/gvn_dead_code_elimination_test.cc +++ b/compiler/dex/gvn_dead_code_elimination_test.cc @@ -143,7 +143,7 @@ class GvnDeadCodeEliminationTest : 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, def->type, false); + MirIFieldLoweringInfo field_info(def->field_idx, def->type); if (def->declaring_dex_file != 0u) { field_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file); field_info.declaring_field_idx_ = def->declaring_field_idx; diff --git a/compiler/dex/local_value_numbering.h b/compiler/dex/local_value_numbering.h index 379c952..97ea05a 100644 --- a/compiler/dex/local_value_numbering.h +++ b/compiler/dex/local_value_numbering.h @@ -21,8 +21,8 @@ #include "base/arena_object.h" #include "base/logging.h" -#include "dex_instruction_utils.h" #include "global_value_numbering.h" +#include "utils/dex_instruction_utils.h" namespace art { diff --git a/compiler/dex/local_value_numbering_test.cc b/compiler/dex/local_value_numbering_test.cc index 566527a..d1c3a6b 100644 --- a/compiler/dex/local_value_numbering_test.cc +++ b/compiler/dex/local_value_numbering_test.cc @@ -96,7 +96,7 @@ 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, def->type, false); + MirIFieldLoweringInfo field_info(def->field_idx, def->type); if (def->declaring_dex_file != 0u) { field_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file); field_info.declaring_field_idx_ = def->declaring_field_idx; diff --git a/compiler/dex/mir_analysis.cc b/compiler/dex/mir_analysis.cc index a89b250..31dbc60 100644 --- a/compiler/dex/mir_analysis.cc +++ b/compiler/dex/mir_analysis.cc @@ -416,8 +416,8 @@ static const uint16_t kAnalysisAttributes[kMirOpLast] = { // 72 INVOKE_INTERFACE {vD, vE, vF, vG, vA} kAnInvoke | kAnHeavyWeight, - // 73 RETURN_VOID_BARRIER - kAnBranch, + // 73 UNUSED_73 + kAnNone, // 74 INVOKE_VIRTUAL_RANGE {vCCCC .. vNNNN} kAnInvoke | kAnHeavyWeight, @@ -752,88 +752,88 @@ static const uint16_t kAnalysisAttributes[kMirOpLast] = { // E2 USHR_INT_LIT8 vAA, vBB, #+CC kAnMath | kAnInt, - // E3 IGET_QUICK + // E3 IGET_VOLATILE kAnNone, - // E4 IGET_WIDE_QUICK + // E4 IPUT_VOLATILE kAnNone, - // E5 IGET_OBJECT_QUICK + // E5 SGET_VOLATILE kAnNone, - // E6 IPUT_QUICK + // E6 SPUT_VOLATILE kAnNone, - // E7 IPUT_WIDE_QUICK + // E7 IGET_OBJECT_VOLATILE kAnNone, - // E8 IPUT_OBJECT_QUICK + // E8 IGET_WIDE_VOLATILE kAnNone, - // E9 INVOKE_VIRTUAL_QUICK - kAnInvoke | kAnHeavyWeight, - - // EA INVOKE_VIRTUAL_RANGE_QUICK - kAnInvoke | kAnHeavyWeight, - - // EB IPUT_BOOLEAN_QUICK + // E9 IPUT_WIDE_VOLATILE kAnNone, - // EC IPUT_BYTE_QUICK + // EA SGET_WIDE_VOLATILE kAnNone, - // ED IPUT_CHAR_QUICK + // EB SPUT_WIDE_VOLATILE kAnNone, - // EE IPUT_SHORT_QUICK + // EC BREAKPOINT kAnNone, - // EF IGET_BOOLEAN_QUICK - kAnNone, + // ED THROW_VERIFICATION_ERROR + kAnHeavyWeight | kAnBranch, - // F0 IGET_BYTE_QUICK + // EE EXECUTE_INLINE kAnNone, - // F1 IGET_CHAR_QUICK + // EF EXECUTE_INLINE_RANGE kAnNone, - // F2 IGET_SHORT_QUICK - kAnNone, + // F0 INVOKE_OBJECT_INIT_RANGE + kAnInvoke | kAnHeavyWeight, - // F3 UNUSED_F3 - kAnNone, + // F1 RETURN_VOID_BARRIER + kAnBranch, - // F4 UNUSED_F4 + // F2 IGET_QUICK kAnNone, - // F5 UNUSED_F5 + // F3 IGET_WIDE_QUICK kAnNone, - // F6 UNUSED_F6 + // F4 IGET_OBJECT_QUICK kAnNone, - // F7 UNUSED_F7 + // F5 IPUT_QUICK kAnNone, - // F8 UNUSED_F8 + // F6 IPUT_WIDE_QUICK kAnNone, - // F9 UNUSED_F9 + // F7 IPUT_OBJECT_QUICK kAnNone, - // FA UNUSED_FA - kAnNone, + // F8 INVOKE_VIRTUAL_QUICK + kAnInvoke | kAnHeavyWeight, - // FB UNUSED_FB - kAnNone, + // F9 INVOKE_VIRTUAL_QUICK_RANGE + kAnInvoke | kAnHeavyWeight, - // FC UNUSED_FC + // FA INVOKE_SUPER_QUICK + kAnInvoke | kAnHeavyWeight, + + // FB INVOKE_SUPER_QUICK_RANGE + kAnInvoke | kAnHeavyWeight, + + // FC IPUT_OBJECT_VOLATILE kAnNone, - // FD UNUSED_FD + // FD SGET_OBJECT_VOLATILE kAnNone, - // FE UNUSED_FE + // FE SPUT_OBJECT_VOLATILE kAnNone, // FF UNUSED_FF @@ -1203,13 +1203,12 @@ bool MIRGraph::SkipCompilation(std::string* skip_message) { } void MIRGraph::DoCacheFieldLoweringInfo() { - static constexpr uint32_t kFieldIndexFlagQuickened = 0x80000000; // All IGET/IPUT/SGET/SPUT instructions take 2 code units and there must also be a RETURN. const uint32_t max_refs = (GetNumDalvikInsns() - 1u) / 2u; ScopedArenaAllocator allocator(&cu_->arena_stack); - auto* field_idxs = allocator.AllocArray<uint32_t>(max_refs, kArenaAllocMisc); - DexMemAccessType* field_types = allocator.AllocArray<DexMemAccessType>( - max_refs, kArenaAllocMisc); + uint16_t* field_idxs = allocator.AllocArray<uint16_t>(max_refs, kArenaAllocMisc); + DexMemAccessType* field_types = allocator.AllocArray<DexMemAccessType>(max_refs, kArenaAllocMisc); + // Find IGET/IPUT/SGET/SPUT insns, store IGET/IPUT fields at the beginning, SGET/SPUT at the end. size_t ifield_pos = 0u; size_t sfield_pos = max_refs; @@ -1222,36 +1221,23 @@ void MIRGraph::DoCacheFieldLoweringInfo() { // 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. - const bool is_iget_or_iput = IsInstructionIGetOrIPut(mir->dalvikInsn.opcode); - const bool is_iget_or_iput_quick = IsInstructionIGetQuickOrIPutQuick(mir->dalvikInsn.opcode); - if (is_iget_or_iput || is_iget_or_iput_quick) { - uint32_t field_idx; - DexMemAccessType access_type; - if (is_iget_or_iput) { - field_idx = mir->dalvikInsn.vC; - access_type = IGetOrIPutMemAccessType(mir->dalvikInsn.opcode); - } else { - DCHECK(is_iget_or_iput_quick); - // Set kFieldIndexFlagQuickened so that we don't deduplicate against non quickened field - // indexes. - field_idx = mir->offset | kFieldIndexFlagQuickened; - access_type = IGetQuickOrIPutQuickMemAccessType(mir->dalvikInsn.opcode); - } + 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], access_type); + 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] = access_type; + field_types[ifield_pos] = IGetOrIPutMemAccessType(mir->dalvikInsn.opcode); ++ifield_pos; } } else if (IsInstructionSGetOrSPut(mir->dalvikInsn.opcode)) { - auto field_idx = mir->dalvikInsn.vB; + uint16_t field_idx = mir->dalvikInsn.vB; size_t i = sfield_pos; while (i != max_refs && field_idxs[i] != field_idx) { ++i; @@ -1275,12 +1261,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) { - const uint32_t field_idx = field_idxs[pos]; - const bool is_quickened = (field_idx & kFieldIndexFlagQuickened) != 0; - const uint32_t masked_field_idx = field_idx & ~kFieldIndexFlagQuickened; - CHECK_LT(masked_field_idx, 1u << 16); - ifield_lowering_infos_.push_back( - MirIFieldLoweringInfo(masked_field_idx, field_types[pos], is_quickened)); + ifield_lowering_infos_.push_back(MirIFieldLoweringInfo(field_idxs[pos], field_types[pos])); } MirIFieldLoweringInfo::Resolve(cu_->compiler_driver, GetCurrentDexCompilationUnit(), ifield_lowering_infos_.data(), ifield_pos); @@ -1301,19 +1282,18 @@ void MIRGraph::DoCacheFieldLoweringInfo() { void MIRGraph::DoCacheMethodLoweringInfo() { static constexpr uint16_t invoke_types[] = { kVirtual, kSuper, kDirect, kStatic, kInterface }; - static constexpr uint32_t kMethodIdxFlagQuickened = 0x80000000; // Embed the map value in the entry to avoid extra padding in 64-bit builds. struct MapEntry { // Map key: target_method_idx, invoke_type, devirt_target. Ordered to avoid padding. const MethodReference* devirt_target; - uint32_t target_method_idx; - uint32_t vtable_idx; + uint16_t target_method_idx; uint16_t invoke_type; // Map value. uint32_t lowering_info_index; }; + // Sort INVOKEs by method index, then by opcode, then by devirtualization target. struct MapEntryComparator { bool operator()(const MapEntry& lhs, const MapEntry& rhs) const { if (lhs.target_method_idx != rhs.target_method_idx) { @@ -1322,9 +1302,6 @@ void MIRGraph::DoCacheMethodLoweringInfo() { if (lhs.invoke_type != rhs.invoke_type) { return lhs.invoke_type < rhs.invoke_type; } - if (lhs.vtable_idx != rhs.vtable_idx) { - return lhs.vtable_idx < rhs.vtable_idx; - } if (lhs.devirt_target != rhs.devirt_target) { if (lhs.devirt_target == nullptr) { return true; @@ -1342,7 +1319,7 @@ void MIRGraph::DoCacheMethodLoweringInfo() { ScopedArenaAllocator allocator(&cu_->arena_stack); // All INVOKE instructions take 3 code units and there must also be a RETURN. - const uint32_t max_refs = (GetNumDalvikInsns() - 1u) / 3u; + uint32_t max_refs = (GetNumDalvikInsns() - 1u) / 3u; // Map invoke key (see MapEntry) to lowering info index and vice versa. // The invoke_map and sequential entries are essentially equivalent to Boost.MultiIndex's @@ -1353,43 +1330,28 @@ void MIRGraph::DoCacheMethodLoweringInfo() { allocator.AllocArray<const MapEntry*>(max_refs, kArenaAllocMisc); // Find INVOKE insns and their devirtualization targets. - const VerifiedMethod* verified_method = GetCurrentDexCompilationUnit()->GetVerifiedMethod(); AllNodesIterator iter(this); for (BasicBlock* bb = iter.Next(); bb != nullptr; bb = iter.Next()) { if (bb->block_type != kDalvikByteCode) { continue; } for (MIR* mir = bb->first_mir_insn; mir != nullptr; mir = mir->next) { - const bool is_quick_invoke = IsInstructionQuickInvoke(mir->dalvikInsn.opcode); - const bool is_invoke = IsInstructionInvoke(mir->dalvikInsn.opcode); - if (is_quick_invoke || is_invoke) { - uint32_t vtable_index = 0; - uint32_t target_method_idx = 0; - uint32_t invoke_type_idx = 0; // Default to virtual (in case of quickened). - DCHECK_EQ(invoke_types[invoke_type_idx], kVirtual); - if (is_quick_invoke) { - // We need to store the vtable index since we can't necessarily recreate it at resolve - // phase if the dequickening resolved to an interface method. - vtable_index = mir->dalvikInsn.vB; - // Fake up the method index by storing the mir offset so that we can read the dequicken - // info in resolve. - target_method_idx = mir->offset | kMethodIdxFlagQuickened; - } else { - DCHECK(is_invoke); - // Decode target method index and invoke type. - invoke_type_idx = InvokeInstructionType(mir->dalvikInsn.opcode); - target_method_idx = mir->dalvikInsn.vB; - } + if (IsInstructionInvoke(mir->dalvikInsn.opcode)) { + // Decode target method index and invoke type. + 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 // ordered by dex pc as well? That would allow us to keep an iterator to devirt targets // and increment it as needed instead of making O(log n) lookups. + const VerifiedMethod* verified_method = GetCurrentDexCompilationUnit()->GetVerifiedMethod(); const MethodReference* devirt_target = verified_method->GetDevirtTarget(mir->offset); + // Try to insert a new entry. If the insertion fails, we will have found an old one. MapEntry entry = { devirt_target, target_method_idx, - vtable_index, invoke_types[invoke_type_idx], static_cast<uint32_t>(invoke_map.size()) }; @@ -1400,24 +1362,22 @@ void MIRGraph::DoCacheMethodLoweringInfo() { } } } + if (invoke_map.empty()) { return; } + // Prepare unique method infos, set method info indexes for their MIRs. + DCHECK_EQ(method_lowering_infos_.size(), 0u); const size_t count = invoke_map.size(); method_lowering_infos_.reserve(count); for (size_t pos = 0u; pos != count; ++pos) { const MapEntry* entry = sequential_entries[pos]; - const bool is_quick = (entry->target_method_idx & kMethodIdxFlagQuickened) != 0; - const uint32_t masked_method_idx = entry->target_method_idx & ~kMethodIdxFlagQuickened; - MirMethodLoweringInfo method_info(masked_method_idx, - static_cast<InvokeType>(entry->invoke_type), is_quick); + MirMethodLoweringInfo method_info(entry->target_method_idx, + static_cast<InvokeType>(entry->invoke_type)); if (entry->devirt_target != nullptr) { method_info.SetDevirtualizationTarget(*entry->devirt_target); } - if (is_quick) { - method_info.SetVTableIndex(entry->vtable_idx); - } method_lowering_infos_.push_back(method_info); } MirMethodLoweringInfo::Resolve(cu_->compiler_driver, GetCurrentDexCompilationUnit(), diff --git a/compiler/dex/mir_dataflow.cc b/compiler/dex/mir_dataflow.cc index dfaff6c..f9f7e22 100644 --- a/compiler/dex/mir_dataflow.cc +++ b/compiler/dex/mir_dataflow.cc @@ -374,7 +374,7 @@ const uint64_t MIRGraph::oat_data_flow_attributes_[kMirOpLast] = { // 72 INVOKE_INTERFACE {vD, vE, vF, vG, vA} DF_FORMAT_35C | DF_NULL_CHK_OUT0 | DF_UMS, - // 73 RETURN_VOID_BARRIER + // 73 UNUSED_73 DF_NOP, // 74 INVOKE_VIRTUAL_RANGE {vCCCC .. vNNNN} @@ -710,89 +710,89 @@ const uint64_t MIRGraph::oat_data_flow_attributes_[kMirOpLast] = { // E2 USHR_INT_LIT8 vAA, vBB, #+CC DF_DA | DF_UB | DF_CORE_A | DF_CORE_B, - // E3 IGET_QUICK + // E3 IGET_VOLATILE DF_DA | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN, - // E4 IGET_WIDE_QUICK - DF_DA | DF_A_WIDE | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN, - - // E5 IGET_OBJECT_QUICK - DF_DA | DF_UB | DF_NULL_CHK_B | DF_REF_A | DF_REF_B | DF_IFIELD | DF_LVN, - - // E6 IPUT_QUICK + // E4 IPUT_VOLATILE DF_UA | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN, - // E7 IPUT_WIDE_QUICK - DF_UA | DF_A_WIDE | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN, + // E5 SGET_VOLATILE + DF_DA | DF_SFIELD | DF_CLINIT | DF_UMS, - // E8 IPUT_OBJECT_QUICK - DF_UA | DF_UB | DF_NULL_CHK_B | DF_REF_A | DF_REF_B | DF_IFIELD | DF_LVN, + // E6 SPUT_VOLATILE + DF_UA | DF_SFIELD | DF_CLINIT | DF_UMS, - // E9 INVOKE_VIRTUAL_QUICK - DF_FORMAT_35C | DF_NULL_CHK_OUT0 | DF_UMS, + // E7 IGET_OBJECT_VOLATILE + DF_DA | DF_UB | DF_NULL_CHK_B | DF_REF_A | DF_REF_B | DF_IFIELD | DF_LVN, - // EA INVOKE_VIRTUAL_RANGE_QUICK - DF_FORMAT_3RC | DF_NULL_CHK_OUT0 | DF_UMS, + // E8 IGET_WIDE_VOLATILE + DF_DA | DF_A_WIDE | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN, - // EB IPUT_BOOLEAN_QUICK vA, vB, index - DF_UA | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN, + // E9 IPUT_WIDE_VOLATILE + DF_UA | DF_A_WIDE | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN, - // EC IPUT_BYTE_QUICK vA, vB, index - DF_UA | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN, + // EA SGET_WIDE_VOLATILE + DF_DA | DF_A_WIDE | DF_SFIELD | DF_CLINIT | DF_UMS, - // ED IPUT_CHAR_QUICK vA, vB, index - DF_UA | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN, + // EB SPUT_WIDE_VOLATILE + DF_UA | DF_A_WIDE | DF_SFIELD | DF_CLINIT | DF_UMS, - // EE IPUT_SHORT_QUICK vA, vB, index - DF_UA | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN, + // EC BREAKPOINT + DF_NOP, - // EF IGET_BOOLEAN_QUICK vA, vB, index - DF_DA | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN, + // ED THROW_VERIFICATION_ERROR + DF_NOP | DF_UMS, - // F0 IGET_BYTE_QUICK vA, vB, index - DF_DA | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN, + // EE EXECUTE_INLINE + DF_FORMAT_35C, - // F1 IGET_CHAR_QUICK vA, vB, index - DF_DA | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN, + // EF EXECUTE_INLINE_RANGE + DF_FORMAT_3RC, - // F2 IGET_SHORT_QUICK vA, vB, index - DF_DA | DF_UB | DF_NULL_CHK_B | DF_REF_B | DF_IFIELD | DF_LVN, - - // F3 UNUSED_F3 + // F0 INVOKE_OBJECT_INIT_RANGE DF_NOP, - // F4 UNUSED_F4 + // F1 RETURN_VOID_BARRIER DF_NOP, - // F5 UNUSED_F5 - DF_NOP, + // F2 IGET_QUICK + DF_DA | DF_UB | DF_NULL_CHK_B | DF_IFIELD | DF_LVN, - // F6 UNUSED_F6 - DF_NOP, + // F3 IGET_WIDE_QUICK + DF_DA | DF_A_WIDE | DF_UB | DF_NULL_CHK_B | DF_IFIELD | DF_LVN, - // F7 UNUSED_F7 - DF_NOP, + // F4 IGET_OBJECT_QUICK + DF_DA | DF_UB | DF_NULL_CHK_B | DF_IFIELD | DF_LVN, - // F8 UNUSED_F8 - DF_NOP, + // F5 IPUT_QUICK + DF_UA | DF_UB | DF_NULL_CHK_B | DF_IFIELD | DF_LVN, - // F9 UNUSED_F9 - DF_NOP, + // F6 IPUT_WIDE_QUICK + DF_UA | DF_A_WIDE | DF_UB | DF_NULL_CHK_B | DF_IFIELD | DF_LVN, - // FA UNUSED_FA - DF_NOP, + // F7 IPUT_OBJECT_QUICK + DF_UA | DF_UB | DF_NULL_CHK_B | DF_IFIELD | DF_LVN, - // FB UNUSED_FB - DF_NOP, + // F8 INVOKE_VIRTUAL_QUICK + DF_FORMAT_35C | DF_NULL_CHK_OUT0 | DF_UMS, - // FC UNUSED_FC - DF_NOP, + // F9 INVOKE_VIRTUAL_QUICK_RANGE + DF_FORMAT_3RC | DF_NULL_CHK_OUT0 | DF_UMS, - // FD UNUSED_FD - DF_NOP, + // FA INVOKE_SUPER_QUICK + DF_FORMAT_35C | DF_NULL_CHK_OUT0 | DF_UMS, - // FE UNUSED_FE - DF_NOP, + // FB INVOKE_SUPER_QUICK_RANGE + DF_FORMAT_3RC | DF_NULL_CHK_OUT0 | DF_UMS, + + // FC IPUT_OBJECT_VOLATILE + DF_UA | DF_UB | DF_NULL_CHK_B | DF_REF_A | DF_REF_B | DF_IFIELD | DF_LVN, + + // FD SGET_OBJECT_VOLATILE + DF_DA | DF_REF_A | DF_SFIELD | DF_CLINIT | DF_UMS, + + // FE SPUT_OBJECT_VOLATILE + DF_UA | DF_REF_A | DF_SFIELD | DF_CLINIT | DF_UMS, // FF UNUSED_FF DF_NOP, diff --git a/compiler/dex/mir_field_info.cc b/compiler/dex/mir_field_info.cc index d2079a2..53afcad 100644 --- a/compiler/dex/mir_field_info.cc +++ b/compiler/dex/mir_field_info.cc @@ -35,9 +35,8 @@ 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_, it->MemAccessType(), it->IsQuickened()); - unresolved.field_offset_ = it->field_offset_; - unresolved.CheckEquals(*it); + MirIFieldLoweringInfo unresolved(it->field_idx_, it->MemAccessType()); + DCHECK_EQ(memcmp(&unresolved, &*it, sizeof(*it)), 0); } } @@ -50,30 +49,13 @@ void MirIFieldLoweringInfo::Resolve(CompilerDriver* compiler_driver, hs.NewHandle(compiler_driver->GetClassLoader(soa, mUnit))); Handle<mirror::Class> referrer_class(hs.NewHandle( compiler_driver->ResolveCompilingMethodsClass(soa, dex_cache, class_loader, mUnit))); - const VerifiedMethod* const verified_method = mUnit->GetVerifiedMethod(); // Even if the referrer class is unresolved (i.e. we're compiling a method without class // definition) we still want to resolve fields and record all available info. + for (auto it = field_infos, end = field_infos + count; it != end; ++it) { - uint32_t field_idx; - mirror::ArtField* resolved_field; - if (!it->IsQuickened()) { - field_idx = it->field_idx_; - resolved_field = compiler_driver->ResolveField(soa, dex_cache, class_loader, mUnit, - field_idx, false); - } else { - const auto mir_offset = it->field_idx_; - // For quickened instructions, it->field_offset_ actually contains the mir offset. - // We need to use the de-quickening info to get dex file / field idx - auto* field_idx_ptr = verified_method->GetDequickenIndex(mir_offset); - CHECK(field_idx_ptr != nullptr); - field_idx = field_idx_ptr->index; - StackHandleScope<1> hs2(soa.Self()); - auto h_dex_cache = hs2.NewHandle(compiler_driver->FindDexCache(field_idx_ptr->dex_file)); - resolved_field = compiler_driver->ResolveFieldWithDexFile( - soa, h_dex_cache, class_loader, field_idx_ptr->dex_file, field_idx, false); - // Since we don't have a valid field index we can't go slow path later. - CHECK(resolved_field != nullptr); - } + uint32_t field_idx = it->field_idx_; + mirror::ArtField* resolved_field = + compiler_driver->ResolveField(soa, dex_cache, class_loader, mUnit, field_idx, false); if (UNLIKELY(resolved_field == nullptr)) { continue; } diff --git a/compiler/dex/mir_field_info.h b/compiler/dex/mir_field_info.h index ca56958..98b2da8 100644 --- a/compiler/dex/mir_field_info.h +++ b/compiler/dex/mir_field_info.h @@ -19,8 +19,8 @@ #include "base/macros.h" #include "dex_file.h" -#include "dex_instruction_utils.h" #include "offsets.h" +#include "utils/dex_instruction_utils.h" namespace art { @@ -39,9 +39,6 @@ class MirFieldInfo { uint16_t FieldIndex() const { return field_idx_; } - void SetFieldIndex(uint16_t field_idx) { - field_idx_ = field_idx; - } bool IsStatic() const { return (flags_ & kFlagIsStatic) != 0u; @@ -54,9 +51,6 @@ class MirFieldInfo { const DexFile* DeclaringDexFile() const { return declaring_dex_file_; } - void SetDeclaringDexFile(const DexFile* dex_file) { - declaring_dex_file_ = dex_file; - } uint16_t DeclaringClassIndex() const { return declaring_class_idx_; @@ -70,35 +64,20 @@ class MirFieldInfo { return (flags_ & kFlagIsVolatile) != 0u; } - // IGET_QUICK, IGET_BYTE_QUICK, ... - bool IsQuickened() const { - return (flags_ & kFlagIsQuickened) != 0u; - } - DexMemAccessType MemAccessType() const { return static_cast<DexMemAccessType>((flags_ >> kBitMemAccessTypeBegin) & kMemAccessTypeMask); } - void CheckEquals(const MirFieldInfo& other) const { - CHECK_EQ(field_idx_, other.field_idx_); - CHECK_EQ(flags_, other.flags_); - CHECK_EQ(declaring_field_idx_, other.declaring_field_idx_); - CHECK_EQ(declaring_class_idx_, other.declaring_class_idx_); - CHECK_EQ(declaring_dex_file_, other.declaring_dex_file_); - } - protected: enum { kBitIsStatic = 0, kBitIsVolatile, - kBitIsQuickened, 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 kFlagIsQuickened = 1u << kBitIsQuickened; static constexpr uint16_t kMemAccessTypeMask = 7u; static_assert((1u << (kBitMemAccessTypeEnd - kBitMemAccessTypeBegin)) - 1u == kMemAccessTypeMask, "Invalid raw type mask"); @@ -138,10 +117,8 @@ class MirIFieldLoweringInfo : public MirFieldInfo { LOCKS_EXCLUDED(Locks::mutator_lock_); // Construct an unresolved instance field lowering info. - explicit MirIFieldLoweringInfo(uint16_t field_idx, DexMemAccessType type, bool is_quickened) - : MirFieldInfo(field_idx, - kFlagIsVolatile | (is_quickened ? kFlagIsQuickened : 0u), - type), // Without kFlagIsStatic. + explicit MirIFieldLoweringInfo(uint16_t field_idx, DexMemAccessType type) + : MirFieldInfo(field_idx, kFlagIsVolatile, type), // Without kFlagIsStatic. field_offset_(0u) { } @@ -157,11 +134,6 @@ class MirIFieldLoweringInfo : public MirFieldInfo { return field_offset_; } - void CheckEquals(const MirIFieldLoweringInfo& other) const { - MirFieldInfo::CheckEquals(other); - CHECK_EQ(field_offset_.Uint32Value(), other.field_offset_.Uint32Value()); - } - private: enum { kBitFastGet = kFieldInfoBitEnd, diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc index f354a49..76b5e44 100644 --- a/compiler/dex/mir_graph.cc +++ b/compiler/dex/mir_graph.cc @@ -1673,6 +1673,12 @@ void MIRGraph::GetBlockName(BasicBlock* bb, char* name) { } } +const char* MIRGraph::GetShortyFromTargetIdx(int target_idx) { + // TODO: for inlining support, use current code unit. + const DexFile::MethodId& method_id = cu_->dex_file->GetMethodId(target_idx); + return cu_->dex_file->GetShorty(method_id.proto_idx_); +} + const char* MIRGraph::GetShortyFromMethodReference(const MethodReference& target_method) { const DexFile::MethodId& method_id = target_method.dex_file->GetMethodId(target_method.dex_method_index); @@ -1718,7 +1724,8 @@ void MIRGraph::DumpMIRGraph() { * high-word loc for wide arguments. Also pull up any following * MOVE_RESULT and incorporate it into the invoke. */ -CallInfo* MIRGraph::NewMemCallInfo(BasicBlock* bb, MIR* mir, InvokeType type, bool is_range) { +CallInfo* MIRGraph::NewMemCallInfo(BasicBlock* bb, MIR* mir, InvokeType type, + bool is_range) { CallInfo* info = static_cast<CallInfo*>(arena_->Alloc(sizeof(CallInfo), kArenaAllocMisc)); MIR* move_result_mir = FindMoveResult(bb, mir); @@ -1737,13 +1744,6 @@ CallInfo* MIRGraph::NewMemCallInfo(BasicBlock* bb, MIR* mir, InvokeType type, bo info->opt_flags = mir->optimization_flags; info->type = type; info->is_range = is_range; - if (IsInstructionQuickInvoke(mir->dalvikInsn.opcode)) { - const auto& method_info = GetMethodLoweringInfo(mir); - info->method_ref = method_info.GetTargetMethod(); - } else { - info->method_ref = MethodReference(GetCurrentDexCompilationUnit()->GetDexFile(), - mir->dalvikInsn.vB); - } info->index = mir->dalvikInsn.vB; info->offset = mir->offset; info->mir = mir; diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h index 3dae5b4..e5abd3b 100644 --- a/compiler/dex/mir_graph.h +++ b/compiler/dex/mir_graph.h @@ -504,7 +504,6 @@ struct CallInfo { int opt_flags; InvokeType type; uint32_t dex_idx; - MethodReference method_ref; uint32_t index; // Method idx for invokes, type idx for FilledNewArray. uintptr_t direct_code; uintptr_t direct_method; @@ -688,7 +687,7 @@ class MIRGraph { void DoCacheMethodLoweringInfo(); - const MirMethodLoweringInfo& GetMethodLoweringInfo(MIR* mir) const { + const MirMethodLoweringInfo& GetMethodLoweringInfo(MIR* mir) { DCHECK_LT(mir->meta.method_lowering_info, method_lowering_infos_.size()); return method_lowering_infos_[mir->meta.method_lowering_info]; } @@ -1133,6 +1132,7 @@ class MIRGraph { std::string GetSSAName(int ssa_reg); std::string GetSSANameWithConst(int ssa_reg, bool singles_only); void GetBlockName(BasicBlock* bb, char* name); + const char* GetShortyFromTargetIdx(int); const char* GetShortyFromMethodReference(const MethodReference& target_method); void DumpMIRGraph(); CallInfo* NewMemCallInfo(BasicBlock* bb, MIR* mir, InvokeType type, bool is_range); diff --git a/compiler/dex/mir_method_info.cc b/compiler/dex/mir_method_info.cc index 3d3d979..b234950 100644 --- a/compiler/dex/mir_method_info.cc +++ b/compiler/dex/mir_method_info.cc @@ -33,103 +33,51 @@ void MirMethodLoweringInfo::Resolve(CompilerDriver* compiler_driver, DCHECK(method_infos != nullptr); DCHECK_NE(count, 0u); for (auto it = method_infos, end = method_infos + count; it != end; ++it) { - MirMethodLoweringInfo unresolved(it->MethodIndex(), it->GetInvokeType(), it->IsQuickened()); - unresolved.declaring_dex_file_ = it->declaring_dex_file_; - unresolved.vtable_idx_ = it->vtable_idx_; + MirMethodLoweringInfo unresolved(it->MethodIndex(), it->GetInvokeType()); if (it->target_dex_file_ != nullptr) { unresolved.target_dex_file_ = it->target_dex_file_; unresolved.target_method_idx_ = it->target_method_idx_; } - if (kIsDebugBuild) { - unresolved.CheckEquals(*it); - } + DCHECK_EQ(memcmp(&unresolved, &*it, sizeof(*it)), 0); } } // We're going to resolve methods and check access in a tight loop. It's better to hold // the lock and needed references once than re-acquiring them again and again. ScopedObjectAccess soa(Thread::Current()); - StackHandleScope<4> hs(soa.Self()); + StackHandleScope<3> hs(soa.Self()); Handle<mirror::DexCache> dex_cache(hs.NewHandle(compiler_driver->GetDexCache(mUnit))); Handle<mirror::ClassLoader> class_loader( hs.NewHandle(compiler_driver->GetClassLoader(soa, mUnit))); Handle<mirror::Class> referrer_class(hs.NewHandle( compiler_driver->ResolveCompilingMethodsClass(soa, dex_cache, class_loader, mUnit))); - auto current_dex_cache(hs.NewHandle<mirror::DexCache>(nullptr)); // Even if the referrer class is unresolved (i.e. we're compiling a method without class // definition) we still want to resolve methods and record all available info. - const DexFile* const dex_file = mUnit->GetDexFile(); - const bool use_jit = Runtime::Current()->UseJit(); - const VerifiedMethod* const verified_method = mUnit->GetVerifiedMethod(); for (auto it = method_infos, end = method_infos + count; it != end; ++it) { - // For quickened invokes, the dex method idx is actually the mir offset. - if (it->IsQuickened()) { - const auto* dequicken_ref = verified_method->GetDequickenIndex(it->method_idx_); - CHECK(dequicken_ref != nullptr); - it->target_dex_file_ = dequicken_ref->dex_file; - it->target_method_idx_ = dequicken_ref->index; - } // Remember devirtualized invoke target and set the called method to the default. MethodReference devirt_ref(it->target_dex_file_, it->target_method_idx_); MethodReference* devirt_target = (it->target_dex_file_ != nullptr) ? &devirt_ref : nullptr; + it->target_dex_file_ = mUnit->GetDexFile(); + it->target_method_idx_ = it->MethodIndex(); + InvokeType invoke_type = it->GetInvokeType(); - mirror::ArtMethod* resolved_method = nullptr; - if (!it->IsQuickened()) { - it->target_dex_file_ = dex_file; - it->target_method_idx_ = it->MethodIndex(); - current_dex_cache.Assign(dex_cache.Get()); - resolved_method = compiler_driver->ResolveMethod(soa, dex_cache, class_loader, mUnit, - it->MethodIndex(), invoke_type); - } else { - // The method index is actually the dex PC in this case. - // Calculate the proper dex file and target method idx. - CHECK(use_jit); - CHECK_EQ(invoke_type, kVirtual); - // Don't devirt if we are in a different dex file since we can't have direct invokes in - // another dex file unless we always put a direct / patch pointer. - devirt_target = nullptr; - current_dex_cache.Assign( - Runtime::Current()->GetClassLinker()->FindDexCache(*it->target_dex_file_)); - CHECK(current_dex_cache.Get() != nullptr); - DexCompilationUnit cu( - mUnit->GetCompilationUnit(), mUnit->GetClassLoader(), mUnit->GetClassLinker(), - *it->target_dex_file_, nullptr /* code_item not used */, 0u /* class_def_idx not used */, - it->target_method_idx_, 0u /* access_flags not used */, - nullptr /* verified_method not used */); - resolved_method = compiler_driver->ResolveMethod(soa, current_dex_cache, class_loader, &cu, - it->target_method_idx_, invoke_type, false); - if (resolved_method != nullptr) { - // Since this was a dequickened virtual, it is guaranteed to be resolved. However, it may be - // resolved to an interface method. If this is the case then change the invoke type to - // interface with the assumption that sharp_type will be kVirtual. - if (resolved_method->GetInvokeType() == kInterface) { - it->flags_ = (it->flags_ & ~(kInvokeTypeMask << kBitInvokeTypeBegin)) | - (static_cast<uint16_t>(kInterface) << kBitInvokeTypeBegin); - } - } - } + mirror::ArtMethod* resolved_method = + compiler_driver->ResolveMethod(soa, dex_cache, class_loader, mUnit, it->MethodIndex(), + invoke_type); if (UNLIKELY(resolved_method == nullptr)) { continue; } compiler_driver->GetResolvedMethodDexFileLocation(resolved_method, &it->declaring_dex_file_, &it->declaring_class_idx_, &it->declaring_method_idx_); - if (!it->IsQuickened()) { - // For quickened invoke virtuals we may have desharpened to an interface method which - // wont give us the right method index, in this case blindly dispatch or else we can't - // compile the method. Converting the invoke to interface dispatch doesn't work since we - // have no way to get the dex method index for quickened invoke virtuals in the interface - // trampolines. - it->vtable_idx_ = - compiler_driver->GetResolvedMethodVTableIndex(resolved_method, invoke_type); - } + it->vtable_idx_ = compiler_driver->GetResolvedMethodVTableIndex(resolved_method, invoke_type); - MethodReference target_method(it->target_dex_file_, it->target_method_idx_); + MethodReference target_method(mUnit->GetDexFile(), it->MethodIndex()); int fast_path_flags = compiler_driver->IsFastInvoke( - soa, dex_cache, class_loader, mUnit, referrer_class.Get(), resolved_method, - &invoke_type, &target_method, devirt_target, &it->direct_code_, &it->direct_method_); - const bool is_referrers_class = referrer_class.Get() == resolved_method->GetDeclaringClass(); - const bool is_class_initialized = + soa, dex_cache, class_loader, mUnit, referrer_class.Get(), resolved_method, &invoke_type, + &target_method, devirt_target, &it->direct_code_, &it->direct_method_); + bool is_referrers_class = (referrer_class.Get() == resolved_method->GetDeclaringClass()); + bool is_class_initialized = compiler_driver->IsMethodsClassInitialized(referrer_class.Get(), resolved_method); uint16_t other_flags = it->flags_ & ~(kFlagFastPath | kFlagClassIsInitialized | (kInvokeTypeMask << kBitSharpTypeBegin)); diff --git a/compiler/dex/mir_method_info.h b/compiler/dex/mir_method_info.h index e131c96..08fb103 100644 --- a/compiler/dex/mir_method_info.h +++ b/compiler/dex/mir_method_info.h @@ -46,9 +46,6 @@ class MirMethodInfo { const DexFile* DeclaringDexFile() const { return declaring_dex_file_; } - void SetDeclaringDexFile(const DexFile* dex_file) { - declaring_dex_file_ = dex_file; - } uint16_t DeclaringClassIndex() const { return declaring_class_idx_; @@ -101,12 +98,11 @@ class MirMethodLoweringInfo : public MirMethodInfo { MirMethodLoweringInfo* method_infos, size_t count) LOCKS_EXCLUDED(Locks::mutator_lock_); - MirMethodLoweringInfo(uint16_t method_idx, InvokeType type, bool is_quickened) + MirMethodLoweringInfo(uint16_t method_idx, InvokeType type) : MirMethodInfo(method_idx, ((type == kStatic) ? kFlagIsStatic : 0u) | (static_cast<uint16_t>(type) << kBitInvokeTypeBegin) | - (static_cast<uint16_t>(type) << kBitSharpTypeBegin) | - (is_quickened ? kFlagQuickened : 0u)), + (static_cast<uint16_t>(type) << kBitSharpTypeBegin)), direct_code_(0u), direct_method_(0u), target_dex_file_(nullptr), @@ -135,11 +131,6 @@ class MirMethodLoweringInfo : public MirMethodInfo { return (flags_ & kFlagClassIsInitialized) != 0u; } - // Returns true iff the method invoke is INVOKE_VIRTUAL_QUICK or INVOKE_VIRTUAL_RANGE_QUICK. - bool IsQuickened() const { - return (flags_ & kFlagQuickened) != 0u; - } - InvokeType GetInvokeType() const { return static_cast<InvokeType>((flags_ >> kBitInvokeTypeBegin) & kInvokeTypeMask); } @@ -155,9 +146,6 @@ class MirMethodLoweringInfo : public MirMethodInfo { uint16_t VTableIndex() const { return vtable_idx_; } - void SetVTableIndex(uint16_t index) { - vtable_idx_ = index; - } uintptr_t DirectCode() const { return direct_code_; @@ -171,20 +159,6 @@ class MirMethodLoweringInfo : public MirMethodInfo { return stats_flags_; } - void CheckEquals(const MirMethodLoweringInfo& info) const { - CHECK_EQ(method_idx_, info.method_idx_); - CHECK_EQ(flags_, info.flags_); - CHECK_EQ(declaring_method_idx_, info.declaring_method_idx_); - CHECK_EQ(declaring_class_idx_, info.declaring_class_idx_); - CHECK_EQ(declaring_dex_file_, info.declaring_dex_file_); - CHECK_EQ(direct_code_, info.direct_code_); - CHECK_EQ(direct_method_, info.direct_method_); - CHECK_EQ(target_dex_file_, info.target_dex_file_); - CHECK_EQ(target_method_idx_, info.target_method_idx_); - CHECK_EQ(vtable_idx_, info.vtable_idx_); - CHECK_EQ(stats_flags_, info.stats_flags_); - } - private: enum { kBitFastPath = kMethodInfoBitEnd, @@ -194,14 +168,12 @@ class MirMethodLoweringInfo : public MirMethodInfo { kBitSharpTypeEnd = kBitSharpTypeBegin + 3, // 3 bits for sharp type. kBitIsReferrersClass = kBitSharpTypeEnd, kBitClassIsInitialized, - kBitQuickened, kMethodLoweringInfoBitEnd }; static_assert(kMethodLoweringInfoBitEnd <= 16, "Too many flags"); static constexpr uint16_t kFlagFastPath = 1u << kBitFastPath; static constexpr uint16_t kFlagIsReferrersClass = 1u << kBitIsReferrersClass; static constexpr uint16_t kFlagClassIsInitialized = 1u << kBitClassIsInitialized; - static constexpr uint16_t kFlagQuickened = 1u << kBitQuickened; static constexpr uint16_t kInvokeTypeMask = 7u; static_assert((1u << (kBitInvokeTypeEnd - kBitInvokeTypeBegin)) - 1u == kInvokeTypeMask, "assert invoke type bits failed"); diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc index 93749e4..fd67d4e 100644 --- a/compiler/dex/mir_optimization.cc +++ b/compiler/dex/mir_optimization.cc @@ -1437,7 +1437,7 @@ void MIRGraph::ComputeInlineIFieldLoweringInfo(uint16_t field_idx, MIR* invoke, 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 */); DexMemAccessType type = IGetOrIPutMemAccessType(iget_or_iput->dalvikInsn.opcode); - MirIFieldLoweringInfo inlined_field_info(field_idx, type, false); + MirIFieldLoweringInfo inlined_field_info(field_idx, type); MirIFieldLoweringInfo::Resolve(cu_->compiler_driver, &inlined_unit, &inlined_field_info, 1u); DCHECK(inlined_field_info.IsResolved()); diff --git a/compiler/dex/mir_optimization_test.cc b/compiler/dex/mir_optimization_test.cc index 9ce5ebb..be05b80 100644 --- a/compiler/dex/mir_optimization_test.cc +++ b/compiler/dex/mir_optimization_test.cc @@ -254,7 +254,7 @@ class MirOptimizationTest : public testing::Test { cu_.mir_graph->method_lowering_infos_.reserve(count); for (size_t i = 0u; i != count; ++i) { const MethodDef* def = &defs[i]; - MirMethodLoweringInfo method_info(def->method_idx, def->invoke_type, false); + MirMethodLoweringInfo method_info(def->method_idx, def->invoke_type); if (def->declaring_dex_file != 0u) { method_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file); method_info.declaring_class_idx_ = def->declaring_class_idx; @@ -407,7 +407,7 @@ 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, def->type, false); + MirIFieldLoweringInfo field_info(def->field_idx, def->type); if (def->declaring_dex_file != 0u) { field_info.declaring_dex_file_ = reinterpret_cast<const DexFile*>(def->declaring_dex_file); field_info.declaring_class_idx_ = def->declaring_class_idx; diff --git a/compiler/dex/quick/dex_file_method_inliner.cc b/compiler/dex/quick/dex_file_method_inliner.cc index f636e3b..7245853 100644 --- a/compiler/dex/quick/dex_file_method_inliner.cc +++ b/compiler/dex/quick/dex_file_method_inliner.cc @@ -427,7 +427,7 @@ bool DexFileMethodInliner::GenIntrinsic(Mir2Lir* backend, CallInfo* info) { InlineMethod intrinsic; { ReaderMutexLock mu(Thread::Current(), lock_); - auto it = inline_methods_.find(info->method_ref.dex_method_index); + auto it = inline_methods_.find(info->index); if (it == inline_methods_.end() || (it->second.flags & kInlineIntrinsic) == 0) { return false; } diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc index 6f68d1a..3c9b7a3 100644 --- a/compiler/dex/quick/gen_common.cc +++ b/compiler/dex/quick/gen_common.cc @@ -865,12 +865,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); - if (kIsDebugBuild) { - auto mem_access_type = IsInstructionIGetQuickOrIPutQuick(mir->dalvikInsn.opcode) ? - IGetQuickOrIPutQuickMemAccessType(mir->dalvikInsn.opcode) : - IGetMemAccessType(mir->dalvikInsn.opcode); - DCHECK_EQ(mem_access_type, field_info.MemAccessType()) << mir->dalvikInsn.opcode; - } + DCHECK_EQ(IGetMemAccessType(mir->dalvikInsn.opcode), field_info.MemAccessType()); cu_->compiler_driver->ProcessedInstanceField(field_info.FastGet()); if (!ForceSlowFieldPath(cu_) && field_info.FastGet()) { RegisterClass reg_class = RegClassForFieldLoadStore(size, field_info.IsVolatile()); @@ -895,9 +890,6 @@ void Mir2Lir::GenIGet(MIR* mir, int opt_flags, OpSize size, Primitive::Type type StoreValue(rl_dest, rl_result); } } else { - if (field_info.DeclaringDexFile() != nullptr) { - DCHECK_EQ(field_info.DeclaringDexFile(), cu_->dex_file); - } DCHECK(SizeMatchesTypeForEntrypoint(size, type)); QuickEntrypointEnum target; switch (type) { @@ -947,12 +939,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); - if (kIsDebugBuild) { - auto mem_access_type = IsInstructionIGetQuickOrIPutQuick(mir->dalvikInsn.opcode) ? - IGetQuickOrIPutQuickMemAccessType(mir->dalvikInsn.opcode) : - IPutMemAccessType(mir->dalvikInsn.opcode); - DCHECK_EQ(mem_access_type, field_info.MemAccessType()); - } + DCHECK_EQ(IPutMemAccessType(mir->dalvikInsn.opcode), field_info.MemAccessType()); cu_->compiler_driver->ProcessedInstanceField(field_info.FastPut()); if (!ForceSlowFieldPath(cu_) && field_info.FastPut()) { RegisterClass reg_class = RegClassForFieldLoadStore(size, field_info.IsVolatile()); diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc index 040b07c..8e3df7c 100755 --- a/compiler/dex/quick/gen_invoke.cc +++ b/compiler/dex/quick/gen_invoke.cc @@ -863,12 +863,11 @@ RegLocation Mir2Lir::InlineTarget(CallInfo* info) { RegLocation res; if (info->result.location == kLocInvalid) { // If result is unused, return a sink target based on type of invoke target. - res = GetReturn( - ShortyToRegClass(mir_graph_->GetShortyFromMethodReference(info->method_ref)[0])); + res = GetReturn(ShortyToRegClass(mir_graph_->GetShortyFromTargetIdx(info->index)[0])); } else { res = info->result; DCHECK_EQ(LocToRegClass(res), - ShortyToRegClass(mir_graph_->GetShortyFromMethodReference(info->method_ref)[0])); + ShortyToRegClass(mir_graph_->GetShortyFromTargetIdx(info->index)[0])); } return res; } @@ -877,12 +876,11 @@ RegLocation Mir2Lir::InlineTargetWide(CallInfo* info) { RegLocation res; if (info->result.location == kLocInvalid) { // If result is unused, return a sink target based on type of invoke target. - res = GetReturnWide(ShortyToRegClass( - mir_graph_->GetShortyFromMethodReference(info->method_ref)[0])); + res = GetReturnWide(ShortyToRegClass(mir_graph_->GetShortyFromTargetIdx(info->index)[0])); } else { res = info->result; DCHECK_EQ(LocToRegClass(res), - ShortyToRegClass(mir_graph_->GetShortyFromMethodReference(info->method_ref)[0])); + ShortyToRegClass(mir_graph_->GetShortyFromTargetIdx(info->index)[0])); } return res; } @@ -1420,8 +1418,7 @@ bool Mir2Lir::GenInlinedUnsafePut(CallInfo* info, bool is_long, void Mir2Lir::GenInvoke(CallInfo* info) { DCHECK(cu_->compiler_driver->GetMethodInlinerMap() != nullptr); - const DexFile* dex_file = info->method_ref.dex_file; - if (cu_->compiler_driver->GetMethodInlinerMap()->GetMethodInliner(dex_file) + if (cu_->compiler_driver->GetMethodInlinerMap()->GetMethodInliner(cu_->dex_file) ->GenIntrinsic(this, info)) { return; } @@ -1431,7 +1428,7 @@ void Mir2Lir::GenInvoke(CallInfo* info) { void Mir2Lir::GenInvokeNoInline(CallInfo* info) { int call_state = 0; LIR* null_ck; - LIR** p_null_ck = nullptr; + LIR** p_null_ck = NULL; NextCallInsn next_call_insn; FlushAllRegs(); /* Everything to home location */ // Explicit register usage @@ -1443,7 +1440,6 @@ void Mir2Lir::GenInvokeNoInline(CallInfo* info) { info->type = method_info.GetSharpType(); bool fast_path = method_info.FastPath(); bool skip_this; - if (info->type == kInterface) { next_call_insn = fast_path ? NextInterfaceCallInsn : NextInterfaceCallInsnWithAccessCheck; skip_this = fast_path; @@ -1473,8 +1469,7 @@ void Mir2Lir::GenInvokeNoInline(CallInfo* info) { // Finish up any of the call sequence not interleaved in arg loading while (call_state >= 0) { call_state = next_call_insn(cu_, info, call_state, target_method, method_info.VTableIndex(), - method_info.DirectCode(), method_info.DirectMethod(), - original_type); + method_info.DirectCode(), method_info.DirectMethod(), original_type); } LIR* call_insn = GenCallInsn(method_info); MarkSafepointPC(call_insn); diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc index 966a92d..34e5e25 100644 --- a/compiler/dex/quick/mir_to_lir.cc +++ b/compiler/dex/quick/mir_to_lir.cc @@ -540,7 +540,6 @@ void Mir2Lir::CompileDalvikInstruction(MIR* mir, BasicBlock* bb, LIR* label_list GenMoveException(rl_dest); break; - case Instruction::RETURN_VOID_BARRIER: case Instruction::RETURN_VOID: if (((cu_->access_flags & kAccConstructor) != 0) && cu_->compiler_driver->RequiresConstructorBarrier(Thread::Current(), cu_->dex_file, @@ -791,12 +790,10 @@ void Mir2Lir::CompileDalvikInstruction(MIR* mir, BasicBlock* bb, LIR* label_list GenArrayPut(opt_flags, kUnsignedByte, rl_src[1], rl_src[2], rl_src[0], 0, false); break; - case Instruction::IGET_OBJECT_QUICK: case Instruction::IGET_OBJECT: GenIGet(mir, opt_flags, kReference, Primitive::kPrimNot, rl_dest, rl_src[0]); break; - case Instruction::IGET_WIDE_QUICK: case Instruction::IGET_WIDE: // kPrimLong and kPrimDouble share the same entrypoints. if (rl_dest.fp) { @@ -806,7 +803,6 @@ void Mir2Lir::CompileDalvikInstruction(MIR* mir, BasicBlock* bb, LIR* label_list } break; - case Instruction::IGET_QUICK: case Instruction::IGET: if (rl_dest.fp) { GenIGet(mir, opt_flags, kSingle, Primitive::kPrimFloat, rl_dest, rl_src[0]); @@ -815,54 +811,43 @@ void Mir2Lir::CompileDalvikInstruction(MIR* mir, BasicBlock* bb, LIR* label_list } break; - case Instruction::IGET_CHAR_QUICK: case Instruction::IGET_CHAR: GenIGet(mir, opt_flags, kUnsignedHalf, Primitive::kPrimChar, rl_dest, rl_src[0]); break; - case Instruction::IGET_SHORT_QUICK: case Instruction::IGET_SHORT: GenIGet(mir, opt_flags, kSignedHalf, Primitive::kPrimShort, rl_dest, rl_src[0]); break; - case Instruction::IGET_BOOLEAN_QUICK: case Instruction::IGET_BOOLEAN: GenIGet(mir, opt_flags, kUnsignedByte, Primitive::kPrimBoolean, rl_dest, rl_src[0]); break; - case Instruction::IGET_BYTE_QUICK: case Instruction::IGET_BYTE: GenIGet(mir, opt_flags, kSignedByte, Primitive::kPrimByte, rl_dest, rl_src[0]); break; - case Instruction::IPUT_WIDE_QUICK: case Instruction::IPUT_WIDE: GenIPut(mir, opt_flags, rl_src[0].fp ? kDouble : k64, rl_src[0], rl_src[1]); break; - case Instruction::IPUT_OBJECT_QUICK: case Instruction::IPUT_OBJECT: GenIPut(mir, opt_flags, kReference, rl_src[0], rl_src[1]); break; - case Instruction::IPUT_QUICK: case Instruction::IPUT: GenIPut(mir, opt_flags, rl_src[0].fp ? kSingle : k32, rl_src[0], rl_src[1]); break; - case Instruction::IPUT_BYTE_QUICK: - case Instruction::IPUT_BOOLEAN_QUICK: case Instruction::IPUT_BYTE: case Instruction::IPUT_BOOLEAN: GenIPut(mir, opt_flags, kUnsignedByte, rl_src[0], rl_src[1]); break; - case Instruction::IPUT_CHAR_QUICK: case Instruction::IPUT_CHAR: GenIPut(mir, opt_flags, kUnsignedHalf, rl_src[0], rl_src[1]); break; - case Instruction::IPUT_SHORT_QUICK: case Instruction::IPUT_SHORT: GenIPut(mir, opt_flags, kSignedHalf, rl_src[0], rl_src[1]); break; @@ -936,12 +921,9 @@ void Mir2Lir::CompileDalvikInstruction(MIR* mir, BasicBlock* bb, LIR* label_list GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kDirect, true)); break; - case Instruction::INVOKE_VIRTUAL_QUICK: case Instruction::INVOKE_VIRTUAL: GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kVirtual, false)); break; - - case Instruction::INVOKE_VIRTUAL_RANGE_QUICK: case Instruction::INVOKE_VIRTUAL_RANGE: GenInvoke(mir_graph_->NewMemCallInfo(bb, mir, kVirtual, true)); break; diff --git a/compiler/dex/quick/quick_compiler.cc b/compiler/dex/quick/quick_compiler.cc index fcf4716..19c2a5a 100644 --- a/compiler/dex/quick/quick_compiler.cc +++ b/compiler/dex/quick/quick_compiler.cc @@ -542,11 +542,6 @@ bool QuickCompiler::CanCompileMethod(uint32_t method_idx, const DexFile& dex_fil void QuickCompiler::InitCompilationUnit(CompilationUnit& cu) const { // Disable optimizations according to instruction set. cu.disable_opt |= kDisabledOptimizationsPerISA[cu.instruction_set]; - if (Runtime::Current()->UseJit()) { - // Disable these optimizations for JIT until quickened byte codes are done being implemented. - // TODO: Find a cleaner way to do this. - cu.disable_opt |= 1u << kLocalValueNumbering; - } } void QuickCompiler::Init() { diff --git a/compiler/dex/verification_results.cc b/compiler/dex/verification_results.cc index 51a3d84..4ff173d 100644 --- a/compiler/dex/verification_results.cc +++ b/compiler/dex/verification_results.cc @@ -66,10 +66,8 @@ bool VerificationResults::ProcessVerifiedMethod(verifier::MethodVerifier* method // TODO: Investigate why are we doing the work again for this method and try to avoid it. LOG(WARNING) << "Method processed more than once: " << PrettyMethod(ref.dex_method_index, *ref.dex_file); - if (!Runtime::Current()->UseJit()) { - DCHECK_EQ(it->second->GetDevirtMap().size(), verified_method->GetDevirtMap().size()); - DCHECK_EQ(it->second->GetSafeCastSet().size(), verified_method->GetSafeCastSet().size()); - } + DCHECK_EQ(it->second->GetDevirtMap().size(), verified_method->GetDevirtMap().size()); + DCHECK_EQ(it->second->GetSafeCastSet().size(), verified_method->GetSafeCastSet().size()); DCHECK_EQ(it->second->GetDexGcMap().size(), verified_method->GetDexGcMap().size()); delete it->second; verified_methods_.erase(it); diff --git a/compiler/dex/verified_method.cc b/compiler/dex/verified_method.cc index 42d66be..21e965d 100644 --- a/compiler/dex/verified_method.cc +++ b/compiler/dex/verified_method.cc @@ -24,7 +24,6 @@ #include "base/stl_util.h" #include "dex_file.h" #include "dex_instruction-inl.h" -#include "dex_instruction_utils.h" #include "mirror/art_method-inl.h" #include "mirror/class-inl.h" #include "mirror/dex_cache-inl.h" @@ -53,11 +52,6 @@ const VerifiedMethod* VerifiedMethod::Create(verifier::MethodVerifier* method_ve if (method_verifier->HasVirtualOrInterfaceInvokes()) { verified_method->GenerateDevirtMap(method_verifier); } - - // Only need dequicken info for JIT so far. - if (Runtime::Current()->UseJit()) { - verified_method->GenerateDequickenMap(method_verifier); - } } if (method_verifier->HasCheckCasts()) { @@ -71,12 +65,6 @@ const MethodReference* VerifiedMethod::GetDevirtTarget(uint32_t dex_pc) const { return (it != devirt_map_.end()) ? &it->second : nullptr; } -const DexFileReference* VerifiedMethod::GetDequickenIndex(uint32_t dex_pc) const { - DCHECK(Runtime::Current()->UseJit()); - auto it = dequicken_map_.find(dex_pc); - return (it != dequicken_map_.end()) ? &it->second : nullptr; -} - bool VerifiedMethod::IsSafeCast(uint32_t pc) const { return std::binary_search(safe_cast_set_.begin(), safe_cast_set_.end(), pc); } @@ -194,7 +182,7 @@ void VerifiedMethod::ComputeGcMapSizes(verifier::MethodVerifier* method_verifier *log2_max_gc_pc = i; } -void VerifiedMethod::GenerateDequickenMap(verifier::MethodVerifier* method_verifier) { +void VerifiedMethod::GenerateDeQuickenMap(verifier::MethodVerifier* method_verifier) { if (method_verifier->HasFailures()) { return; } @@ -208,24 +196,13 @@ void VerifiedMethod::GenerateDequickenMap(verifier::MethodVerifier* method_verif if (is_virtual_quick || is_range_quick) { uint32_t dex_pc = inst->GetDexPc(insns); verifier::RegisterLine* line = method_verifier->GetRegLine(dex_pc); - mirror::ArtMethod* method = - method_verifier->GetQuickInvokedMethod(inst, line, is_range_quick); + mirror::ArtMethod* method = method_verifier->GetQuickInvokedMethod(inst, line, + is_range_quick); CHECK(method != nullptr); // The verifier must know what the type of the object was or else we would have gotten a // failure. Put the dex method index in the dequicken map since we need this to get number of // arguments in the compiler. - dequicken_map_.Put(dex_pc, DexFileReference(method->GetDexFile(), - method->GetDexMethodIndex())); - } else if (IsInstructionIGetQuickOrIPutQuick(inst->Opcode())) { - uint32_t dex_pc = inst->GetDexPc(insns); - verifier::RegisterLine* line = method_verifier->GetRegLine(dex_pc); - mirror::ArtField* field = method_verifier->GetQuickFieldAccess(inst, line); - CHECK(field != nullptr); - // The verifier must know what the type of the field was or else we would have gotten a - // failure. Put the dex field index in the dequicken map since we need this for lowering - // in the compiler. - // TODO: Putting a field index in a method reference is gross. - dequicken_map_.Put(dex_pc, DexFileReference(field->GetDexFile(), field->GetDexFieldIndex())); + dequicken_map_.Put(dex_pc, method->ToMethodReference()); } } } diff --git a/compiler/dex/verified_method.h b/compiler/dex/verified_method.h index 748bdcb..fe9dfd1 100644 --- a/compiler/dex/verified_method.h +++ b/compiler/dex/verified_method.h @@ -20,7 +20,6 @@ #include <vector> #include "base/mutex.h" -#include "dex_file.h" #include "method_reference.h" #include "safe_map.h" @@ -40,9 +39,6 @@ class VerifiedMethod { // Devirtualization map type maps dex offset to concrete method reference. typedef SafeMap<uint32_t, MethodReference> DevirtualizationMap; - // Devirtualization map type maps dex offset to field / method idx. - typedef SafeMap<uint32_t, DexFileReference> DequickenMap; - static const VerifiedMethod* Create(verifier::MethodVerifier* method_verifier, bool compile) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); ~VerifiedMethod() = default; @@ -62,10 +58,6 @@ class VerifiedMethod { // Returns the devirtualization target method, or nullptr if none. const MethodReference* GetDevirtTarget(uint32_t dex_pc) const; - // Returns the dequicken field / method for a quick invoke / field get. Returns null if there is - // no entry for that dex pc. - const DexFileReference* GetDequickenIndex(uint32_t dex_pc) const; - // Returns true if the cast can statically be verified to be redundant // by using the check-cast elision peephole optimization in the verifier. bool IsSafeCast(uint32_t pc) const; @@ -94,7 +86,7 @@ class VerifiedMethod { SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Generate dequickening map into dequicken_map_. - void GenerateDequickenMap(verifier::MethodVerifier* method_verifier) + void GenerateDeQuickenMap(verifier::MethodVerifier* method_verifier) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Generate safe case set into safe_cast_set_. @@ -103,9 +95,9 @@ class VerifiedMethod { std::vector<uint8_t> dex_gc_map_; DevirtualizationMap devirt_map_; - // Dequicken map is required for compiling quickened byte codes. The quicken maps from - // dex PC to dex method index or dex field index based on the instruction. - DequickenMap dequicken_map_; + // Dequicken map is required for having the compiler compiled quickened invokes. The quicken map + // enables us to get the dex method index so that we can get the required argument count. + DevirtualizationMap dequicken_map_; SafeCastSet safe_cast_set_; }; diff --git a/compiler/dex/vreg_analysis.cc b/compiler/dex/vreg_analysis.cc index 2b78e38..b620969 100644 --- a/compiler/dex/vreg_analysis.cc +++ b/compiler/dex/vreg_analysis.cc @@ -19,7 +19,6 @@ #include "compiler_ir.h" #include "dex/dataflow_iterator-inl.h" #include "dex_flags.h" -#include "driver/dex_compilation_unit.h" namespace art { @@ -260,8 +259,8 @@ bool MIRGraph::InferTypeAndSize(BasicBlock* bb, MIR* mir, bool changed) { if ((flags & Instruction::kInvoke) && (attrs & (DF_FORMAT_35C | DF_FORMAT_3RC))) { DCHECK_EQ(next, 0); - const auto& lowering_info = GetMethodLoweringInfo(mir); - const char* shorty = GetShortyFromMethodReference(lowering_info.GetTargetMethod()); + int target_idx = mir->dalvikInsn.vB; + const char* shorty = GetShortyFromTargetIdx(target_idx); // Handle result type if floating point if ((shorty[0] == 'F') || (shorty[0] == 'D')) { MIR* move_result_mir = FindMoveResult(bb, mir); diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h index 4a35e9f..9948c82 100644 --- a/compiler/driver/compiler_driver-inl.h +++ b/compiler/driver/compiler_driver-inl.h @@ -56,13 +56,14 @@ inline mirror::Class* CompilerDriver::ResolveCompilingMethodsClass( return referrer_class; } -inline mirror::ArtField* CompilerDriver::ResolveFieldWithDexFile( +inline mirror::ArtField* CompilerDriver::ResolveField( const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache, - Handle<mirror::ClassLoader> class_loader, const DexFile* dex_file, + Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit, uint32_t field_idx, bool is_static) { - DCHECK_EQ(dex_cache->GetDexFile(), dex_file); - mirror::ArtField* resolved_field = Runtime::Current()->GetClassLinker()->ResolveField( - *dex_file, field_idx, dex_cache, class_loader, is_static); + DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile()); + DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader())); + mirror::ArtField* resolved_field = mUnit->GetClassLinker()->ResolveField( + *mUnit->GetDexFile(), field_idx, dex_cache, class_loader, is_static); DCHECK_EQ(resolved_field == nullptr, soa.Self()->IsExceptionPending()); if (UNLIKELY(resolved_field == nullptr)) { // Clean up any exception left by type resolution. @@ -77,19 +78,6 @@ inline mirror::ArtField* CompilerDriver::ResolveFieldWithDexFile( return resolved_field; } -inline mirror::DexCache* CompilerDriver::FindDexCache(const DexFile* dex_file) { - return Runtime::Current()->GetClassLinker()->FindDexCache(*dex_file); -} - -inline mirror::ArtField* CompilerDriver::ResolveField( - const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache, - Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit, - uint32_t field_idx, bool is_static) { - DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader())); - return ResolveFieldWithDexFile(soa, dex_cache, class_loader, mUnit->GetDexFile(), field_idx, - is_static); -} - inline void CompilerDriver::GetResolvedFieldDexFileLocation( mirror::ArtField* resolved_field, const DexFile** declaring_dex_file, uint16_t* declaring_class_idx, uint16_t* declaring_field_idx) { @@ -184,7 +172,7 @@ inline bool CompilerDriver::IsStaticFieldsClassInitialized(mirror::Class* referr inline mirror::ArtMethod* CompilerDriver::ResolveMethod( ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit, - uint32_t method_idx, InvokeType invoke_type, bool check_incompatible_class_change) { + uint32_t method_idx, InvokeType invoke_type) { DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile()); DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader())); mirror::ArtMethod* resolved_method = mUnit->GetClassLinker()->ResolveMethod( @@ -196,8 +184,7 @@ inline mirror::ArtMethod* CompilerDriver::ResolveMethod( soa.Self()->ClearException(); return nullptr; } - if (check_incompatible_class_change && - UNLIKELY(resolved_method->CheckIncompatibleClassChange(invoke_type))) { + if (UNLIKELY(resolved_method->CheckIncompatibleClassChange(invoke_type))) { // Silently return nullptr on incompatible class change. return nullptr; } @@ -240,14 +227,14 @@ inline int CompilerDriver::IsFastInvoke( target_method->dex_method_index))) { return 0; } + // Sharpen a virtual call into a direct call when the target is known not to have been // overridden (ie is final). - const bool same_dex_file = target_method->dex_file == mUnit->GetDexFile(); - bool can_sharpen_virtual_based_on_type = same_dex_file && + bool can_sharpen_virtual_based_on_type = (*invoke_type == kVirtual) && (resolved_method->IsFinal() || methods_class->IsFinal()); // For invoke-super, ensure the vtable index will be correct to dispatch in the vtable of // the super class. - bool can_sharpen_super_based_on_type = same_dex_file && (*invoke_type == kSuper) && + bool can_sharpen_super_based_on_type = (*invoke_type == kSuper) && (referrer_class != methods_class) && referrer_class->IsSubClass(methods_class) && resolved_method->GetMethodIndex() < methods_class->GetVTableLength() && (methods_class->GetVTableEntry(resolved_method->GetMethodIndex()) == resolved_method) && @@ -256,10 +243,10 @@ inline int CompilerDriver::IsFastInvoke( if (can_sharpen_virtual_based_on_type || can_sharpen_super_based_on_type) { // Sharpen a virtual call into a direct call. The method_idx is into referrer's // dex cache, check that this resolved method is where we expect it. - CHECK_EQ(target_method->dex_file, mUnit->GetDexFile()); - DCHECK_EQ(dex_cache.Get(), mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile())); - CHECK_EQ(referrer_class->GetDexCache()->GetResolvedMethod(target_method->dex_method_index), - resolved_method) << PrettyMethod(resolved_method); + CHECK(target_method->dex_file == mUnit->GetDexFile()); + DCHECK(dex_cache.Get() == mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile())); + CHECK(referrer_class->GetDexCache()->GetResolvedMethod(target_method->dex_method_index) == + resolved_method) << PrettyMethod(resolved_method); int stats_flags = kFlagMethodResolved; GetCodeAndMethodForDirectCall(/*out*/invoke_type, kDirect, // Sharp type diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 15b3d08..b8a8936 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -360,7 +360,6 @@ CompilerDriver::CompilerDriver(const CompilerOptions* compiler_options, classes_to_compile_(compiled_classes), thread_count_(thread_count), stats_(new AOTCompilationStats), - dedupe_enabled_(true), dump_stats_(dump_stats), dump_passes_(dump_passes), dump_cfg_file_name_(dump_cfg_file_name), @@ -381,7 +380,12 @@ CompilerDriver::CompilerDriver(const CompilerOptions* compiler_options, compiler_->Init(); - CHECK_EQ(image_, image_classes_.get() != nullptr); + CHECK(!Runtime::Current()->IsStarted()); + if (image_) { + CHECK(image_classes_.get() != nullptr); + } else { + CHECK(image_classes_.get() == nullptr); + } // Read the profile file if one is provided. if (!profile_file.empty()) { @@ -395,32 +399,26 @@ CompilerDriver::CompilerDriver(const CompilerOptions* compiler_options, } SwapVector<uint8_t>* CompilerDriver::DeduplicateCode(const ArrayRef<const uint8_t>& code) { - DCHECK(dedupe_enabled_); return dedupe_code_.Add(Thread::Current(), code); } SwapSrcMap* CompilerDriver::DeduplicateSrcMappingTable(const ArrayRef<SrcMapElem>& src_map) { - DCHECK(dedupe_enabled_); return dedupe_src_mapping_table_.Add(Thread::Current(), src_map); } SwapVector<uint8_t>* CompilerDriver::DeduplicateMappingTable(const ArrayRef<const uint8_t>& code) { - DCHECK(dedupe_enabled_); return dedupe_mapping_table_.Add(Thread::Current(), code); } SwapVector<uint8_t>* CompilerDriver::DeduplicateVMapTable(const ArrayRef<const uint8_t>& code) { - DCHECK(dedupe_enabled_); return dedupe_vmap_table_.Add(Thread::Current(), code); } SwapVector<uint8_t>* CompilerDriver::DeduplicateGCMap(const ArrayRef<const uint8_t>& code) { - DCHECK(dedupe_enabled_); return dedupe_gc_map_.Add(Thread::Current(), code); } SwapVector<uint8_t>* CompilerDriver::DeduplicateCFIInfo(const ArrayRef<const uint8_t>& cfi_info) { - DCHECK(dedupe_enabled_); return dedupe_cfi_info_.Add(Thread::Current(), cfi_info); } @@ -493,12 +491,8 @@ void CompilerDriver::CompileAll(jobject class_loader, static DexToDexCompilationLevel GetDexToDexCompilationlevel( Thread* self, Handle<mirror::ClassLoader> class_loader, const DexFile& dex_file, const DexFile::ClassDef& class_def) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - auto* const runtime = Runtime::Current(); - if (runtime->UseJit()) { - return kDontDexToDexCompile; - } const char* descriptor = dex_file.GetClassDescriptor(class_def); - ClassLinker* class_linker = runtime->GetClassLinker(); + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); mirror::Class* klass = class_linker->FindClass(self, descriptor, class_loader); if (klass == nullptr) { CHECK(self->IsExceptionPending()); @@ -524,8 +518,9 @@ static DexToDexCompilationLevel GetDexToDexCompilationlevel( } } -void CompilerDriver::CompileOne(Thread* self, mirror::ArtMethod* method, TimingLogger* timings) { +void CompilerDriver::CompileOne(mirror::ArtMethod* method, TimingLogger* timings) { DCHECK(!Runtime::Current()->IsStarted()); + Thread* self = Thread::Current(); jobject jclass_loader; const DexFile* dex_file; uint16_t class_def_idx; @@ -534,8 +529,9 @@ void CompilerDriver::CompileOne(Thread* self, mirror::ArtMethod* method, TimingL InvokeType invoke_type = method->GetInvokeType(); { ScopedObjectAccessUnchecked soa(self); - ScopedLocalRef<jobject> local_class_loader( - soa.Env(), soa.AddLocalReference<jobject>(method->GetDeclaringClass()->GetClassLoader())); + ScopedLocalRef<jobject> + local_class_loader(soa.Env(), + soa.AddLocalReference<jobject>(method->GetDeclaringClass()->GetClassLoader())); jclass_loader = soa.Env()->NewGlobalRef(local_class_loader.get()); // Find the dex_file dex_file = method->GetDexFile(); @@ -553,7 +549,7 @@ void CompilerDriver::CompileOne(Thread* self, mirror::ArtMethod* method, TimingL // Can we run DEX-to-DEX compiler on this class ? DexToDexCompilationLevel dex_to_dex_compilation_level = kDontDexToDexCompile; { - ScopedObjectAccess soa(self); + ScopedObjectAccess soa(Thread::Current()); const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_idx); StackHandleScope<1> hs(soa.Self()); Handle<mirror::ClassLoader> class_loader( @@ -561,33 +557,12 @@ void CompilerDriver::CompileOne(Thread* self, mirror::ArtMethod* method, TimingL dex_to_dex_compilation_level = GetDexToDexCompilationlevel(self, class_loader, *dex_file, class_def); } - CompileMethod(self, code_item, access_flags, invoke_type, class_def_idx, method_idx, - jclass_loader, *dex_file, dex_to_dex_compilation_level, true); + CompileMethod(code_item, access_flags, invoke_type, class_def_idx, method_idx, jclass_loader, + *dex_file, dex_to_dex_compilation_level, true); self->GetJniEnv()->DeleteGlobalRef(jclass_loader); - self->TransitionFromSuspendedToRunnable(); -} -CompiledMethod* CompilerDriver::CompileMethod(Thread* self, mirror::ArtMethod* method) { - const uint32_t method_idx = method->GetDexMethodIndex(); - const uint32_t access_flags = method->GetAccessFlags(); - const InvokeType invoke_type = method->GetInvokeType(); - StackHandleScope<1> hs(self); - Handle<mirror::ClassLoader> class_loader(hs.NewHandle( - method->GetDeclaringClass()->GetClassLoader())); - jobject jclass_loader = class_loader.ToJObject(); - const DexFile* dex_file = method->GetDexFile(); - const uint16_t class_def_idx = method->GetClassDefIndex(); - const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_idx); - DexToDexCompilationLevel dex_to_dex_compilation_level = - GetDexToDexCompilationlevel(self, class_loader, *dex_file, class_def); - const DexFile::CodeItem* code_item = dex_file->GetCodeItem(method->GetCodeItemOffset()); - self->TransitionFromRunnableToSuspended(kNative); - CompileMethod(self, code_item, access_flags, invoke_type, class_def_idx, method_idx, - jclass_loader, *dex_file, dex_to_dex_compilation_level, true); - auto* compiled_method = GetCompiledMethod(MethodReference(dex_file, method_idx)); self->TransitionFromSuspendedToRunnable(); - return compiled_method; } void CompilerDriver::Resolve(jobject class_loader, const std::vector<const DexFile*>& dex_files, @@ -1060,8 +1035,7 @@ bool CompilerDriver::CanEmbedTypeInCode(const DexFile& dex_file, uint32_t type_i bool* is_type_initialized, bool* use_direct_type_ptr, uintptr_t* direct_type_ptr, bool* out_is_finalizable) { ScopedObjectAccess soa(Thread::Current()); - Runtime* runtime = Runtime::Current(); - mirror::DexCache* dex_cache = runtime->GetClassLinker()->FindDexCache(dex_file); + mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file); mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx); if (resolved_class == nullptr) { return false; @@ -1071,8 +1045,7 @@ bool CompilerDriver::CanEmbedTypeInCode(const DexFile& dex_file, uint32_t type_i return false; } *out_is_finalizable = resolved_class->IsFinalizable(); - gc::Heap* heap = runtime->GetHeap(); - const bool compiling_boot = heap->IsCompilingBoot(); + const bool compiling_boot = Runtime::Current()->GetHeap()->IsCompilingBoot(); const bool support_boot_image_fixup = GetSupportBootImageFixup(); if (compiling_boot) { // boot -> boot class pointers. @@ -1088,15 +1061,10 @@ bool CompilerDriver::CanEmbedTypeInCode(const DexFile& dex_file, uint32_t type_i } else { return false; } - } else if (runtime->UseJit() && !heap->IsMovableObject(resolved_class)) { - *is_type_initialized = resolved_class->IsInitialized(); - // If the class may move around, then don't embed it as a direct pointer. - *use_direct_type_ptr = true; - *direct_type_ptr = reinterpret_cast<uintptr_t>(resolved_class); - return true; } else { // True if the class is in the image at app compiling time. - const bool class_in_image = heap->FindSpaceFromObject(resolved_class, false)->IsImageSpace(); + const bool class_in_image = + Runtime::Current()->GetHeap()->FindSpaceFromObject(resolved_class, false)->IsImageSpace(); if (class_in_image && support_boot_image_fixup) { // boot -> app class pointers. *is_type_initialized = resolved_class->IsInitialized(); @@ -1289,10 +1257,8 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType // invoked, so this can be passed to the out-of-line runtime support code. *direct_code = 0; *direct_method = 0; - Runtime* const runtime = Runtime::Current(); - gc::Heap* const heap = runtime->GetHeap(); bool use_dex_cache = GetCompilerOptions().GetCompilePic(); // Off by default - const bool compiling_boot = heap->IsCompilingBoot(); + const bool compiling_boot = Runtime::Current()->GetHeap()->IsCompilingBoot(); // TODO This is somewhat hacky. We should refactor all of this invoke codepath. const bool force_relocations = (compiling_boot || GetCompilerOptions().GetIncludePatchInformation()); @@ -1301,15 +1267,14 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType } // TODO: support patching on all architectures. use_dex_cache = use_dex_cache || (force_relocations && !support_boot_image_fixup_); - mirror::Class* declaring_class = method->GetDeclaringClass(); - bool method_code_in_boot = declaring_class->GetClassLoader() == nullptr; + bool method_code_in_boot = (method->GetDeclaringClass()->GetClassLoader() == nullptr); if (!use_dex_cache) { if (!method_code_in_boot) { use_dex_cache = true; } else { bool has_clinit_trampoline = - method->IsStatic() && !declaring_class->IsInitialized(); - if (has_clinit_trampoline && declaring_class != referrer_class) { + method->IsStatic() && !method->GetDeclaringClass()->IsInitialized(); + if (has_clinit_trampoline && (method->GetDeclaringClass() != referrer_class)) { // Ensure we run the clinit trampoline unless we are invoking a static method in the same // class. use_dex_cache = true; @@ -1337,9 +1302,7 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType // The method is defined not within this dex file. We need a dex cache slot within the current // dex file or direct pointers. bool must_use_direct_pointers = false; - mirror::DexCache* dex_cache = declaring_class->GetDexCache(); - if (target_method->dex_file == dex_cache->GetDexFile() && - !(runtime->UseJit() && dex_cache->GetResolvedMethod(method->GetDexMethodIndex()) == nullptr)) { + if (target_method->dex_file == method->GetDeclaringClass()->GetDexCache()->GetDexFile()) { target_method->dex_method_index = method->GetDexMethodIndex(); } else { if (no_guarantee_of_dex_cache_entry) { @@ -1352,7 +1315,7 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType } else { if (force_relocations && !use_dex_cache) { target_method->dex_method_index = method->GetDexMethodIndex(); - target_method->dex_file = dex_cache->GetDexFile(); + target_method->dex_file = method->GetDeclaringClass()->GetDexCache()->GetDexFile(); } must_use_direct_pointers = true; } @@ -1367,7 +1330,8 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType *type = sharp_type; } } else { - bool method_in_image = heap->FindSpaceFromObject(method, false)->IsImageSpace(); + bool method_in_image = + Runtime::Current()->GetHeap()->FindSpaceFromObject(method, false)->IsImageSpace(); if (method_in_image || compiling_boot) { // We know we must be able to get to the method in the image, so use that pointer. CHECK(!method->IsAbstract()); @@ -2036,11 +2000,10 @@ void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, siz const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index); ClassLinker* class_linker = manager->GetClassLinker(); jobject jclass_loader = manager->GetClassLoader(); - Thread* self = Thread::Current(); { // Use a scoped object access to perform to the quick SkipClass check. const char* descriptor = dex_file.GetClassDescriptor(class_def); - ScopedObjectAccess soa(self); + ScopedObjectAccess soa(Thread::Current()); StackHandleScope<3> hs(soa.Self()); Handle<mirror::ClassLoader> class_loader( hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader))); @@ -2067,7 +2030,7 @@ void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, siz // Can we run DEX-to-DEX compiler on this class ? DexToDexCompilationLevel dex_to_dex_compilation_level = kDontDexToDexCompile; { - ScopedObjectAccess soa(self); + ScopedObjectAccess soa(Thread::Current()); StackHandleScope<1> hs(soa.Self()); Handle<mirror::ClassLoader> class_loader( hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader))); @@ -2098,7 +2061,7 @@ void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, siz continue; } previous_direct_method_idx = method_idx; - driver->CompileMethod(self, it.GetMethodCodeItem(), it.GetMethodAccessFlags(), + driver->CompileMethod(it.GetMethodCodeItem(), it.GetMethodAccessFlags(), it.GetMethodInvokeType(class_def), class_def_index, method_idx, jclass_loader, dex_file, dex_to_dex_compilation_level, compilation_enabled); @@ -2115,7 +2078,7 @@ void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, siz continue; } previous_virtual_method_idx = method_idx; - driver->CompileMethod(self, it.GetMethodCodeItem(), it.GetMethodAccessFlags(), + driver->CompileMethod(it.GetMethodCodeItem(), it.GetMethodAccessFlags(), it.GetMethodInvokeType(class_def), class_def_index, method_idx, jclass_loader, dex_file, dex_to_dex_compilation_level, compilation_enabled); @@ -2148,10 +2111,10 @@ static bool InstructionSetHasGenericJniStub(InstructionSet isa) { } } -void CompilerDriver::CompileMethod(Thread* self, const DexFile::CodeItem* code_item, - uint32_t access_flags, InvokeType invoke_type, - uint16_t class_def_idx, uint32_t method_idx, - jobject class_loader, const DexFile& dex_file, +void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t access_flags, + InvokeType invoke_type, uint16_t class_def_idx, + uint32_t method_idx, jobject class_loader, + const DexFile& dex_file, DexToDexCompilationLevel dex_to_dex_compilation_level, bool compilation_enabled) { CompiledMethod* compiled_method = nullptr; @@ -2199,6 +2162,7 @@ void CompilerDriver::CompileMethod(Thread* self, const DexFile::CodeItem* code_i } } + Thread* self = Thread::Current(); if (compiled_method != nullptr) { // Count non-relative linker patches. size_t non_relative_linker_patch_count = 0u; @@ -2230,21 +2194,6 @@ void CompilerDriver::CompileMethod(Thread* self, const DexFile::CodeItem* code_i } } -void CompilerDriver::RemoveCompiledMethod(const MethodReference& method_ref) { - CompiledMethod* compiled_method = nullptr; - { - MutexLock mu(Thread::Current(), compiled_methods_lock_); - auto it = compiled_methods_.find(method_ref); - if (it != compiled_methods_.end()) { - compiled_method = it->second; - compiled_methods_.erase(it); - } - } - if (compiled_method != nullptr) { - CompiledMethod::ReleaseSwapAllocatedCompiledMethod(this, compiled_method); - } -} - CompiledClass* CompilerDriver::GetCompiledClass(ClassReference ref) const { MutexLock mu(Thread::Current(), compiled_classes_lock_); ClassTable::const_iterator it = compiled_classes_.find(ref); diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index 24b6f17..b756244 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -45,10 +45,6 @@ namespace art { -namespace mirror { -class DexCache; -} // namespace mirror - namespace verifier { class MethodVerifier; } // namespace verifier @@ -111,11 +107,8 @@ class CompilerDriver { TimingLogger* timings) LOCKS_EXCLUDED(Locks::mutator_lock_); - CompiledMethod* CompileMethod(Thread* self, mirror::ArtMethod*) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) WARN_UNUSED; - // Compile a single Method. - void CompileOne(Thread* self, mirror::ArtMethod* method, TimingLogger* timings) + void CompileOne(mirror::ArtMethod* method, TimingLogger* timings) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); VerificationResults* GetVerificationResults() const { @@ -179,9 +172,6 @@ class CompilerDriver { size_t GetNonRelativeLinkerPatchCount() const LOCKS_EXCLUDED(compiled_methods_lock_); - // Remove and delete a compiled method. - void RemoveCompiledMethod(const MethodReference& method_ref); - void AddRequiresConstructorBarrier(Thread* self, const DexFile* dex_file, uint16_t class_def_index); bool RequiresConstructorBarrier(Thread* self, const DexFile* dex_file, uint16_t class_def_index); @@ -236,13 +226,6 @@ class CompilerDriver { uint32_t field_idx, bool is_static) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - // Resolve a field with a given dex file. - mirror::ArtField* ResolveFieldWithDexFile( - const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache, - Handle<mirror::ClassLoader> class_loader, const DexFile* dex_file, - uint32_t field_idx, bool is_static) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - // Get declaration location of a resolved field. void GetResolvedFieldDexFileLocation( mirror::ArtField* resolved_field, const DexFile** declaring_dex_file, @@ -252,10 +235,6 @@ class CompilerDriver { bool IsFieldVolatile(mirror::ArtField* field) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); MemberOffset GetFieldOffset(mirror::ArtField* field) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - // Find a dex cache for a dex file. - inline mirror::DexCache* FindDexCache(const DexFile* dex_file) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - // Can we fast-path an IGET/IPUT access to an instance field? If yes, compute the field offset. std::pair<bool, bool> IsFastInstanceField( mirror::DexCache* dex_cache, mirror::Class* referrer_class, @@ -282,7 +261,7 @@ class CompilerDriver { mirror::ArtMethod* ResolveMethod( ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit, - uint32_t method_idx, InvokeType invoke_type, bool check_incompatible_class_change = true) + uint32_t method_idx, InvokeType invoke_type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Get declaration location of a resolved field. @@ -316,13 +295,6 @@ class CompilerDriver { void ProcessedStaticField(bool resolved, bool local); void ProcessedInvoke(InvokeType invoke_type, int flags); - void ComputeFieldInfo(uint32_t field_idx, const DexCompilationUnit* mUnit, - const ScopedObjectAccess& soa, bool is_static, - mirror::ArtField** resolved_field, - mirror::Class** referrer_class, - mirror::DexCache** dex_cache) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - // Can we fast path instance field access? Computes field's offset and volatility. bool ComputeInstanceFieldInfo(uint32_t field_idx, const DexCompilationUnit* mUnit, bool is_put, MemberOffset* field_offset, bool* is_volatile) @@ -408,13 +380,6 @@ class CompilerDriver { return timings_logger_; } - void SetDedupeEnabled(bool dedupe_enabled) { - dedupe_enabled_ = dedupe_enabled; - } - bool DedupeEnabled() const { - return dedupe_enabled_; - } - // Checks if class specified by type_idx is one of the image_classes_ bool IsImageClass(const char* descriptor) const; @@ -519,7 +484,7 @@ class CompilerDriver { const std::vector<const DexFile*>& dex_files, ThreadPool* thread_pool, TimingLogger* timings) LOCKS_EXCLUDED(Locks::mutator_lock_); - void CompileMethod(Thread* self, const DexFile::CodeItem* code_item, uint32_t access_flags, + void CompileMethod(const DexFile::CodeItem* code_item, uint32_t access_flags, InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const DexFile& dex_file, DexToDexCompilationLevel dex_to_dex_compilation_level, @@ -580,7 +545,6 @@ class CompilerDriver { class AOTCompilationStats; std::unique_ptr<AOTCompilationStats> stats_; - bool dedupe_enabled_; bool dump_stats_; const bool dump_passes_; const std::string& dump_cfg_file_name_; diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc deleted file mode 100644 index b1d972e..0000000 --- a/compiler/jit/jit_compiler.cc +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Copyright 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. - */ - -#include "jit_compiler.h" - -#include "arch/instruction_set.h" -#include "arch/instruction_set_features.h" -#include "compiler_callbacks.h" -#include "dex/pass_manager.h" -#include "dex/quick_compiler_callbacks.h" -#include "driver/compiler_driver.h" -#include "driver/compiler_options.h" -#include "jit/jit.h" -#include "jit/jit_code_cache.h" -#include "mirror/art_method-inl.h" -#include "oat_file-inl.h" -#include "object_lock.h" -#include "thread_list.h" -#include "verifier/method_verifier-inl.h" - -namespace art { -namespace jit { - -JitCompiler* JitCompiler::Create() { - return new JitCompiler(); -} - -extern "C" void* jit_load(CompilerCallbacks** callbacks) { - VLOG(jit) << "loading jit compiler"; - auto* const jit_compiler = JitCompiler::Create(); - CHECK(jit_compiler != nullptr); - *callbacks = jit_compiler->GetCompilerCallbacks(); - VLOG(jit) << "Done loading jit compiler"; - return jit_compiler; -} - -extern "C" void jit_unload(void* handle) { - DCHECK(handle != nullptr); - delete reinterpret_cast<JitCompiler*>(handle); -} - -extern "C" bool jit_compile_method(void* handle, mirror::ArtMethod* method, Thread* self) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - auto* jit_compiler = reinterpret_cast<JitCompiler*>(handle); - DCHECK(jit_compiler != nullptr); - return jit_compiler->CompileMethod(self, method); -} - -JitCompiler::JitCompiler() : total_time_(0) { - auto* pass_manager_options = new PassManagerOptions; - pass_manager_options->SetDisablePassList("GVN,DCE"); - compiler_options_.reset(new CompilerOptions( - CompilerOptions::kDefaultCompilerFilter, - CompilerOptions::kDefaultHugeMethodThreshold, - CompilerOptions::kDefaultLargeMethodThreshold, - CompilerOptions::kDefaultSmallMethodThreshold, - CompilerOptions::kDefaultTinyMethodThreshold, - CompilerOptions::kDefaultNumDexMethodsThreshold, - false, - false, - CompilerOptions::kDefaultTopKProfileThreshold, - false, - false, - false, - false, - true, // pic - nullptr, - pass_manager_options, - nullptr)); - const InstructionSet instruction_set = kRuntimeISA; - instruction_set_features_.reset(InstructionSetFeatures::FromCppDefines()); - cumulative_logger_.reset(new CumulativeLogger("jit times")); - verification_results_.reset(new VerificationResults(compiler_options_.get())); - method_inliner_map_.reset(new DexFileToMethodInlinerMap); - callbacks_.reset(new QuickCompilerCallbacks(verification_results_.get(), - method_inliner_map_.get())); - compiler_driver_.reset(new CompilerDriver( - compiler_options_.get(), verification_results_.get(), method_inliner_map_.get(), - Compiler::kQuick, instruction_set, instruction_set_features_.get(), false, - nullptr, new std::set<std::string>, 1, false, true, - std::string(), cumulative_logger_.get(), -1, std::string())); - // Disable dedupe so we can remove compiled methods. - compiler_driver_->SetDedupeEnabled(false); - compiler_driver_->SetSupportBootImageFixup(false); -} - -JitCompiler::~JitCompiler() { -} - -bool JitCompiler::CompileMethod(Thread* self, mirror::ArtMethod* method) { - uint64_t start_time = NanoTime(); - StackHandleScope<2> hs(self); - self->AssertNoPendingException(); - Runtime* runtime = Runtime::Current(); - Handle<mirror::ArtMethod> h_method(hs.NewHandle(method)); - if (runtime->GetJit()->GetCodeCache()->ContainsMethod(method)) { - VLOG(jit) << "Already compiled " << PrettyMethod(method); - return true; // Already compiled - } - Handle<mirror::Class> h_class(hs.NewHandle(h_method->GetDeclaringClass())); - if (!runtime->GetClassLinker()->EnsureInitialized(self, h_class, true, true)) { - VLOG(jit) << "JIT failed to initialize " << PrettyMethod(h_method.Get()); - return false; - } - const DexFile* dex_file = h_class->GetDexCache()->GetDexFile(); - MethodReference method_ref(dex_file, h_method->GetDexMethodIndex()); - // Only verify if we don't already have verification results. - if (verification_results_->GetVerifiedMethod(method_ref) == nullptr) { - std::string error; - if (verifier::MethodVerifier::VerifyMethod(h_method.Get(), true, &error) == - verifier::MethodVerifier::kHardFailure) { - VLOG(jit) << "Not compile method " << PrettyMethod(h_method.Get()) - << " due to verification failure " << error; - return false; - } - } - CompiledMethod* compiled_method(compiler_driver_->CompileMethod(self, h_method.Get())); - if (compiled_method == nullptr) { - return false; - } - total_time_ += NanoTime() - start_time; - const bool result = MakeExecutable(compiled_method, h_method.Get()); - // Remove the compiled method to save memory. - compiler_driver_->RemoveCompiledMethod(method_ref); - return result; -} - -CompilerCallbacks* JitCompiler::GetCompilerCallbacks() const { - return callbacks_.get(); -} - -uint8_t* JitCompiler::WriteMethodHeaderAndCode(const CompiledMethod* compiled_method, - uint8_t* reserve_begin, uint8_t* reserve_end, - const uint8_t* mapping_table, - const uint8_t* vmap_table, - const uint8_t* gc_map) { - reserve_begin += sizeof(OatQuickMethodHeader); - reserve_begin = reinterpret_cast<uint8_t*>( - compiled_method->AlignCode(reinterpret_cast<uintptr_t>(reserve_begin))); - const auto* quick_code = compiled_method->GetQuickCode(); - CHECK_LE(reserve_begin, reserve_end); - CHECK_LE(quick_code->size(), static_cast<size_t>(reserve_end - reserve_begin)); - auto* code_ptr = reserve_begin; - OatQuickMethodHeader* method_header = reinterpret_cast<OatQuickMethodHeader*>(code_ptr) - 1; - // Construct the header last. - const auto frame_size_in_bytes = compiled_method->GetFrameSizeInBytes(); - const auto core_spill_mask = compiled_method->GetCoreSpillMask(); - const auto fp_spill_mask = compiled_method->GetFpSpillMask(); - const auto code_size = quick_code->size(); - CHECK_NE(code_size, 0U); - std::copy(quick_code->data(), quick_code->data() + code_size, code_ptr); - // After we are done writing we need to update the method header. - // Write out the method header last. - method_header = new(method_header)OatQuickMethodHeader( - code_ptr - mapping_table, code_ptr - vmap_table, code_ptr - gc_map, frame_size_in_bytes, - core_spill_mask, fp_spill_mask, code_size); - // Return the code ptr. - return code_ptr; -} - -bool JitCompiler::AddToCodeCache(mirror::ArtMethod* method, const CompiledMethod* compiled_method, - OatFile::OatMethod* out_method) { - Runtime* runtime = Runtime::Current(); - JitCodeCache* const code_cache = runtime->GetJit()->GetCodeCache(); - const auto* quick_code = compiled_method->GetQuickCode(); - if (quick_code == nullptr) { - return false; - } - const auto code_size = quick_code->size(); - Thread* const self = Thread::Current(); - const uint8_t* base = code_cache->CodeCachePtr(); - auto* const mapping_table = compiled_method->GetMappingTable(); - auto* const vmap_table = compiled_method->GetVmapTable(); - auto* const gc_map = compiled_method->GetGcMap(); - // Write out pre-header stuff. - uint8_t* const mapping_table_ptr = code_cache->AddDataArray( - self, mapping_table->data(), mapping_table->data() + mapping_table->size()); - if (mapping_table == nullptr) { - return false; // Out of data cache. - } - uint8_t* const vmap_table_ptr = code_cache->AddDataArray( - self, vmap_table->data(), vmap_table->data() + vmap_table->size()); - if (vmap_table == nullptr) { - return false; // Out of data cache. - } - uint8_t* const gc_map_ptr = code_cache->AddDataArray( - self, gc_map->data(), gc_map->data() + gc_map->size()); - if (gc_map == nullptr) { - return false; // Out of data cache. - } - // Don't touch this until you protect / unprotect the code. - const size_t reserve_size = sizeof(OatQuickMethodHeader) + quick_code->size() + 32; - uint8_t* const code_reserve = code_cache->ReserveCode(self, reserve_size); - if (code_reserve == nullptr) { - return false; - } - auto* code_ptr = WriteMethodHeaderAndCode( - compiled_method, code_reserve, code_reserve + reserve_size, mapping_table_ptr, - vmap_table_ptr, gc_map_ptr); - - const size_t thumb_offset = compiled_method->CodeDelta(); - const uint32_t code_offset = code_ptr - base + thumb_offset; - *out_method = OatFile::OatMethod(base, code_offset); - DCHECK_EQ(out_method->GetGcMap(), gc_map_ptr); - DCHECK_EQ(out_method->GetMappingTable(), mapping_table_ptr); - DCHECK_EQ(out_method->GetVmapTable(), vmap_table_ptr); - DCHECK_EQ(out_method->GetFrameSizeInBytes(), compiled_method->GetFrameSizeInBytes()); - DCHECK_EQ(out_method->GetCoreSpillMask(), compiled_method->GetCoreSpillMask()); - DCHECK_EQ(out_method->GetFpSpillMask(), compiled_method->GetFpSpillMask()); - VLOG(jit) << "JIT added " << PrettyMethod(method) << "@" << method << " ccache_size=" - << PrettySize(code_cache->CodeCacheSize()) << ": " << reinterpret_cast<void*>(code_ptr) - << "," << reinterpret_cast<void*>(code_ptr + code_size); - return true; -} - -bool JitCompiler::MakeExecutable(CompiledMethod* compiled_method, mirror::ArtMethod* method) { - CHECK(method != nullptr); - CHECK(compiled_method != nullptr); - OatFile::OatMethod oat_method(nullptr, 0); - if (!AddToCodeCache(method, compiled_method, &oat_method)) { - return false; - } - // TODO: Flush instruction cache. - oat_method.LinkMethod(method); - CHECK(Runtime::Current()->GetJit()->GetCodeCache()->ContainsMethod(method)) - << PrettyMethod(method); - return true; -} - -} // namespace jit -} // namespace art diff --git a/compiler/jit/jit_compiler.h b/compiler/jit/jit_compiler.h deleted file mode 100644 index 0876499..0000000 --- a/compiler/jit/jit_compiler.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2015 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_JIT_JIT_COMPILER_H_ -#define ART_COMPILER_JIT_JIT_COMPILER_H_ - -#include "base/mutex.h" -#include "compiler_callbacks.h" -#include "compiled_method.h" -#include "dex/verification_results.h" -#include "dex/quick/dex_file_to_method_inliner_map.h" -#include "driver/compiler_driver.h" -#include "driver/compiler_options.h" -#include "oat_file.h" - -namespace art { - -class InstructionSetFeatures; - -namespace mirror { -class ArtMethod; -} - -namespace jit { - -class JitCompiler { - public: - static JitCompiler* Create(); - virtual ~JitCompiler(); - bool CompileMethod(Thread* self, mirror::ArtMethod* method) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - // This is in the compiler since the runtime doesn't have access to the compiled method - // structures. - bool AddToCodeCache(mirror::ArtMethod* method, const CompiledMethod* compiled_method, - OatFile::OatMethod* out_method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - CompilerCallbacks* GetCompilerCallbacks() const; - size_t GetTotalCompileTime() const { - return total_time_; - } - - private: - uint64_t total_time_; - std::unique_ptr<CompilerOptions> compiler_options_; - std::unique_ptr<CumulativeLogger> cumulative_logger_; - std::unique_ptr<VerificationResults> verification_results_; - std::unique_ptr<DexFileToMethodInlinerMap> method_inliner_map_; - std::unique_ptr<CompilerCallbacks> callbacks_; - std::unique_ptr<CompilerDriver> compiler_driver_; - std::unique_ptr<const InstructionSetFeatures> instruction_set_features_; - - explicit JitCompiler(); - uint8_t* WriteMethodHeaderAndCode( - const CompiledMethod* compiled_method, uint8_t* reserve_begin, uint8_t* reserve_end, - const uint8_t* mapping_table, const uint8_t* vmap_table, const uint8_t* gc_map); - bool MakeExecutable(CompiledMethod* compiled_method, mirror::ArtMethod* method) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); -}; - -} // namespace jit - -} // namespace art - -#endif // ART_COMPILER_JIT_JIT_COMPILER_H_ diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index 8411091..9c0157e 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -549,7 +549,7 @@ struct OatWriter::MappingTableDataAccess { struct OatWriter::VmapTableDataAccess { static const SwapVector<uint8_t>* GetData(const CompiledMethod* compiled_method) ALWAYS_INLINE { - return compiled_method->GetVmapTable(); + return &compiled_method->GetVmapTable(); } static uint32_t GetOffset(OatClass* oat_class, size_t method_offsets_index) ALWAYS_INLINE { diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h index 980611f..e020d31 100644 --- a/compiler/oat_writer.h +++ b/compiler/oat_writer.h @@ -341,8 +341,8 @@ class OatWriter { if (UNLIKELY(lhs->GetMappingTable() != rhs->GetMappingTable())) { return lhs->GetMappingTable() < rhs->GetMappingTable(); } - if (UNLIKELY(lhs->GetVmapTable() != rhs->GetVmapTable())) { - return lhs->GetVmapTable() < rhs->GetVmapTable(); + if (UNLIKELY(&lhs->GetVmapTable() != &rhs->GetVmapTable())) { + return &lhs->GetVmapTable() < &rhs->GetVmapTable(); } if (UNLIKELY(lhs->GetGcMap() != rhs->GetGcMap())) { return lhs->GetGcMap() < rhs->GetGcMap(); diff --git a/compiler/utils/dex_instruction_utils.h b/compiler/utils/dex_instruction_utils.h new file mode 100644 index 0000000..bb2c592 --- /dev/null +++ b/compiler/utils/dex_instruction_utils.h @@ -0,0 +1,200 @@ +/* + * 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 IsInstructionReturn(Instruction::Code opcode) { + return Instruction::RETURN_VOID <= opcode && opcode <= Instruction::RETURN_OBJECT; +} + +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 IsInstructionGoto(Instruction::Code opcode) { + return Instruction::GOTO <= opcode && opcode <= Instruction::GOTO_32; +} + +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; +} + +constexpr bool IsInstructionBinOp2Addr(Instruction::Code code) { + return Instruction::ADD_INT_2ADDR <= code && code <= Instruction::REM_DOUBLE_2ADDR; +} + +// 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<DexInvokeType>(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<DexMemAccessType>(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<DexMemAccessType>(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<DexMemAccessType>(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<DexMemAccessType>(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<DexMemAccessType>(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<DexMemAccessType>(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_ |