Refine the DexOptNeeded codes.
To expose information useful for optimizing how dex2oat is invoked in
the presence of vdex files.
Bug: 30937355
Test: art-test-host
Change-Id: I8e09fabf8c56bf1e1041f43d3d9edf7850adc395
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 6197120..4d1e1ea 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -146,14 +146,13 @@
return true;
}
-OatFileAssistant::DexOptNeeded
-OatFileAssistant::GetDexOptNeeded(CompilerFilter::Filter target, bool profile_changed) {
+int OatFileAssistant::GetDexOptNeeded(CompilerFilter::Filter target, bool profile_changed) {
OatFileInfo& info = GetBestInfo();
DexOptNeeded dexopt_needed = info.GetDexOptNeeded(target, profile_changed);
- if (dexopt_needed == kPatchOatNeeded && info.IsOatLocation()) {
- dexopt_needed = kSelfPatchOatNeeded;
+ if (info.IsOatLocation() || dexopt_needed == kDex2OatFromScratch) {
+ return dexopt_needed;
}
- return dexopt_needed;
+ return -dexopt_needed;
}
// Figure out the currently specified compile filter option in the runtime.
@@ -191,13 +190,21 @@
OatFileInfo& info = GetBestInfo();
switch (info.GetDexOptNeeded(target, profile_changed)) {
- case kNoDexOptNeeded: return kUpdateSucceeded;
- case kDex2OatNeeded: return GenerateOatFile(error_msg);
- case kPatchOatNeeded: return RelocateOatFile(info.Filename(), error_msg);
+ case kNoDexOptNeeded:
+ return kUpdateSucceeded;
- // kSelfPatchOatNeeded will never be returned by GetDexOptNeeded for an
- // individual OatFileInfo.
- case kSelfPatchOatNeeded: UNREACHABLE();
+ // TODO: For now, don't bother with all the different ways we can call
+ // dex2oat to generate the oat file. Always generate the oat file as if it
+ // were kDex2OatFromScratch.
+ case kDex2OatFromScratch:
+ case kDex2OatForBootImage:
+ case kDex2OatForRelocation:
+ case kDex2OatForFilter:
+ return GenerateOatFile(error_msg);
+
+ case kPatchoatForRelocation: {
+ return RelocateOatFile(info.Filename(), error_msg);
+ }
}
UNREACHABLE();
}
@@ -830,29 +837,43 @@
OatFileAssistant::DexOptNeeded OatFileAssistant::OatFileInfo::GetDexOptNeeded(
CompilerFilter::Filter target, bool profile_changed) {
bool compilation_desired = CompilerFilter::IsBytecodeCompilationEnabled(target);
+ bool filter_okay = CompilerFilterIsOkay(target, profile_changed);
- if (CompilerFilterIsOkay(target, profile_changed)) {
- if (Status() == kOatUpToDate) {
- // The oat file is in good shape as is.
- return kNoDexOptNeeded;
- }
-
- if (Status() == kOatRelocationOutOfDate) {
- if (!compilation_desired) {
- // If no compilation is desired, then it doesn't matter if the oat
- // file needs relocation. It's in good shape as is.
- return kNoDexOptNeeded;
- }
-
- if (compilation_desired && HasPatchInfo()) {
- // Relocate if we can.
- return kPatchOatNeeded;
- }
- }
+ if (filter_okay && Status() == kOatUpToDate) {
+ // The oat file is in good shape as is.
+ return kNoDexOptNeeded;
}
- // We can only run dex2oat if there are original dex files.
- return oat_file_assistant_->HasOriginalDexFiles() ? kDex2OatNeeded : kNoDexOptNeeded;
+ if (filter_okay && !compilation_desired && Status() == kOatRelocationOutOfDate) {
+ // If no compilation is desired, then it doesn't matter if the oat
+ // file needs relocation. It's in good shape as is.
+ return kNoDexOptNeeded;
+ }
+
+ if (filter_okay && Status() == kOatRelocationOutOfDate && HasPatchInfo()) {
+ return kPatchoatForRelocation;
+ }
+
+ if (oat_file_assistant_->HasOriginalDexFiles()) {
+ // Run dex2oat for relocation if we didn't have the patch info necessary
+ // to use patchoat.
+ if (filter_okay && Status() == kOatRelocationOutOfDate) {
+ return kDex2OatForRelocation;
+ }
+
+ if (IsUseable()) {
+ return kDex2OatForFilter;
+ }
+
+ if (Status() == kOatBootImageOutOfDate) {
+ return kDex2OatForBootImage;
+ }
+
+ return kDex2OatFromScratch;
+ }
+
+ // Otherwise there is nothing we can do, even if we want to.
+ return kNoDexOptNeeded;
}
const OatFile* OatFileAssistant::OatFileInfo::GetFile() {
diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h
index 3a838d7..bed1edc 100644
--- a/runtime/oat_file_assistant.h
+++ b/runtime/oat_file_assistant.h
@@ -48,25 +48,33 @@
class OatFileAssistant {
public:
enum DexOptNeeded {
- // kNoDexOptNeeded - The code for this dex location is up to date and can
- // be used as is.
+ // No dexopt should (or can) be done to update the apk/jar.
// Matches Java: dalvik.system.DexFile.NO_DEXOPT_NEEDED = 0
kNoDexOptNeeded = 0,
- // kDex2OatNeeded - In order to make the code for this dex location up to
- // date, dex2oat must be run on the dex file.
- // Matches Java: dalvik.system.DexFile.DEX2OAT_NEEDED = 1
- kDex2OatNeeded = 1,
+ // dex2oat should be run to update the apk/jar from scratch.
+ // Matches Java: dalvik.system.DexFile.DEX2OAT_FROM_SCRATCH = 1
+ kDex2OatFromScratch = 1,
- // kPatchOatNeeded - In order to make the code for this dex location up to
- // date, patchoat must be run on the odex file.
- // Matches Java: dalvik.system.DexFile.PATCHOAT_NEEDED = 2
- kPatchOatNeeded = 2,
+ // dex2oat should be run to update the apk/jar because the existing code
+ // is out of date with respect to the boot image.
+ // Matches Java: dalvik.system.DexFile.DEX2OAT_FOR_BOOT_IMAGE
+ kDex2OatForBootImage = 2,
- // kSelfPatchOatNeeded - In order to make the code for this dex location
- // up to date, patchoat must be run on the oat file.
- // Matches Java: dalvik.system.DexFile.SELF_PATCHOAT_NEEDED = 3
- kSelfPatchOatNeeded = 3,
+ // dex2oat should be run to update the apk/jar because the existing code
+ // is out of date with respect to the target compiler filter.
+ // Matches Java: dalvik.system.DexFile.DEX2OAT_FOR_FILTER
+ kDex2OatForFilter = 3,
+
+ // dex2oat should be run to update the apk/jar because the existing code
+ // is not relocated to match the boot image and does not have the
+ // necessary patch information to use patchoat.
+ // Matches Java: dalvik.system.DexFile.DEX2OAT_FOR_RELOCATION
+ kDex2OatForRelocation = 4,
+
+ // patchoat should be run to update the apk/jar.
+ // Matches Java: dalvik.system.DexFile.PATCHOAT_FOR_RELOCATION
+ kPatchoatForRelocation = 5,
};
enum OatStatus {
@@ -149,8 +157,10 @@
// dex location that is at least as good as an oat file generated with the
// given compiler filter. profile_changed should be true to indicate the
// profile has recently changed for this dex location.
- DexOptNeeded GetDexOptNeeded(CompilerFilter::Filter target_compiler_filter,
- bool profile_changed = false);
+ // Returns a positive status code if the status refers to the oat file in
+ // the oat location. Returns a negative status code if the status refers to
+ // the oat file in the odex location.
+ int GetDexOptNeeded(CompilerFilter::Filter target_compiler_filter, bool profile_changed = false);
// Returns true if there is up-to-date code for this dex location,
// irrespective of the compiler filter of the up-to-date code.
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index 1848255..5730cf2 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -306,13 +306,13 @@
OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly));
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeedProfile));
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
@@ -356,7 +356,7 @@
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly));
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
@@ -380,7 +380,7 @@
OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
@@ -402,9 +402,9 @@
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeedProfile, false));
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly, false));
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeedProfile, true));
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly, true));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
@@ -448,7 +448,7 @@
Copy(GetMultiDexSrc2(), dex_location);
OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed, false));
EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
}
@@ -497,9 +497,9 @@
Copy(GetDexSrc2(), dex_location);
OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
@@ -522,11 +522,11 @@
/*with_alternate_image*/true);
OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatForBootImage,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatForBootImage,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly));
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatForBootImage,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
@@ -553,7 +553,7 @@
OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
@@ -577,7 +577,7 @@
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
- EXPECT_EQ(OatFileAssistant::kPatchOatNeeded,
+ EXPECT_EQ(-OatFileAssistant::kPatchoatForRelocation,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
@@ -606,7 +606,7 @@
// Verify the status.
OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
- EXPECT_EQ(OatFileAssistant::kPatchOatNeeded,
+ EXPECT_EQ(-OatFileAssistant::kPatchoatForRelocation,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
@@ -659,7 +659,7 @@
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
- EXPECT_EQ(OatFileAssistant::kPatchOatNeeded,
+ EXPECT_EQ(-OatFileAssistant::kPatchoatForRelocation,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, // Can't run dex2oat because dex file is stripped.
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
@@ -747,9 +747,9 @@
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly));
- EXPECT_EQ(OatFileAssistant::kSelfPatchOatNeeded,
+ EXPECT_EQ(OatFileAssistant::kPatchoatForRelocation,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
@@ -793,7 +793,7 @@
OatFileAssistant oat_file_assistant(dex_location.c_str(),
oat_location.c_str(), kRuntimeISA, true);
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatForRelocation,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
// Make the oat file up to date.
@@ -832,10 +832,10 @@
OatFileAssistant oat_file_assistant(dex_location.c_str(),
oat_location.c_str(), kRuntimeISA, true);
- // kSelfPatchOatNeeded is expected rather than kPatchOatNeeded based on the
- // assumption that the oat location is more up-to-date than the odex
+ // kPatchoatForRelocation is expected rather than -kPatchoatForRelocation
+ // based on the assumption that the oat location is more up-to-date than the odex
// location, even if they both need relocation.
- EXPECT_EQ(OatFileAssistant::kSelfPatchOatNeeded,
+ EXPECT_EQ(OatFileAssistant::kPatchoatForRelocation,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
@@ -868,7 +868,7 @@
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
@@ -892,7 +892,7 @@
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
@@ -1070,7 +1070,7 @@
OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
@@ -1106,7 +1106,7 @@
OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
@@ -1241,7 +1241,7 @@
oat_file_assistant.MakeUpToDate(false, &error_msg)) << error_msg;
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly));
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
Runtime::Current()->AddCompilerOption("--compiler-filter=speed");
@@ -1278,6 +1278,15 @@
// Verify the dexopt status values from dalvik.system.DexFile
// match the OatFileAssistant::DexOptStatus values.
TEST_F(OatFileAssistantTest, DexOptStatusValues) {
+ std::pair<OatFileAssistant::DexOptNeeded, const char*> mapping[] = {
+ {OatFileAssistant::kNoDexOptNeeded, "NO_DEXOPT_NEEDED"},
+ {OatFileAssistant::kDex2OatFromScratch, "DEX2OAT_FROM_SCRATCH"},
+ {OatFileAssistant::kDex2OatForBootImage, "DEX2OAT_FOR_BOOT_IMAGE"},
+ {OatFileAssistant::kDex2OatForFilter, "DEX2OAT_FOR_FILTER"},
+ {OatFileAssistant::kDex2OatForRelocation, "DEX2OAT_FOR_RELOCATION"},
+ {OatFileAssistant::kPatchoatForRelocation, "PATCHOAT_FOR_RELOCATION"}
+ };
+
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<1> hs(soa.Self());
ClassLinker* linker = Runtime::Current()->GetClassLinker();
@@ -1286,29 +1295,13 @@
ASSERT_FALSE(dexfile.Get() == nullptr);
linker->EnsureInitialized(soa.Self(), dexfile, true, true);
- ArtField* no_dexopt_needed = mirror::Class::FindStaticField(
- soa.Self(), dexfile, "NO_DEXOPT_NEEDED", "I");
- ASSERT_FALSE(no_dexopt_needed == nullptr);
- EXPECT_EQ(no_dexopt_needed->GetTypeAsPrimitiveType(), Primitive::kPrimInt);
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, no_dexopt_needed->GetInt(dexfile.Get()));
-
- ArtField* dex2oat_needed = mirror::Class::FindStaticField(
- soa.Self(), dexfile, "DEX2OAT_NEEDED", "I");
- ASSERT_FALSE(dex2oat_needed == nullptr);
- EXPECT_EQ(dex2oat_needed->GetTypeAsPrimitiveType(), Primitive::kPrimInt);
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded, dex2oat_needed->GetInt(dexfile.Get()));
-
- ArtField* patchoat_needed = mirror::Class::FindStaticField(
- soa.Self(), dexfile, "PATCHOAT_NEEDED", "I");
- ASSERT_FALSE(patchoat_needed == nullptr);
- EXPECT_EQ(patchoat_needed->GetTypeAsPrimitiveType(), Primitive::kPrimInt);
- EXPECT_EQ(OatFileAssistant::kPatchOatNeeded, patchoat_needed->GetInt(dexfile.Get()));
-
- ArtField* self_patchoat_needed = mirror::Class::FindStaticField(
- soa.Self(), dexfile, "SELF_PATCHOAT_NEEDED", "I");
- ASSERT_FALSE(self_patchoat_needed == nullptr);
- EXPECT_EQ(self_patchoat_needed->GetTypeAsPrimitiveType(), Primitive::kPrimInt);
- EXPECT_EQ(OatFileAssistant::kSelfPatchOatNeeded, self_patchoat_needed->GetInt(dexfile.Get()));
+ for (std::pair<OatFileAssistant::DexOptNeeded, const char*> field : mapping) {
+ ArtField* art_field = mirror::Class::FindStaticField(
+ soa.Self(), dexfile, field.second, "I");
+ ASSERT_FALSE(art_field == nullptr);
+ EXPECT_EQ(art_field->GetTypeAsPrimitiveType(), Primitive::kPrimInt);
+ EXPECT_EQ(field.first, art_field->GetInt(dexfile.Get()));
+ }
}
// TODO: More Tests: