diff options
| -rw-r--r-- | dex2oat/dex2oat.cc | 26 | ||||
| -rw-r--r-- | runtime/native/dalvik_system_DexFile.cc | 54 | ||||
| -rw-r--r-- | runtime/oat.cc | 20 | ||||
| -rw-r--r-- | runtime/oat.h | 8 | ||||
| -rw-r--r-- | runtime/oat_file.cc | 4 | ||||
| -rw-r--r-- | runtime/oat_file.h | 2 | ||||
| -rw-r--r-- | runtime/oat_file_assistant.cc | 208 | ||||
| -rw-r--r-- | runtime/oat_file_assistant.h | 117 | ||||
| -rw-r--r-- | runtime/oat_file_assistant_test.cc | 188 | ||||
| -rw-r--r-- | runtime/oat_file_manager.cc | 5 |
10 files changed, 260 insertions, 372 deletions
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 374d0d37a1..44e7fc9017 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -1034,9 +1034,11 @@ class Dex2Oat FINAL { key_value_store_->Put( OatHeader::kDebuggableKey, compiler_options_->debuggable_ ? OatHeader::kTrueValue : OatHeader::kFalseValue); - key_value_store_->Put( - OatHeader::kExtractOnlyKey, - compiler_options_->IsExtractOnly() ? OatHeader::kTrueValue : OatHeader::kFalseValue); + if (compiler_options_->IsExtractOnly()) { + key_value_store_->Put(OatHeader::kCompilationType, OatHeader::kExtractOnlyValue); + } else if (UseProfileGuidedCompilation()) { + key_value_store_->Put(OatHeader::kCompilationType, OatHeader::kProfileGuideCompiledValue); + } } // Parse the arguments from the command line. In case of an unrecognized option or impossible @@ -1891,13 +1893,6 @@ class Dex2Oat FINAL { return success; } - bool ShouldCompileBasedOnProfiles() const { - DCHECK(UseProfileGuidedCompilation()); - // If we are given a profile, compile only if we have some data in it. - return (profile_compilation_info_ != nullptr) && - (profile_compilation_info_->GetNumberOfMethods() != 0); - } - private: template <typename T> static std::vector<T*> MakeNonOwningPointerVector(const std::vector<std::unique_ptr<T>>& src) { @@ -2595,16 +2590,11 @@ static int dex2oat(int argc, char** argv) { // Parse arguments. Argument mistakes will lead to exit(EXIT_FAILURE) in UsageError. dex2oat->ParseArgs(argc, argv); - // Process profile information and assess if we need to do a profile guided compilation. + // If needed, process profile information for profile guided compilation. // This operation involves I/O. if (dex2oat->UseProfileGuidedCompilation()) { - if (dex2oat->LoadProfile()) { - if (!dex2oat->ShouldCompileBasedOnProfiles()) { - LOG(INFO) << "Skipped compilation because of insignificant profile delta"; - return EXIT_SUCCESS; - } - } else { - LOG(WARNING) << "Failed to process profile files"; + if (!dex2oat->LoadProfile()) { + LOG(ERROR) << "Failed to process profile file"; return EXIT_FAILURE; } } diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc index 6643ac2231..f1e0fa7b57 100644 --- a/runtime/native/dalvik_system_DexFile.cc +++ b/runtime/native/dalvik_system_DexFile.cc @@ -347,15 +347,14 @@ static jobjectArray DexFile_getClassNameList(JNIEnv* env, jclass, jobject cookie static jint GetDexOptNeeded(JNIEnv* env, const char* filename, - const char* pkgname, const char* instruction_set, - const jboolean defer) { + const int target_compilation_type_mask) { if ((filename == nullptr) || !OS::FileExists(filename)) { LOG(ERROR) << "DexFile_getDexOptNeeded file '" << filename << "' does not exist"; ScopedLocalRef<jclass> fnfe(env, env->FindClass("java/io/FileNotFoundException")); const char* message = (filename == nullptr) ? "<empty file name>" : filename; env->ThrowNew(fnfe.get(), message); - return OatFileAssistant::kNoDexOptNeeded; + return -1; } const InstructionSet target_instruction_set = GetInstructionSetFromString(instruction_set); @@ -363,73 +362,52 @@ static jint GetDexOptNeeded(JNIEnv* env, ScopedLocalRef<jclass> iae(env, env->FindClass("java/lang/IllegalArgumentException")); std::string message(StringPrintf("Instruction set %s is invalid.", instruction_set)); env->ThrowNew(iae.get(), message.c_str()); - return 0; + return -1; } // TODO: Verify the dex location is well formed, and throw an IOException if // not? - - OatFileAssistant oat_file_assistant(filename, target_instruction_set, false, pkgname); + OatFileAssistant oat_file_assistant(filename, target_compilation_type_mask, + target_instruction_set, false); // Always treat elements of the bootclasspath as up-to-date. if (oat_file_assistant.IsInBootClassPath()) { return OatFileAssistant::kNoDexOptNeeded; } - // TODO: Checking the profile should probably be done in the GetStatus() - // function. We have it here because GetStatus() should not be copying - // profile files. But who should be copying profile files? - if (oat_file_assistant.OdexFileIsOutOfDate()) { - // Needs recompile if profile has changed significantly. - if (Runtime::Current()->GetProfilerOptions().IsEnabled()) { - if (oat_file_assistant.IsProfileChangeSignificant()) { - if (!defer) { - oat_file_assistant.CopyProfileFile(); - } - return OatFileAssistant::kDex2OatNeeded; - } else if (oat_file_assistant.ProfileExists() - && !oat_file_assistant.OldProfileExists()) { - if (!defer) { - oat_file_assistant.CopyProfileFile(); - } - } - } - } - return oat_file_assistant.GetDexOptNeeded(); } static jint DexFile_getDexOptNeeded(JNIEnv* env, jclass, jstring javaFilename, - jstring javaPkgname, jstring javaInstructionSet, - jboolean defer) { + jint javaTargetCompilationTypeMask) { ScopedUtfChars filename(env, javaFilename); if (env->ExceptionCheck()) { - return 0; + return -1; } - NullableScopedUtfChars pkgname(env, javaPkgname); - ScopedUtfChars instruction_set(env, javaInstructionSet); if (env->ExceptionCheck()) { - return 0; + return -1; } return GetDexOptNeeded(env, filename.c_str(), - pkgname.c_str(), instruction_set.c_str(), - defer); + javaTargetCompilationTypeMask); } -// public API, null pkgname +// public API static jboolean DexFile_isDexOptNeeded(JNIEnv* env, jclass, jstring javaFilename) { const char* instruction_set = GetInstructionSetString(kRuntimeISA); ScopedUtfChars filename(env, javaFilename); - jint status = GetDexOptNeeded(env, filename.c_str(), nullptr /* pkgname */, - instruction_set, false /* defer */); + jint status = GetDexOptNeeded( + env, + filename.c_str(), + instruction_set, + OatFileAssistant::kFullCompilation | OatFileAssistant::kProfileGuideCompilation); return (status != OatFileAssistant::kNoDexOptNeeded) ? JNI_TRUE : JNI_FALSE; } @@ -445,7 +423,7 @@ static JNINativeMethod gMethods[] = { 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;I)I"), NATIVE_METHOD(DexFile, openDexFileNative, "(Ljava/lang/String;" "Ljava/lang/String;" diff --git a/runtime/oat.cc b/runtime/oat.cc index 4948558f84..2ac105291d 100644 --- a/runtime/oat.cc +++ b/runtime/oat.cc @@ -29,6 +29,8 @@ constexpr uint8_t OatHeader::kOatMagic[4]; constexpr uint8_t OatHeader::kOatVersion[4]; constexpr const char OatHeader::kTrueValue[]; constexpr const char OatHeader::kFalseValue[]; +constexpr const char OatHeader::kExtractOnlyValue[]; +constexpr const char OatHeader::kProfileGuideCompiledValue[]; static size_t ComputeOatHeaderSize(const SafeMap<std::string, std::string>* variable_data) { size_t estimate = 0U; @@ -467,12 +469,24 @@ bool OatHeader::IsDebuggable() const { } bool OatHeader::IsExtractOnly() const { - return IsKeyEnabled(OatHeader::kExtractOnlyKey); + return KeyHasValue(kCompilationType, + kExtractOnlyValue, + sizeof(kExtractOnlyValue)); } -bool OatHeader::IsKeyEnabled(const char* key) const { +bool OatHeader::IsProfileGuideCompiled() const { + return KeyHasValue(kCompilationType, + kProfileGuideCompiledValue, + sizeof(kProfileGuideCompiledValue)); +} + +bool OatHeader::KeyHasValue(const char* key, const char* value, size_t value_size) const { const char* key_value = GetStoreValueByKey(key); - return (key_value != nullptr && strncmp(key_value, kTrueValue, sizeof(kTrueValue)) == 0); + return (key_value != nullptr && strncmp(key_value, value, value_size) == 0); +} + +bool OatHeader::IsKeyEnabled(const char* key) const { + return KeyHasValue(key, kTrueValue, sizeof(kTrueValue)); } void OatHeader::Flatten(const SafeMap<std::string, std::string>* key_value_store) { diff --git a/runtime/oat.h b/runtime/oat.h index fde386f37e..0660e19ff4 100644 --- a/runtime/oat.h +++ b/runtime/oat.h @@ -38,12 +38,15 @@ class PACKED(4) OatHeader { static constexpr const char* kDex2OatHostKey = "dex2oat-host"; static constexpr const char* kPicKey = "pic"; static constexpr const char* kDebuggableKey = "debuggable"; - static constexpr const char* kExtractOnlyKey = "extract-only"; + static constexpr const char* kCompilationType = "compilation-type"; static constexpr const char* kClassPathKey = "classpath"; static constexpr const char* kBootClassPath = "bootclasspath"; static constexpr const char kTrueValue[] = "true"; static constexpr const char kFalseValue[] = "false"; + static constexpr const char kExtractOnlyValue[] = "extract-only"; + static constexpr const char kProfileGuideCompiledValue[] = "profile-guide"; + static OatHeader* Create(InstructionSet instruction_set, const InstructionSetFeatures* instruction_set_features, @@ -108,8 +111,11 @@ class PACKED(4) OatHeader { bool IsPic() const; bool IsDebuggable() const; bool IsExtractOnly() const; + bool IsProfileGuideCompiled() const; private: + bool KeyHasValue(const char* key, const char* value, size_t value_size) const; + OatHeader(InstructionSet instruction_set, const InstructionSetFeatures* instruction_set_features, uint32_t dex_file_count, diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index c3895479b7..c0f5906fb4 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -1232,6 +1232,10 @@ bool OatFile::IsExtractOnly() const { return GetOatHeader().IsExtractOnly(); } +bool OatFile::IsProfileGuideCompiled() const { + return GetOatHeader().IsProfileGuideCompiled(); +} + static constexpr char kDexClassPathEncodingSeparator = '*'; std::string OatFile::EncodeDexFileDependencies(const std::vector<const DexFile*>& dex_files) { diff --git a/runtime/oat_file.h b/runtime/oat_file.h index fb91a8cdff..1084253a88 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -93,6 +93,8 @@ class OatFile { bool IsExtractOnly() const; + bool IsProfileGuideCompiled() const; + const std::string& GetLocation() const { return location_; } diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc index 262c932766..90712c625c 100644 --- a/runtime/oat_file_assistant.cc +++ b/runtime/oat_file_assistant.cc @@ -36,7 +36,6 @@ #include "image.h" #include "oat.h" #include "os.h" -#include "profiler.h" #include "runtime.h" #include "scoped_thread_state_change.h" #include "ScopedFd.h" @@ -45,28 +44,19 @@ namespace art { OatFileAssistant::OatFileAssistant(const char* dex_location, + const int target_compilation_type_mask, const InstructionSet isa, bool load_executable) - : OatFileAssistant(dex_location, nullptr, isa, load_executable, nullptr) { } + : OatFileAssistant(dex_location, nullptr, target_compilation_type_mask, isa, load_executable) +{ } OatFileAssistant::OatFileAssistant(const char* dex_location, const char* oat_location, + const int target_compilation_type_mask, const InstructionSet isa, bool load_executable) - : OatFileAssistant(dex_location, oat_location, isa, load_executable, nullptr) { } - -OatFileAssistant::OatFileAssistant(const char* dex_location, - const InstructionSet isa, - bool load_executable, - const char* package_name) - : OatFileAssistant(dex_location, nullptr, isa, load_executable, package_name) { } - -OatFileAssistant::OatFileAssistant(const char* dex_location, - const char* oat_location, - const InstructionSet isa, - bool load_executable, - const char* package_name) - : isa_(isa), package_name_(package_name), load_executable_(load_executable) { + : target_compilation_type_mask_(target_compilation_type_mask), isa_(isa), + load_executable_(load_executable) { CHECK(dex_location != nullptr) << "OatFileAssistant: null dex location"; dex_location_.assign(dex_location); @@ -83,18 +73,6 @@ OatFileAssistant::OatFileAssistant(const char* dex_location, cached_oat_file_name_attempted_ = true; cached_oat_file_name_found_ = true; } - - // If there is no package name given, we will not be able to find any - // profiles associated with this dex location. Preemptively mark that to - // be the case, rather than trying to find and load the profiles later. - // Similarly, if profiling is disabled. - if (package_name == nullptr - || !Runtime::Current()->GetProfilerOptions().IsEnabled()) { - profile_load_attempted_ = true; - profile_load_succeeded_ = false; - old_profile_load_attempted_ = true; - old_profile_load_succeeded_ = false; - } } OatFileAssistant::~OatFileAssistant() { @@ -138,10 +116,23 @@ bool OatFileAssistant::Lock(std::string* error_msg) { return true; } -OatFileAssistant::DexOptNeeded OatFileAssistant::GetDexOptNeeded() { - // TODO: If the profiling code is ever restored, it's worth considering - // whether we should check to see if the profile is out of date here. +// Returns the compilation mode of the given oat file. +static OatFileAssistant::CompilationType GetCompilationType(const OatFile& oat_file) { + if (oat_file.IsExtractOnly()) { + return OatFileAssistant::kExtractOnly; + } + if (oat_file.IsProfileGuideCompiled()) { + return OatFileAssistant::kProfileGuideCompilation; + } + // Assume that if the oat files is not extract-only or profile-guide compiled + // then it must be fully compiled. + // NB: this does not necessary mean that the oat file is actually fully compiled. It + // might have been compiled in a different way (e.g. interpret-only) which does + // not record a type in the header. + return OatFileAssistant::kFullCompilation; +} +OatFileAssistant::DexOptNeeded OatFileAssistant::GetDexOptNeeded() { if (OatFileIsUpToDate() || OdexFileIsUpToDate()) { return kNoDexOptNeeded; } @@ -419,6 +410,11 @@ OatFileAssistant::OatStatus OatFileAssistant::GivenOatFileStatus(const OatFile& } bool OatFileAssistant::GivenOatFileIsOutOfDate(const OatFile& file) { + // Verify the file satisfies the desired compilation type. + if ((target_compilation_type_mask_ & GetCompilationType(file)) == 0) { + return true; + } + // Verify the dex checksum. // Note: GetOatDexFile will return null if the dex checksum doesn't match // what we provide, which verifies the primary dex checksum for us. @@ -541,104 +537,6 @@ bool OatFileAssistant::GivenOatFileIsUpToDate(const OatFile& file) { return true; } -bool OatFileAssistant::ProfileExists() { - return GetProfile() != nullptr; -} - -bool OatFileAssistant::OldProfileExists() { - return GetOldProfile() != nullptr; -} - -// TODO: The IsProfileChangeSignificant implementation was copied from likely -// bit-rotted code. -bool OatFileAssistant::IsProfileChangeSignificant() { - ProfileFile* profile = GetProfile(); - if (profile == nullptr) { - return false; - } - - ProfileFile* old_profile = GetOldProfile(); - if (old_profile == nullptr) { - return false; - } - - // TODO: The following code to compare two profile files should live with - // the rest of the profiler code, not the oat file assistant code. - - // A change in profile is considered significant if X% (change_thr property) - // of the top K% (compile_thr property) samples has changed. - const ProfilerOptions& options = Runtime::Current()->GetProfilerOptions(); - const double top_k_threshold = options.GetTopKThreshold(); - const double change_threshold = options.GetTopKChangeThreshold(); - std::set<std::string> top_k, old_top_k; - profile->GetTopKSamples(top_k, top_k_threshold); - old_profile->GetTopKSamples(old_top_k, top_k_threshold); - std::set<std::string> diff; - std::set_difference(top_k.begin(), top_k.end(), old_top_k.begin(), - old_top_k.end(), std::inserter(diff, diff.end())); - - // TODO: consider using the usedPercentage instead of the plain diff count. - double change_percent = 100.0 * static_cast<double>(diff.size()) - / static_cast<double>(top_k.size()); - std::set<std::string>::iterator end = diff.end(); - for (std::set<std::string>::iterator it = diff.begin(); it != end; it++) { - VLOG(oat) << "Profile new in topK: " << *it; - } - - if (change_percent > change_threshold) { - VLOG(oat) << "Oat File Assistant: Profile for " << dex_location_ - << "has changed significantly: (top " - << top_k_threshold << "% samples changed in proportion of " - << change_percent << "%)"; - return true; - } - return false; -} - -// TODO: The CopyProfileFile implementation was copied from likely bit-rotted -// code. -void OatFileAssistant::CopyProfileFile() { - if (!ProfileExists()) { - return; - } - - std::string profile_name = ProfileFileName(); - std::string old_profile_name = OldProfileFileName(); - - ScopedFd src(open(old_profile_name.c_str(), O_RDONLY)); - if (src.get() == -1) { - PLOG(WARNING) << "Failed to open profile file " << old_profile_name - << ". My uid:gid is " << getuid() << ":" << getgid(); - return; - } - - struct stat stat_src; - if (fstat(src.get(), &stat_src) == -1) { - PLOG(WARNING) << "Failed to get stats for profile file " << old_profile_name - << ". My uid:gid is " << getuid() << ":" << getgid(); - return; - } - - // Create the copy with rw------- (only accessible by system) - ScopedFd dst(open(profile_name.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0600)); - if (dst.get() == -1) { - PLOG(WARNING) << "Failed to create/write prev profile file " << profile_name - << ". My uid:gid is " << getuid() << ":" << getgid(); - return; - } - -#ifdef __linux__ - if (sendfile(dst.get(), src.get(), nullptr, stat_src.st_size) == -1) { -#else - off_t len; - if (sendfile(dst.get(), src.get(), 0, &len, nullptr, 0) == -1) { -#endif - PLOG(WARNING) << "Failed to copy profile file " << old_profile_name - << " to " << profile_name << ". My uid:gid is " << getuid() - << ":" << getgid(); - } -} - bool OatFileAssistant::RelocateOatFile(const std::string* input_file, std::string* error_msg) { CHECK(error_msg != nullptr); @@ -694,6 +592,15 @@ bool OatFileAssistant::RelocateOatFile(const std::string* input_file, bool OatFileAssistant::GenerateOatFile(std::string* error_msg) { CHECK(error_msg != nullptr); + // TODO: Currently we only know how to make a fully-compiled oat file. + // Perhaps we should support generating other kinds of oat files? + if ((target_compilation_type_mask_ & kFullCompilation) == 0) { + *error_msg = "Generation of oat file for dex location " + dex_location_ + + " not attempted because full compilation was not specified" + + " as an acceptable target compilation type."; + return false; + } + Runtime* runtime = Runtime::Current(); if (!runtime->IsDex2OatEnabled()) { *error_msg = "Generation of oat file for dex location " + dex_location_ @@ -861,21 +768,6 @@ std::string OatFileAssistant::DalvikCacheDirectory() { return result; } -std::string OatFileAssistant::ProfileFileName() { - if (package_name_ != nullptr) { - return DalvikCacheDirectory() + std::string("profiles/") + package_name_; - } - return ""; -} - -std::string OatFileAssistant::OldProfileFileName() { - std::string profile_name = ProfileFileName(); - if (profile_name.empty()) { - return ""; - } - return profile_name + "@old"; -} - std::string OatFileAssistant::ImageLocation() { Runtime* runtime = Runtime::Current(); const std::vector<gc::space::ImageSpace*>& image_spaces = @@ -1007,34 +899,6 @@ const OatFileAssistant::ImageInfo* OatFileAssistant::GetImageInfo() { return image_info_load_succeeded_ ? &cached_image_info_ : nullptr; } -ProfileFile* OatFileAssistant::GetProfile() { - if (!profile_load_attempted_) { - CHECK(package_name_ != nullptr) - << "pakage_name_ is nullptr: " - << "profile_load_attempted_ should have been true"; - profile_load_attempted_ = true; - std::string profile_name = ProfileFileName(); - if (!profile_name.empty()) { - profile_load_succeeded_ = cached_profile_.LoadFile(profile_name); - } - } - return profile_load_succeeded_ ? &cached_profile_ : nullptr; -} - -ProfileFile* OatFileAssistant::GetOldProfile() { - if (!old_profile_load_attempted_) { - CHECK(package_name_ != nullptr) - << "pakage_name_ is nullptr: " - << "old_profile_load_attempted_ should have been true"; - old_profile_load_attempted_ = true; - std::string old_profile_name = OldProfileFileName(); - if (!old_profile_name.empty()) { - old_profile_load_succeeded_ = cached_old_profile_.LoadFile(old_profile_name); - } - } - return old_profile_load_succeeded_ ? &cached_old_profile_ : nullptr; -} - gc::space::ImageSpace* OatFileAssistant::OpenImageSpace(const OatFile* oat_file) { DCHECK(oat_file != nullptr); std::string art_file = ArtFileName(oat_file); diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h index 7b45bca946..893aea2ab9 100644 --- a/runtime/oat_file_assistant.h +++ b/runtime/oat_file_assistant.h @@ -44,9 +44,6 @@ class ImageSpace; // The oat file assistant is intended to be used with dex locations not on the // boot class path. See the IsInBootClassPath method for a way to check if the // dex location is in the boot class path. -// -// TODO: All the profiling related code is old and untested. It should either -// be restored and tested, or removed. class OatFileAssistant { public: enum DexOptNeeded { @@ -73,8 +70,8 @@ class OatFileAssistant { enum OatStatus { // kOatOutOfDate - An oat file is said to be out of date if the file does - // not exist, or is out of date with respect to the dex file or boot - // image. + // not exist, is out of date with respect to the dex file or boot image, + // or does not meet the target compilation type. kOatOutOfDate, // kOatNeedsRelocation - An oat file is said to need relocation if the @@ -88,6 +85,20 @@ class OatFileAssistant { kOatUpToDate, }; + // Represents the different compilation types of oat files that OatFileAssitant + // and external GetDexOptNeeded callers care about. + // Note: these should be able to be used as part of a mask. + enum CompilationType { + // Matches Java: dalvik.system.DexFile.COMPILATION_TYPE_FULL = 1 + kFullCompilation = 1, + + // Matches Java: dalvik.system.DexFile.COMPILATION_TYPE_PROFILE_GUIDE = 2 + kProfileGuideCompilation = 2, + + // Matches Java: dalvik.system.DexFile.COMPILATION_TYPE_EXTRACT_ONLY = 4 + kExtractOnly = 4, + }; + // Constructs an OatFileAssistant object to assist the oat file // corresponding to the given dex location with the target instruction set. // @@ -99,31 +110,28 @@ class OatFileAssistant { // Note: Currently the dex_location must have an extension. // TODO: Relax this restriction? // + // The target compilation type specifies a set of CompilationTypes that + // should be considered up to date. An oat file compiled in a way not + // included in the set is considered out of date. For example, to consider + // otherwise up-to-date fully compiled and profile-guide compiled oat + // files as up to date, but to consider extract-only files as out of date, + // specify: (kFullCompilation | kProfileGuideCompilation). + // // The isa should be either the 32 bit or 64 bit variant for the current // device. For example, on an arm device, use arm or arm64. An oat file can // be loaded executable only if the ISA matches the current runtime. - OatFileAssistant(const char* dex_location, const InstructionSet isa, + OatFileAssistant(const char* dex_location, + int target_compilation_type_mask, + const InstructionSet isa, bool load_executable); // Constructs an OatFileAssistant, providing an explicit target oat_location // to use instead of the standard oat location. - OatFileAssistant(const char* dex_location, const char* oat_location, - const InstructionSet isa, bool load_executable); - - // Constructs an OatFileAssistant, providing an additional package_name used - // solely for the purpose of locating profile files. - // - // TODO: Why is the name of the profile file based on the package name and - // not the dex location? If there is no technical reason the dex_location - // can't be used, we should prefer that instead. - OatFileAssistant(const char* dex_location, const InstructionSet isa, - bool load_executable, const char* package_name); - - // Constructs an OatFileAssistant with user specified oat location and a - // package name. - OatFileAssistant(const char* dex_location, const char* oat_location, - const InstructionSet isa, bool load_executable, - const char* package_name); + OatFileAssistant(const char* dex_location, + const char* oat_location, + int target_compilation_type_mask, + const InstructionSet isa, + bool load_executable); ~OatFileAssistant(); @@ -233,28 +241,6 @@ class OatFileAssistant { bool GivenOatFileNeedsRelocation(const OatFile& file); bool GivenOatFileIsUpToDate(const OatFile& file); - // Returns true if there is an accessible profile associated with the dex - // location. - // This returns false if profiling is disabled. - bool ProfileExists(); - - // The old profile is a file containing a previous snapshot of profiling - // information associated with the dex file code. This is used to track how - // the profiling information has changed over time. - // - // Returns true if there is an accessible old profile associated with the - // dex location. - // This returns false if profiling is disabled. - bool OldProfileExists(); - - // Returns true if there has been a significant change between the old - // profile and the current profile. - // This returns false if profiling is disabled. - bool IsProfileChangeSignificant(); - - // Copy the current profile to the old profile location. - void CopyProfileFile(); - // Generates the oat file by relocation from the named input file. // This does not check the current status before attempting to relocate the // oat file. @@ -309,16 +295,6 @@ class OatFileAssistant { // Returns an empty string if we can't get the dalvik cache directory path. std::string DalvikCacheDirectory(); - // Constructs the filename for the profile file. - // Returns an empty string if we do not have the necessary information to - // construct the filename. - std::string ProfileFileName(); - - // Constructs the filename for the old profile file. - // Returns an empty string if we do not have the necessary information to - // construct the filename. - std::string OldProfileFileName(); - // Returns the current image location. // Returns an empty string if the image location could not be retrieved. // @@ -364,35 +340,18 @@ class OatFileAssistant { // The caller shouldn't clean up or free the returned pointer. const ImageInfo* GetImageInfo(); - // Returns the loaded profile. - // Loads the profile if needed. Returns null if the profile failed - // to load. - // The caller shouldn't clean up or free the returned pointer. - ProfileFile* GetProfile(); - - // Returns the loaded old profile. - // Loads the old profile if needed. Returns null if the old profile - // failed to load. - // The caller shouldn't clean up or free the returned pointer. - ProfileFile* GetOldProfile(); - // To implement Lock(), we lock a dummy file where the oat file would go // (adding ".flock" to the target file name) and retain the lock for the // remaining lifetime of the OatFileAssistant object. ScopedFlock flock_; std::string dex_location_; + const int target_compilation_type_mask_; // In a properly constructed OatFileAssistant object, isa_ should be either // the 32 or 64 bit variant for the current device. const InstructionSet isa_ = kNone; - // The package name, used solely to find the profile file. - // This may be null in a properly constructed object. In this case, - // profile_load_attempted_ and old_profile_load_attempted_ will be true, and - // profile_load_succeeded_ and old_profile_load_succeeded_ will be false. - const char* package_name_ = nullptr; - // Whether we will attempt to load oat files executable. bool load_executable_ = false; @@ -451,18 +410,6 @@ class OatFileAssistant { bool image_info_load_succeeded_ = false; ImageInfo cached_image_info_; - // Cached value of the profile file. - // Use the GetProfile method rather than accessing these directly. - bool profile_load_attempted_ = false; - bool profile_load_succeeded_ = false; - ProfileFile cached_profile_; - - // Cached value of the profile file. - // Use the GetOldProfile method rather than accessing these directly. - bool old_profile_load_attempted_ = false; - bool old_profile_load_succeeded_ = false; - ProfileFile cached_old_profile_; - // For debugging only. // If this flag is set, the oat or odex file has been released to the user // of the OatFileAssistant object and the OatFileAssistant object is in a diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc index 83d4457a1c..4541468cb3 100644 --- a/runtime/oat_file_assistant_test.cc +++ b/runtime/oat_file_assistant_test.cc @@ -260,7 +260,7 @@ class OatFileAssistantTest : public CommonRuntimeTest { } void GenerateExtractOnlyOdexForTest(const std::string& dex_location, - const std::string& odex_location) { + const std::string& odex_location) { std::vector<std::string> args; args.push_back("--dex-file=" + dex_location); args.push_back("--oat-file=" + odex_location); @@ -277,7 +277,26 @@ class OatFileAssistantTest : public CommonRuntimeTest { EXPECT_EQ(odex_file->GetOatHeader().GetImageFileLocationOatChecksum(), 0u); EXPECT_EQ(odex_file->GetOatHeader().GetImageFileLocationOatDataBegin(), 0u); EXPECT_EQ(odex_file->GetOatHeader().GetImagePatchDelta(), 0); -} + } + + void GenerateProfileGuideOdexForTest(const std::string& dex_location, + const std::string& odex_location) { + std::vector<std::string> args; + args.push_back("--dex-file=" + dex_location); + args.push_back("--oat-file=" + odex_location); + ScratchFile profile_file; + args.push_back("--profile-file=" + profile_file.GetFilename()); + std::string error_msg; + ASSERT_TRUE(OatFileAssistant::Dex2Oat(args, &error_msg)) << error_msg; + + // Verify the odex file was generated as expected. + std::unique_ptr<OatFile> odex_file(OatFile::Open( + odex_location.c_str(), odex_location.c_str(), nullptr, nullptr, + false, dex_location.c_str(), &error_msg)); + printf("error %s", error_msg.c_str()); + ASSERT_TRUE(odex_file.get() != nullptr) << error_msg; + EXPECT_TRUE(odex_file->IsProfileGuideCompiled()); + } private: // Reserve memory around where the image will be loaded so other memory @@ -344,7 +363,8 @@ class OatFileAssistantNoDex2OatTest : public OatFileAssistantTest { // Generate an oat file for the purposes of test, as opposed to testing // generation of oat files. static void GenerateOatForTest(const char* dex_location) { - OatFileAssistant oat_file_assistant(dex_location, kRuntimeISA, false); + OatFileAssistant oat_file_assistant(dex_location, + OatFileAssistant::kFullCompilation, kRuntimeISA, false); std::string error_msg; ASSERT_TRUE(oat_file_assistant.GenerateOatFile(&error_msg)) << error_msg; @@ -356,7 +376,8 @@ TEST_F(OatFileAssistantTest, DexNoOat) { std::string dex_location = GetScratchDir() + "/DexNoOat.jar"; Copy(GetDexSrc1(), dex_location); - OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false); + OatFileAssistant oat_file_assistant(dex_location.c_str(), + OatFileAssistant::kFullCompilation, kRuntimeISA, false); EXPECT_EQ(OatFileAssistant::kDex2OatNeeded, oat_file_assistant.GetDexOptNeeded()); @@ -379,7 +400,8 @@ TEST_F(OatFileAssistantTest, DexNoOat) { TEST_F(OatFileAssistantTest, NoDexNoOat) { std::string dex_location = GetScratchDir() + "/NoDexNoOat.jar"; - OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true); + OatFileAssistant oat_file_assistant(dex_location.c_str(), + OatFileAssistant::kFullCompilation, kRuntimeISA, true); EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded()); EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles()); @@ -400,7 +422,8 @@ TEST_F(OatFileAssistantTest, OatUpToDate) { Copy(GetDexSrc1(), dex_location); GenerateOatForTest(dex_location.c_str()); - OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false); + OatFileAssistant oat_file_assistant(dex_location.c_str(), + OatFileAssistant::kFullCompilation, kRuntimeISA, false); EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded()); EXPECT_FALSE(oat_file_assistant.IsInBootClassPath()); @@ -422,7 +445,8 @@ TEST_F(OatFileAssistantTest, MultiDexOatUpToDate) { Copy(GetMultiDexSrc1(), dex_location); GenerateOatForTest(dex_location.c_str()); - OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true); + OatFileAssistant oat_file_assistant(dex_location.c_str(), + OatFileAssistant::kFullCompilation, kRuntimeISA, true); EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded()); EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles()); @@ -448,7 +472,8 @@ TEST_F(OatFileAssistantTest, MultiDexSecondaryOutOfDate) { // is out of date. Copy(GetMultiDexSrc2(), dex_location); - OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true); + OatFileAssistant oat_file_assistant(dex_location.c_str(), + OatFileAssistant::kFullCompilation, kRuntimeISA, true); EXPECT_EQ(OatFileAssistant::kDex2OatNeeded, oat_file_assistant.GetDexOptNeeded()); EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles()); } @@ -475,6 +500,7 @@ TEST_F(OatFileAssistantTest, RelativeEncodedDexLocation) { // Verify we can load both dex files. OatFileAssistant oat_file_assistant(dex_location.c_str(), oat_location.c_str(), + OatFileAssistant::kFullCompilation, kRuntimeISA, true); std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile(); ASSERT_TRUE(oat_file.get() != nullptr); @@ -495,7 +521,8 @@ TEST_F(OatFileAssistantTest, OatOutOfDate) { GenerateOatForTest(dex_location.c_str()); Copy(GetDexSrc2(), dex_location); - OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false); + OatFileAssistant oat_file_assistant(dex_location.c_str(), + OatFileAssistant::kFullCompilation, kRuntimeISA, false); EXPECT_EQ(OatFileAssistant::kDex2OatNeeded, oat_file_assistant.GetDexOptNeeded()); EXPECT_FALSE(oat_file_assistant.IsInBootClassPath()); @@ -508,32 +535,6 @@ TEST_F(OatFileAssistantTest, OatOutOfDate) { EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles()); } -// Case: We have a DEX file and an extract-only ODEX file out of date relative -// to the DEX file. -// Expect: The status is kDex2OatNeeded. -TEST_F(OatFileAssistantTest, ExtractOnlyOdexOutOfDate) { - std::string dex_location = GetScratchDir() + "/ExtractOnlyOdexOutOfDate.jar"; - std::string odex_location = GetOdexDir() + "/ExtractOnlyOdexOutOfDate.odex"; - - // We create a dex, generate an oat for it, then overwrite the dex with a - // different dex to make the oat out of date. - Copy(GetDexSrc1(), dex_location); - GenerateExtractOnlyOdexForTest(dex_location.c_str(), odex_location.c_str()); - Copy(GetDexSrc2(), dex_location); - - OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false); - EXPECT_EQ(OatFileAssistant::kDex2OatNeeded, oat_file_assistant.GetDexOptNeeded()); - - EXPECT_FALSE(oat_file_assistant.IsInBootClassPath()); - EXPECT_TRUE(oat_file_assistant.OdexFileExists()); - EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate()); - EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate()); - EXPECT_FALSE(oat_file_assistant.OatFileExists()); - EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate()); - EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate()); - EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles()); -} - // Case: We have a DEX file and an ODEX file, but no OAT file. // Expect: The status is kPatchOatNeeded. TEST_F(OatFileAssistantTest, DexOdexNoOat) { @@ -545,7 +546,8 @@ TEST_F(OatFileAssistantTest, DexOdexNoOat) { GenerateOdexForTest(dex_location, odex_location); // Verify the status. - OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false); + OatFileAssistant oat_file_assistant(dex_location.c_str(), + OatFileAssistant::kFullCompilation, kRuntimeISA, false); EXPECT_EQ(OatFileAssistant::kPatchOatNeeded, oat_file_assistant.GetDexOptNeeded()); @@ -578,7 +580,8 @@ TEST_F(OatFileAssistantTest, StrippedDexOdexNoOat) { Copy(GetStrippedDexSrc1(), dex_location); // Verify the status. - OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true); + OatFileAssistant oat_file_assistant(dex_location.c_str(), + OatFileAssistant::kFullCompilation, kRuntimeISA, true); EXPECT_EQ(OatFileAssistant::kPatchOatNeeded, oat_file_assistant.GetDexOptNeeded()); @@ -633,7 +636,8 @@ TEST_F(OatFileAssistantTest, StrippedDexOdexOat) { Copy(GetStrippedDexSrc1(), dex_location); // Verify the status. - OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true); + OatFileAssistant oat_file_assistant(dex_location.c_str(), + OatFileAssistant::kFullCompilation, kRuntimeISA, true); EXPECT_EQ(OatFileAssistant::kPatchOatNeeded, oat_file_assistant.GetDexOptNeeded()); @@ -681,7 +685,8 @@ TEST_F(OatFileAssistantTest, ResourceOnlyDex) { Copy(GetStrippedDexSrc1(), dex_location); // Verify the status. - OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true); + OatFileAssistant oat_file_assistant(dex_location.c_str(), + OatFileAssistant::kFullCompilation, kRuntimeISA, true); EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded()); @@ -724,7 +729,7 @@ TEST_F(OatFileAssistantTest, SelfRelocation) { GenerateOdexForTest(dex_location, oat_location); OatFileAssistant oat_file_assistant(dex_location.c_str(), - oat_location.c_str(), kRuntimeISA, true); + oat_location.c_str(), OatFileAssistant::kFullCompilation, kRuntimeISA, true); EXPECT_EQ(OatFileAssistant::kSelfPatchOatNeeded, oat_file_assistant.GetDexOptNeeded()); @@ -782,7 +787,7 @@ TEST_F(OatFileAssistantTest, OdexOatOverlap) { // Verify things don't go bad. OatFileAssistant oat_file_assistant(dex_location.c_str(), - oat_location.c_str(), kRuntimeISA, true); + oat_location.c_str(), OatFileAssistant::kFullCompilation, kRuntimeISA, true); EXPECT_EQ(OatFileAssistant::kPatchOatNeeded, oat_file_assistant.GetDexOptNeeded()); @@ -816,7 +821,8 @@ TEST_F(OatFileAssistantTest, DexPicOdexNoOat) { GeneratePicOdexForTest(dex_location, odex_location); // Verify the status. - OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false); + OatFileAssistant oat_file_assistant(dex_location.c_str(), + OatFileAssistant::kFullCompilation, kRuntimeISA, false); EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded()); @@ -841,7 +847,9 @@ TEST_F(OatFileAssistantTest, DexExtractOnlyOdexNoOat) { GenerateExtractOnlyOdexForTest(dex_location, odex_location); // Verify the status. - OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false); + OatFileAssistant oat_file_assistant(dex_location.c_str(), + OatFileAssistant::kFullCompilation | OatFileAssistant::kExtractOnly, + kRuntimeISA, false); EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded()); @@ -864,7 +872,8 @@ TEST_F(OatFileAssistantTest, LoadOatUpToDate) { GenerateOatForTest(dex_location.c_str()); // Load the oat using an oat file assistant. - OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true); + OatFileAssistant oat_file_assistant(dex_location.c_str(), + OatFileAssistant::kFullCompilation, kRuntimeISA, true); std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile(); ASSERT_TRUE(oat_file.get() != nullptr); @@ -883,7 +892,8 @@ TEST_F(OatFileAssistantTest, LoadNoExecOatUpToDate) { GenerateOatForTest(dex_location.c_str()); // Load the oat using an oat file assistant. - OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false); + OatFileAssistant oat_file_assistant(dex_location.c_str(), + OatFileAssistant::kFullCompilation, kRuntimeISA, false); std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile(); ASSERT_TRUE(oat_file.get() != nullptr); @@ -903,7 +913,8 @@ TEST_F(OatFileAssistantTest, LoadDexNoAlternateOat) { Copy(GetDexSrc1(), dex_location); OatFileAssistant oat_file_assistant( - dex_location.c_str(), oat_location.c_str(), kRuntimeISA, true); + dex_location.c_str(), oat_location.c_str(), + OatFileAssistant::kFullCompilation, kRuntimeISA, true); std::string error_msg; ASSERT_TRUE(oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg; @@ -917,7 +928,8 @@ TEST_F(OatFileAssistantTest, LoadDexNoAlternateOat) { EXPECT_TRUE(OS::FileExists(oat_location.c_str())); // Verify it didn't create an oat in the default location. - OatFileAssistant ofm(dex_location.c_str(), kRuntimeISA, false); + OatFileAssistant ofm(dex_location.c_str(), + OatFileAssistant::kFullCompilation, kRuntimeISA, false); EXPECT_FALSE(ofm.OatFileExists()); } @@ -933,7 +945,8 @@ TEST_F(OatFileAssistantTest, LoadDexUnwriteableAlternateOat) { Copy(GetDexSrc1(), dex_location); OatFileAssistant oat_file_assistant( - dex_location.c_str(), oat_location.c_str(), kRuntimeISA, true); + dex_location.c_str(), oat_location.c_str(), + OatFileAssistant::kFullCompilation, kRuntimeISA, true); std::string error_msg; ASSERT_FALSE(oat_file_assistant.MakeUpToDate(&error_msg)); @@ -948,7 +961,8 @@ TEST_F(OatFileAssistantTest, GenNoDex) { std::string oat_location = GetScratchDir() + "/GenNoDex.oat"; OatFileAssistant oat_file_assistant( - dex_location.c_str(), oat_location.c_str(), kRuntimeISA, true); + dex_location.c_str(), oat_location.c_str(), + OatFileAssistant::kFullCompilation, kRuntimeISA, true); std::string error_msg; ASSERT_FALSE(oat_file_assistant.GenerateOatFile(&error_msg)); } @@ -996,7 +1010,8 @@ TEST_F(OatFileAssistantTest, NonAbsoluteDexLocation) { Copy(GetDexSrc1(), abs_dex_location); std::string dex_location = MakePathRelative(abs_dex_location); - OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true); + OatFileAssistant oat_file_assistant(dex_location.c_str(), + OatFileAssistant::kFullCompilation, kRuntimeISA, true); EXPECT_FALSE(oat_file_assistant.IsInBootClassPath()); EXPECT_EQ(OatFileAssistant::kDex2OatNeeded, oat_file_assistant.GetDexOptNeeded()); @@ -1013,7 +1028,8 @@ TEST_F(OatFileAssistantTest, NonAbsoluteDexLocation) { TEST_F(OatFileAssistantTest, ShortDexLocation) { std::string dex_location = "/xx"; - OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true); + OatFileAssistant oat_file_assistant(dex_location.c_str(), + OatFileAssistant::kFullCompilation, kRuntimeISA, true); EXPECT_FALSE(oat_file_assistant.IsInBootClassPath()); EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded()); @@ -1037,7 +1053,8 @@ TEST_F(OatFileAssistantTest, LongDexExtension) { std::string dex_location = GetScratchDir() + "/LongDexExtension.jarx"; Copy(GetDexSrc1(), dex_location); - OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false); + OatFileAssistant oat_file_assistant(dex_location.c_str(), + OatFileAssistant::kFullCompilation, kRuntimeISA, false); EXPECT_EQ(OatFileAssistant::kDex2OatNeeded, oat_file_assistant.GetDexOptNeeded()); @@ -1134,7 +1151,8 @@ TEST_F(OatFileAssistantNoDex2OatTest, LoadDexOdexNoOat) { GenerateOdexForTest(dex_location, odex_location); // Load the oat using an executable oat file assistant. - OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true); + OatFileAssistant oat_file_assistant(dex_location.c_str(), + OatFileAssistant::kFullCompilation, kRuntimeISA, true); std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile(); ASSERT_TRUE(oat_file.get() != nullptr); @@ -1156,7 +1174,8 @@ TEST_F(OatFileAssistantNoDex2OatTest, LoadMultiDexOdexNoOat) { GenerateOdexForTest(dex_location, odex_location); // Load the oat using an executable oat file assistant. - OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true); + OatFileAssistant oat_file_assistant(dex_location.c_str(), + OatFileAssistant::kFullCompilation, kRuntimeISA, true); std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile(); ASSERT_TRUE(oat_file.get() != nullptr); @@ -1184,6 +1203,45 @@ TEST(OatFileAssistantUtilsTest, DexFilenameToOdexFilename) { "/foo/bar/baz_noext", kArm, &odex_file, &error_msg)); } +// Case: We have a DEX file, extract-only ODEX, and fully compiled OAT. +// Expect: The status depends on the target compilation type mask. +TEST_F(OatFileAssistantTest, TargetCompilationType) { + std::string dex_location = GetScratchDir() + "/TargetCompilationType.jar"; + std::string odex_location = GetOdexDir() + "/TargetCompilationType.odex"; + Copy(GetDexSrc1(), dex_location); + GenerateExtractOnlyOdexForTest(dex_location, odex_location); + GenerateOatForTest(dex_location.c_str()); + + OatFileAssistant ofa_full(dex_location.c_str(), + OatFileAssistant::kFullCompilation, kRuntimeISA, false); + EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, ofa_full.GetDexOptNeeded()); + EXPECT_FALSE(ofa_full.IsInBootClassPath()); + EXPECT_TRUE(ofa_full.OdexFileIsOutOfDate()); + EXPECT_TRUE(ofa_full.OatFileIsUpToDate()); + + OatFileAssistant ofa_extract(dex_location.c_str(), + OatFileAssistant::kExtractOnly, kRuntimeISA, false); + EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, ofa_extract.GetDexOptNeeded()); + EXPECT_FALSE(ofa_extract.IsInBootClassPath()); + EXPECT_TRUE(ofa_extract.OdexFileIsUpToDate()); + EXPECT_TRUE(ofa_extract.OatFileIsOutOfDate()); + + OatFileAssistant ofa_profile(dex_location.c_str(), + OatFileAssistant::kProfileGuideCompilation, kRuntimeISA, false); + EXPECT_EQ(OatFileAssistant::kDex2OatNeeded, ofa_profile.GetDexOptNeeded()); + EXPECT_FALSE(ofa_profile.IsInBootClassPath()); + EXPECT_TRUE(ofa_profile.OdexFileIsOutOfDate()); + EXPECT_TRUE(ofa_profile.OatFileIsOutOfDate()); + + OatFileAssistant ofa_extract_full(dex_location.c_str(), + OatFileAssistant::kFullCompilation | OatFileAssistant::kExtractOnly, + kRuntimeISA, false); + EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, ofa_extract_full.GetDexOptNeeded()); + EXPECT_FALSE(ofa_extract_full.IsInBootClassPath()); + EXPECT_TRUE(ofa_extract_full.OdexFileIsUpToDate()); + EXPECT_TRUE(ofa_extract_full.OatFileIsUpToDate()); +} + // Verify the dexopt status values from dalvik.system.DexFile // match the OatFileAssistant::DexOptStatus values. TEST_F(OatFileAssistantTest, DexOptStatusValues) { @@ -1218,13 +1276,31 @@ TEST_F(OatFileAssistantTest, DexOptStatusValues) { ASSERT_FALSE(self_patchoat_needed == nullptr); EXPECT_EQ(self_patchoat_needed->GetTypeAsPrimitiveType(), Primitive::kPrimInt); EXPECT_EQ(OatFileAssistant::kSelfPatchOatNeeded, self_patchoat_needed->GetInt(dexfile.Get())); + + ArtField* compilation_type_full = mirror::Class::FindStaticField( + soa.Self(), dexfile, "COMPILATION_TYPE_FULL", "I"); + ASSERT_FALSE(compilation_type_full == nullptr); + EXPECT_EQ(compilation_type_full->GetTypeAsPrimitiveType(), Primitive::kPrimInt); + EXPECT_EQ(OatFileAssistant::kFullCompilation, compilation_type_full->GetInt(dexfile.Get())); + + ArtField* compilation_type_profile_guide = mirror::Class::FindStaticField( + soa.Self(), dexfile, "COMPILATION_TYPE_PROFILE_GUIDE", "I"); + ASSERT_FALSE(compilation_type_profile_guide == nullptr); + EXPECT_EQ(compilation_type_profile_guide->GetTypeAsPrimitiveType(), Primitive::kPrimInt); + EXPECT_EQ(OatFileAssistant::kProfileGuideCompilation, + compilation_type_profile_guide->GetInt(dexfile.Get())); + + ArtField* compilation_type_extract_only = mirror::Class::FindStaticField( + soa.Self(), dexfile, "COMPILATION_TYPE_EXTRACT_ONLY", "I"); + ASSERT_FALSE(compilation_type_extract_only == nullptr); + EXPECT_EQ(compilation_type_extract_only->GetTypeAsPrimitiveType(), Primitive::kPrimInt); + EXPECT_EQ(OatFileAssistant::kExtractOnly, compilation_type_extract_only->GetInt(dexfile.Get())); } // TODO: More Tests: // * Test class linker falls back to unquickened dex for DexNoOat // * Test class linker falls back to unquickened dex for MultiDexNoOat // * Test using secondary isa -// * Test with profiling info? // * Test for status of oat while oat is being generated (how?) // * Test case where 32 and 64 bit boot class paths differ, // and we ask IsInBootClassPath for a class in exactly one of the 32 or @@ -1233,5 +1309,7 @@ TEST_F(OatFileAssistantTest, DexOptStatusValues) { // - Dex is stripped, don't have odex. // - Oat file corrupted after status check, before reload unexecutable // because it's unrelocated and no dex2oat +// * Test unrelocated specific target compilation type can be relocated to +// make it up to date. } // namespace art diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc index 95b142c833..e57125bef1 100644 --- a/runtime/oat_file_manager.cc +++ b/runtime/oat_file_manager.cc @@ -307,8 +307,13 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat( Thread* const self = Thread::Current(); Locks::mutator_lock_->AssertNotHeld(self); Runtime* const runtime = Runtime::Current(); + + int target_compilation_type_mask = OatFileAssistant::kFullCompilation + | OatFileAssistant::kProfileGuideCompilation + | OatFileAssistant::kExtractOnly; OatFileAssistant oat_file_assistant(dex_location, oat_location, + target_compilation_type_mask, kRuntimeISA, !runtime->IsAotCompiler()); |