runtime/base/variant_map_test.cc \
runtime/base/unix_file/fd_file_test.cc \
runtime/class_linker_test.cc \
- runtime/compiler_filter_test.cc \
runtime/dex_file_test.cc \
runtime/dex_file_verifier_test.cc \
runtime/dex_instruction_test.cc \
return false;
}
// Don't compile class initializers unless kEverything.
- if ((compiler_options_->GetCompilerFilter() != CompilerFilter::kEverything) &&
+ if ((compiler_options_->GetCompilerFilter() != CompilerOptions::kEverything) &&
((access_flags & kAccConstructor) != 0) && ((access_flags & kAccStatic) != 0)) {
return false;
}
// because we don't want to include the PassManagerOptions definition from the header file.
}
-CompilerOptions::CompilerOptions(CompilerFilter::Filter compiler_filter,
+CompilerOptions::CompilerOptions(CompilerFilter compiler_filter,
size_t huge_method_threshold,
size_t large_method_threshold,
size_t small_method_threshold,
bool CompilerOptions::ParseCompilerOption(const StringPiece& option, UsageFn Usage) {
if (option.starts_with("--compiler-filter=")) {
const char* compiler_filter_string = option.substr(strlen("--compiler-filter=")).data();
- if (!CompilerFilter::ParseCompilerFilter(compiler_filter_string, &compiler_filter_)) {
+ if (strcmp(compiler_filter_string, "verify-none") == 0) {
+ compiler_filter_ = CompilerOptions::kVerifyNone;
+ } else if (strcmp(compiler_filter_string, "interpret-only") == 0) {
+ compiler_filter_ = CompilerOptions::kInterpretOnly;
+ } else if (strcmp(compiler_filter_string, "verify-at-runtime") == 0) {
+ compiler_filter_ = CompilerOptions::kVerifyAtRuntime;
+ } else if (strcmp(compiler_filter_string, "space") == 0) {
+ compiler_filter_ = CompilerOptions::kSpace;
+ } else if (strcmp(compiler_filter_string, "balanced") == 0) {
+ compiler_filter_ = CompilerOptions::kBalanced;
+ } else if (strcmp(compiler_filter_string, "speed") == 0) {
+ compiler_filter_ = CompilerOptions::kSpeed;
+ } else if (strcmp(compiler_filter_string, "everything") == 0) {
+ compiler_filter_ = CompilerOptions::kEverything;
+ } else if (strcmp(compiler_filter_string, "time") == 0) {
+ compiler_filter_ = CompilerOptions::kTime;
+ } else if (strcmp(compiler_filter_string, "verify-profile") == 0) {
+ compiler_filter_ = CompilerOptions::kVerifyProfile;
+ } else {
Usage("Unknown --compiler-filter value %s", compiler_filter_string);
}
} else if (option == "--compile-pic") {
#include <vector>
#include "base/macros.h"
-#include "compiler_filter.h"
#include "globals.h"
#include "utils.h"
class CompilerOptions FINAL {
public:
+ enum CompilerFilter {
+ kVerifyNone, // Skip verification and compile nothing except JNI stubs.
+ kInterpretOnly, // Verify, and compile only JNI stubs.
+ kVerifyAtRuntime, // Only compile JNI stubs and verify at runtime.
+ kSpace, // Maximize space savings.
+ kBalanced, // Try to get the best performance return on compilation investment.
+ kSpeed, // Maximize runtime performance.
+ kEverything, // Force compilation of everything capable of being compiled.
+ kTime, // Compile methods, but minimize compilation time.
+ kVerifyProfile, // Verify only the classes in the profile.
+ };
+
// Guide heuristics to determine whether to compile method if profile data not available.
- static const CompilerFilter::Filter kDefaultCompilerFilter = CompilerFilter::kSpeed;
+ static const CompilerFilter kDefaultCompilerFilter = kSpeed;
static const size_t kDefaultHugeMethodThreshold = 10000;
static const size_t kDefaultLargeMethodThreshold = 600;
static const size_t kDefaultSmallMethodThreshold = 60;
CompilerOptions();
~CompilerOptions();
- CompilerOptions(CompilerFilter::Filter compiler_filter,
+ CompilerOptions(CompilerFilter compiler_filter,
size_t huge_method_threshold,
size_t large_method_threshold,
size_t small_method_threshold,
bool dump_cfg_append,
bool force_determinism);
- CompilerFilter::Filter GetCompilerFilter() const {
+ CompilerFilter GetCompilerFilter() const {
return compiler_filter_;
}
- void SetCompilerFilter(CompilerFilter::Filter compiler_filter) {
+ void SetCompilerFilter(CompilerFilter compiler_filter) {
compiler_filter_ = compiler_filter;
}
bool VerifyAtRuntime() const {
- return compiler_filter_ == CompilerFilter::kVerifyAtRuntime;
+ return compiler_filter_ == CompilerOptions::kVerifyAtRuntime;
}
bool IsCompilationEnabled() const {
- return CompilerFilter::IsCompilationEnabled(compiler_filter_);
+ return compiler_filter_ != CompilerOptions::kVerifyNone &&
+ compiler_filter_ != CompilerOptions::kInterpretOnly &&
+ compiler_filter_ != CompilerOptions::kVerifyAtRuntime &&
+ compiler_filter_ != CompilerOptions::kVerifyProfile;
}
bool IsVerificationEnabled() const {
- return CompilerFilter::IsVerificationEnabled(compiler_filter_);
+ return compiler_filter_ != CompilerOptions::kVerifyNone &&
+ compiler_filter_ != CompilerOptions::kVerifyAtRuntime;
}
bool NeverVerify() const {
- return compiler_filter_ == CompilerFilter::kVerifyNone;
+ return compiler_filter_ == CompilerOptions::kVerifyNone;
+ }
+
+ bool IsExtractOnly() const {
+ return compiler_filter_ == CompilerOptions::kVerifyAtRuntime;
}
bool VerifyOnlyProfile() const {
- return compiler_filter_ == CompilerFilter::kVerifyProfile;
+ return compiler_filter_ == CompilerOptions::kVerifyProfile;
}
size_t GetHugeMethodThreshold() const {
void ParseLargeMethodMax(const StringPiece& option, UsageFn Usage);
void ParseHugeMethodMax(const StringPiece& option, UsageFn Usage);
- CompilerFilter::Filter compiler_filter_;
+ CompilerFilter compiler_filter_;
size_t huge_method_threshold_;
size_t large_method_threshold_;
size_t small_method_threshold_;
DISALLOW_COPY_AND_ASSIGN(CompilerOptions);
};
+std::ostream& operator<<(std::ostream& os, const CompilerOptions::CompilerFilter& rhs);
} // namespace art
bool HGraphBuilder::SkipCompilation(const DexFile::CodeItem& code_item,
size_t number_of_branches) {
const CompilerOptions& compiler_options = compiler_driver_->GetCompilerOptions();
- CompilerFilter::Filter compiler_filter = compiler_options.GetCompilerFilter();
- if (compiler_filter == CompilerFilter::kEverything) {
+ CompilerOptions::CompilerFilter compiler_filter = compiler_options.GetCompilerFilter();
+ if (compiler_filter == CompilerOptions::kEverything) {
return false;
}
// code units is bigger than 128.
static constexpr size_t kSpaceFilterOptimizingThreshold = 128;
const CompilerOptions& compiler_options = compiler_driver->GetCompilerOptions();
- if ((compiler_options.GetCompilerFilter() == CompilerFilter::kSpace)
+ if ((compiler_options.GetCompilerFilter() == CompilerOptions::kSpace)
&& (code_item->insns_size_in_code_units_ > kSpaceFilterOptimizingThreshold)) {
MaybeRecordStat(MethodCompilationStat::kNotCompiledSpaceFilter);
return nullptr;
"|verify-at-runtime"
"|verify-profile"
"|interpret-only"
- "|time"
- "|space-profile"
"|space"
"|balanced"
- "|speed-profile"
"|speed"
- "|everything-profile"
- "|everything):");
+ "|everything"
+ "|time):");
UsageError(" select compiler filter.");
UsageError(" verify-profile requires a --profile(-fd) to also be passed in.");
UsageError(" Example: --compiler-filter=everything");
Usage("Profile file should not be specified with both --profile-file-fd and --profile-file");
}
+ if (compiler_options_->VerifyOnlyProfile() && !have_profile_file && !have_profile_fd) {
+ Usage("verify-profile compiler filter must be used with a profile file or fd");
+ }
+
if (!parser_options->oat_symbols.empty()) {
oat_unstripped_ = std::move(parser_options->oat_symbols);
}
// time here, which is orthogonal to space.
if (compiler_options_->inline_depth_limit_ == CompilerOptions::kUnsetInlineDepthLimit) {
compiler_options_->inline_depth_limit_ =
- (compiler_options_->compiler_filter_ == CompilerFilter::kSpace)
+ (compiler_options_->compiler_filter_ == CompilerOptions::kSpace)
// Implementation of the space filter: limit inlining depth.
? CompilerOptions::kSpaceFilterInlineDepthLimit
: CompilerOptions::kDefaultInlineDepthLimit;
}
if (compiler_options_->inline_max_code_units_ == CompilerOptions::kUnsetInlineMaxCodeUnits) {
compiler_options_->inline_max_code_units_ =
- (compiler_options_->compiler_filter_ == CompilerFilter::kSpace)
+ (compiler_options_->compiler_filter_ == CompilerOptions::kSpace)
// Implementation of the space filter: limit inlining max code units.
? CompilerOptions::kSpaceFilterInlineMaxCodeUnits
: CompilerOptions::kDefaultInlineMaxCodeUnits;
key_value_store_->Put(
OatHeader::kNativeDebuggableKey,
compiler_options_->GetNativeDebuggable() ? OatHeader::kTrueValue : OatHeader::kFalseValue);
- key_value_store_->Put(OatHeader::kCompilerFilter,
- CompilerFilter::NameOfFilter(compiler_options_->GetCompilerFilter()));
+ 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 false;
}
- if (CompilerFilter::DependsOnImageChecksum(compiler_options_->GetCompilerFilter())) {
+ if (compiler_options_->IsExtractOnly()) {
+ // ExtractOnly oat files only contain non-quickened DEX code and are
+ // therefore independent of the image file.
+ image_file_location_oat_checksum_ = 0u;
+ image_file_location_oat_data_begin_ = 0u;
+ image_patch_delta_ = 0;
+ } else {
TimingLogger::ScopedTiming t3("Loading image checksum", timings_);
std::vector<gc::space::ImageSpace*> image_spaces =
Runtime::Current()->GetHeap()->GetBootImageSpaces();
if (!image_file_location.empty()) {
key_value_store_->Put(OatHeader::kImageLocationKey, image_file_location);
}
- } else {
- image_file_location_oat_checksum_ = 0u;
- image_file_location_oat_data_begin_ = 0u;
- image_patch_delta_ = 0;
}
// Open dex files for class path.
num_methods += dex_file->NumMethodIds();
}
if (num_methods <= compiler_options_->GetNumDexMethodsThreshold()) {
- compiler_options_->SetCompilerFilter(CompilerFilter::kSpeed);
+ compiler_options_->SetCompilerFilter(CompilerOptions::kSpeed);
VLOG(compiler) << "Below method threshold, compiling anyways";
}
}
}
bool UseProfileGuidedCompilation() const {
- return CompilerFilter::DependsOnProfile(compiler_options_->GetCompilerFilter());
+ return !profile_file_.empty() || (profile_file_fd_ != kInvalidFd);
}
bool LoadProfile() {
profile_compilation_info_.reset(new ProfileCompilationInfo());
ScopedFlock flock;
- bool success = true;
+ bool success = false;
std::string error;
if (profile_file_fd_ != -1) {
// The file doesn't need to be flushed so don't check the usage.
if (flock.Init(&file, &error)) {
success = profile_compilation_info_->Load(profile_file_fd_);
}
- } else if (profile_file_ != "") {
+ } else {
if (flock.Init(profile_file_.c_str(), O_RDONLY, /* block */ true, &error)) {
success = profile_compilation_info_->Load(flock.GetFile()->Fd());
}
class_table.cc \
code_simulator_container.cc \
common_throws.cc \
- compiler_filter.cc \
debugger.cc \
dex_file.cc \
dex_file_verifier.cc \
filename_ = getenv("ANDROID_DATA");
filename_ += "/TmpFile-XXXXXX";
int fd = mkstemp(&filename_[0]);
- CHECK_NE(-1, fd) << strerror(errno) << " for " << filename_;
+ CHECK_NE(-1, fd);
file_.reset(new File(fd, GetFilename(), true));
}
+++ /dev/null
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "compiler_filter.h"
-
-#include "utils.h"
-
-namespace art {
-
-bool CompilerFilter::IsCompilationEnabled(Filter filter) {
- switch (filter) {
- case CompilerFilter::kVerifyNone:
- case CompilerFilter::kVerifyAtRuntime:
- case CompilerFilter::kVerifyProfile:
- case CompilerFilter::kInterpretOnly: return false;
-
- case CompilerFilter::kSpaceProfile:
- case CompilerFilter::kSpace:
- case CompilerFilter::kBalanced:
- case CompilerFilter::kTime:
- case CompilerFilter::kSpeedProfile:
- case CompilerFilter::kSpeed:
- case CompilerFilter::kEverythingProfile:
- case CompilerFilter::kEverything: return true;
- }
- UNREACHABLE();
-}
-
-bool CompilerFilter::IsVerificationEnabled(Filter filter) {
- switch (filter) {
- case CompilerFilter::kVerifyNone:
- case CompilerFilter::kVerifyAtRuntime: return false;
-
- case CompilerFilter::kVerifyProfile:
- case CompilerFilter::kInterpretOnly:
- case CompilerFilter::kSpaceProfile:
- case CompilerFilter::kSpace:
- case CompilerFilter::kBalanced:
- case CompilerFilter::kTime:
- case CompilerFilter::kSpeedProfile:
- case CompilerFilter::kSpeed:
- case CompilerFilter::kEverythingProfile:
- case CompilerFilter::kEverything: return true;
- }
- UNREACHABLE();
-}
-
-bool CompilerFilter::DependsOnImageChecksum(Filter filter) {
- // We run dex2dex with verification, so the oat file will depend on the
- // image checksum if verification is enabled.
- return IsVerificationEnabled(filter);
-}
-
-bool CompilerFilter::DependsOnProfile(Filter filter) {
- switch (filter) {
- case CompilerFilter::kVerifyNone:
- case CompilerFilter::kVerifyAtRuntime:
- case CompilerFilter::kInterpretOnly:
- case CompilerFilter::kSpace:
- case CompilerFilter::kBalanced:
- case CompilerFilter::kTime:
- case CompilerFilter::kSpeed:
- case CompilerFilter::kEverything: return false;
-
- case CompilerFilter::kVerifyProfile:
- case CompilerFilter::kSpaceProfile:
- case CompilerFilter::kSpeedProfile:
- case CompilerFilter::kEverythingProfile: return true;
- }
- UNREACHABLE();
-}
-
-bool CompilerFilter::IsAsGoodAs(Filter current, Filter target) {
- return current >= target;
-}
-
-std::string CompilerFilter::NameOfFilter(Filter filter) {
- switch (filter) {
- case CompilerFilter::kVerifyNone: return "verify-none";
- case CompilerFilter::kVerifyAtRuntime: return "verify-at-runtime";
- case CompilerFilter::kVerifyProfile: return "verify-profile";
- case CompilerFilter::kInterpretOnly: return "interpret-only";
- case CompilerFilter::kSpaceProfile: return "space-profile";
- case CompilerFilter::kSpace: return "space";
- case CompilerFilter::kBalanced: return "balanced";
- case CompilerFilter::kTime: return "time";
- case CompilerFilter::kSpeedProfile: return "speed-profile";
- case CompilerFilter::kSpeed: return "speed";
- case CompilerFilter::kEverythingProfile: return "everything-profile";
- case CompilerFilter::kEverything: return "everything";
- }
- UNREACHABLE();
-}
-
-bool CompilerFilter::ParseCompilerFilter(const char* option, Filter* filter) {
- CHECK(filter != nullptr);
-
- if (strcmp(option, "verify-none") == 0) {
- *filter = kVerifyNone;
- } else if (strcmp(option, "interpret-only") == 0) {
- *filter = kInterpretOnly;
- } else if (strcmp(option, "verify-profile") == 0) {
- *filter = kVerifyProfile;
- } else if (strcmp(option, "verify-at-runtime") == 0) {
- *filter = kVerifyAtRuntime;
- } else if (strcmp(option, "space") == 0) {
- *filter = kSpace;
- } else if (strcmp(option, "space-profile") == 0) {
- *filter = kSpaceProfile;
- } else if (strcmp(option, "balanced") == 0) {
- *filter = kBalanced;
- } else if (strcmp(option, "speed") == 0) {
- *filter = kSpeed;
- } else if (strcmp(option, "speed-profile") == 0) {
- *filter = kSpeedProfile;
- } else if (strcmp(option, "everything") == 0) {
- *filter = kEverything;
- } else if (strcmp(option, "everything-profile") == 0) {
- *filter = kEverythingProfile;
- } else if (strcmp(option, "time") == 0) {
- *filter = kTime;
- } else {
- return false;
- }
- return true;
-}
-
-std::ostream& operator<<(std::ostream& os, const CompilerFilter::Filter& rhs) {
- return os << CompilerFilter::NameOfFilter(rhs);
-}
-
-} // namespace art
+++ /dev/null
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_COMPILER_FILTER_H_
-#define ART_RUNTIME_COMPILER_FILTER_H_
-
-#include <ostream>
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-
-namespace art {
-
-class CompilerFilter FINAL {
- public:
- // Note: Order here matters. Later filter choices are considered "as good
- // as" earlier filter choices.
- enum Filter {
- kVerifyNone, // Skip verification and compile nothing except JNI stubs.
- kVerifyAtRuntime, // Only compile JNI stubs and verify at runtime.
- kVerifyProfile, // Verify only the classes in the profile.
- kInterpretOnly, // Verify, and compile only JNI stubs.
- kTime, // Compile methods, but minimize compilation time.
- kSpaceProfile, // Maximize space savings based on profile.
- kSpace, // Maximize space savings.
- kBalanced, // Good performance return on compilation investment.
- kSpeedProfile, // Maximize runtime performance based on profile.
- kSpeed, // Maximize runtime performance.
- kEverythingProfile, // Compile everything capable of being compiled based on profile.
- kEverything, // Compile everything capable of being compiled.
- };
-
- // Returns true if an oat file with this compiler filter contains
- // compiled executable code.
- static bool IsCompilationEnabled(Filter filter);
-
- // Returns true if this compiler filter requires running verification.
- static bool IsVerificationEnabled(Filter filter);
-
- // Returns true if an oat file with this compiler filter depends on the
- // boot image checksum.
- static bool DependsOnImageChecksum(Filter filter);
-
- // Returns true if an oat file with this compiler filter depends on a
- // profile.
- static bool DependsOnProfile(Filter filter);
-
- // Returns true if the 'current' compiler filter is considered at least as
- // good as the 'target' compilation type.
- // For example: kSpeed is as good as kInterpretOnly, but kInterpretOnly is
- // not as good as kSpeed.
- static bool IsAsGoodAs(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
- // ParseCompilerFilter.
- static std::string NameOfFilter(Filter filter);
-
- // Parse the compiler filter from the given name.
- // Returns true and sets filter to the parsed value if name refers to a
- // valid filter. Returns false if no filter matches that name.
- // 'filter' must be non-null.
- static bool ParseCompilerFilter(const char* name, /*out*/Filter* filter);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(CompilerFilter);
-};
-
-std::ostream& operator<<(std::ostream& os, const CompilerFilter::Filter& rhs);
-
-} // namespace art
-
-#endif // ART_RUNTIME_COMPILER_FILTER_H_
+++ /dev/null
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "compiler_filter.h"
-
-#include <gtest/gtest.h>
-
-namespace art {
-
-static void TestCompilerFilterName(CompilerFilter::Filter filter, std::string name) {
- CompilerFilter::Filter parsed;
- EXPECT_TRUE(CompilerFilter::ParseCompilerFilter(name.c_str(), &parsed));
- EXPECT_EQ(filter, parsed);
-
- EXPECT_EQ(name, CompilerFilter::NameOfFilter(filter));
-}
-
-// Verify the dexopt status values from dalvik.system.DexFile
-// match the OatFileAssistant::DexOptStatus values.
-TEST(CompilerFilterTest, ParseCompilerFilter) {
- CompilerFilter::Filter filter;
-
- TestCompilerFilterName(CompilerFilter::kVerifyNone, "verify-none");
- TestCompilerFilterName(CompilerFilter::kVerifyAtRuntime, "verify-at-runtime");
- TestCompilerFilterName(CompilerFilter::kVerifyProfile, "verify-profile");
- TestCompilerFilterName(CompilerFilter::kInterpretOnly, "interpret-only");
- TestCompilerFilterName(CompilerFilter::kTime, "time");
- TestCompilerFilterName(CompilerFilter::kSpaceProfile, "space-profile");
- TestCompilerFilterName(CompilerFilter::kSpace, "space");
- TestCompilerFilterName(CompilerFilter::kBalanced, "balanced");
- TestCompilerFilterName(CompilerFilter::kSpeedProfile, "speed-profile");
- TestCompilerFilterName(CompilerFilter::kSpeed, "speed");
- TestCompilerFilterName(CompilerFilter::kEverythingProfile, "everything-profile");
- TestCompilerFilterName(CompilerFilter::kEverything, "everything");
-
- EXPECT_FALSE(CompilerFilter::ParseCompilerFilter("super-awesome-filter", &filter));
-}
-
-} // namespace art
static jint GetDexOptNeeded(JNIEnv* env,
const char* filename,
const char* instruction_set,
- const char* compiler_filter_name,
- bool profile_changed) {
+ 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"));
return -1;
}
- CompilerFilter::Filter filter;
- if (!CompilerFilter::ParseCompilerFilter(compiler_filter_name, &filter)) {
- ScopedLocalRef<jclass> iae(env, env->FindClass("java/lang/IllegalArgumentException"));
- std::string message(StringPrintf("Compiler filter %s is invalid.", compiler_filter_name));
- env->ThrowNew(iae.get(), message.c_str());
- return -1;
- }
-
// TODO: Verify the dex location is well formed, and throw an IOException if
// not?
-
- OatFileAssistant oat_file_assistant(filename, target_instruction_set, profile_changed, false);
+ 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;
}
- return oat_file_assistant.GetDexOptNeeded(filter);
+
+ return oat_file_assistant.GetDexOptNeeded();
}
static jint DexFile_getDexOptNeeded(JNIEnv* env,
return -1;
}
- // TODO: Take profile changed and compiler filter as arguments.
- // For now, we use "speed" by default, unless EXTRACT_ONLY = 0x4 was
- // included in the mask.
- const char* compiler_filter = "speed";
- if (javaTargetCompilationTypeMask & 0x4) {
- compiler_filter = "verify-at-runtime";
- }
return GetDexOptNeeded(env,
filename.c_str(),
instruction_set.c_str(),
- compiler_filter,
- /*profile_changed*/false);
+ javaTargetCompilationTypeMask);
}
// public API
env,
filename.c_str(),
instruction_set,
- "speed-profile",
- /*profile_changed*/false);
+ OatFileAssistant::kFullCompilation | OatFileAssistant::kProfileGuideCompilation);
return (status != OatFileAssistant::kNoDexOptNeeded) ? JNI_TRUE : JNI_FALSE;
}
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;
return IsKeyEnabled(OatHeader::kNativeDebuggableKey);
}
-CompilerFilter::Filter OatHeader::GetCompilerFilter() const {
- CompilerFilter::Filter filter;
- const char* key_value = GetStoreValueByKey(kCompilerFilter);
- CHECK(key_value != nullptr) << "compiler-filter not found in oat header";
- CHECK(CompilerFilter::ParseCompilerFilter(key_value, &filter))
- << "Invalid compiler-filter in oat header: " << key_value;
- return filter;
+bool OatHeader::IsExtractOnly() const {
+ return KeyHasValue(kCompilationType,
+ kExtractOnlyValue,
+ sizeof(kExtractOnlyValue));
+}
+
+bool OatHeader::IsProfileGuideCompiled() const {
+ return KeyHasValue(kCompilationType,
+ kProfileGuideCompiledValue,
+ sizeof(kProfileGuideCompiledValue));
}
bool OatHeader::KeyHasValue(const char* key, const char* value, size_t value_size) const {
#include "arch/instruction_set.h"
#include "base/macros.h"
-#include "compiler_filter.h"
#include "dex_file.h"
#include "safe_map.h"
class PACKED(4) OatHeader {
public:
static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' };
- static constexpr uint8_t kOatVersion[] = { '0', '7', '6', '\0' };
+ static constexpr uint8_t kOatVersion[] = { '0', '7', '5', '\0' };
static constexpr const char* kImageLocationKey = "image-location";
static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
static constexpr const char* kPicKey = "pic";
static constexpr const char* kDebuggableKey = "debuggable";
static constexpr const char* kNativeDebuggableKey = "native-debuggable";
- static constexpr const char* kCompilerFilter = "compiler-filter";
+ 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,
bool IsPic() const;
bool IsDebuggable() const;
bool IsNativeDebuggable() const;
- CompilerFilter::Filter GetCompilerFilter() const;
+ bool IsExtractOnly() const;
+ bool IsProfileGuideCompiled() const;
private:
bool KeyHasValue(const char* key, const char* value, size_t value_size) const;
return GetOatHeader().IsDebuggable();
}
-CompilerFilter::Filter OatFile::GetCompilerFilter() const {
- return GetOatHeader().GetCompilerFilter();
+bool OatFile::IsExtractOnly() const {
+ return GetOatHeader().IsExtractOnly();
+}
+
+bool OatFile::IsProfileGuideCompiled() const {
+ return GetOatHeader().IsProfileGuideCompiled();
}
static constexpr char kDexClassPathEncodingSeparator = '*';
// Indicates whether the oat file was compiled with full debugging capability.
bool IsDebuggable() const;
- CompilerFilter::Filter GetCompilerFilter() const;
+ bool IsExtractOnly() const;
+
+ bool IsProfileGuideCompiled() const;
const std::string& GetLocation() const {
return location_;
namespace art {
OatFileAssistant::OatFileAssistant(const char* dex_location,
+ const int target_compilation_type_mask,
const InstructionSet isa,
- bool profile_changed,
bool load_executable)
- : OatFileAssistant(dex_location, nullptr, isa, profile_changed, load_executable)
+ : 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 profile_changed,
bool load_executable)
- : isa_(isa), profile_changed_(profile_changed), 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);
return true;
}
-bool OatFileAssistant::OatFileCompilerFilterIsOkay(CompilerFilter::Filter target) {
- const OatFile* oat_file = GetOatFile();
- if (oat_file != nullptr) {
- CompilerFilter::Filter current = oat_file->GetCompilerFilter();
- return CompilerFilter::IsAsGoodAs(current, target);
- }
- return false;
-}
-
-bool OatFileAssistant::OdexFileCompilerFilterIsOkay(CompilerFilter::Filter target) {
- const OatFile* odex_file = GetOdexFile();
- if (odex_file != nullptr) {
- CompilerFilter::Filter current = odex_file->GetCompilerFilter();
- return CompilerFilter::IsAsGoodAs(current, target);
- }
- return false;
+// 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(CompilerFilter::Filter target) {
- bool compilation_desired = CompilerFilter::IsCompilationEnabled(target);
-
- // See if the oat file is in good shape as is.
- bool oat_okay = OatFileCompilerFilterIsOkay(target);
- if (oat_okay) {
- if (compilation_desired) {
- if (OatFileIsUpToDate()) {
- return kNoDexOptNeeded;
- }
- } else {
- if (!OatFileIsOutOfDate()) {
- return kNoDexOptNeeded;
- }
- }
+OatFileAssistant::DexOptNeeded OatFileAssistant::GetDexOptNeeded() {
+ if (OatFileIsUpToDate() || OdexFileIsUpToDate()) {
+ return kNoDexOptNeeded;
}
- // See if the odex file is in good shape as is.
- bool odex_okay = OdexFileCompilerFilterIsOkay(target);
- if (odex_okay) {
- if (compilation_desired) {
- if (OdexFileIsUpToDate()) {
- return kNoDexOptNeeded;
- }
- } else {
- if (!OdexFileIsOutOfDate()) {
- return kNoDexOptNeeded;
- }
- }
+ if (OdexFileNeedsRelocation()) {
+ return kPatchOatNeeded;
}
- // See if we can get an up-to-date file by running patchoat.
- if (compilation_desired) {
- if (odex_okay && OdexFileNeedsRelocation()) {
- // TODO: don't return kPatchOatNeeded if the odex file contains no
- // patch information.
- return kPatchOatNeeded;
- }
-
- if (oat_okay && OatFileNeedsRelocation()) {
- // TODO: don't return kSelfPatchOatNeeded if the oat file contains no
- // patch information.
- return kSelfPatchOatNeeded;
- }
+ if (OatFileNeedsRelocation()) {
+ return kSelfPatchOatNeeded;
}
- // We can only run dex2oat if there are original dex files.
return HasOriginalDexFiles() ? kDex2OatNeeded : kNoDexOptNeeded;
}
-bool OatFileAssistant::MakeUpToDate(CompilerFilter::Filter target, std::string* error_msg) {
- switch (GetDexOptNeeded(target)) {
+bool OatFileAssistant::MakeUpToDate(std::string* error_msg) {
+ switch (GetDexOptNeeded()) {
case kNoDexOptNeeded: return true;
- case kDex2OatNeeded: return GenerateOatFile(target, error_msg);
+ case kDex2OatNeeded: return GenerateOatFile(error_msg);
case kPatchOatNeeded: return RelocateOatFile(OdexFileName(), error_msg);
case kSelfPatchOatNeeded: return RelocateOatFile(OatFileName(), error_msg);
}
}
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.
}
}
- CompilerFilter::Filter current_compiler_filter = file.GetCompilerFilter();
- VLOG(oat) << "Compiler filter for " << file.GetLocation() << " is " << current_compiler_filter;
-
- // Verify the image checksum
- if (CompilerFilter::DependsOnImageChecksum(current_compiler_filter)) {
- const ImageInfo* image_info = GetImageInfo();
- if (image_info == nullptr) {
- VLOG(oat) << "No image for oat image checksum to match against.";
- return true;
+ if (file.IsExtractOnly()) {
+ VLOG(oat) << "Oat file is extract-only. Image checksum test skipped.";
+ if (kIsDebugBuild) {
+ // Sanity check that no classes have compiled code. Does not test that
+ // the DEX code has not been quickened.
+ std::string error_msg;
+ for (const OatFile::OatDexFile* current : file.GetOatDexFiles()) {
+ std::unique_ptr<const DexFile> dex_file = current->OpenDexFile(&error_msg);
+ DCHECK(dex_file != nullptr);
+ for (size_t i = 0, e = dex_file->NumClassDefs(); i < e; ++i) {
+ DCHECK_EQ(current->GetOatClass(i).GetType(), kOatClassNoneCompiled);
+ }
+ }
}
+ return false;
+ }
- if (file.GetOatHeader().GetImageFileLocationOatChecksum() != image_info->oat_checksum) {
- VLOG(oat) << "Oat image checksum does not match image checksum.";
- return true;
- }
- } else {
- VLOG(oat) << "Image checksum test skipped for compiler filter " << current_compiler_filter;
+ // Verify the image checksum
+ const ImageInfo* image_info = GetImageInfo();
+ if (image_info == nullptr) {
+ VLOG(oat) << "No image for oat image checksum to match against.";
+ return true;
}
- // Verify the profile hasn't changed recently.
- // TODO: Move this check to OatFileCompilerFilterIsOkay? Nothing bad should
- // happen if we use an oat file compiled with an out-of-date profile.
- if (CompilerFilter::DependsOnProfile(current_compiler_filter)) {
- if (profile_changed_) {
- VLOG(oat) << "The profile has changed recently.";
- return true;
- }
- } else {
- VLOG(oat) << "Profile check skipped for compiler filter " << current_compiler_filter;
+ if (file.GetOatHeader().GetImageFileLocationOatChecksum() != image_info->oat_checksum) {
+ VLOG(oat) << "Oat image checksum does not match image checksum.";
+ return true;
}
- // Everything looks good; the dex file is not out of date.
+ // The checksums are all good; the dex file is not out of date.
return false;
}
return false;
}
- CompilerFilter::Filter current_compiler_filter = file.GetCompilerFilter();
+ if (file.IsPic() || file.IsExtractOnly()) {
+ // Oat files compiled in PIC mode do not require relocation and extract-only
+ // oat files do not contain any compiled code. Skip the relocation test.
+ VLOG(oat) << "Oat relocation test skipped.";
+ return true;
+ }
- // Don't consider an oat file as up-to-date with compiled code unless
- // compilation is enabled. This ensures we fall back to a non-executable oat
- // file if there is no compiled code.
- if (!CompilerFilter::IsCompilationEnabled(current_compiler_filter)) {
- VLOG(oat) << "Compilation not enabled for " << current_compiler_filter;
+ const ImageInfo* image_info = GetImageInfo();
+ if (image_info == nullptr) {
+ VLOG(oat) << "No image to check oat relocation against.";
return false;
}
- if (!file.IsPic()) {
- const ImageInfo* image_info = GetImageInfo();
- if (image_info == nullptr) {
- VLOG(oat) << "No image to check oat relocation against.";
- return false;
- }
-
- // Verify the oat_data_begin recorded for the image in the oat file matches
- // the actual oat_data_begin for boot.oat in the image.
- const OatHeader& oat_header = file.GetOatHeader();
- uintptr_t oat_data_begin = oat_header.GetImageFileLocationOatDataBegin();
- if (oat_data_begin != image_info->oat_data_begin) {
- VLOG(oat) << file.GetLocation() <<
- ": Oat file image oat_data_begin (" << oat_data_begin << ")"
- << " does not match actual image oat_data_begin ("
- << image_info->oat_data_begin << ")";
- return false;
- }
+ // Verify the oat_data_begin recorded for the image in the oat file matches
+ // the actual oat_data_begin for boot.oat in the image.
+ const OatHeader& oat_header = file.GetOatHeader();
+ uintptr_t oat_data_begin = oat_header.GetImageFileLocationOatDataBegin();
+ if (oat_data_begin != image_info->oat_data_begin) {
+ VLOG(oat) << file.GetLocation() <<
+ ": Oat file image oat_data_begin (" << oat_data_begin << ")"
+ << " does not match actual image oat_data_begin ("
+ << image_info->oat_data_begin << ")";
+ return false;
+ }
- // Verify the oat_patch_delta recorded for the image in the oat file matches
- // the actual oat_patch_delta for the image.
- int32_t oat_patch_delta = oat_header.GetImagePatchDelta();
- if (oat_patch_delta != image_info->patch_delta) {
- VLOG(oat) << file.GetLocation() <<
- ": Oat file image patch delta (" << oat_patch_delta << ")"
- << " does not match actual image patch delta ("
- << image_info->patch_delta << ")";
- return false;
- }
- } else {
- // Oat files compiled in PIC mode do not require relocation and extract-only
- // oat files do not contain any compiled code. Skip the relocation test.
- VLOG(oat) << "Oat relocation test skipped for PIC oat file";
+ // Verify the oat_patch_delta recorded for the image in the oat file matches
+ // the actual oat_patch_delta for the image.
+ int32_t oat_patch_delta = oat_header.GetImagePatchDelta();
+ if (oat_patch_delta != image_info->patch_delta) {
+ VLOG(oat) << file.GetLocation() <<
+ ": Oat file image patch delta (" << oat_patch_delta << ")"
+ << " does not match actual image patch delta ("
+ << image_info->patch_delta << ")";
+ return false;
}
return true;
}
return true;
}
-bool OatFileAssistant::GenerateOatFile(CompilerFilter::Filter target, std::string* error_msg) {
+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_
args.push_back("--dex-file=" + dex_location_);
args.push_back("--oat-fd=" + std::to_string(oat_file->Fd()));
args.push_back("--oat-location=" + oat_file_name);
- args.push_back("--compiler-filter=" + CompilerFilter::NameOfFilter(target));
if (!Dex2Oat(args, error_msg)) {
// Manually delete the file. This ensures there is no garbage left over if
std::string OatFileAssistant::DalvikCacheDirectory() {
// Note: We don't cache this, because it will only be called once by
- // OatFileName.
+ // OatFileName, and we don't care about the performance of the profiling
+ // code, which isn't used in practice.
// TODO: The work done in GetDalvikCache is overkill for what we need.
// Ideally a new API for getting the DalvikCacheDirectory the way we want
#include "arch/instruction_set.h"
#include "base/scoped_flock.h"
#include "base/unix_file/fd_file.h"
-#include "compiler_filter.h"
#include "oat_file.h"
#include "os.h"
#include "profiler.h"
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.
- //
- // profile_changed should be true if the profile has recently changed
- // for this dex location.
- //
- // load_executable should be true if the caller intends to try and load
- // executable code for this dex location.
OatFileAssistant(const char* dex_location,
+ int target_compilation_type_mask,
const InstructionSet isa,
- bool profile_changed,
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,
+ int target_compilation_type_mask,
const InstructionSet isa,
- bool profile_changed,
bool load_executable);
~OatFileAssistant();
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.
- DexOptNeeded GetDexOptNeeded(CompilerFilter::Filter target_compiler_filter);
+ // dex location.
+ DexOptNeeded GetDexOptNeeded();
// Attempts to generate or relocate the oat file as needed to make it up to
- // date with in a way that is at least as good as an oat file generated with
- // the given compiler filter.
+ // date.
// Returns true on success.
//
// If there is a failure, the value of error_msg will be set to a string
// describing why there was failure. error_msg must not be null.
- bool MakeUpToDate(CompilerFilter::Filter target_compiler_filter, std::string* error_msg);
+ bool MakeUpToDate(std::string* error_msg);
// Returns an oat file that can be used for loading dex files.
// Returns null if no suitable oat file was found.
// describing why there was failure. error_msg must not be null.
bool RelocateOatFile(const std::string* input_file, std::string* error_msg);
- // Generate the oat file from the dex file using the given compiler filter.
+ // Generate the oat file from the dex file.
// This does not check the current status before attempting to generate the
// oat file.
// Returns true on success.
//
// If there is a failure, the value of error_msg will be set to a string
// describing why there was failure. error_msg must not be null.
- bool GenerateOatFile(CompilerFilter::Filter filter, std::string* error_msg);
+ bool GenerateOatFile(std::string* error_msg);
// Executes dex2oat using the current runtime configuration overridden with
// the given arguments. This does not check to see if dex2oat is enabled in
// The caller shouldn't clean up or free the returned pointer.
const OatFile* GetOdexFile();
- // Returns true if the compiler filter used to generate the odex file is at
- // least as good as the given target filter.
- bool OdexFileCompilerFilterIsOkay(CompilerFilter::Filter target);
-
// Returns true if the odex file is opened executable.
bool OdexFileIsExecutable();
// The caller shouldn't clean up or free the returned pointer.
const OatFile* GetOatFile();
- // Returns true if the compiler filter used to generate the oat file is at
- // least as good as the given target filter.
- bool OatFileCompilerFilterIsOkay(CompilerFilter::Filter target);
-
// Returns true if the oat file is opened executable.
bool OatFileIsExecutable();
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;
- // Whether the profile has recently changed.
- bool profile_changed_ = false;
-
// Whether we will attempt to load oat files executable.
bool load_executable_ = false;
// Generate a non-PIC odex file for the purposes of test.
// The generated odex file will be un-relocated.
void GenerateOdexForTest(const std::string& dex_location,
- const std::string& odex_location,
- CompilerFilter::Filter filter) {
+ const std::string& odex_location) {
// To generate an un-relocated odex file, we first compile a relocated
// version of the file, then manually call patchoat to make it look as if
// it is unrelocated.
std::vector<std::string> args;
args.push_back("--dex-file=" + dex_location);
args.push_back("--oat-file=" + relocated_odex_location);
- args.push_back("--compiler-filter=" + CompilerFilter::NameOfFilter(filter));
+ args.push_back("--include-patch-information");
// We need to use the quick compiler to generate non-PIC code, because
// the optimizing compiler always generates PIC.
args.push_back("--compiler-backend=Quick");
- args.push_back("--include-patch-information");
std::string error_msg;
ASSERT_TRUE(OatFileAssistant::Dex2Oat(args, &error_msg)) << error_msg;
dex_location.c_str(),
&error_msg));
ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
- EXPECT_FALSE(odex_file->IsPic());
- EXPECT_EQ(filter, odex_file->GetCompilerFilter());
- if (CompilerFilter::IsCompilationEnabled(filter)) {
- const std::vector<gc::space::ImageSpace*> image_spaces =
+ const std::vector<gc::space::ImageSpace*> image_spaces =
runtime->GetHeap()->GetBootImageSpaces();
- ASSERT_TRUE(!image_spaces.empty() && image_spaces[0] != nullptr);
- const ImageHeader& image_header = image_spaces[0]->GetImageHeader();
- const OatHeader& oat_header = odex_file->GetOatHeader();
- EXPECT_EQ(image_header.GetOatChecksum(), oat_header.GetImageFileLocationOatChecksum());
- EXPECT_NE(reinterpret_cast<uintptr_t>(image_header.GetOatDataBegin()),
- oat_header.GetImageFileLocationOatDataBegin());
- EXPECT_NE(image_header.GetPatchDelta(), oat_header.GetImagePatchDelta());
- }
+ ASSERT_TRUE(!image_spaces.empty() && image_spaces[0] != nullptr);
+ const ImageHeader& image_header = image_spaces[0]->GetImageHeader();
+ const OatHeader& oat_header = odex_file->GetOatHeader();
+ EXPECT_FALSE(odex_file->IsPic());
+ EXPECT_EQ(image_header.GetOatChecksum(), oat_header.GetImageFileLocationOatChecksum());
+ EXPECT_NE(reinterpret_cast<uintptr_t>(image_header.GetOatDataBegin()),
+ oat_header.GetImageFileLocationOatDataBegin());
+ EXPECT_NE(image_header.GetPatchDelta(), oat_header.GetImagePatchDelta());
}
void GeneratePicOdexForTest(const std::string& dex_location,
- const std::string& odex_location,
- CompilerFilter::Filter filter) {
+ const std::string& odex_location) {
// Temporarily redirect the dalvik cache so dex2oat doesn't find the
// relocated image file.
std::string android_data_tmp = GetScratchDir() + "AndroidDataTmp";
std::vector<std::string> args;
args.push_back("--dex-file=" + dex_location);
args.push_back("--oat-file=" + odex_location);
- args.push_back("--compiler-filter=" + CompilerFilter::NameOfFilter(filter));
args.push_back("--compile-pic");
args.push_back("--runtime-arg");
args.push_back("-Xnorelocate");
&error_msg));
ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
EXPECT_TRUE(odex_file->IsPic());
- EXPECT_EQ(filter, odex_file->GetCompilerFilter());
+ }
+
+ void GenerateExtractOnlyOdexForTest(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);
+ args.push_back("--compiler-filter=verify-at-runtime");
+ 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,
+ /*low_4gb*/false,
+ dex_location.c_str(),
+ &error_msg));
+ ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
+ EXPECT_TRUE(odex_file->IsExtractOnly());
+ 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,
+ /*low_4gb*/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:
// Generate an oat file for the purposes of test, as opposed to testing
// generation of oat files.
-static void GenerateOatForTest(const char* dex_location, CompilerFilter::Filter filter) {
- // Use an oat file assistant to find the proper oat location.
- OatFileAssistant ofa(dex_location, kRuntimeISA, false, false);
- const std::string* oat_location = ofa.OatFileName();
- ASSERT_TRUE(oat_location != nullptr);
+static void GenerateOatForTest(const char* dex_location) {
+ OatFileAssistant oat_file_assistant(dex_location,
+ OatFileAssistant::kFullCompilation, kRuntimeISA, false);
- std::vector<std::string> args;
- args.push_back("--dex-file=" + std::string(dex_location));
- args.push_back("--oat-file=" + *oat_location);
- args.push_back("--compiler-filter=" + CompilerFilter::NameOfFilter(filter));
- args.push_back("--runtime-arg");
- args.push_back("-Xnorelocate");
std::string error_msg;
- ASSERT_TRUE(OatFileAssistant::Dex2Oat(args, &error_msg)) << error_msg;
-
- // Verify the oat file was generated as expected.
- std::unique_ptr<OatFile> oat_file(OatFile::Open(oat_location->c_str(),
- oat_location->c_str(),
- nullptr,
- nullptr,
- false,
- /*low_4gb*/false,
- dex_location,
- &error_msg));
- ASSERT_TRUE(oat_file.get() != nullptr) << error_msg;
- EXPECT_EQ(filter, oat_file->GetCompilerFilter());
+ ASSERT_TRUE(oat_file_assistant.GenerateOatFile(&error_msg)) << error_msg;
}
// Case: We have a DEX file, but no OAT file for it.
std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
Copy(GetDexSrc1(), dex_location);
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ OatFileAssistant::kFullCompilation, kRuntimeISA, false);
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly));
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeedProfile));
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
+ EXPECT_EQ(OatFileAssistant::kDex2OatNeeded, oat_file_assistant.GetDexOptNeeded());
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_FALSE(oat_file_assistant.OdexFileExists());
TEST_F(OatFileAssistantTest, NoDexNoOat) {
std::string dex_location = GetScratchDir() + "/NoDexNoOat.jar";
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ OatFileAssistant::kFullCompilation, kRuntimeISA, true);
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
+ EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded());
EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
// Trying to make the oat file up to date should not fail or crash.
std::string error_msg;
- EXPECT_TRUE(oat_file_assistant.MakeUpToDate(CompilerFilter::kSpeed, &error_msg));
+ EXPECT_TRUE(oat_file_assistant.MakeUpToDate(&error_msg));
// Trying to get the best oat file should fail, but not crash.
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
TEST_F(OatFileAssistantTest, OatUpToDate) {
std::string dex_location = GetScratchDir() + "/OatUpToDate.jar";
Copy(GetDexSrc1(), dex_location);
- GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
-
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, false);
-
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly));
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
+ GenerateOatForTest(dex_location.c_str());
- EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_FALSE(oat_file_assistant.OdexFileExists());
- EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
- EXPECT_TRUE(oat_file_assistant.OatFileExists());
- EXPECT_FALSE(oat_file_assistant.OatFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OatFileNeedsRelocation());
- EXPECT_TRUE(oat_file_assistant.OatFileIsUpToDate());
- EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
- EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
-}
-
-// Case: We have a DEX file and speed-profile OAT file for it.
-// Expect: The status is kNoDexOptNeeded if the profile hasn't changed.
-TEST_F(OatFileAssistantTest, ProfileOatUpToDate) {
- std::string dex_location = GetScratchDir() + "/ProfileOatUpToDate.jar";
- Copy(GetDexSrc1(), dex_location);
- GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeedProfile);
-
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, false);
-
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeedProfile));
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly));
+ 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());
EXPECT_FALSE(oat_file_assistant.OdexFileExists());
EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
}
-// Case: We have a DEX file and speed-profile OAT file for it.
-// Expect: The status is kNoDex2OatNeeded if the profile has changed.
-TEST_F(OatFileAssistantTest, ProfileOatOutOfDate) {
- std::string dex_location = GetScratchDir() + "/ProfileOatOutOfDate.jar";
- Copy(GetDexSrc1(), dex_location);
- GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeedProfile);
-
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true, false);
-
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeedProfile));
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly));
-
- EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_FALSE(oat_file_assistant.OdexFileExists());
- EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
- EXPECT_TRUE(oat_file_assistant.OatFileExists());
- EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OatFileNeedsRelocation());
- EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
- EXPECT_EQ(OatFileAssistant::kOatOutOfDate, oat_file_assistant.OatFileStatus());
- EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
-}
-
// Case: We have a MultiDEX file and up-to-date OAT file for it.
// Expect: The status is kNoDexOptNeeded and we load all dex files.
TEST_F(OatFileAssistantTest, MultiDexOatUpToDate) {
std::string dex_location = GetScratchDir() + "/MultiDexOatUpToDate.jar";
Copy(GetMultiDexSrc1(), dex_location);
- GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
+ GenerateOatForTest(dex_location.c_str());
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, true);
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
+ 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());
// Verify we can load both dex files.
// Compile code for GetMultiDexSrc1.
Copy(GetMultiDexSrc1(), dex_location);
- GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
+ GenerateOatForTest(dex_location.c_str());
// Now overwrite the dex file with GetMultiDexSrc2 so the secondary checksum
// is out of date.
Copy(GetMultiDexSrc2(), dex_location);
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, true);
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
+ 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());
}
args.push_back("--dex-file=" + dex_location);
args.push_back("--dex-location=" + std::string("RelativeEncodedDexLocation.jar"));
args.push_back("--oat-file=" + oat_location);
- args.push_back("--compiler-filter=speed");
std::string error_msg;
ASSERT_TRUE(OatFileAssistant::Dex2Oat(args, &error_msg)) << error_msg;
// Verify we can load both dex files.
OatFileAssistant oat_file_assistant(dex_location.c_str(),
oat_location.c_str(),
- kRuntimeISA, false, true);
+ OatFileAssistant::kFullCompilation,
+ kRuntimeISA, true);
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
ASSERT_TRUE(oat_file.get() != nullptr);
EXPECT_TRUE(oat_file->IsExecutable());
// 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);
- GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
+ GenerateOatForTest(dex_location.c_str());
Copy(GetDexSrc2(), dex_location);
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, false);
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
+ 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_FALSE(oat_file_assistant.OdexFileExists());
// Create the dex and odex files
Copy(GetDexSrc1(), dex_location);
- GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
+ GenerateOdexForTest(dex_location, odex_location);
// Verify the status.
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ OatFileAssistant::kFullCompilation, kRuntimeISA, false);
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
- EXPECT_EQ(OatFileAssistant::kPatchOatNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
+ EXPECT_EQ(OatFileAssistant::kPatchOatNeeded, oat_file_assistant.GetDexOptNeeded());
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_TRUE(oat_file_assistant.OdexFileExists());
// Create the dex and odex files
Copy(GetDexSrc1(), dex_location);
- GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
+ GenerateOdexForTest(dex_location, odex_location);
// Strip the dex file
Copy(GetStrippedDexSrc1(), dex_location);
// Verify the status.
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ OatFileAssistant::kFullCompilation, kRuntimeISA, true);
- EXPECT_EQ(OatFileAssistant::kPatchOatNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
+ EXPECT_EQ(OatFileAssistant::kPatchOatNeeded, oat_file_assistant.GetDexOptNeeded());
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_TRUE(oat_file_assistant.OdexFileExists());
// Make the oat file up to date.
std::string error_msg;
- ASSERT_TRUE(oat_file_assistant.MakeUpToDate(CompilerFilter::kSpeed, &error_msg)) << error_msg;
+ ASSERT_TRUE(oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg;
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
+ EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded());
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_TRUE(oat_file_assistant.OdexFileExists());
// Create the oat file from a different dex file so it looks out of date.
Copy(GetDexSrc2(), dex_location);
- GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
+ GenerateOatForTest(dex_location.c_str());
// Create the odex file
Copy(GetDexSrc1(), dex_location);
- GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
+ GenerateOdexForTest(dex_location, odex_location);
// Strip the dex file.
Copy(GetStrippedDexSrc1(), dex_location);
// Verify the status.
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ OatFileAssistant::kFullCompilation, kRuntimeISA, true);
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
- EXPECT_EQ(OatFileAssistant::kPatchOatNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, // Can't run dex2oat because dex file is stripped.
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
+ EXPECT_EQ(OatFileAssistant::kPatchOatNeeded, oat_file_assistant.GetDexOptNeeded());
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_TRUE(oat_file_assistant.OdexFileExists());
// Make the oat file up to date.
std::string error_msg;
- ASSERT_TRUE(oat_file_assistant.MakeUpToDate(CompilerFilter::kSpeed, &error_msg)) << error_msg;
+ ASSERT_TRUE(oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg;
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, // Can't run dex2oat because dex file is stripped.
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
+ EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded());
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_TRUE(oat_file_assistant.OdexFileExists());
Copy(GetStrippedDexSrc1(), dex_location);
// Verify the status.
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ OatFileAssistant::kFullCompilation, kRuntimeISA, true);
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly));
+ EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded());
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_FALSE(oat_file_assistant.OdexFileExists());
// Make the oat file up to date. This should have no effect.
std::string error_msg;
- EXPECT_TRUE(oat_file_assistant.MakeUpToDate(CompilerFilter::kSpeed, &error_msg)) << error_msg;
+ EXPECT_TRUE(oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg;
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
+ EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded());
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_FALSE(oat_file_assistant.OdexFileExists());
// Create the dex and odex files
Copy(GetDexSrc1(), dex_location);
- GenerateOdexForTest(dex_location, oat_location, CompilerFilter::kSpeed);
+ GenerateOdexForTest(dex_location, oat_location);
OatFileAssistant oat_file_assistant(dex_location.c_str(),
- oat_location.c_str(), kRuntimeISA, false, true);
+ oat_location.c_str(), OatFileAssistant::kFullCompilation, kRuntimeISA, true);
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly));
- EXPECT_EQ(OatFileAssistant::kSelfPatchOatNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
+ EXPECT_EQ(OatFileAssistant::kSelfPatchOatNeeded, oat_file_assistant.GetDexOptNeeded());
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_FALSE(oat_file_assistant.OdexFileExists());
// Make the oat file up to date.
std::string error_msg;
- ASSERT_TRUE(oat_file_assistant.MakeUpToDate(CompilerFilter::kSpeed, &error_msg)) << error_msg;
+ ASSERT_TRUE(oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg;
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
+ EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded());
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_FALSE(oat_file_assistant.OdexFileExists());
// Create the dex and odex files
Copy(GetDexSrc1(), dex_location);
- GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
+ GenerateOdexForTest(dex_location, odex_location);
// Create the oat file by copying the odex so they are located in the same
// place in memory.
// Verify things don't go bad.
OatFileAssistant oat_file_assistant(dex_location.c_str(),
- oat_location.c_str(), kRuntimeISA, false, true);
+ oat_location.c_str(), OatFileAssistant::kFullCompilation, kRuntimeISA, true);
- EXPECT_EQ(OatFileAssistant::kPatchOatNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
+ EXPECT_EQ(OatFileAssistant::kPatchOatNeeded, oat_file_assistant.GetDexOptNeeded());
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_TRUE(oat_file_assistant.OdexFileExists());
// Create the dex and odex files
Copy(GetDexSrc1(), dex_location);
- GeneratePicOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
+ GeneratePicOdexForTest(dex_location, odex_location);
// Verify the status.
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ OatFileAssistant::kFullCompilation, kRuntimeISA, false);
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
+ EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded());
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_TRUE(oat_file_assistant.OdexFileExists());
EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
}
-// Case: We have a DEX file and a VerifyAtRuntime ODEX file, but no OAT file.
-// Expect: The status is kNoDexOptNeeded, because VerifyAtRuntime contains no code.
-TEST_F(OatFileAssistantTest, DexVerifyAtRuntimeOdexNoOat) {
- std::string dex_location = GetScratchDir() + "/DexVerifyAtRuntimeOdexNoOat.jar";
- std::string odex_location = GetOdexDir() + "/DexVerifyAtRuntimeOdexNoOat.odex";
+// Case: We have a DEX file and a ExtractOnly ODEX file, but no OAT file.
+// Expect: The status is kNoDexOptNeeded, because ExtractOnly contains no code.
+TEST_F(OatFileAssistantTest, DexExtractOnlyOdexNoOat) {
+ std::string dex_location = GetScratchDir() + "/DexExtractOnlyOdexNoOat.jar";
+ std::string odex_location = GetOdexDir() + "/DexExtractOnlyOdexNoOat.odex";
// Create the dex and odex files
Copy(GetDexSrc1(), dex_location);
- GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kVerifyAtRuntime);
+ GenerateExtractOnlyOdexForTest(dex_location, odex_location);
// Verify the status.
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ OatFileAssistant::kFullCompilation | OatFileAssistant::kExtractOnly,
+ kRuntimeISA, false);
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
+ EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded());
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_TRUE(oat_file_assistant.OdexFileExists());
EXPECT_FALSE(oat_file_assistant.OdexFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
+ EXPECT_TRUE(oat_file_assistant.OdexFileIsUpToDate());
EXPECT_FALSE(oat_file_assistant.OatFileExists());
EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
std::string dex_location = GetScratchDir() + "/LoadOatUpToDate.jar";
Copy(GetDexSrc1(), dex_location);
- GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
+ GenerateOatForTest(dex_location.c_str());
// Load the oat using an oat file assistant.
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, 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);
EXPECT_EQ(1u, dex_files.size());
}
-// Case: We have a DEX file and up-to-date non-executable OAT file for it.
-// Expect: We should load a non-executable dex file.
-TEST_F(OatFileAssistantTest, LoadNonExecOatUpToDate) {
- std::string dex_location = GetScratchDir() + "/LoadNonExecOatUpToDate.jar";
-
- Copy(GetDexSrc1(), dex_location);
- GenerateOatForTest(dex_location.c_str(), CompilerFilter::kInterpretOnly);
-
- // Load the oat using an oat file assistant.
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, true);
-
- std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
- ASSERT_TRUE(oat_file.get() != nullptr);
- EXPECT_FALSE(oat_file->IsExecutable());
- std::vector<std::unique_ptr<const DexFile>> dex_files;
- dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
- EXPECT_EQ(1u, dex_files.size());
-}
-
// Case: We have a DEX file and up-to-date OAT file for it.
// Expect: Loading non-executable should load the oat non-executable.
TEST_F(OatFileAssistantTest, LoadNoExecOatUpToDate) {
std::string dex_location = GetScratchDir() + "/LoadNoExecOatUpToDate.jar";
Copy(GetDexSrc1(), dex_location);
- GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
+ GenerateOatForTest(dex_location.c_str());
// Load the oat using an oat file assistant.
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, 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, false, true);
+ dex_location.c_str(), oat_location.c_str(),
+ OatFileAssistant::kFullCompilation, kRuntimeISA, true);
std::string error_msg;
- ASSERT_TRUE(oat_file_assistant.MakeUpToDate(CompilerFilter::kSpeed, &error_msg)) << error_msg;
+ ASSERT_TRUE(oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg;
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
ASSERT_TRUE(oat_file.get() != nullptr);
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, 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, false, true);
+ dex_location.c_str(), oat_location.c_str(),
+ OatFileAssistant::kFullCompilation, kRuntimeISA, true);
std::string error_msg;
- ASSERT_FALSE(oat_file_assistant.MakeUpToDate(CompilerFilter::kSpeed, &error_msg));
+ ASSERT_FALSE(oat_file_assistant.MakeUpToDate(&error_msg));
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
ASSERT_TRUE(oat_file.get() == nullptr);
std::string oat_location = GetScratchDir() + "/GenNoDex.oat";
OatFileAssistant oat_file_assistant(
- dex_location.c_str(), oat_location.c_str(), kRuntimeISA, false, true);
+ dex_location.c_str(), oat_location.c_str(),
+ OatFileAssistant::kFullCompilation, kRuntimeISA, true);
std::string error_msg;
- ASSERT_FALSE(oat_file_assistant.GenerateOatFile(CompilerFilter::kSpeed, &error_msg));
+ ASSERT_FALSE(oat_file_assistant.GenerateOatFile(&error_msg));
}
// Turn an absolute path into a path relative to the current working
Copy(GetDexSrc1(), abs_dex_location);
std::string dex_location = MakePathRelative(abs_dex_location);
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, 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(CompilerFilter::kSpeed));
+ EXPECT_EQ(OatFileAssistant::kDex2OatNeeded, oat_file_assistant.GetDexOptNeeded());
EXPECT_FALSE(oat_file_assistant.OdexFileExists());
EXPECT_FALSE(oat_file_assistant.OatFileExists());
EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
TEST_F(OatFileAssistantTest, ShortDexLocation) {
std::string dex_location = "/xx";
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, 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(CompilerFilter::kSpeed));
+ EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded());
EXPECT_FALSE(oat_file_assistant.OdexFileExists());
EXPECT_FALSE(oat_file_assistant.OatFileExists());
EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
// Trying to make it up to date should have no effect.
std::string error_msg;
- EXPECT_TRUE(oat_file_assistant.MakeUpToDate(CompilerFilter::kSpeed, &error_msg));
+ EXPECT_TRUE(oat_file_assistant.MakeUpToDate(&error_msg));
EXPECT_TRUE(error_msg.empty());
}
std::string dex_location = GetScratchDir() + "/LongDexExtension.jarx";
Copy(GetDexSrc1(), dex_location);
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ OatFileAssistant::kFullCompilation, kRuntimeISA, false);
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
+ EXPECT_EQ(OatFileAssistant::kDex2OatNeeded, oat_file_assistant.GetDexOptNeeded());
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_FALSE(oat_file_assistant.OdexFileExists());
// Create the dex and odex files
Copy(GetDexSrc1(), dex_location);
- GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
+ GenerateOdexForTest(dex_location, odex_location);
// Load the oat using an executable oat file assistant.
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, 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);
// Create the dex and odex files
Copy(GetMultiDexSrc1(), dex_location);
- GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
+ GenerateOdexForTest(dex_location, odex_location);
// Load the oat using an executable oat file assistant.
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, 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:
-// * Image checksum change is out of date for kIntepretOnly, but not
-// kVerifyAtRuntime. But target of kVerifyAtRuntime still says current
-// kInterpretOnly is out of date.
// * Test class linker falls back to unquickened dex for DexNoOat
// * Test class linker falls back to unquickened dex for MultiDexNoOat
// * Test using secondary isa
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,
- /*profile_changed*/false,
!runtime->IsAotCompiler());
// Lock the target oat location to avoid races generating and loading the
// Update the oat file on disk if we can. This may fail, but that's okay.
// Best effort is all that matters here.
- if (!oat_file_assistant.MakeUpToDate(CompilerFilter::kSpeed, /*out*/ &error_msg)) {
+ if (!oat_file_assistant.MakeUpToDate(/*out*/&error_msg)) {
LOG(INFO) << error_msg;
}
if (ContainsElement(boot_oat_files, oat_file.get())) {
continue;
}
- os << oat_file->GetLocation() << ": " << oat_file->GetCompilerFilter() << "\n";
+ // Use "platform-default" if it's neither extract nor profile guided.
+ // Saying 'full' could be misleading if for example the platform uses
+ // compiler filters.
+ const char* status = oat_file->IsExtractOnly()
+ ? OatHeader::kExtractOnlyValue
+ : oat_file->IsProfileGuideCompiled()
+ ? OatHeader::kProfileGuideCompiledValue
+ : "platform-default";
+ os << oat_file->GetLocation() << ": " << status << "\n";
}
}
}
const OatFile* oat_file = oat_dex_file->GetOatFile();
- return !oat_file->IsPic()
- && CompilerFilter::IsCompilationEnabled(oat_file->GetCompilerFilter());
+ return !oat_file->IsPic() && !oat_file->IsExtractOnly();
}
};