Merge "Revert "Revert "x86: Fix art_quick_instrumentation_exit"""
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index ef2d9a6..3ca85bf 100755
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -692,33 +692,27 @@
     Clobber(rs_r2);
     LockTemp(rs_r2);
 
-    // Assume that the result will be in EDX.
-    rl_result = {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, rs_r2, INVALID_SREG, INVALID_SREG};
+    // Assume that the result will be in EDX for divide, and EAX for remainder.
+    rl_result = {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, is_div ? rs_r2 : rs_r0,
+                 INVALID_SREG, INVALID_SREG};
 
-    // Numerator into EAX.
-    RegStorage numerator_reg;
-    if (!is_div || (imm > 0 && magic < 0) || (imm < 0 && magic > 0)) {
-      // We will need the value later.
-      rl_src = LoadValue(rl_src, kCoreReg);
-      numerator_reg = rl_src.reg;
-      OpRegCopy(rs_r0, numerator_reg);
-    } else {
-      // Only need this once.  Just put it into EAX.
-      LoadValueDirectFixed(rl_src, rs_r0);
-    }
+    // We need the value at least twice.  Load into a temp.
+    rl_src = LoadValue(rl_src, kCoreReg);
+    RegStorage numerator_reg = rl_src.reg;
 
-    // Check if numerator is 0
-    OpRegImm(kOpCmp, rs_r0, 0);
+    // Check if numerator is 0.
+    OpRegImm(kOpCmp, numerator_reg, 0);
     LIR* branch = NewLIR2(kX86Jcc8, 0, kX86CondNe);
-    LoadConstantNoClobber(rs_r2, 0);
+    // Return result 0 if numerator was 0.
+    LoadConstantNoClobber(rl_result.reg, 0);
     LIR* done = NewLIR1(kX86Jmp8, 0);
     branch->target = NewLIR0(kPseudoTargetLabel);
 
-    // EDX = magic.
-    LoadConstantNoClobber(rs_r2, magic);
+    // EAX = magic.
+    LoadConstant(rs_r0, magic);
 
-    // EDX:EAX = magic & dividend.
-    NewLIR1(kX86Imul32DaR, rs_r2.GetReg());
+    // EDX:EAX = magic * numerator.
+    NewLIR1(kX86Imul32DaR, numerator_reg.GetReg());
 
     if (imm > 0 && magic < 0) {
       // Add numerator to EDX.
@@ -756,11 +750,10 @@
       // EAX = numerator * imm.
       OpRegRegImm(kOpMul, rs_r2, rs_r2, imm);
 
-      // EDX -= EAX.
+      // EAX -= EDX.
       NewLIR2(kX86Sub32RR, rs_r0.GetReg(), rs_r2.GetReg());
 
       // For this case, return the result in EAX.
-      rl_result.reg.SetReg(r0);
     }
     done->target = NewLIR0(kPseudoTargetLabel);
   }
@@ -2045,7 +2038,8 @@
     Clobber(rs_r2q);
     LockTemp(rs_r2q);
 
-    RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, rs_r2q, INVALID_SREG, INVALID_SREG};
+    RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1,
+                             is_div ? rs_r2q : rs_r0q, INVALID_SREG, INVALID_SREG};
 
     // Use H.S.Warren's Hacker's Delight Chapter 10 and
     // T,Grablund, P.L.Montogomery's Division by invariant integers using multiplication.
@@ -2069,24 +2063,35 @@
      * 5. Thus, RDX is the quotient
      */
 
-    // Numerator into RAX.
+    // RAX = magic.
+    LoadConstantWide(rs_r0q, magic);
+
+    // Multiply by numerator.
     RegStorage numerator_reg;
     if (!is_div || (imm > 0 && magic < 0) || (imm < 0 && magic > 0)) {
       // We will need the value later.
       rl_src = LoadValueWide(rl_src, kCoreReg);
       numerator_reg = rl_src.reg;
-      OpRegCopyWide(rs_r0q, numerator_reg);
+
+      // RDX:RAX = magic * numerator.
+      NewLIR1(kX86Imul64DaR, numerator_reg.GetReg());
     } else {
-      // Only need this once.  Just put it into RAX.
-      LoadValueDirectWideFixed(rl_src, rs_r0q);
+      // Only need this once.  Multiply directly from the value.
+      rl_src = UpdateLocWideTyped(rl_src, kCoreReg);
+      if (rl_src.location != kLocPhysReg) {
+        // Okay, we can do this from memory.
+        ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
+        int displacement = SRegOffset(rl_src.s_reg_low);
+        // RDX:RAX = magic * numerator.
+        LIR *m = NewLIR2(kX86Imul64DaM, rs_rX86_SP.GetReg(), displacement);
+        AnnotateDalvikRegAccess(m, displacement >> 2,
+                                true /* is_load */, true /* is_64bit */);
+      } else {
+        // RDX:RAX = magic * numerator.
+        NewLIR1(kX86Imul64DaR, rl_src.reg.GetReg());
+      }
     }
 
-    // RDX = magic.
-    LoadConstantWide(rs_r2q, magic);
-
-    // RDX:RAX = magic & dividend.
-    NewLIR1(kX86Imul64DaR, rs_r2q.GetReg());
-
     if (imm > 0 && magic < 0) {
       // Add numerator to RDX.
       DCHECK(numerator_reg.Valid());
@@ -2134,14 +2139,12 @@
         NewLIR3(kX86Imul64RRI, rs_r2q.GetReg(), rs_r2q.GetReg(), short_imm);
       }
 
-      // RDX -= RAX.
+      // RAX -= RDX.
       OpRegReg(kOpSub, rs_r0q, rs_r2q);
 
-      // Store result.
-      OpRegCopyWide(rl_result.reg, rs_r0q);
+      // Result in RAX.
     } else {
-      // Store result.
-      OpRegCopyWide(rl_result.reg, rs_r2q);
+      // Result in RDX.
     }
     StoreValueWide(rl_dest, rl_result);
     FreeTemp(rs_r0q);
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index ad436d0..1e64c00 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -785,7 +785,19 @@
   return NULL;
 }
 
-static bool LoadMultiDexFilesFromOatFile(const OatFile* oat_file, const char* dex_location,
+
+// Loads all multi dex files from the given oat file returning true on success.
+//
+// Parameters:
+//   oat_file - the oat file to load from
+//   dex_location - the dex location used to generate the oat file
+//   dex_location_checksum - the checksum of the dex_location (may be null for pre-opted files)
+//   generated - whether or not the oat_file existed before or was just (re)generated
+//   error_msgs - any error messages will be appended here
+//   dex_files - the loaded dex_files will be appended here (only if the loading succeeds)
+static bool LoadMultiDexFilesFromOatFile(const OatFile* oat_file,
+                                         const char* dex_location,
+                                         const uint32_t* dex_location_checksum,
                                          bool generated,
                                          std::vector<std::string>* error_msgs,
                                          std::vector<const DexFile*>* dex_files) {
@@ -800,12 +812,20 @@
     std::string next_name_str = DexFile::GetMultiDexClassesDexName(i, dex_location);
     const char* next_name = next_name_str.c_str();
 
-    uint32_t dex_location_checksum;
-    uint32_t* dex_location_checksum_pointer = &dex_location_checksum;
+    uint32_t next_location_checksum;
+    uint32_t* next_location_checksum_pointer = &next_location_checksum;
     std::string error_msg;
-    if (!DexFile::GetChecksum(next_name, dex_location_checksum_pointer, &error_msg)) {
+    if ((i == 0) && (strcmp(next_name, dex_location) == 0)) {
+      // When i=0 the multidex name should be the same as the location name. We already have the
+      // checksum it so we don't need to recompute it.
+      if (dex_location_checksum == nullptr) {
+        next_location_checksum_pointer = nullptr;
+      } else {
+        next_location_checksum = *dex_location_checksum;
+      }
+    } else if (!DexFile::GetChecksum(next_name, next_location_checksum_pointer, &error_msg)) {
       DCHECK_EQ(false, i == 0 && generated);
-      dex_location_checksum_pointer = nullptr;
+      next_location_checksum_pointer = nullptr;
     }
 
     const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(next_name, nullptr, false);
@@ -814,7 +834,7 @@
       if (i == 0 && generated) {
         std::string error_msg;
         error_msg = StringPrintf("\nFailed to find dex file '%s' (checksum 0x%x) in generated out "
-                                 " file'%s'", dex_location, dex_location_checksum,
+                                 " file'%s'", dex_location, next_location_checksum,
                                  oat_file->GetLocation().c_str());
         error_msgs->push_back(error_msg);
       }
@@ -823,8 +843,8 @@
 
     // Checksum test. Test must succeed when generated.
     success = !generated;
-    if (dex_location_checksum_pointer != nullptr) {
-      success = dex_location_checksum == oat_dex_file->GetDexFileLocationChecksum();
+    if (next_location_checksum_pointer != nullptr) {
+      success = next_location_checksum == oat_dex_file->GetDexFileLocationChecksum();
     }
 
     if (success) {
@@ -840,7 +860,7 @@
     // When we generated the file, we expect success, or something is terribly wrong.
     CHECK_EQ(false, generated && !success)
         << "dex_location=" << next_name << " oat_location=" << oat_file->GetLocation().c_str()
-        << std::hex << " dex_location_checksum=" << dex_location_checksum
+        << std::hex << " dex_location_checksum=" << next_location_checksum
         << " OatDexFile::GetLocationChecksum()=" << oat_dex_file->GetDexFileLocationChecksum();
   }
 
@@ -877,6 +897,7 @@
   bool have_checksum = true;
   std::string checksum_error_msg;
   if (!DexFile::GetChecksum(dex_location, dex_location_checksum_pointer, &checksum_error_msg)) {
+    // This happens for pre-opted files since the corresponding dex files are no longer on disk.
     dex_location_checksum_pointer = nullptr;
     have_checksum = false;
   }
@@ -942,8 +963,9 @@
 
   // 3) If we have an oat file, check all contained multidex files for our dex_location.
   // Note: LoadMultiDexFilesFromOatFile will check for nullptr in the first argument.
-  bool success = LoadMultiDexFilesFromOatFile(open_oat_file.get(), dex_location, false, error_msgs,
-                                              dex_files);
+  bool success = LoadMultiDexFilesFromOatFile(open_oat_file.get(), dex_location,
+                                              dex_location_checksum_pointer,
+                                              false, error_msgs, dex_files);
   if (success) {
     const OatFile* oat_file = open_oat_file.release();  // Avoid deleting it.
     if (needs_registering) {
@@ -1004,8 +1026,8 @@
   }
 
   // Try to load again, but stronger checks.
-  success = LoadMultiDexFilesFromOatFile(open_oat_file.get(), dex_location, true, error_msgs,
-                                         dex_files);
+  success = LoadMultiDexFilesFromOatFile(open_oat_file.get(), dex_location, dex_location_checksum_pointer,
+                                         true, error_msgs, dex_files);
   if (success) {
     RegisterOatFile(open_oat_file.release());
     return true;
@@ -1189,24 +1211,18 @@
     return false;
   }
 
-  if (dex_location_checksum != oat_dex_file->GetDexFileLocationChecksum()) {
-    *error_msg = StringPrintf("oat file '%s' mismatch (0x%x) with '%s' (0x%x)",
-                              oat_file->GetLocation().c_str(),
-                              oat_dex_file->GetDexFileLocationChecksum(),
-                              dex_location, dex_location_checksum);
-    return false;
-  }
+  DCHECK_EQ(dex_location_checksum, oat_dex_file->GetDexFileLocationChecksum());
   return true;
 }
 
 bool ClassLinker::VerifyOatWithDexFile(const OatFile* oat_file,
                                        const char* dex_location,
+                                       const uint32_t* dex_location_checksum,
                                        std::string* error_msg) {
   CHECK(oat_file != nullptr);
   CHECK(dex_location != nullptr);
   std::unique_ptr<const DexFile> dex_file;
-  uint32_t dex_location_checksum;
-  if (!DexFile::GetChecksum(dex_location, &dex_location_checksum, error_msg)) {
+  if (dex_location_checksum == nullptr) {
     // If no classes.dex found in dex_location, it has been stripped or is corrupt, assume oat is
     // up-to-date. This is the common case in user builds for jar's and apk's in the /system
     // directory.
@@ -1219,13 +1235,13 @@
     }
     dex_file.reset(oat_dex_file->OpenDexFile(error_msg));
   } else {
-    bool verified = VerifyOatAndDexFileChecksums(oat_file, dex_location, dex_location_checksum,
+    bool verified = VerifyOatAndDexFileChecksums(oat_file, dex_location, *dex_location_checksum,
                                                  kRuntimeISA, error_msg);
     if (!verified) {
       return false;
     }
     dex_file.reset(oat_file->GetOatDexFile(dex_location,
-                                           &dex_location_checksum)->OpenDexFile(error_msg));
+                                           dex_location_checksum)->OpenDexFile(error_msg));
   }
   return dex_file.get() != nullptr;
 }
@@ -1249,7 +1265,8 @@
                                        dex_location));
     return nullptr;
   } else if (oat_file->IsExecutable() &&
-             !VerifyOatWithDexFile(oat_file.get(), dex_location, &error_msg)) {
+             !VerifyOatWithDexFile(oat_file.get(), dex_location,
+                                   dex_location_checksum, &error_msg)) {
     error_msgs->push_back(StringPrintf("Failed to verify oat file '%s' found for dex location "
                                        "'%s': %s", oat_file->GetLocation().c_str(), dex_location,
                                        error_msg.c_str()));
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 7750c8e..d1f5aa0 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -613,9 +613,18 @@
                                                              bool* obsolete_file_cleanup_failed)
       LOCKS_EXCLUDED(dex_lock_, Locks::mutator_lock_);
 
-  // verify an oat file with the given dex file. Will return false when the dex file could not be
-  // verified. Will return true otherwise.
+  // Verifies:
+  //  - that the oat file contains the dex file (with a matching checksum, which may be null if the
+  // file was pre-opted)
+  //  - the checksums of the oat file (against the image space)
+  //  - the checksum of the dex file against dex_location_checksum
+  //  - that the dex file can be opened
+  // Returns true iff all verification succeed.
+  //
+  // The dex_location is the dex location as stored in the oat file header.
+  // (see DexFile::GetDexCanonicalLocation for a description of location conventions)
   bool VerifyOatWithDexFile(const OatFile* oat_file, const char* dex_location,
+                            const uint32_t* dex_location_checksum,
                             std::string* error_msg);
 
   mirror::ArtMethod* CreateProxyConstructor(Thread* self, ConstHandle<mirror::Class> klass,
diff --git a/test/036-finalizer/expected.txt b/test/036-finalizer/expected.txt
index a2a74fc..36fa5f8 100644
--- a/test/036-finalizer/expected.txt
+++ b/test/036-finalizer/expected.txt
@@ -11,3 +11,4 @@
 sleep
 reborn: [FinalizerTest message=nothing, finalized=false]
 wimp: null
+Finalized 1024 / 1024
diff --git a/test/036-finalizer/src/Main.java b/test/036-finalizer/src/Main.java
index 328425f..390472d 100644
--- a/test/036-finalizer/src/Main.java
+++ b/test/036-finalizer/src/Main.java
@@ -120,6 +120,39 @@
 
         System.out.println("reborn: " + FinalizerTest.mReborn);
         System.out.println("wimp: " + wimpString(wimp));
+        // Test runFinalization with multiple objects.
+        runFinalizationTest();
+    }
+
+    static class FinalizeCounter {
+      private static Object finalizeLock = new Object();
+      private static volatile int finalizeCount = 0;
+      private int index;
+      static int getCount() {
+        return finalizeCount;
+      }
+      FinalizeCounter(int index) {
+        this.index = index;
+      }
+      protected void finalize() {
+        synchronized(finalizeLock) {
+          ++finalizeCount;
+        }
+      }
+    }
+
+    private static void runFinalizationTest() {
+      int count = 1024;
+      Object[] objs = new Object[count];
+      for (int i = 0; i < count; ++i) {
+        objs[i] = new FinalizeCounter(i);
+      }
+      for (int i = 0; i < count; ++i) {
+        objs[i] = null;
+      }
+      System.gc();
+      System.runFinalization();
+      System.out.println("Finalized " + FinalizeCounter.getCount() + " / "  + count);
     }
 
     public static class FinalizerTest {