Remove DexToDexCompiler
Since quickening is deprecated, it is no longer used.
This CL only removes compile-time dead code.
Bug: 170086509
Test: test-art-host-gtest
Test: test.py -r -b --host
Change-Id: I46c02fb7a9304f8361cecfafb9507c906a93592f
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index 6915b7c..ed8168a 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -102,10 +102,6 @@
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 73c0946..5bd7f00 100644
--- a/dex2oat/Android.bp
+++ b/dex2oat/Android.bp
@@ -28,7 +28,6 @@
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 @@
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 db64fe4..1f62cd7 100644
--- a/dex2oat/common_compiler_driver_test.cc
+++ b/dex2oat/common_compiler_driver_test.cc
@@ -59,7 +59,6 @@
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 384436d..0000000
--- 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 16030bd..0000000
--- 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 280ac45..9d14608 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 @@
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 @@
}
}
-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 @@
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 @@
method_idx,
class_loader,
dex_file,
- dex_to_dex_compilation_level,
dex_cache);
if (kTimeCompileMethod) {
@@ -473,68 +411,6 @@
}
}
-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 @@
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 @@
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 @@
}
}
}
- 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 @@
method_idx,
class_loader,
dex_file,
- dex_to_dex_compilation_level,
dex_cache,
quick_fn);
}
@@ -843,13 +709,8 @@
}
}
-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 @@
// 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 @@
method_idx,
class_loader,
dex_file,
- dex_to_dex_compilation_level,
dex_cache);
}
};
@@ -2780,7 +2636,6 @@
: 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 @@
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 137f6f1..0a3c0fe 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 @@
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 @@
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 d6eff94..9070ed2 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -892,12 +892,6 @@
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 @@
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 6b2b495..5c55d47 100644
--- a/dex2oat/linker/oat_writer.h
+++ b/dex2oat/linker/oat_writer.h
@@ -278,8 +278,6 @@
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 92fc2e4..e77e361 100644
--- a/dex2oat/linker/oat_writer_test.cc
+++ b/dex2oat/linker/oat_writer_test.cc
@@ -293,11 +293,7 @@
}
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 6291329..a6d1c80 100644
--- a/libartbase/base/compiler_filter.cc
+++ b/libartbase/base/compiler_filter.cc
@@ -54,14 +54,8 @@
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 b4a83ec..4ca3c76 100644
--- a/libartbase/base/compiler_filter.h
+++ b/libartbase/base/compiler_filter.h
@@ -56,10 +56,6 @@
// 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);