diff options
-rw-r--r-- | compiler/driver/compiler_options.h | 4 | ||||
-rw-r--r-- | dex2oat/Android.bp | 2 | ||||
-rw-r--r-- | dex2oat/common_compiler_driver_test.cc | 1 | ||||
-rw-r--r-- | dex2oat/dex/dex_to_dex_compiler.cc | 608 | ||||
-rw-r--r-- | dex2oat/dex/dex_to_dex_compiler.h | 126 | ||||
-rw-r--r-- | dex2oat/driver/compiler_driver.cc | 168 | ||||
-rw-r--r-- | dex2oat/driver/compiler_driver.h | 8 | ||||
-rw-r--r-- | dex2oat/linker/oat_writer.cc | 169 | ||||
-rw-r--r-- | dex2oat/linker/oat_writer.h | 2 | ||||
-rw-r--r-- | dex2oat/linker/oat_writer_test.cc | 6 | ||||
-rw-r--r-- | libartbase/base/compiler_filter.cc | 8 | ||||
-rw-r--r-- | libartbase/base/compiler_filter.h | 4 |
12 files changed, 9 insertions, 1097 deletions
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h index 6915b7cdd6..ed8168a2b3 100644 --- a/compiler/driver/compiler_options.h +++ b/compiler/driver/compiler_options.h @@ -102,10 +102,6 @@ class CompilerOptions final { return CompilerFilter::IsJniCompilationEnabled(compiler_filter_); } - bool IsQuickeningCompilationEnabled() const { - return CompilerFilter::IsQuickeningCompilationEnabled(compiler_filter_); - } - bool IsVerificationEnabled() const { return CompilerFilter::IsVerificationEnabled(compiler_filter_); } diff --git a/dex2oat/Android.bp b/dex2oat/Android.bp index 73c0946187..5bd7f0042d 100644 --- a/dex2oat/Android.bp +++ b/dex2oat/Android.bp @@ -28,7 +28,6 @@ art_cc_defaults { defaults: ["art_defaults"], host_supported: true, srcs: [ - "dex/dex_to_dex_compiler.cc", "dex/quick_compiler_callbacks.cc", "driver/compiler_driver.cc", "linker/elf_writer.cc", @@ -89,7 +88,6 @@ gensrcs { cmd: "$(location generate_operator_out) art/dex2oat $(in) > $(out)", tools: ["generate_operator_out"], srcs: [ - "dex/dex_to_dex_compiler.h", "linker/image_writer.h", ], output_extension: "operator_out.cc", diff --git a/dex2oat/common_compiler_driver_test.cc b/dex2oat/common_compiler_driver_test.cc index db64fe4851..1f62cd7da5 100644 --- a/dex2oat/common_compiler_driver_test.cc +++ b/dex2oat/common_compiler_driver_test.cc @@ -59,7 +59,6 @@ void CommonCompilerDriverTest::CompileAll(jobject class_loader, void CommonCompilerDriverTest::SetDexFilesForOatFile(const std::vector<const DexFile*>& dex_files) { compiler_options_->dex_files_for_oat_file_ = dex_files; compiler_driver_->compiled_classes_.AddDexFiles(dex_files); - compiler_driver_->dex_to_dex_compiler_.SetDexFiles(dex_files); } void CommonCompilerDriverTest::ReserveImageSpace() { diff --git a/dex2oat/dex/dex_to_dex_compiler.cc b/dex2oat/dex/dex_to_dex_compiler.cc deleted file mode 100644 index 384436d5e9..0000000000 --- a/dex2oat/dex/dex_to_dex_compiler.cc +++ /dev/null @@ -1,608 +0,0 @@ -/* - * Copyright (C) 2011 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 "dex_to_dex_compiler.h" - -#include <android-base/logging.h> -#include <android-base/stringprintf.h> - -#include "art_field-inl.h" -#include "art_method-inl.h" -#include "base/logging.h" // For VLOG -#include "base/macros.h" -#include "base/mutex.h" -#include "compiled_method.h" -#include "dex/bytecode_utils.h" -#include "dex/class_accessor-inl.h" -#include "dex/dex_file-inl.h" -#include "dex/dex_instruction-inl.h" -#include "dex_to_dex_decompiler.h" -#include "driver/compiler_driver.h" -#include "driver/compiler_options.h" -#include "driver/dex_compilation_unit.h" -#include "mirror/dex_cache.h" -#include "quicken_info.h" -#include "thread-current-inl.h" - -namespace art { -namespace optimizer { - -using android::base::StringPrintf; - -// Controls quickening activation. -const bool kEnableQuickening = true; - -// Holds the state for compiling a single method. -struct DexToDexCompiler::CompilationState { - struct QuickenedInfo { - QuickenedInfo(uint32_t pc, uint16_t index) : dex_pc(pc), dex_member_index(index) {} - - uint32_t dex_pc; - uint16_t dex_member_index; - }; - - CompilationState(DexToDexCompiler* compiler, - const DexCompilationUnit& unit, - const CompilationLevel compilation_level, - const std::vector<uint8_t>* quicken_data); - - const std::vector<QuickenedInfo>& GetQuickenedInfo() const { - return quickened_info_; - } - - // Returns the quickening info, or an empty array if it was not quickened. - // If already_quickened is true, then don't change anything but still return what the quicken - // data would have been. - std::vector<uint8_t> Compile(); - - const DexFile& GetDexFile() const; - - // Compiles a RETURN-VOID into a RETURN-VOID-BARRIER within a constructor where - // a barrier is required. - void CompileReturnVoid(Instruction* inst, uint32_t dex_pc); - - // Compiles a field access into a quick field access. - // The field index is replaced by an offset within an Object where we can read - // from / write to this field. Therefore, this does not involve any resolution - // at runtime. - // Since the field index is encoded with 16 bits, we can replace it only if the - // field offset can be encoded with 16 bits too. - void CompileInstanceFieldAccess(Instruction* inst, uint32_t dex_pc, - Instruction::Code new_opcode, bool is_put); - - // Compiles a virtual method invocation into a quick virtual method invocation. - // The method index is replaced by the vtable index where the corresponding - // executable can be found. Therefore, this does not involve any resolution - // at runtime. - // Since the method index is encoded with 16 bits, we can replace it only if the - // vtable index can be encoded with 16 bits too. - void CompileInvokeVirtual(Instruction* inst, uint32_t dex_pc, - Instruction::Code new_opcode, bool is_range); - - // Return the next index. - uint16_t NextIndex(); - - // Returns the dequickened index if an instruction is quickened, otherwise return index. - uint16_t GetIndexForInstruction(const Instruction* inst, uint32_t index); - - DexToDexCompiler* const compiler_; - CompilerDriver& driver_; - const DexCompilationUnit& unit_; - const CompilationLevel compilation_level_; - - // Filled by the compiler when quickening, in order to encode that information - // in the .oat file. The runtime will use that information to get to the original - // opcodes. - std::vector<QuickenedInfo> quickened_info_; - - // True if we optimized a return void to a return void no barrier. - bool optimized_return_void_ = false; - - // If the code item was already quickened previously. - const bool already_quickened_; - const QuickenInfoTable existing_quicken_info_; - uint32_t quicken_index_ = 0u; - - DISALLOW_COPY_AND_ASSIGN(CompilationState); -}; - -DexToDexCompiler::DexToDexCompiler(CompilerDriver* driver) - : driver_(driver), - lock_("Quicken lock", kDexToDexCompilerLock) { - DCHECK(driver != nullptr); -} - -void DexToDexCompiler::ClearState() { - MutexLock lock(Thread::Current(), lock_); - active_dex_file_ = nullptr; - active_bit_vector_ = nullptr; - should_quicken_.clear(); - shared_code_item_quicken_info_.clear(); -} - -size_t DexToDexCompiler::NumCodeItemsToQuicken(Thread* self) const { - MutexLock lock(self, lock_); - return num_code_items_; -} - -BitVector* DexToDexCompiler::GetOrAddBitVectorForDex(const DexFile* dex_file) { - if (active_dex_file_ != dex_file) { - active_dex_file_ = dex_file; - auto inserted = should_quicken_.emplace(dex_file, - BitVector(dex_file->NumMethodIds(), - /*expandable*/ false, - Allocator::GetMallocAllocator())); - active_bit_vector_ = &inserted.first->second; - } - return active_bit_vector_; -} - -void DexToDexCompiler::MarkForCompilation(Thread* self, - const MethodReference& method_ref) { - MutexLock lock(self, lock_); - BitVector* const bitmap = GetOrAddBitVectorForDex(method_ref.dex_file); - DCHECK(bitmap != nullptr); - DCHECK(!bitmap->IsBitSet(method_ref.index)); - bitmap->SetBit(method_ref.index); - ++num_code_items_; -} - -DexToDexCompiler::CompilationState::CompilationState(DexToDexCompiler* compiler, - const DexCompilationUnit& unit, - const CompilationLevel compilation_level, - const std::vector<uint8_t>* quicken_data) - : compiler_(compiler), - driver_(*compiler->GetDriver()), - unit_(unit), - compilation_level_(compilation_level), - already_quickened_(quicken_data != nullptr), - existing_quicken_info_(already_quickened_ - ? ArrayRef<const uint8_t>(*quicken_data) : ArrayRef<const uint8_t>()) {} - -uint16_t DexToDexCompiler::CompilationState::NextIndex() { - DCHECK(already_quickened_); - if (kIsDebugBuild && quicken_index_ >= existing_quicken_info_.NumIndices()) { - for (const DexInstructionPcPair& pair : unit_.GetCodeItemAccessor()) { - LOG(ERROR) << pair->DumpString(nullptr); - } - LOG(FATAL) << "Mismatched number of quicken slots."; - } - const uint16_t ret = existing_quicken_info_.GetData(quicken_index_); - quicken_index_++; - return ret; -} - -uint16_t DexToDexCompiler::CompilationState::GetIndexForInstruction(const Instruction* inst, - uint32_t index) { - if (UNLIKELY(already_quickened_)) { - return inst->IsQuickened() ? NextIndex() : index; - } - DCHECK(!inst->IsQuickened()); - return index; -} - -bool DexToDexCompiler::ShouldCompileMethod(const MethodReference& ref) { - // TODO: It's probably safe to avoid the lock here if the active_dex_file_ matches since we only - // only call ShouldCompileMethod on one dex at a time. - MutexLock lock(Thread::Current(), lock_); - return GetOrAddBitVectorForDex(ref.dex_file)->IsBitSet(ref.index); -} - -std::vector<uint8_t> DexToDexCompiler::CompilationState::Compile() { - DCHECK_EQ(compilation_level_, CompilationLevel::kOptimize); - const CodeItemDataAccessor& instructions = unit_.GetCodeItemAccessor(); - for (DexInstructionIterator it = instructions.begin(); it != instructions.end(); ++it) { - const uint32_t dex_pc = it.DexPc(); - Instruction* inst = const_cast<Instruction*>(&it.Inst()); - - if (!already_quickened_) { - DCHECK(!inst->IsQuickened()); - } - - switch (inst->Opcode()) { - case Instruction::RETURN_VOID: - CompileReturnVoid(inst, dex_pc); - break; - - case Instruction::IGET: - case Instruction::IGET_QUICK: - CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_QUICK, false); - break; - - case Instruction::IGET_WIDE: - case Instruction::IGET_WIDE_QUICK: - CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_WIDE_QUICK, false); - break; - - case Instruction::IGET_OBJECT: - case Instruction::IGET_OBJECT_QUICK: - CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_OBJECT_QUICK, false); - break; - - case Instruction::IGET_BOOLEAN: - case Instruction::IGET_BOOLEAN_QUICK: - CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_BOOLEAN_QUICK, false); - break; - - case Instruction::IGET_BYTE: - case Instruction::IGET_BYTE_QUICK: - CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_BYTE_QUICK, false); - break; - - case Instruction::IGET_CHAR: - case Instruction::IGET_CHAR_QUICK: - CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_CHAR_QUICK, false); - break; - - case Instruction::IGET_SHORT: - case Instruction::IGET_SHORT_QUICK: - CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_SHORT_QUICK, false); - break; - - case Instruction::IPUT: - case Instruction::IPUT_QUICK: - CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_QUICK, true); - break; - - case Instruction::IPUT_BOOLEAN: - case Instruction::IPUT_BOOLEAN_QUICK: - CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_BOOLEAN_QUICK, true); - break; - - case Instruction::IPUT_BYTE: - case Instruction::IPUT_BYTE_QUICK: - CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_BYTE_QUICK, true); - break; - - case Instruction::IPUT_CHAR: - case Instruction::IPUT_CHAR_QUICK: - CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_CHAR_QUICK, true); - break; - - case Instruction::IPUT_SHORT: - case Instruction::IPUT_SHORT_QUICK: - CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_SHORT_QUICK, true); - break; - - case Instruction::IPUT_WIDE: - case Instruction::IPUT_WIDE_QUICK: - CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_WIDE_QUICK, true); - break; - - case Instruction::IPUT_OBJECT: - case Instruction::IPUT_OBJECT_QUICK: - CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_OBJECT_QUICK, true); - break; - - case Instruction::INVOKE_VIRTUAL: - case Instruction::INVOKE_VIRTUAL_QUICK: - CompileInvokeVirtual(inst, dex_pc, Instruction::INVOKE_VIRTUAL_QUICK, false); - break; - - case Instruction::INVOKE_VIRTUAL_RANGE: - case Instruction::INVOKE_VIRTUAL_RANGE_QUICK: - CompileInvokeVirtual(inst, dex_pc, Instruction::INVOKE_VIRTUAL_RANGE_QUICK, true); - break; - - default: - // Nothing to do. - break; - } - } - - if (already_quickened_) { - DCHECK_EQ(quicken_index_, existing_quicken_info_.NumIndices()); - } - - // Even if there are no indices, generate an empty quicken info so that we know the method was - // quickened. - - std::vector<uint8_t> quicken_data; - if (kIsDebugBuild) { - // Double check that the counts line up with the size of the quicken info. - size_t quicken_count = 0; - for (const DexInstructionPcPair& pair : instructions) { - if (QuickenInfoTable::NeedsIndexForInstruction(&pair.Inst())) { - ++quicken_count; - } - } - CHECK_EQ(quicken_count, GetQuickenedInfo().size()); - } - - QuickenInfoTable::Builder builder(&quicken_data, GetQuickenedInfo().size()); - // Length is encoded by the constructor. - for (const CompilationState::QuickenedInfo& info : GetQuickenedInfo()) { - // Dex pc is not serialized, only used for checking the instructions. Since we access the - // array based on the index of the quickened instruction, the indexes must line up perfectly. - // The reader side uses the NeedsIndexForInstruction function too. - const Instruction& inst = instructions.InstructionAt(info.dex_pc); - CHECK(QuickenInfoTable::NeedsIndexForInstruction(&inst)) << inst.Opcode(); - builder.AddIndex(info.dex_member_index); - } - DCHECK(!quicken_data.empty()); - return quicken_data; -} - -void DexToDexCompiler::CompilationState::CompileReturnVoid(Instruction* inst, uint32_t dex_pc) { - DCHECK_EQ(inst->Opcode(), Instruction::RETURN_VOID); - if (unit_.IsConstructor()) { - // Are we compiling a non clinit constructor which needs a barrier ? - if (!unit_.IsStatic() && unit_.RequiresConstructorBarrier()) { - return; - } - } - // Replace RETURN_VOID by RETURN_VOID_NO_BARRIER. - VLOG(compiler) << "Replacing " << Instruction::Name(inst->Opcode()) - << " by " << Instruction::Name(Instruction::RETURN_VOID_NO_BARRIER) - << " at dex pc " << StringPrintf("0x%x", dex_pc) << " in method " - << GetDexFile().PrettyMethod(unit_.GetDexMethodIndex(), true); - inst->SetOpcode(Instruction::RETURN_VOID_NO_BARRIER); - optimized_return_void_ = true; -} - -void DexToDexCompiler::CompilationState::CompileInstanceFieldAccess(Instruction* inst, - uint32_t dex_pc, - Instruction::Code new_opcode, - bool is_put) { - if (!kEnableQuickening) { - return; - } - uint32_t field_idx = GetIndexForInstruction(inst, inst->VRegC_22c()); - MemberOffset field_offset(0u); - bool is_volatile; - bool fast_path = driver_.ComputeInstanceFieldInfo(field_idx, &unit_, is_put, - &field_offset, &is_volatile); - if (fast_path && !is_volatile && IsUint<16>(field_offset.Int32Value())) { - VLOG(compiler) << "Quickening " << Instruction::Name(inst->Opcode()) - << " to " << Instruction::Name(new_opcode) - << " by replacing field index " << field_idx - << " by field offset " << field_offset.Int32Value() - << " at dex pc " << StringPrintf("0x%x", dex_pc) << " in method " - << GetDexFile().PrettyMethod(unit_.GetDexMethodIndex(), true); - if (!already_quickened_) { - // We are modifying 4 consecutive bytes. - inst->SetOpcode(new_opcode); - // Replace field index by field offset. - inst->SetVRegC_22c(static_cast<uint16_t>(field_offset.Int32Value())); - } - quickened_info_.push_back(QuickenedInfo(dex_pc, field_idx)); - } -} - -const DexFile& DexToDexCompiler::CompilationState::GetDexFile() const { - return *unit_.GetDexFile(); -} - -void DexToDexCompiler::CompilationState::CompileInvokeVirtual(Instruction* inst, - uint32_t dex_pc, - Instruction::Code new_opcode, - bool is_range) { - if (!kEnableQuickening) { - return; - } - uint32_t method_idx = GetIndexForInstruction(inst, - is_range ? inst->VRegB_3rc() : inst->VRegB_35c()); - ScopedObjectAccess soa(Thread::Current()); - - ClassLinker* class_linker = unit_.GetClassLinker(); - ArtMethod* resolved_method = - class_linker->ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>( - method_idx, - unit_.GetDexCache(), - unit_.GetClassLoader(), - /* referrer= */ nullptr, - kVirtual); - - if (UNLIKELY(resolved_method == nullptr)) { - // Clean up any exception left by type resolution. - soa.Self()->ClearException(); - return; - } - - uint32_t vtable_idx = resolved_method->GetMethodIndex(); - DCHECK(IsUint<16>(vtable_idx)); - VLOG(compiler) << "Quickening " << Instruction::Name(inst->Opcode()) - << "(" << GetDexFile().PrettyMethod(method_idx, true) << ")" - << " to " << Instruction::Name(new_opcode) - << " by replacing method index " << method_idx - << " by vtable index " << vtable_idx - << " at dex pc " << StringPrintf("0x%x", dex_pc) << " in method " - << GetDexFile().PrettyMethod(unit_.GetDexMethodIndex(), true); - if (!already_quickened_) { - // We are modifying 4 consecutive bytes. - inst->SetOpcode(new_opcode); - // Replace method index by vtable index. - if (is_range) { - inst->SetVRegB_3rc(static_cast<uint16_t>(vtable_idx)); - } else { - inst->SetVRegB_35c(static_cast<uint16_t>(vtable_idx)); - } - } - quickened_info_.push_back(QuickenedInfo(dex_pc, method_idx)); -} - -CompiledMethod* DexToDexCompiler::CompileMethod( - const dex::CodeItem* code_item, - uint32_t access_flags, - InvokeType invoke_type ATTRIBUTE_UNUSED, - uint16_t class_def_idx, - uint32_t method_idx, - Handle<mirror::ClassLoader> class_loader, - const DexFile& dex_file, - CompilationLevel compilation_level) { - if (compilation_level == CompilationLevel::kDontDexToDexCompile) { - return nullptr; - } - - ScopedObjectAccess soa(Thread::Current()); - StackHandleScope<1> hs(soa.Self()); - ClassLinker* const class_linker = Runtime::Current()->GetClassLinker(); - art::DexCompilationUnit unit( - class_loader, - class_linker, - dex_file, - code_item, - class_def_idx, - method_idx, - access_flags, - driver_->GetCompilerOptions().GetVerifiedMethod(&dex_file, method_idx), - hs.NewHandle(class_linker->FindDexCache(soa.Self(), dex_file))); - - std::vector<uint8_t> quicken_data; - // If the code item is shared with multiple different method ids, make sure that we quicken only - // once and verify that all the dequicken maps match. - if (UNLIKELY(shared_code_items_.find(code_item) != shared_code_items_.end())) { - // Avoid quickening the shared code items for now because the existing conflict detection logic - // does not currently handle cases where the code item is quickened in one place but - // compiled in another. - static constexpr bool kAvoidQuickeningSharedCodeItems = true; - if (kAvoidQuickeningSharedCodeItems) { - return nullptr; - } - // For shared code items, use a lock to prevent races. - MutexLock mu(soa.Self(), lock_); - auto existing = shared_code_item_quicken_info_.find(code_item); - QuickenState* existing_data = nullptr; - std::vector<uint8_t>* existing_quicken_data = nullptr; - if (existing != shared_code_item_quicken_info_.end()) { - existing_data = &existing->second; - if (existing_data->conflict_) { - return nullptr; - } - existing_quicken_data = &existing_data->quicken_data_; - } - bool optimized_return_void; - { - CompilationState state(this, unit, compilation_level, existing_quicken_data); - quicken_data = state.Compile(); - optimized_return_void = state.optimized_return_void_; - } - - // Already quickened, check that the data matches what was previously seen. - MethodReference method_ref(&dex_file, method_idx); - if (existing_data != nullptr) { - if (*existing_quicken_data != quicken_data || - existing_data->optimized_return_void_ != optimized_return_void) { - VLOG(compiler) << "Quicken data mismatch, for method " - << dex_file.PrettyMethod(method_idx); - // Mark the method as a conflict to never attempt to quicken it in the future. - existing_data->conflict_ = true; - } - existing_data->methods_.push_back(method_ref); - } else { - QuickenState new_state; - new_state.methods_.push_back(method_ref); - new_state.quicken_data_ = quicken_data; - new_state.optimized_return_void_ = optimized_return_void; - bool inserted = shared_code_item_quicken_info_.emplace(code_item, new_state).second; - CHECK(inserted) << "Failed to insert " << dex_file.PrettyMethod(method_idx); - } - - // Easy check of the validity is to check that the existing stuff matches by re-quickening using - // the newly produced quicken data. - // Note that this needs to be behind the lock for this case since we may unquicken in another - // thread. - if (kIsDebugBuild) { - CompilationState state2(this, unit, compilation_level, &quicken_data); - std::vector<uint8_t> new_data = state2.Compile(); - CHECK(new_data == quicken_data) << "Mismatch producing new quicken data"; - } - } else { - CompilationState state(this, unit, compilation_level, /*quicken_data*/ nullptr); - quicken_data = state.Compile(); - - // Easy check of the validity is to check that the existing stuff matches by re-quickening using - // the newly produced quicken data. - if (kIsDebugBuild) { - CompilationState state2(this, unit, compilation_level, &quicken_data); - std::vector<uint8_t> new_data = state2.Compile(); - CHECK(new_data == quicken_data) << "Mismatch producing new quicken data"; - } - } - - if (quicken_data.empty()) { - return nullptr; - } - - // Create a `CompiledMethod`, with the quickened information in the vmap table. - InstructionSet instruction_set = driver_->GetCompilerOptions().GetInstructionSet(); - if (instruction_set == InstructionSet::kThumb2) { - // Don't use the thumb2 instruction set to avoid the one off code delta. - instruction_set = InstructionSet::kArm; - } - CompiledMethod* ret = CompiledMethod::SwapAllocCompiledMethod( - driver_->GetCompiledMethodStorage(), - instruction_set, - ArrayRef<const uint8_t>(), // no code - ArrayRef<const uint8_t>(quicken_data), // vmap_table - ArrayRef<const uint8_t>(), // cfi data - ArrayRef<const linker::LinkerPatch>()); - DCHECK(ret != nullptr); - return ret; -} - -void DexToDexCompiler::SetDexFiles(const std::vector<const DexFile*>& dex_files) { - // Record what code items are already seen to detect when multiple methods have the same code - // item. - std::unordered_set<const dex::CodeItem*> seen_code_items; - for (const DexFile* dex_file : dex_files) { - for (ClassAccessor accessor : dex_file->GetClasses()) { - for (const ClassAccessor::Method& method : accessor.GetMethods()) { - const dex::CodeItem* code_item = method.GetCodeItem(); - // Detect the shared code items. - if (!seen_code_items.insert(code_item).second) { - shared_code_items_.insert(code_item); - } - } - } - } - VLOG(compiler) << "Shared code items " << shared_code_items_.size(); -} - -void DexToDexCompiler::UnquickenConflictingMethods() { - MutexLock mu(Thread::Current(), lock_); - size_t unquicken_count = 0; - for (const auto& pair : shared_code_item_quicken_info_) { - const dex::CodeItem* code_item = pair.first; - const QuickenState& state = pair.second; - CHECK_GE(state.methods_.size(), 1u); - if (state.conflict_) { - // Unquicken using the existing quicken data. - // TODO: Do we really need to pass a dex file in? - optimizer::ArtDecompileDEX(*state.methods_[0].dex_file, - *code_item, - ArrayRef<const uint8_t>(state.quicken_data_), - /* decompile_return_instruction*/ true); - ++unquicken_count; - // Go clear the vmaps for all the methods that were already quickened to avoid writing them - // out during oat writing. - for (const MethodReference& ref : state.methods_) { - CompiledMethod* method = driver_->RemoveCompiledMethod(ref); - if (method != nullptr) { - // There is up to one compiled method for each method ref. Releasing it leaves the - // deduped data intact, this means its safe to do even when other threads might be - // compiling. - CompiledMethod::ReleaseSwapAllocatedCompiledMethod(driver_->GetCompiledMethodStorage(), - method); - } - } - } - } -} - -} // namespace optimizer - -} // namespace art diff --git a/dex2oat/dex/dex_to_dex_compiler.h b/dex2oat/dex/dex_to_dex_compiler.h deleted file mode 100644 index 16030bd854..0000000000 --- a/dex2oat/dex/dex_to_dex_compiler.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (C) 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_DEX2OAT_DEX_DEX_TO_DEX_COMPILER_H_ -#define ART_DEX2OAT_DEX_DEX_TO_DEX_COMPILER_H_ - -#include <set> -#include <unordered_map> -#include <unordered_set> - -#include "base/bit_vector.h" -#include "base/mutex.h" -#include "dex/invoke_type.h" -#include "dex/method_reference.h" -#include "handle.h" -#include "quicken_info.h" - -namespace art { - -class CompiledMethod; -class CompilerDriver; -class DexCompilationUnit; -class DexFile; - -namespace dex { -struct CodeItem; -} // namespace dex - -namespace mirror { -class ClassLoader; -} // namespace mirror - -namespace optimizer { - -class DexToDexCompiler { - public: - enum class CompilationLevel { - kDontDexToDexCompile, // Only meaning wrt image time interpretation. - kOptimize // Perform peep-hole optimizations. - }; - - explicit DexToDexCompiler(CompilerDriver* driver); - - CompiledMethod* CompileMethod(const dex::CodeItem* code_item, - uint32_t access_flags, - InvokeType invoke_type, - uint16_t class_def_idx, - uint32_t method_idx, - Handle<mirror::ClassLoader> class_loader, - const DexFile& dex_file, - const CompilationLevel compilation_level) WARN_UNUSED; - - void MarkForCompilation(Thread* self, - const MethodReference& method_ref); - - void ClearState(); - - // Unquicken all methods that have conflicting quicken info. This is not done during the - // quickening process to avoid race conditions. - void UnquickenConflictingMethods(); - - CompilerDriver* GetDriver() { - return driver_; - } - - bool ShouldCompileMethod(const MethodReference& ref); - - // Return the number of code items to quicken. - size_t NumCodeItemsToQuicken(Thread* self) const; - - void SetDexFiles(const std::vector<const DexFile*>& dex_files); - - private: - // Holds the state for compiling a single method. - struct CompilationState; - - // Quicken state for a code item, may be referenced by multiple methods. - struct QuickenState { - std::vector<MethodReference> methods_; - std::vector<uint8_t> quicken_data_; - bool optimized_return_void_ = false; - bool conflict_ = false; - }; - - BitVector* GetOrAddBitVectorForDex(const DexFile* dex_file) REQUIRES(lock_); - - CompilerDriver* const driver_; - - // State for adding methods (should this be in its own class?). - const DexFile* active_dex_file_ = nullptr; - BitVector* active_bit_vector_ = nullptr; - - // Lock that guards duplicate code items and the bitmap. - mutable Mutex lock_; - // Record what method references are going to get quickened. - std::unordered_map<const DexFile*, BitVector> should_quicken_; - // Guarded by lock_ during writing, accessed without a lock during quickening. - // This is safe because no thread is adding to the shared code items during the quickening phase. - std::unordered_set<const dex::CodeItem*> shared_code_items_; - // Blacklisted code items are unquickened in UnquickenConflictingMethods. - std::unordered_map<const dex::CodeItem*, QuickenState> shared_code_item_quicken_info_ - GUARDED_BY(lock_); - // Number of added code items. - size_t num_code_items_ GUARDED_BY(lock_) = 0u; -}; - -std::ostream& operator<<(std::ostream& os, DexToDexCompiler::CompilationLevel rhs); - -} // namespace optimizer - -} // namespace art - -#endif // ART_DEX2OAT_DEX_DEX_TO_DEX_COMPILER_H_ diff --git a/dex2oat/driver/compiler_driver.cc b/dex2oat/driver/compiler_driver.cc index 280ac453c3..9d14608170 100644 --- a/dex2oat/driver/compiler_driver.cc +++ b/dex2oat/driver/compiler_driver.cc @@ -52,7 +52,6 @@ #include "dex/dex_file-inl.h" #include "dex/dex_file_annotations.h" #include "dex/dex_instruction-inl.h" -#include "dex/dex_to_dex_compiler.h" #include "dex/verification_results.h" #include "dex/verified_method.h" #include "driver/compiler_options.h" @@ -265,8 +264,7 @@ CompilerDriver::CompilerDriver( parallel_thread_count_(thread_count), stats_(new AOTCompilationStats), compiled_method_storage_(swap_fd), - max_arena_alloc_(0), - dex_to_dex_compiler_(this) { + max_arena_alloc_(0) { DCHECK(compiler_options_ != nullptr); compiled_method_storage_.SetDedupeEnabled(compiler_options_->DeduplicateCode()); @@ -352,64 +350,6 @@ void CompilerDriver::CompileAll(jobject class_loader, } } -static optimizer::DexToDexCompiler::CompilationLevel GetDexToDexCompilationLevel( - Thread* self, const CompilerDriver& driver, Handle<mirror::ClassLoader> class_loader, - const DexFile& dex_file, const dex::ClassDef& class_def) - REQUIRES_SHARED(Locks::mutator_lock_) { - // When the dex file is uncompressed in the APK, we do not generate a copy in the .vdex - // file. As a result, dex2oat will map the dex file read-only, and we only need to check - // that to know if we can do quickening. - if (dex_file.GetContainer() != nullptr && dex_file.GetContainer()->IsReadOnly()) { - return optimizer::DexToDexCompiler::CompilationLevel::kDontDexToDexCompile; - } - if (!driver.GetCompilerOptions().IsQuickeningCompilationEnabled()) { - // b/170086509 Quickening compilation is being deprecated. - return optimizer::DexToDexCompiler::CompilationLevel::kDontDexToDexCompile; - } - auto* const runtime = Runtime::Current(); - const char* descriptor = dex_file.GetClassDescriptor(class_def); - ClassLinker* class_linker = runtime->GetClassLinker(); - ObjPtr<mirror::Class> klass = class_linker->FindClass(self, descriptor, class_loader); - if (klass == nullptr) { - CHECK(self->IsExceptionPending()); - self->ClearException(); - return optimizer::DexToDexCompiler::CompilationLevel::kDontDexToDexCompile; - } - // DexToDex at the kOptimize level may introduce quickened opcodes, which replace symbolic - // references with actual offsets. We cannot re-verify such instructions. - // - // We store the verification information in the class status in the oat file, which the linker - // can validate (checksums) and use to skip load-time verification. It is thus safe to - // optimize when a class has been fully verified before. - optimizer::DexToDexCompiler::CompilationLevel max_level = - optimizer::DexToDexCompiler::CompilationLevel::kOptimize; - if (driver.GetCompilerOptions().GetDebuggable()) { - // We are debuggable so definitions of classes might be changed. We don't want to do any - // optimizations that could break that. - max_level = optimizer::DexToDexCompiler::CompilationLevel::kDontDexToDexCompile; - } - if (klass->IsVerified()) { - // Class is verified so we can enable DEX-to-DEX compilation for performance. - return max_level; - } else { - // Class verification has failed: do not run DEX-to-DEX optimizations. - return optimizer::DexToDexCompiler::CompilationLevel::kDontDexToDexCompile; - } -} - -static optimizer::DexToDexCompiler::CompilationLevel GetDexToDexCompilationLevel( - Thread* self, - const CompilerDriver& driver, - jobject jclass_loader, - const DexFile& dex_file, - const dex::ClassDef& class_def) { - ScopedObjectAccess soa(self); - StackHandleScope<1> hs(soa.Self()); - Handle<mirror::ClassLoader> class_loader( - hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader))); - return GetDexToDexCompilationLevel(self, driver, class_loader, dex_file, class_def); -} - // Does the runtime for the InstructionSet provide an implementation returned by // GetQuickGenericJniStub allowing down calls that aren't compiled using a JNI compiler? static bool InstructionSetHasGenericJniStub(InstructionSet isa) { @@ -434,7 +374,6 @@ static void CompileMethodHarness( uint32_t method_idx, Handle<mirror::ClassLoader> class_loader, const DexFile& dex_file, - optimizer::DexToDexCompiler::CompilationLevel dex_to_dex_compilation_level, Handle<mirror::DexCache> dex_cache, CompileFn compile_fn) { DCHECK(driver != nullptr); @@ -451,7 +390,6 @@ static void CompileMethodHarness( method_idx, class_loader, dex_file, - dex_to_dex_compilation_level, dex_cache); if (kTimeCompileMethod) { @@ -473,68 +411,6 @@ static void CompileMethodHarness( } } -static void CompileMethodDex2Dex( - Thread* self, - CompilerDriver* driver, - const dex::CodeItem* code_item, - uint32_t access_flags, - InvokeType invoke_type, - uint16_t class_def_idx, - uint32_t method_idx, - Handle<mirror::ClassLoader> class_loader, - const DexFile& dex_file, - optimizer::DexToDexCompiler::CompilationLevel dex_to_dex_compilation_level, - Handle<mirror::DexCache> dex_cache) { - auto dex_2_dex_fn = [](Thread* self ATTRIBUTE_UNUSED, - CompilerDriver* driver, - const dex::CodeItem* code_item, - uint32_t access_flags, - InvokeType invoke_type, - uint16_t class_def_idx, - uint32_t method_idx, - Handle<mirror::ClassLoader> class_loader, - const DexFile& dex_file, - optimizer::DexToDexCompiler::CompilationLevel dex_to_dex_compilation_level, - Handle<mirror::DexCache> dex_cache ATTRIBUTE_UNUSED) -> CompiledMethod* { - DCHECK(driver != nullptr); - MethodReference method_ref(&dex_file, method_idx); - - optimizer::DexToDexCompiler* const compiler = &driver->GetDexToDexCompiler(); - - if (compiler->ShouldCompileMethod(method_ref)) { - const VerificationResults* results = driver->GetCompilerOptions().GetVerificationResults(); - DCHECK(results != nullptr); - const VerifiedMethod* verified_method = results->GetVerifiedMethod(method_ref); - // Do not optimize if a VerifiedMethod is missing. SafeCast elision, - // for example, relies on it. - return compiler->CompileMethod( - code_item, - access_flags, - invoke_type, - class_def_idx, - method_idx, - class_loader, - dex_file, - (verified_method != nullptr) - ? dex_to_dex_compilation_level - : optimizer::DexToDexCompiler::CompilationLevel::kDontDexToDexCompile); - } - return nullptr; - }; - CompileMethodHarness(self, - driver, - code_item, - access_flags, - invoke_type, - class_def_idx, - method_idx, - class_loader, - dex_file, - dex_to_dex_compilation_level, - dex_cache, - dex_2_dex_fn); -} - static void CompileMethodQuick( Thread* self, CompilerDriver* driver, @@ -545,10 +421,9 @@ static void CompileMethodQuick( uint32_t method_idx, Handle<mirror::ClassLoader> class_loader, const DexFile& dex_file, - optimizer::DexToDexCompiler::CompilationLevel dex_to_dex_compilation_level, Handle<mirror::DexCache> dex_cache) { auto quick_fn = []( - Thread* self, + Thread* self ATTRIBUTE_UNUSED, CompilerDriver* driver, const dex::CodeItem* code_item, uint32_t access_flags, @@ -557,7 +432,6 @@ static void CompileMethodQuick( uint32_t method_idx, Handle<mirror::ClassLoader> class_loader, const DexFile& dex_file, - optimizer::DexToDexCompiler::CompilationLevel dex_to_dex_compilation_level, Handle<mirror::DexCache> dex_cache) { DCHECK(driver != nullptr); CompiledMethod* compiled_method = nullptr; @@ -629,13 +503,6 @@ static void CompileMethodQuick( } } } - if (compiled_method == nullptr && - dex_to_dex_compilation_level != - optimizer::DexToDexCompiler::CompilationLevel::kDontDexToDexCompile) { - DCHECK(!Runtime::Current()->UseJitCompilation()); - // TODO: add a command-line option to disable DEX-to-DEX compilation ? - driver->GetDexToDexCompiler().MarkForCompilation(self, method_ref); - } } return compiled_method; }; @@ -648,7 +515,6 @@ static void CompileMethodQuick( method_idx, class_loader, dex_file, - dex_to_dex_compilation_level, dex_cache, quick_fn); } @@ -843,13 +709,8 @@ static void EnsureVerifiedOrVerifyAtRuntime(jobject jclass_loader, } } -void CompilerDriver::PrepareDexFilesForOatFile(TimingLogger* timings) { +void CompilerDriver::PrepareDexFilesForOatFile(TimingLogger* timings ATTRIBUTE_UNUSED) { compiled_classes_.AddDexFiles(GetCompilerOptions().GetDexFilesForOatFile()); - - if (GetCompilerOptions().IsQuickeningCompilationEnabled()) { - TimingLogger::ScopedTiming t2("Dex2Dex SetDexFiles", timings); - dex_to_dex_compiler_.SetDexFiles(GetCompilerOptions().GetDexFilesForOatFile()); - } } class CreateConflictTablesVisitor : public ClassVisitor { @@ -2738,10 +2599,6 @@ static void CompileDexFile(CompilerDriver* driver, // Go to native so that we don't block GC during compilation. ScopedThreadSuspension sts(soa.Self(), kNative); - // Can we run DEX-to-DEX compiler on this class ? - optimizer::DexToDexCompiler::CompilationLevel dex_to_dex_compilation_level = - GetDexToDexCompilationLevel(soa.Self(), *driver, jclass_loader, dex_file, class_def); - // Compile direct and virtual methods. int64_t previous_method_idx = -1; for (const ClassAccessor::Method& method : accessor.GetMethods()) { @@ -2761,7 +2618,6 @@ static void CompileDexFile(CompilerDriver* driver, method_idx, class_loader, dex_file, - dex_to_dex_compilation_level, dex_cache); } }; @@ -2780,7 +2636,6 @@ void CompilerDriver::Compile(jobject class_loader, : profile_compilation_info->DumpInfo(dex_files)); } - dex_to_dex_compiler_.ClearState(); for (const DexFile* dex_file : dex_files) { CHECK(dex_file != nullptr); CompileDexFile(this, @@ -2798,23 +2653,6 @@ void CompilerDriver::Compile(jobject class_loader, Runtime::Current()->ReclaimArenaPoolMemory(); } - if (dex_to_dex_compiler_.NumCodeItemsToQuicken(Thread::Current()) > 0u) { - // TODO: Not visit all of the dex files, its probably rare that only one would have quickened - // methods though. - for (const DexFile* dex_file : dex_files) { - CompileDexFile(this, - class_loader, - *dex_file, - dex_files, - parallel_thread_pool_.get(), - parallel_thread_count_, - timings, - "Compile Dex File Dex2Dex", - CompileMethodDex2Dex); - } - dex_to_dex_compiler_.ClearState(); - } - VLOG(compiler) << "Compile: " << GetMemoryUsageString(false); } diff --git a/dex2oat/driver/compiler_driver.h b/dex2oat/driver/compiler_driver.h index 137f6f138e..0a3c0fe578 100644 --- a/dex2oat/driver/compiler_driver.h +++ b/dex2oat/driver/compiler_driver.h @@ -35,7 +35,6 @@ #include "compiler.h" #include "dex/class_reference.h" #include "dex/dex_file_types.h" -#include "dex/dex_to_dex_compiler.h" #include "dex/method_reference.h" #include "driver/compiled_method_storage.h" #include "thread_pool.h" @@ -223,10 +222,6 @@ class CompilerDriver { return &compiled_method_storage_; } - optimizer::DexToDexCompiler& GetDexToDexCompiler() { - return dex_to_dex_compiler_; - } - private: void LoadImageClasses(TimingLogger* timings, /*inout*/ HashSet<std::string>* image_classes) REQUIRES(!Locks::mutator_lock_); @@ -336,9 +331,6 @@ class CompilerDriver { size_t max_arena_alloc_; - // Compiler for dex to dex (quickening). - optimizer::DexToDexCompiler dex_to_dex_compiler_; - friend class CommonCompilerDriverTest; friend class CompileClassVisitor; friend class DexToDexDecompilerTest; diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc index d6eff94f76..9070ed2d4f 100644 --- a/dex2oat/linker/oat_writer.cc +++ b/dex2oat/linker/oat_writer.cc @@ -892,12 +892,6 @@ static bool HasCompiledCode(const CompiledMethod* method) { return method != nullptr && !method->GetQuickCode().empty(); } -static bool HasQuickeningInfo(const CompiledMethod* method) { - // The dextodexcompiler puts the quickening info table into the CompiledMethod - // for simplicity. - return method != nullptr && method->GetQuickCode().empty() && !method->GetVmapTable().empty(); -} - class OatWriter::InitBssLayoutMethodVisitor : public DexMethodVisitor { public: explicit InitBssLayoutMethodVisitor(OatWriter* writer) @@ -2523,165 +2517,10 @@ bool OatWriter::WriteRodata(OutputStream* out) { return true; } -class OatWriter::WriteQuickeningInfoMethodVisitor { - public: - WriteQuickeningInfoMethodVisitor(OatWriter* writer, /*out*/std::vector<uint8_t>* buffer) - : writer_(writer), - buffer_(buffer) {} - - void VisitDexMethods(const std::vector<const DexFile*>& dex_files) { - // Map of offsets for quicken info related to method indices. - SafeMap<const uint8_t*, uint32_t> offset_map; - // Use method index order to minimize the encoded size of the offset table. - for (const DexFile* dex_file : dex_files) { - std::vector<uint32_t>* const offsets = - &quicken_info_offset_indices_.Put(dex_file, std::vector<uint32_t>())->second; - for (uint32_t method_idx = 0; method_idx < dex_file->NumMethodIds(); ++method_idx) { - uint32_t offset = 0u; - MethodReference method_ref(dex_file, method_idx); - CompiledMethod* compiled_method = writer_->compiler_driver_->GetCompiledMethod(method_ref); - if (compiled_method != nullptr && HasQuickeningInfo(compiled_method)) { - ArrayRef<const uint8_t> map = compiled_method->GetVmapTable(); - - // Record each index if required. written_bytes_ is the offset from the start of the - // quicken info data. - // May be already inserted for duplicate items. - // Add offset of one to make sure 0 represents unused. - auto pair = offset_map.emplace(map.data(), written_bytes_ + 1); - offset = pair.first->second; - // Write out the map if it's not already written. - if (pair.second) { - static_assert(sizeof(map[0]) == 1u); - buffer_->insert(buffer_->end(), map.begin(), map.end()); - written_bytes_ += map.size(); - } - } - offsets->push_back(offset); - } - } - } - - size_t GetNumberOfWrittenBytes() const { - return written_bytes_; - } - - SafeMap<const DexFile*, std::vector<uint32_t>>& GetQuickenInfoOffsetIndices() { - return quicken_info_offset_indices_; - } - - private: - OatWriter* const writer_; - std::vector<uint8_t>* const buffer_; - size_t written_bytes_ = 0u; - SafeMap<const DexFile*, std::vector<uint32_t>> quicken_info_offset_indices_; -}; - -class OatWriter::WriteQuickeningInfoOffsetsMethodVisitor { - public: - WriteQuickeningInfoOffsetsMethodVisitor( - /*out*/std::vector<uint8_t>* buffer, - uint32_t start_offset, - SafeMap<const DexFile*, std::vector<uint32_t>>* quicken_info_offset_indices, - std::vector<uint32_t>* out_table_offsets) - : buffer_(buffer), - start_offset_(start_offset), - quicken_info_offset_indices_(quicken_info_offset_indices), - out_table_offsets_(out_table_offsets) {} - - void VisitDexMethods(const std::vector<const DexFile*>& dex_files) { - for (const DexFile* dex_file : dex_files) { - auto it = quicken_info_offset_indices_->find(dex_file); - DCHECK(it != quicken_info_offset_indices_->end()) << "Failed to find dex file " - << dex_file->GetLocation(); - const std::vector<uint32_t>* const offsets = &it->second; - - const uint32_t current_offset = start_offset_ + written_bytes_; - CHECK_ALIGNED_PARAM(current_offset, CompactOffsetTable::kAlignment); - - // Generate and write the data. - std::vector<uint8_t> table_data; - CompactOffsetTable::Build(*offsets, &table_data); - - // Store the offset since we need to put those after the dex file. Table offsets are relative - // to the start of the quicken info section. - out_table_offsets_->push_back(current_offset); - - static_assert(sizeof(table_data[0]) == 1u); - buffer_->insert(buffer_->end(), table_data.begin(), table_data.end()); - written_bytes_ += table_data.size(); - } - } - - size_t GetNumberOfWrittenBytes() const { - return written_bytes_; - } - - private: - std::vector<uint8_t>* const buffer_; - const uint32_t start_offset_; - size_t written_bytes_ = 0u; - // Maps containing the offsets for the tables. - SafeMap<const DexFile*, std::vector<uint32_t>>* const quicken_info_offset_indices_; - std::vector<uint32_t>* const out_table_offsets_; -}; - -void OatWriter::WriteQuickeningInfo(/*out*/std::vector<uint8_t>* buffer) { - if (!extract_dex_files_into_vdex_ || !GetCompilerOptions().IsQuickeningCompilationEnabled()) { - // Nothing to write. Leave `vdex_size_` untouched and unaligned. - vdex_quickening_info_offset_ = vdex_size_; - size_quickening_info_alignment_ = 0; - return; - } - - TimingLogger::ScopedTiming split("VDEX quickening info", timings_); - - // Make sure the table is properly aligned. - size_t start_offset = RoundUp(vdex_size_, 4u); - const size_t padding_bytes = start_offset - vdex_size_; - buffer->resize(buffer->size() + padding_bytes, 0u); - - WriteQuickeningInfoMethodVisitor write_quicken_info_visitor(this, buffer); - write_quicken_info_visitor.VisitDexMethods(*dex_files_); - - uint32_t quicken_info_offset = write_quicken_info_visitor.GetNumberOfWrittenBytes(); - uint32_t extra_bytes_offset = start_offset + quicken_info_offset; - size_t current_offset = RoundUp(extra_bytes_offset, CompactOffsetTable::kAlignment); - const size_t extra_bytes = current_offset - extra_bytes_offset; - buffer->resize(buffer->size() + extra_bytes, 0u); - quicken_info_offset += extra_bytes; - - std::vector<uint32_t> table_offsets; - WriteQuickeningInfoOffsetsMethodVisitor table_visitor( - buffer, - quicken_info_offset, - &write_quicken_info_visitor.GetQuickenInfoOffsetIndices(), - /*out*/ &table_offsets); - table_visitor.VisitDexMethods(*dex_files_); - - CHECK_EQ(table_offsets.size(), dex_files_->size()); - - current_offset += table_visitor.GetNumberOfWrittenBytes(); - - // Store the offset table offset as a preheader for each dex. - size_t index = 0; - for (const OatDexFile& oat_dex_file : oat_dex_files_) { - auto* quickening_table_offset = reinterpret_cast<VdexFile::QuickeningTableOffsetType*>( - vdex_begin_ + oat_dex_file.dex_file_offset_ - sizeof(VdexFile::QuickeningTableOffsetType)); - *quickening_table_offset = table_offsets[index]; - ++index; - } - size_quickening_info_ = current_offset - start_offset; - - if (size_quickening_info_ == 0) { - // Nothing was written. Leave `vdex_size_` untouched and unaligned. - buffer->resize(buffer->size() - padding_bytes); // Drop the padding data. - vdex_quickening_info_offset_ = vdex_size_; - size_quickening_info_alignment_ = 0; - } else { - size_quickening_info_alignment_ = padding_bytes; - vdex_quickening_info_offset_ = start_offset; - vdex_size_ = start_offset + size_quickening_info_; - } +void OatWriter::WriteQuickeningInfo(/*out*/std::vector<uint8_t>* ATTRIBUTE_UNUSED) { + // Nothing to write. Leave `vdex_size_` untouched and unaligned. + vdex_quickening_info_offset_ = vdex_size_; + size_quickening_info_alignment_ = 0; } void OatWriter::WriteVerifierDeps(verifier::VerifierDeps* verifier_deps, diff --git a/dex2oat/linker/oat_writer.h b/dex2oat/linker/oat_writer.h index 6b2b4950ae..5c55d47049 100644 --- a/dex2oat/linker/oat_writer.h +++ b/dex2oat/linker/oat_writer.h @@ -278,8 +278,6 @@ class OatWriter { class InitImageMethodVisitor; class WriteCodeMethodVisitor; class WriteMapMethodVisitor; - class WriteQuickeningInfoMethodVisitor; - class WriteQuickeningInfoOffsetsMethodVisitor; // Visit all the methods in all the compiled dex files in their definition order // with a given DexMethodVisitor. diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc index 92fc2e450e..e77e361570 100644 --- a/dex2oat/linker/oat_writer_test.cc +++ b/dex2oat/linker/oat_writer_test.cc @@ -293,11 +293,7 @@ class OatTest : public CommonCompilerDriverTest { } const VdexFile::DexSectionHeader &vdex_header = opened_oat_file->GetVdexFile()->GetDexSectionHeader(); - if (!compiler_driver_->GetCompilerOptions().IsQuickeningCompilationEnabled()) { - // If quickening is enabled we will always write the table since there is no special logic - // that checks for all methods not being quickened (not worth the complexity). - ASSERT_EQ(vdex_header.GetQuickeningInfoSize(), 0u); - } + ASSERT_EQ(vdex_header.GetQuickeningInfoSize(), 0u); int64_t actual_vdex_size = vdex_file.GetFile()->GetLength(); ASSERT_GE(actual_vdex_size, 0); diff --git a/libartbase/base/compiler_filter.cc b/libartbase/base/compiler_filter.cc index 6291329f5a..a6d1c80afa 100644 --- a/libartbase/base/compiler_filter.cc +++ b/libartbase/base/compiler_filter.cc @@ -54,14 +54,8 @@ bool CompilerFilter::IsJniCompilationEnabled(Filter filter) { UNREACHABLE(); } -bool CompilerFilter::IsQuickeningCompilationEnabled(Filter filter ATTRIBUTE_UNUSED) { - return false; -} - bool CompilerFilter::IsAnyCompilationEnabled(Filter filter) { - return IsJniCompilationEnabled(filter) || - IsQuickeningCompilationEnabled(filter) || - IsAotCompilationEnabled(filter); + return IsJniCompilationEnabled(filter) || IsAotCompilationEnabled(filter); } bool CompilerFilter::IsVerificationEnabled(Filter filter) { diff --git a/libartbase/base/compiler_filter.h b/libartbase/base/compiler_filter.h index b4a83ece10..4ca3c761a6 100644 --- a/libartbase/base/compiler_filter.h +++ b/libartbase/base/compiler_filter.h @@ -56,10 +56,6 @@ class CompilerFilter final { // compiled executable code for JNI methods. static bool IsJniCompilationEnabled(Filter filter); - // Returns true if an oat file with this compiler filter contains - // quickened dex bytecode. - static bool IsQuickeningCompilationEnabled(Filter filter); - // Returns true if this compiler filter requires running verification. static bool IsVerificationEnabled(Filter filter); |