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;