Merge "Allow DexFile#getDexOptNeeded to check case when downgrading is required"
diff --git a/dexoptanalyzer/dexoptanalyzer.cc b/dexoptanalyzer/dexoptanalyzer.cc
index e2c159a..fc72bbd 100644
--- a/dexoptanalyzer/dexoptanalyzer.cc
+++ b/dexoptanalyzer/dexoptanalyzer.cc
@@ -97,6 +97,9 @@
UsageError(" --android-data=<directory>: optional, the directory which should be used as");
UsageError(" android-data. By default ANDROID_DATA env variable is used.");
UsageError("");
+ UsageError(" --downgrade: optional, if the purpose of dexopt is to downgrade the dex file");
+ UsageError(" By default, dexopt considers upgrade case.");
+ UsageError("");
UsageError("Return code:");
UsageError(" To make it easier to integrate with the internal tools this command will make");
UsageError(" available its result (dexoptNeeded) as the exit/return code. i.e. it will not");
@@ -121,7 +124,9 @@
class DexoptAnalyzer FINAL {
public:
- DexoptAnalyzer() : assume_profile_changed_(false) {}
+ DexoptAnalyzer() :
+ assume_profile_changed_(false),
+ downgrade_(false) {}
void ParseArgs(int argc, char **argv) {
original_argc = argc;
@@ -160,9 +165,9 @@
// compute dalvik-cache folder). This is mostly used in tests.
std::string new_android_data = option.substr(strlen("--android-data=")).ToString();
setenv("ANDROID_DATA", new_android_data.c_str(), 1);
- } else {
- Usage("Unknown argument '%s'", option.data());
- }
+ } else if (option.starts_with("--downgrade")) {
+ downgrade_ = true;
+ } else { Usage("Unknown argument '%s'", option.data()); }
}
if (image_.empty()) {
@@ -225,7 +230,7 @@
return kNoDexOptNeeded;
}
int dexoptNeeded = oat_file_assistant.GetDexOptNeeded(
- compiler_filter_, assume_profile_changed_);
+ compiler_filter_, assume_profile_changed_, downgrade_);
// Convert OatFileAssitant codes to dexoptanalyzer codes.
switch (dexoptNeeded) {
@@ -249,6 +254,7 @@
InstructionSet isa_;
CompilerFilter::Filter compiler_filter_;
bool assume_profile_changed_;
+ bool downgrade_;
std::string image_;
};
diff --git a/dexoptanalyzer/dexoptanalyzer_test.cc b/dexoptanalyzer/dexoptanalyzer_test.cc
index 1703ff4..1cbf546 100644
--- a/dexoptanalyzer/dexoptanalyzer_test.cc
+++ b/dexoptanalyzer/dexoptanalyzer_test.cc
@@ -71,12 +71,13 @@
// as the output of OatFileAssistant::GetDexOptNeeded.
void Verify(const std::string& dex_file,
CompilerFilter::Filter compiler_filter,
- bool assume_profile_changed = false) {
+ bool assume_profile_changed = false,
+ bool downgrade = false) {
int dexoptanalyzerResult = Analyze(dex_file, compiler_filter, assume_profile_changed);
dexoptanalyzerResult = DexoptanalyzerToOatFileAssistant(dexoptanalyzerResult);
OatFileAssistant oat_file_assistant(dex_file.c_str(), kRuntimeISA, /*load_executable*/ false);
int assistantResult = oat_file_assistant.GetDexOptNeeded(
- compiler_filter, assume_profile_changed);
+ compiler_filter, assume_profile_changed, downgrade);
EXPECT_EQ(assistantResult, dexoptanalyzerResult);
}
};
@@ -118,6 +119,16 @@
Verify(dex_location, CompilerFilter::kQuicken, true);
}
+TEST_F(DexoptAnalyzerTest, Downgrade) {
+ std::string dex_location = GetScratchDir() + "/Downgrade.jar";
+ Copy(GetDexSrc1(), dex_location);
+ GenerateOatForTest(dex_location.c_str(), CompilerFilter::kQuicken);
+
+ Verify(dex_location, CompilerFilter::kSpeedProfile, false, true);
+ Verify(dex_location, CompilerFilter::kQuicken, false, true);
+ Verify(dex_location, CompilerFilter::kVerify, false, true);
+}
+
// Case: We have a MultiDEX file and up-to-date OAT file for it.
TEST_F(DexoptAnalyzerTest, MultiDexOatUpToDate) {
std::string dex_location = GetScratchDir() + "/MultiDexOatUpToDate.jar";
diff --git a/runtime/compiler_filter.cc b/runtime/compiler_filter.cc
index 4847f38..7b2dd05 100644
--- a/runtime/compiler_filter.cc
+++ b/runtime/compiler_filter.cc
@@ -165,6 +165,10 @@
return current >= target;
}
+bool CompilerFilter::IsBetter(Filter current, Filter target) {
+ return current > target;
+}
+
std::string CompilerFilter::NameOfFilter(Filter filter) {
switch (filter) {
case CompilerFilter::kAssumeVerified: return "assume-verified";
diff --git a/runtime/compiler_filter.h b/runtime/compiler_filter.h
index f802439..60975b0 100644
--- a/runtime/compiler_filter.h
+++ b/runtime/compiler_filter.h
@@ -84,6 +84,11 @@
// not as good as kSpeed.
static bool IsAsGoodAs(Filter current, Filter target);
+ // Returns true if 'current' compiler filter is better than 'target' compiler
+ // filter. Compared to IsAsGoodAs, this returns false if the compiler filters are
+ // equal.
+ static bool IsBetter(Filter current, Filter target);
+
// Return the flag name of the given filter.
// For example: given kVerifyAtRuntime, returns "verify-at-runtime".
// The name returned corresponds to the name accepted by
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index f6a8360..07dfb65 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -458,7 +458,8 @@
const char* filename,
const char* instruction_set,
const char* compiler_filter_name,
- bool profile_changed) {
+ bool profile_changed,
+ bool downgrade) {
if ((filename == nullptr) || !OS::FileExists(filename)) {
LOG(ERROR) << "DexFile_getDexOptNeeded file '" << filename << "' does not exist";
ScopedLocalRef<jclass> fnfe(env, env->FindClass("java/io/FileNotFoundException"));
@@ -492,7 +493,7 @@
if (oat_file_assistant.IsInBootClassPath()) {
return OatFileAssistant::kNoDexOptNeeded;
}
- return oat_file_assistant.GetDexOptNeeded(filter, profile_changed);
+ return oat_file_assistant.GetDexOptNeeded(filter, profile_changed, downgrade);
}
static jstring DexFile_getDexFileStatus(JNIEnv* env,
@@ -528,7 +529,8 @@
jstring javaFilename,
jstring javaInstructionSet,
jstring javaTargetCompilerFilter,
- jboolean newProfile) {
+ jboolean newProfile,
+ jboolean downgrade) {
ScopedUtfChars filename(env, javaFilename);
if (env->ExceptionCheck()) {
return -1;
@@ -548,7 +550,8 @@
filename.c_str(),
instruction_set.c_str(),
target_compiler_filter.c_str(),
- newProfile == JNI_TRUE);
+ newProfile == JNI_TRUE,
+ downgrade == JNI_TRUE);
}
// public API
@@ -725,7 +728,7 @@
NATIVE_METHOD(DexFile, getClassNameList, "(Ljava/lang/Object;)[Ljava/lang/String;"),
NATIVE_METHOD(DexFile, isDexOptNeeded, "(Ljava/lang/String;)Z"),
NATIVE_METHOD(DexFile, getDexOptNeeded,
- "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)I"),
+ "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZ)I"),
NATIVE_METHOD(DexFile, openDexFileNative,
"(Ljava/lang/String;"
"Ljava/lang/String;"
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index c876657..96423c3 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -187,9 +187,11 @@
return true;
}
-int OatFileAssistant::GetDexOptNeeded(CompilerFilter::Filter target, bool profile_changed) {
+int OatFileAssistant::GetDexOptNeeded(CompilerFilter::Filter target,
+ bool profile_changed,
+ bool downgrade) {
OatFileInfo& info = GetBestInfo();
- DexOptNeeded dexopt_needed = info.GetDexOptNeeded(target, profile_changed);
+ DexOptNeeded dexopt_needed = info.GetDexOptNeeded(target, profile_changed, downgrade);
if (info.IsOatLocation() || dexopt_needed == kDex2OatFromScratch) {
return dexopt_needed;
}
@@ -230,7 +232,7 @@
}
OatFileInfo& info = GetBestInfo();
- switch (info.GetDexOptNeeded(target, profile_changed)) {
+ switch (info.GetDexOptNeeded(target, profile_changed, /*downgrade*/ false)) {
case kNoDexOptNeeded:
return kUpdateSucceeded;
@@ -1005,9 +1007,9 @@
}
OatFileAssistant::DexOptNeeded OatFileAssistant::OatFileInfo::GetDexOptNeeded(
- CompilerFilter::Filter target, bool profile_changed) {
+ CompilerFilter::Filter target, bool profile_changed, bool downgrade) {
bool compilation_desired = CompilerFilter::IsAotCompilationEnabled(target);
- bool filter_okay = CompilerFilterIsOkay(target, profile_changed);
+ bool filter_okay = CompilerFilterIsOkay(target, profile_changed, downgrade);
if (filter_okay && Status() == kOatUpToDate) {
// The oat file is in good shape as is.
@@ -1064,7 +1066,7 @@
}
bool OatFileAssistant::OatFileInfo::CompilerFilterIsOkay(
- CompilerFilter::Filter target, bool profile_changed) {
+ CompilerFilter::Filter target, bool profile_changed, bool downgrade) {
const OatFile* file = GetFile();
if (file == nullptr) {
return false;
@@ -1075,7 +1077,8 @@
VLOG(oat) << "Compiler filter not okay because Profile changed";
return false;
}
- return CompilerFilter::IsAsGoodAs(current, target);
+ return downgrade ? !CompilerFilter::IsBetter(current, target) :
+ CompilerFilter::IsAsGoodAs(current, target);
}
bool OatFileAssistant::OatFileInfo::IsExecutable() {
diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h
index 92d87ea..320aa4f 100644
--- a/runtime/oat_file_assistant.h
+++ b/runtime/oat_file_assistant.h
@@ -147,13 +147,24 @@
bool Lock(std::string* error_msg);
// Return what action needs to be taken to produce up-to-date code for this
- // 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.
+ // dex location. If "downgrade" is set to false, it verifies if the current
+ // compiler filter is at least as good as an oat file generated with the
+ // given compiler filter otherwise, if its set to true, it checks whether
+ // the oat file generated with the target filter will be downgraded as
+ // compared to the current state. For example, if the current compiler filter is
+ // quicken, and target filter is verify, it will recommend to dexopt, while
+ // if the target filter is speed profile, it will recommend to keep it in its
+ // current state.
+ // profile_changed should be true to indicate the profile has recently changed
+ // for this dex location.
+ // If the purpose of the dexopt is to downgrade the compiler filter,
+ // set downgrade to true.
// 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);
+ int GetDexOptNeeded(CompilerFilter::Filter target_compiler_filter,
+ bool profile_changed = false,
+ bool downgrade = 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.
@@ -310,8 +321,11 @@
// given target_compilation_filter.
// profile_changed should be true to indicate the profile has recently
// changed for this dex location.
+ // downgrade should be true if the purpose of dexopt is to downgrade the
+ // compiler filter.
DexOptNeeded GetDexOptNeeded(CompilerFilter::Filter target_compiler_filter,
- bool profile_changed);
+ bool profile_changed,
+ bool downgrade);
// Returns the loaded file.
// Loads the file if needed. Returns null if the file failed to load.
@@ -344,7 +358,9 @@
// least as good as the given target filter. profile_changed should be
// true to indicate the profile has recently changed for this dex
// location.
- bool CompilerFilterIsOkay(CompilerFilter::Filter target, bool profile_changed);
+ // downgrade should be true if the purpose of dexopt is to downgrade the
+ // compiler filter.
+ bool CompilerFilterIsOkay(CompilerFilter::Filter target, bool profile_changed, bool downgrade);
// Release the loaded oat file.
// Returns null if the oat file hasn't been loaded.