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 {