Merge "Make run-jdwp-tests.sh kill zombie dalvikvm processes"
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 528cf3a..c41e9da 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1809,7 +1809,13 @@
       // if the boot image has changed. How exactly we'll know is under
       // experimentation.
       TimingLogger::ScopedTiming time_unquicken("Unquicken", timings_);
-      VdexFile::Unquicken(dex_files_, input_vdex_file_->GetQuickeningInfo());
+
+      // 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_,
+                          input_vdex_file_->GetQuickeningInfo(),
+                          /* decompile_return_instruction */ false);
     } else {
       // Create the main VerifierDeps, here instead of in the compiler since we want to aggregate
       // the results for all the dex files, not just the results for the current dex file.
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index bcf007b..bdc36e8 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -412,6 +412,8 @@
     return instruction_set_;
   }
 
+  typedef std::vector<std::unique_ptr<const DexFile>> DexFileUniqV;
+
   bool Dump(std::ostream& os) {
     bool success = true;
     const OatHeader& oat_header = oat_file_.GetOatHeader();
@@ -563,14 +565,50 @@
       for (size_t i = 0; i < oat_dex_files_.size(); i++) {
         const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
         CHECK(oat_dex_file != nullptr);
+        if (!DumpOatDexFile(os, *oat_dex_file)) {
+          success = false;
+        }
+      }
+    }
 
-        // If file export selected skip file analysis
-        if (options_.export_dex_location_) {
-          if (!ExportDexFile(os, *oat_dex_file)) {
+    if (options_.export_dex_location_) {
+      if (kIsVdexEnabled) {
+        std::string error_msg;
+        std::string vdex_filename = GetVdexFilename(oat_file_.GetLocation());
+        if (!OS::FileExists(vdex_filename.c_str())) {
+          os << "File " << vdex_filename.c_str() << " does not exist\n";
+          return false;
+        }
+
+        DexFileUniqV vdex_dex_files;
+        std::unique_ptr<const VdexFile> vdex_file = OpenVdexUnquicken(vdex_filename,
+                                                                      &vdex_dex_files,
+                                                                      &error_msg);
+        if (vdex_file.get() == nullptr) {
+          os << "Failed to open vdex file: " << error_msg << "\n";
+          return false;
+        }
+        if (oat_dex_files_.size() != vdex_dex_files.size()) {
+          os << "Dex files number in Vdex file does not match Dex files number in Oat file: "
+             << vdex_dex_files.size() << " vs " << oat_dex_files_.size() << '\n';
+          return false;
+        }
+
+        size_t i = 0;
+        for (const auto& vdex_dex_file : vdex_dex_files) {
+          const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
+          CHECK(oat_dex_file != nullptr);
+          CHECK(vdex_dex_file != nullptr);
+          if (!ExportDexFile(os, *oat_dex_file, vdex_dex_file.get())) {
             success = false;
           }
-        } else {
-          if (!DumpOatDexFile(os, *oat_dex_file)) {
+          i++;
+        }
+      } else {
+        for (size_t i = 0; i < oat_dex_files_.size(); i++) {
+          const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
+          CHECK(oat_dex_file != nullptr);
+          if (!ExportDexFile(os, *oat_dex_file, /* vdex_dex_file */ nullptr)) {
             success = false;
           }
         }
@@ -628,6 +666,57 @@
     return nullptr;
   }
 
+  // Returns nullptr and updates error_msg if the Vdex file cannot be opened, otherwise all Dex
+  // files are fully unquickened and stored in dex_files
+  std::unique_ptr<const VdexFile> OpenVdexUnquicken(const std::string& vdex_filename,
+                                                    /* out */ DexFileUniqV* dex_files,
+                                                    /* out */ std::string* error_msg) {
+    std::unique_ptr<const File> file(OS::OpenFileForReading(vdex_filename.c_str()));
+    if (file == nullptr) {
+      *error_msg = "Could not open file " + vdex_filename + " for reading.";
+      return nullptr;
+    }
+
+    int64_t vdex_length = file->GetLength();
+    if (vdex_length == -1) {
+      *error_msg = "Could not read the length of file " + vdex_filename;
+      return nullptr;
+    }
+
+    std::unique_ptr<MemMap> mmap(MemMap::MapFile(
+        file->GetLength(),
+        PROT_READ | PROT_WRITE,
+        MAP_PRIVATE,
+        file->Fd(),
+        /* start offset */ 0,
+        /* low_4gb */ false,
+        vdex_filename.c_str(),
+        error_msg));
+    if (mmap == nullptr) {
+      *error_msg = "Failed to mmap file " + vdex_filename + ": " + *error_msg;
+      return nullptr;
+    }
+
+    std::unique_ptr<VdexFile> vdex_file(new VdexFile(mmap.release()));
+    if (!vdex_file->IsValid()) {
+      *error_msg = "Vdex file is not valid";
+      return nullptr;
+    }
+
+    DexFileUniqV tmp_dex_files;
+    if (!vdex_file->OpenAllDexFiles(&tmp_dex_files, error_msg)) {
+      *error_msg = "Failed to open Dex files from Vdex: " + *error_msg;
+      return nullptr;
+    }
+
+    vdex_file->Unquicken(MakeNonOwningPointerVector(tmp_dex_files),
+                         vdex_file->GetQuickeningInfo(),
+                         /* decompile_return_instruction */ true);
+
+    *dex_files = std::move(tmp_dex_files);
+    return vdex_file;
+  }
+
   struct Stats {
     enum ByteKind {
       kByteKindCode,
@@ -1024,15 +1113,15 @@
     return success;
   }
 
-  bool ExportDexFile(std::ostream& os, const OatFile::OatDexFile& oat_dex_file) {
+  // Backwards compatible Dex file export. If dex_file is nullptr (valid Vdex file not present) the
+  // Dex resource is extracted from the oat_dex_file and its checksum is repaired since it's not
+  // unquickened. Otherwise the dex_file has been fully unquickened and is expected to verify the
+  // original checksum.
+  bool ExportDexFile(std::ostream& os,
+                     const OatFile::OatDexFile& oat_dex_file,
+                     const DexFile* dex_file) {
     std::string error_msg;
     std::string dex_file_location = oat_dex_file.GetDexFileLocation();
-
-    const DexFile* const dex_file = OpenDexFile(&oat_dex_file, &error_msg);
-    if (dex_file == nullptr) {
-      os << "Failed to open dex file '" << dex_file_location << "': " << error_msg;
-      return false;
-    }
     size_t fsize = oat_dex_file.FileSize();
 
     // Some quick checks just in case
@@ -1041,6 +1130,27 @@
       return false;
     }
 
+    if (dex_file == nullptr) {
+      // Exported bytecode is quickened (dex-to-dex transformations present)
+      dex_file = OpenDexFile(&oat_dex_file, &error_msg);
+      if (dex_file == nullptr) {
+        os << "Failed to open dex file '" << dex_file_location << "': " << error_msg;
+        return false;
+      }
+
+      // Recompute checksum
+      reinterpret_cast<DexFile::Header*>(const_cast<uint8_t*>(dex_file->Begin()))->checksum_ =
+          dex_file->CalculateChecksum();
+    } else {
+      // Vdex unquicken output should match original input bytecode
+      uint32_t orig_checksum =
+          reinterpret_cast<DexFile::Header*>(const_cast<uint8_t*>(dex_file->Begin()))->checksum_;
+      if (orig_checksum != dex_file->CalculateChecksum()) {
+        os << "Unexpected checksum from unquicken dex file '" << dex_file_location << "'\n";
+        return false;
+      }
+    }
+
     // Verify output directory exists
     if (!OS::DirectoryExists(options_.export_dex_location_)) {
       // TODO: Extend OS::DirectoryExists if symlink support is required
diff --git a/oatdump/oatdump_test.cc b/oatdump/oatdump_test.cc
index 7260d74..0034469 100644
--- a/oatdump/oatdump_test.cc
+++ b/oatdump/oatdump_test.cc
@@ -70,5 +70,17 @@
   std::string error_msg;
   ASSERT_TRUE(Exec(kStatic, kModeSymbolize, {}, kListOnly, &error_msg)) << error_msg;
 }
+
+TEST_F(OatDumpTest, TestExportDex) {
+  std::string error_msg;
+  ASSERT_TRUE(Exec(kDynamic, kModeOat, {"--export-dex-to=" + tmp_dir_}, kListOnly, &error_msg))
+      << error_msg;
+}
+TEST_F(OatDumpTest, TestExportDexStatic) {
+  TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
+  std::string error_msg;
+  ASSERT_TRUE(Exec(kStatic, kModeOat, {"--export-dex-to=" + tmp_dir_}, kListOnly, &error_msg))
+      << error_msg;
+}
 #endif
 }  // namespace art
diff --git a/oatdump/oatdump_test.h b/oatdump/oatdump_test.h
index 1d5c536..52fe973 100644
--- a/oatdump/oatdump_test.h
+++ b/oatdump/oatdump_test.h
@@ -43,6 +43,24 @@
     CommonRuntimeTest::SetUp();
     core_art_location_ = GetCoreArtLocation();
     core_oat_location_ = GetSystemImageFilename(GetCoreOatLocation().c_str(), kRuntimeISA);
+    tmp_dir_ = GetScratchDir();
+  }
+
+  virtual void TearDown() {
+    ClearDirectory(tmp_dir_.c_str(), /*recursive*/ false);
+    ASSERT_EQ(rmdir(tmp_dir_.c_str()), 0);
+    CommonRuntimeTest::TearDown();
+  }
+
+  std::string GetScratchDir() {
+    // ANDROID_DATA needs to be set
+    CHECK_NE(static_cast<char*>(nullptr), getenv("ANDROID_DATA"));
+    std::string dir = getenv("ANDROID_DATA");
+    dir += "/oatdump-tmp-dir-XXXXXX";
+    if (mkdtemp(&dir[0]) == nullptr) {
+      PLOG(FATAL) << "mkdtemp(\"" << &dir[0] << "\") failed";
+    }
+    return dir;
   }
 
   // Linking flavor.
@@ -217,6 +235,8 @@
     return result;
   }
 
+  std::string tmp_dir_;
+
  private:
   std::string core_art_location_;
   std::string core_oat_location_;
diff --git a/runtime/interpreter/mterp/mips64/header.S b/runtime/interpreter/mterp/mips64/header.S
index b67df20..264c411 100644
--- a/runtime/interpreter/mterp/mips64/header.S
+++ b/runtime/interpreter/mterp/mips64/header.S
@@ -14,17 +14,50 @@
  * limitations under the License.
  */
 
-#include <machine/regdef.h>
+#define zero $$0  /* always zero */
+#define AT   $$at /* assembler temp */
+#define v0   $$2  /* return value */
+#define v1   $$3
+#define a0   $$4  /* argument registers */
+#define a1   $$5
+#define a2   $$6
+#define a3   $$7
+#define a4   $$8  /* expanded register arguments */
+#define a5   $$9
+#define a6   $$10
+#define a7   $$11
+#define ta0  $$8  /* alias */
+#define ta1  $$9
+#define ta2  $$10
+#define ta3  $$11
+#define t0   $$12 /* temp registers (not saved across subroutine calls) */
+#define t1   $$13
+#define t2   $$14
+#define t3   $$15
 
-/* TODO: add the missing file and use its FP register definitions. */
-/* #include <machine/fpregdef.h> */
-/* FP register definitions */
-#define f0  $$f0
-#define f1  $$f1
-#define f2  $$f2
-#define f3  $$f3
-#define f12 $$f12
-#define f13 $$f13
+#define s0   $$16 /* saved across subroutine calls (callee saved) */
+#define s1   $$17
+#define s2   $$18
+#define s3   $$19
+#define s4   $$20
+#define s5   $$21
+#define s6   $$22
+#define s7   $$23
+#define t8   $$24 /* two more temp registers */
+#define t9   $$25
+#define k0   $$26 /* kernel temporary */
+#define k1   $$27
+#define gp   $$28 /* global pointer */
+#define sp   $$29 /* stack pointer */
+#define s8   $$30 /* one more callee saved */
+#define ra   $$31 /* return address */
+
+#define f0   $$f0
+#define f1   $$f1
+#define f2   $$f2
+#define f3   $$f3
+#define f12  $$f12
+#define f13  $$f13
 
 /*
  * It looks like the GNU assembler currently does not support the blec and bgtc
diff --git a/runtime/interpreter/mterp/out/mterp_mips64.S b/runtime/interpreter/mterp/out/mterp_mips64.S
index 408267e..27fa318 100644
--- a/runtime/interpreter/mterp/out/mterp_mips64.S
+++ b/runtime/interpreter/mterp/out/mterp_mips64.S
@@ -21,17 +21,50 @@
  * limitations under the License.
  */
 
-#include <machine/regdef.h>
+#define zero $0  /* always zero */
+#define AT   $at /* assembler temp */
+#define v0   $2  /* return value */
+#define v1   $3
+#define a0   $4  /* argument registers */
+#define a1   $5
+#define a2   $6
+#define a3   $7
+#define a4   $8  /* expanded register arguments */
+#define a5   $9
+#define a6   $10
+#define a7   $11
+#define ta0  $8  /* alias */
+#define ta1  $9
+#define ta2  $10
+#define ta3  $11
+#define t0   $12 /* temp registers (not saved across subroutine calls) */
+#define t1   $13
+#define t2   $14
+#define t3   $15
 
-/* TODO: add the missing file and use its FP register definitions. */
-/* #include <machine/fpregdef.h> */
-/* FP register definitions */
-#define f0  $f0
-#define f1  $f1
-#define f2  $f2
-#define f3  $f3
-#define f12 $f12
-#define f13 $f13
+#define s0   $16 /* saved across subroutine calls (callee saved) */
+#define s1   $17
+#define s2   $18
+#define s3   $19
+#define s4   $20
+#define s5   $21
+#define s6   $22
+#define s7   $23
+#define t8   $24 /* two more temp registers */
+#define t9   $25
+#define k0   $26 /* kernel temporary */
+#define k1   $27
+#define gp   $28 /* global pointer */
+#define sp   $29 /* stack pointer */
+#define s8   $30 /* one more callee saved */
+#define ra   $31 /* return address */
+
+#define f0   $f0
+#define f1   $f1
+#define f2   $f2
+#define f3   $f3
+#define f12  $f12
+#define f13  $f13
 
 /*
  * It looks like the GNU assembler currently does not support the blec and bgtc
diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc
index 55bc9ec..955098d 100644
--- a/runtime/vdex_file.cc
+++ b/runtime/vdex_file.cc
@@ -119,7 +119,9 @@
     if (!vdex->OpenAllDexFiles(&unique_ptr_dex_files, error_msg)) {
       return nullptr;
     }
-    Unquicken(MakeNonOwningPointerVector(unique_ptr_dex_files), vdex->GetQuickeningInfo());
+    Unquicken(MakeNonOwningPointerVector(unique_ptr_dex_files),
+              vdex->GetQuickeningInfo(),
+              /* decompile_return_instruction */ false);
     // Update the quickening info size to pretend there isn't any.
     reinterpret_cast<Header*>(vdex->mmap_->Begin())->quickening_info_size_ = 0;
   }
@@ -218,23 +220,55 @@
 };
 
 void VdexFile::Unquicken(const std::vector<const DexFile*>& dex_files,
-                         const ArrayRef<const uint8_t>& quickening_info) {
-  if (quickening_info.size() == 0) {
-    // Bail early if there is no quickening info.
+                         const ArrayRef<const uint8_t>& quickening_info,
+                         bool decompile_return_instruction) {
+  if (quickening_info.size() == 0 && !decompile_return_instruction) {
+    // Bail early if there is no quickening info and no need to decompile
+    // RETURN_VOID_NO_BARRIER instructions to RETURN_VOID instructions.
     return;
   }
-  // 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).
-  constexpr bool kDecompileReturnInstruction = false;
-  for (uint32_t i = 0; i < dex_files.size(); ++i) {
-    for (QuickeningInfoIterator it(i, dex_files.size(), quickening_info);
-         !it.Done();
-         it.Advance()) {
-      optimizer::ArtDecompileDEX(
-          *dex_files[i]->GetCodeItem(it.GetCurrentCodeItemOffset()),
-          it.GetCurrentQuickeningInfo(),
-          kDecompileReturnInstruction);
+
+  // When we do not decompile RETURN_VOID_NO_BARRIER use the faster
+  // QuickeningInfoIterator, otherwise use the slower ClassDataItemIterator
+  if (!decompile_return_instruction) {
+    for (uint32_t i = 0; i < dex_files.size(); ++i) {
+      for (QuickeningInfoIterator it(i, dex_files.size(), quickening_info);
+           !it.Done();
+           it.Advance()) {
+        optimizer::ArtDecompileDEX(
+            *dex_files[i]->GetCodeItem(it.GetCurrentCodeItemOffset()),
+            it.GetCurrentQuickeningInfo(),
+            decompile_return_instruction);
+      }
+    }
+  } else {
+    for (uint32_t i = 0; i < dex_files.size(); ++i) {
+      QuickeningInfoIterator quick_it(i, dex_files.size(), quickening_info);
+      for (uint32_t j = 0; j < dex_files[i]->NumClassDefs(); ++j) {
+        const DexFile::ClassDef& class_def = dex_files[i]->GetClassDef(j);
+        const uint8_t* class_data = dex_files[i]->GetClassData(class_def);
+        if (class_data != nullptr) {
+          for (ClassDataItemIterator class_it(*dex_files[i], class_data);
+               class_it.HasNext();
+               class_it.Next()) {
+            if (class_it.IsAtMethod() && class_it.GetMethodCodeItem() != nullptr) {
+              uint32_t offset = class_it.GetMethodCodeItemOffset();
+              if (!quick_it.Done() && offset == quick_it.GetCurrentCodeItemOffset()) {
+                optimizer::ArtDecompileDEX(
+                    *class_it.GetMethodCodeItem(),
+                    quick_it.GetCurrentQuickeningInfo(),
+                    decompile_return_instruction);
+                quick_it.Advance();
+              } else {
+                optimizer::ArtDecompileDEX(*class_it.GetMethodCodeItem(),
+                                           /* quickened_info */ {},
+                                           decompile_return_instruction);
+              }
+            }
+          }
+        }
+      }
+      DCHECK(quick_it.Done()) << "Failed to use all quickening info";
     }
   }
 }
diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h
index 63058cf..11f1f52 100644
--- a/runtime/vdex_file.h
+++ b/runtime/vdex_file.h
@@ -87,6 +87,8 @@
 
   typedef uint32_t VdexChecksum;
 
+  explicit VdexFile(MemMap* mmap) : mmap_(mmap) {}
+
   // Returns nullptr if the vdex file cannot be opened or is not valid.
   static std::unique_ptr<VdexFile> Open(const std::string& vdex_filename,
                                         bool writable,
@@ -143,8 +145,12 @@
                        std::string* error_msg);
 
   // In-place unquicken the given `dex_files` based on `quickening_info`.
+  // `decompile_return_instruction` controls if RETURN_VOID_BARRIER instructions are
+  // decompiled to RETURN_VOID instructions using the slower ClassDataItemIterator
+  // instead of the faster QuickeningInfoIterator.
   static void Unquicken(const std::vector<const DexFile*>& dex_files,
-                        const ArrayRef<const uint8_t>& quickening_info);
+                        const ArrayRef<const uint8_t>& quickening_info,
+                        bool decompile_return_instruction);
 
   // Fully unquicken `target_dex_file` based on quickening info stored
   // in this vdex file for `original_dex_file`.
@@ -155,8 +161,6 @@
   const uint8_t* GetQuickenedInfoOf(const DexFile& dex_file, uint32_t code_item_offset) const;
 
  private:
-  explicit VdexFile(MemMap* mmap) : mmap_(mmap) {}
-
   bool HasDexSection() const {
     return GetHeader().GetDexSize() != 0;
   }