diff options
| author | 2017-04-21 17:16:44 +0100 | |
|---|---|---|
| committer | 2017-04-27 16:04:13 +0100 | |
| commit | 4e868fa7b8c47600695ff92deeb373674956a67d (patch) | |
| tree | acdb92a2b765cc87a08459267e430a8866e608cf /compiler | |
| parent | 4dc06e2ef900132d8395539842c35533da8b912a (diff) | |
Make vdex and dexlayout compatible.
Unquicken the vdex before dexlayout, to keep the dex integrity.
bug: 37558732
Test: run-test with speed-profile
Change-Id: Ifcd5c2e4378ccb0df0a66d07f68df31d94b83220
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/Android.bp | 1 | ||||
| -rw-r--r-- | compiler/dex/dex_to_dex_decompiler.cc | 208 | ||||
| -rw-r--r-- | compiler/dex/dex_to_dex_decompiler.h | 39 | ||||
| -rw-r--r-- | compiler/dex/dex_to_dex_decompiler_test.cc | 2 | ||||
| -rw-r--r-- | compiler/dex/verification_results.cc | 5 | ||||
| -rw-r--r-- | compiler/driver/compiler_driver.cc | 71 | ||||
| -rw-r--r-- | compiler/oat_writer.cc | 23 |
7 files changed, 30 insertions, 319 deletions
diff --git a/compiler/Android.bp b/compiler/Android.bp index dec8b577d8..6ef866a3c6 100644 --- a/compiler/Android.bp +++ b/compiler/Android.bp @@ -28,7 +28,6 @@ art_cc_defaults { "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 85d5784c7a..0000000000 --- a/compiler/dex/dex_to_dex_decompiler.cc +++ /dev/null @@ -1,208 +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_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_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_) { - LOG(FATAL) << "Failed to use all values in quickening info." - << " Actual: " << std::hex << quickened_info_ptr_ - << " Expected: " << 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 b5d5b91915..0000000000 --- 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 43100c9ddb..e486e2e6ec 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 4c50797067..3f0df3b2c8 100644 --- a/compiler/dex/verification_results.cc +++ b/compiler/dex/verification_results.cc @@ -104,11 +104,12 @@ void VerificationResults::CreateVerifiedMethodFor(MethodReference ref) { // 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 4f55ed6b8e..fbfa087cfd 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 @@ INTRINSICS_LIST(SETUP_INTRINSICS) 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 @@ void CompilerDriver::CompileAll(jobject class_loader, // 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 964692776c..6b5387ae19 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -2474,11 +2474,28 @@ bool OatWriter::LayoutAndWriteDexFile(OutputStream* out, OatDexFile* oat_dex_fil /* 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; |