Make vdex and dexlayout compatible.
Unquicken the vdex before dexlayout, to keep the dex integrity.
bug: 37558732
Test: run-test with speed-profile
(cherry picked from commit 4e868fa7b8c47600695ff92deeb373674956a67d)
Change-Id: I57ddabb79ff49d01df80bed4e3e53ba8fdb5346e
diff --git a/compiler/Android.bp b/compiler/Android.bp
index dec8b57..6ef866a 100644
--- a/compiler/Android.bp
+++ b/compiler/Android.bp
@@ -28,7 +28,6 @@
"compiled_method.cc",
"debug/elf_debug_writer.cc",
"dex/dex_to_dex_compiler.cc",
- "dex/dex_to_dex_decompiler.cc",
"dex/inline_method_analyser.cc",
"dex/verified_method.cc",
"dex/verification_results.cc",
diff --git a/compiler/dex/dex_to_dex_decompiler.cc b/compiler/dex/dex_to_dex_decompiler.cc
deleted file mode 100644
index c15c9ec..0000000
--- a/compiler/dex/dex_to_dex_decompiler.cc
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright (C) 2016 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_decompiler.h"
-
-#include "base/logging.h"
-#include "base/mutex.h"
-#include "dex_file-inl.h"
-#include "dex_instruction-inl.h"
-#include "bytecode_utils.h"
-
-namespace art {
-namespace optimizer {
-
-class DexDecompiler {
- public:
- DexDecompiler(const DexFile::CodeItem& code_item,
- const ArrayRef<const uint8_t>& quickened_info,
- bool decompile_return_instruction)
- : code_item_(code_item),
- quickened_info_ptr_(quickened_info.data()),
- quickened_info_start_(quickened_info.data()),
- quickened_info_end_(quickened_info.data() + quickened_info.size()),
- decompile_return_instruction_(decompile_return_instruction) {}
-
- bool Decompile();
-
- private:
- void DecompileInstanceFieldAccess(Instruction* inst,
- uint32_t dex_pc,
- Instruction::Code new_opcode) {
- uint16_t index = GetIndexAt(dex_pc);
- inst->SetOpcode(new_opcode);
- inst->SetVRegC_22c(index);
- }
-
- void DecompileInvokeVirtual(Instruction* inst,
- uint32_t dex_pc,
- Instruction::Code new_opcode,
- bool is_range) {
- uint16_t index = GetIndexAt(dex_pc);
- inst->SetOpcode(new_opcode);
- if (is_range) {
- inst->SetVRegB_3rc(index);
- } else {
- inst->SetVRegB_35c(index);
- }
- }
-
- void DecompileNop(Instruction* inst, uint32_t dex_pc) {
- if (quickened_info_ptr_ == quickened_info_end_) {
- return;
- }
- const uint8_t* temporary_pointer = quickened_info_ptr_;
- uint32_t quickened_pc = DecodeUnsignedLeb128(&temporary_pointer);
- if (quickened_pc != dex_pc) {
- return;
- }
- uint16_t reference_index = GetIndexAt(dex_pc);
- uint16_t type_index = GetIndexAt(dex_pc);
- inst->SetOpcode(Instruction::CHECK_CAST);
- inst->SetVRegA_21c(reference_index);
- inst->SetVRegB_21c(type_index);
- }
-
- uint16_t GetIndexAt(uint32_t dex_pc) {
- // Note that as a side effect, DecodeUnsignedLeb128 update the given pointer
- // to the new position in the buffer.
- DCHECK_LT(quickened_info_ptr_, quickened_info_end_);
- uint32_t quickened_pc = DecodeUnsignedLeb128(&quickened_info_ptr_);
- DCHECK_LT(quickened_info_ptr_, quickened_info_end_);
- uint16_t index = DecodeUnsignedLeb128(&quickened_info_ptr_);
- DCHECK_LE(quickened_info_ptr_, quickened_info_end_);
- DCHECK_EQ(quickened_pc, dex_pc);
- return index;
- }
-
- const DexFile::CodeItem& code_item_;
- const uint8_t* quickened_info_ptr_;
- const uint8_t* const quickened_info_start_;
- const uint8_t* const quickened_info_end_;
- const bool decompile_return_instruction_;
-
- DISALLOW_COPY_AND_ASSIGN(DexDecompiler);
-};
-
-bool DexDecompiler::Decompile() {
- // We need to iterate over the code item, and not over the quickening data,
- // because the RETURN_VOID quickening is not encoded in the quickening data. Because
- // unquickening is a rare need and not performance sensitive, it is not worth the
- // added storage to also add the RETURN_VOID quickening in the quickened data.
- for (CodeItemIterator it(code_item_); !it.Done(); it.Advance()) {
- uint32_t dex_pc = it.CurrentDexPc();
- Instruction* inst = const_cast<Instruction*>(&it.CurrentInstruction());
-
- switch (inst->Opcode()) {
- case Instruction::RETURN_VOID_NO_BARRIER:
- if (decompile_return_instruction_) {
- inst->SetOpcode(Instruction::RETURN_VOID);
- }
- break;
-
- case Instruction::NOP:
- DecompileNop(inst, dex_pc);
- break;
-
- case Instruction::IGET_QUICK:
- DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET);
- break;
-
- case Instruction::IGET_WIDE_QUICK:
- DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_WIDE);
- break;
-
- case Instruction::IGET_OBJECT_QUICK:
- DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_OBJECT);
- break;
-
- case Instruction::IGET_BOOLEAN_QUICK:
- DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_BOOLEAN);
- break;
-
- case Instruction::IGET_BYTE_QUICK:
- DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_BYTE);
- break;
-
- case Instruction::IGET_CHAR_QUICK:
- DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_CHAR);
- break;
-
- case Instruction::IGET_SHORT_QUICK:
- DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_SHORT);
- break;
-
- case Instruction::IPUT_QUICK:
- DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT);
- break;
-
- case Instruction::IPUT_BOOLEAN_QUICK:
- DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_BOOLEAN);
- break;
-
- case Instruction::IPUT_BYTE_QUICK:
- DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_BYTE);
- break;
-
- case Instruction::IPUT_CHAR_QUICK:
- DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_CHAR);
- break;
-
- case Instruction::IPUT_SHORT_QUICK:
- DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_SHORT);
- break;
-
- case Instruction::IPUT_WIDE_QUICK:
- DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_WIDE);
- break;
-
- case Instruction::IPUT_OBJECT_QUICK:
- DecompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_OBJECT);
- break;
-
- case Instruction::INVOKE_VIRTUAL_QUICK:
- DecompileInvokeVirtual(inst, dex_pc, Instruction::INVOKE_VIRTUAL, false);
- break;
-
- case Instruction::INVOKE_VIRTUAL_RANGE_QUICK:
- DecompileInvokeVirtual(inst, dex_pc, Instruction::INVOKE_VIRTUAL_RANGE, true);
- break;
-
- default:
- break;
- }
- }
-
- if (quickened_info_ptr_ != quickened_info_end_) {
- if (quickened_info_start_ == quickened_info_ptr_) {
- LOG(WARNING) << "Failed to use any value in quickening info,"
- << " potentially due to duplicate methods.";
- } else {
- LOG(FATAL) << "Failed to use all values in quickening info."
- << " Actual: " << std::hex << reinterpret_cast<uintptr_t>(quickened_info_ptr_)
- << " Expected: " << reinterpret_cast<uintptr_t>(quickened_info_end_);
- return false;
- }
- }
-
- return true;
-}
-
-bool ArtDecompileDEX(const DexFile::CodeItem& code_item,
- const ArrayRef<const uint8_t>& quickened_info,
- bool decompile_return_instruction) {
- if (quickened_info.size() == 0 && !decompile_return_instruction) {
- return true;
- }
- DexDecompiler decompiler(code_item, quickened_info, decompile_return_instruction);
- return decompiler.Decompile();
-}
-
-} // namespace optimizer
-} // namespace art
diff --git a/compiler/dex/dex_to_dex_decompiler.h b/compiler/dex/dex_to_dex_decompiler.h
deleted file mode 100644
index b5d5b91..0000000
--- a/compiler/dex/dex_to_dex_decompiler.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_DEX_DEX_TO_DEX_DECOMPILER_H_
-#define ART_COMPILER_DEX_DEX_TO_DEX_DECOMPILER_H_
-
-#include "base/array_ref.h"
-#include "dex_file.h"
-
-namespace art {
-namespace optimizer {
-
-// "Decompile", that is unquicken, the code item provided, given the
-// associated quickening data.
-// TODO: code_item isn't really a const element, but changing it
-// to non-const has too many repercussions on the code base. We make it
-// consistent with DexToDexCompiler, but we should really change it to
-// DexFile::CodeItem*.
-bool ArtDecompileDEX(const DexFile::CodeItem& code_item,
- const ArrayRef<const uint8_t>& quickened_data,
- bool decompile_return_instruction);
-
-} // namespace optimizer
-} // namespace art
-
-#endif // ART_COMPILER_DEX_DEX_TO_DEX_DECOMPILER_H_
diff --git a/compiler/dex/dex_to_dex_decompiler_test.cc b/compiler/dex/dex_to_dex_decompiler_test.cc
index 9a8d27c..2d300ed 100644
--- a/compiler/dex/dex_to_dex_decompiler_test.cc
+++ b/compiler/dex/dex_to_dex_decompiler_test.cc
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "dex/dex_to_dex_decompiler.h"
+#include "dex_to_dex_decompiler.h"
#include "class_linker.h"
#include "compiler/common_compiler_test.h"
diff --git a/compiler/dex/verification_results.cc b/compiler/dex/verification_results.cc
index 00a7d44..cc85146 100644
--- a/compiler/dex/verification_results.cc
+++ b/compiler/dex/verification_results.cc
@@ -104,11 +104,12 @@
// This method should only be called for classes verified at compile time,
// which have no verifier error, nor has methods that we know will throw
// at runtime.
- AtomicMap::InsertResult result = atomic_verified_methods_.Insert(
+ atomic_verified_methods_.Insert(
ref,
/*expected*/ nullptr,
new VerifiedMethod(/* encountered_error_types */ 0, /* has_runtime_throw */ false));
- DCHECK_EQ(result, AtomicMap::kInsertResultSuccess);
+ // We don't check the result of `Insert` as we could insert twice for the same
+ // MethodReference in the presence of duplicate methods.
}
void VerificationResults::AddRejectedClass(ClassReference ref) {
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index f77b3dd..aae36d3 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -45,7 +45,6 @@
#include "dex_file-inl.h"
#include "dex_instruction-inl.h"
#include "dex/dex_to_dex_compiler.h"
-#include "dex/dex_to_dex_decompiler.h"
#include "dex/verification_results.h"
#include "dex/verified_method.h"
#include "driver/compiler_options.h"
@@ -431,61 +430,6 @@
FreeThreadPools();
}
-// In-place unquicken the given `dex_files` based on `quickening_info`.
-static void Unquicken(const std::vector<const DexFile*>& dex_files,
- const ArrayRef<const uint8_t>& quickening_info,
- bool decompile_return_instruction) {
- const uint8_t* quickening_info_ptr = quickening_info.data();
- const uint8_t* const quickening_info_end = quickening_info.data() + quickening_info.size();
- for (const DexFile* dex_file : dex_files) {
- for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) {
- const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
- const uint8_t* class_data = dex_file->GetClassData(class_def);
- if (class_data == nullptr) {
- continue;
- }
- ClassDataItemIterator it(*dex_file, class_data);
- // Skip fields
- while (it.HasNextStaticField()) {
- it.Next();
- }
- while (it.HasNextInstanceField()) {
- it.Next();
- }
-
- while (it.HasNextDirectMethod()) {
- const DexFile::CodeItem* code_item = it.GetMethodCodeItem();
- if (code_item != nullptr) {
- uint32_t quickening_size = *reinterpret_cast<const uint32_t*>(quickening_info_ptr);
- quickening_info_ptr += sizeof(uint32_t);
- optimizer::ArtDecompileDEX(*code_item,
- ArrayRef<const uint8_t>(quickening_info_ptr, quickening_size),
- decompile_return_instruction);
- quickening_info_ptr += quickening_size;
- }
- it.Next();
- }
-
- while (it.HasNextVirtualMethod()) {
- const DexFile::CodeItem* code_item = it.GetMethodCodeItem();
- if (code_item != nullptr) {
- uint32_t quickening_size = *reinterpret_cast<const uint32_t*>(quickening_info_ptr);
- quickening_info_ptr += sizeof(uint32_t);
- optimizer::ArtDecompileDEX(*code_item,
- ArrayRef<const uint8_t>(quickening_info_ptr, quickening_size),
- decompile_return_instruction);
- quickening_info_ptr += quickening_size;
- }
- it.Next();
- }
- DCHECK(!it.HasNext());
- }
- }
- if (quickening_info_ptr != quickening_info_end) {
- LOG(FATAL) << "Failed to use all quickening info";
- }
-}
-
void CompilerDriver::CompileAll(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
VdexFile* vdex_file,
@@ -494,15 +438,12 @@
// TODO: we unquicken unconditionnally, as we don't know
// if the boot image has changed. How exactly we'll know is under
// experimentation.
- if (vdex_file->GetQuickeningInfo().size() != 0) {
- TimingLogger::ScopedTiming t("Unquicken", timings);
- // We do not decompile a RETURN_VOID_NO_BARRIER into a RETURN_VOID, as the quickening
- // optimization does not depend on the boot image (the optimization relies on not
- // having final fields in a class, which does not change for an app).
- Unquicken(dex_files,
- vdex_file->GetQuickeningInfo(),
- /* decompile_return_instruction */ false);
- }
+ TimingLogger::ScopedTiming t("Unquicken", timings);
+ // We do not decompile a RETURN_VOID_NO_BARRIER into a RETURN_VOID, as the quickening
+ // optimization does not depend on the boot image (the optimization relies on not
+ // having final fields in a class, which does not change for an app).
+ VdexFile::Unquicken(dex_files, vdex_file->GetQuickeningInfo());
+
Runtime::Current()->GetCompilerCallbacks()->SetVerifierDeps(
new verifier::VerifierDeps(dex_files, vdex_file->GetVerifierDepsData()));
}
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index af60def..488a290 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -2474,11 +2474,28 @@
/* verify */ true,
/* verify_checksum */ true,
&error_msg);
- } else {
- CHECK(oat_dex_file->source_.IsRawFile())
- << static_cast<size_t>(oat_dex_file->source_.GetType());
+ } else if (oat_dex_file->source_.IsRawFile()) {
File* raw_file = oat_dex_file->source_.GetRawFile();
dex_file = DexFile::OpenDex(raw_file->Fd(), location, /* verify_checksum */ true, &error_msg);
+ } else {
+ // The source data is a vdex file.
+ CHECK(oat_dex_file->source_.IsRawData())
+ << static_cast<size_t>(oat_dex_file->source_.GetType());
+ const uint8_t* raw_dex_file = oat_dex_file->source_.GetRawData();
+ // Note: The raw data has already been checked to contain the header
+ // and all the data that the header specifies as the file size.
+ DCHECK(raw_dex_file != nullptr);
+ DCHECK(ValidateDexFileHeader(raw_dex_file, oat_dex_file->GetLocation()));
+ const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_dex_file);
+ // Since the source may have had its layout changed, or may be quickened, don't verify it.
+ dex_file = DexFile::Open(raw_dex_file,
+ header->file_size_,
+ location,
+ oat_dex_file->dex_file_location_checksum_,
+ nullptr,
+ /* verify */ false,
+ /* verify_checksum */ false,
+ &error_msg);
}
if (dex_file == nullptr) {
LOG(ERROR) << "Failed to open dex file for layout: " << error_msg;