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
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) {
// 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;
}
}
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);
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;
}
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;"
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;
}
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) {
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,
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,
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) {
bool IsExtractOnly() const;
+ bool IsProfileGuideCompiled() const;
+
const std::string& GetLocation() const {
return location_;
}
#include "image.h"
#include "oat.h"
#include "os.h"
-#include "profiler.h"
#include "runtime.h"
#include "scoped_thread_state_change.h"
#include "ScopedFd.h"
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);
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() {
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;
}
}
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.
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);
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_
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 =
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);
// 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 {
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
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.
//
// 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();
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.
// 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.
//
// 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;
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
}
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);
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
// 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;
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());
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());
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());
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());
// 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());
}
// 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);
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());
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) {
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());
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());
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());
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());
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());
// 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());
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());
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());
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);
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);
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;
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());
}
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));
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));
}
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());
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());
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());
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);
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);
"/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) {
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
// - 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
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());