summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Richard Uhler <ruhler@google.com> 2016-03-18 15:05:30 -0700
committer Richard Uhler <ruhler@google.com> 2016-03-22 15:38:36 -0700
commita62d2f04a6ecf804f8a78e722a6ca8ccb2dfa931 (patch)
treed8624bb85016a3301b473b6503324db4d4cf24a3
parent48e722432bb6e19df7bba02427e4a707e671af06 (diff)
Use compiler filter to determine oat file status.
Record the compiler filter in the oat header. Use that to determine when the oat file is up-to-date with respect to a target compiler filter level. New xxx-profile filter levels are added to specify if a profile should be used instead of testing for the presence of a profile file. This change should allow for different compiler-filters to be set for different package manager use cases. Bug: 27689078 Change-Id: Id6706d0ed91b45f307142692ea4316aa9713b023
-rw-r--r--build/Android.gtest.mk1
-rw-r--r--compiler/dex/verification_results.cc2
-rw-r--r--compiler/driver/compiler_options.cc22
-rw-r--r--compiler/driver/compiler_options.h42
-rw-r--r--compiler/optimizing/builder.cc4
-rw-r--r--compiler/optimizing/optimizing_compiler.cc2
-rw-r--r--dex2oat/dex2oat.cc42
-rw-r--r--runtime/Android.mk1
-rw-r--r--runtime/common_runtime_test.cc2
-rw-r--r--runtime/compiler_filter.cc145
-rw-r--r--runtime/compiler_filter.h88
-rw-r--r--runtime/compiler_filter_test.cc52
-rw-r--r--runtime/native/dalvik_system_DexFile.cc31
-rw-r--r--runtime/oat.cc19
-rw-r--r--runtime/oat.h10
-rw-r--r--runtime/oat_file.cc8
-rw-r--r--runtime/oat_file.h4
-rw-r--r--runtime/oat_file_assistant.cc230
-rw-r--r--runtime/oat_file_assistant.h58
-rw-r--r--runtime/oat_file_assistant_test.cc479
-rw-r--r--runtime/oat_file_manager.cc17
-rw-r--r--test/117-nopatchoat/nopatchoat.cc3
22 files changed, 778 insertions, 484 deletions
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 426c3cac64..f67da3ff4c 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -186,6 +186,7 @@ RUNTIME_GTEST_COMMON_SRC_FILES := \
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 \
diff --git a/compiler/dex/verification_results.cc b/compiler/dex/verification_results.cc
index dd24220e0e..7c9ce1ee60 100644
--- a/compiler/dex/verification_results.cc
+++ b/compiler/dex/verification_results.cc
@@ -109,7 +109,7 @@ bool VerificationResults::IsCandidateForCompilation(MethodReference&,
return false;
}
// Don't compile class initializers unless kEverything.
- if ((compiler_options_->GetCompilerFilter() != CompilerOptions::kEverything) &&
+ if ((compiler_options_->GetCompilerFilter() != CompilerFilter::kEverything) &&
((access_flags & kAccConstructor) != 0) && ((access_flags & kAccStatic) != 0)) {
return false;
}
diff --git a/compiler/driver/compiler_options.cc b/compiler/driver/compiler_options.cc
index f5969aa825..1bd4c3ad80 100644
--- a/compiler/driver/compiler_options.cc
+++ b/compiler/driver/compiler_options.cc
@@ -52,7 +52,7 @@ CompilerOptions::~CompilerOptions() {
// because we don't want to include the PassManagerOptions definition from the header file.
}
-CompilerOptions::CompilerOptions(CompilerFilter compiler_filter,
+CompilerOptions::CompilerOptions(CompilerFilter::Filter compiler_filter,
size_t huge_method_threshold,
size_t large_method_threshold,
size_t small_method_threshold,
@@ -147,25 +147,7 @@ void CompilerOptions::ParseDumpInitFailures(const StringPiece& option,
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 (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 {
+ if (!CompilerFilter::ParseCompilerFilter(compiler_filter_string, &compiler_filter_)) {
Usage("Unknown --compiler-filter value %s", compiler_filter_string);
}
} else if (option == "--compile-pic") {
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index 11a4e06313..c67ab6ef14 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -22,6 +22,7 @@
#include <vector>
#include "base/macros.h"
+#include "compiler_filter.h"
#include "globals.h"
#include "utils.h"
@@ -29,20 +30,8 @@ namespace art {
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 kDefaultCompilerFilter = kSpeed;
+ static const CompilerFilter::Filter kDefaultCompilerFilter = CompilerFilter::kSpeed;
static const size_t kDefaultHugeMethodThreshold = 10000;
static const size_t kDefaultLargeMethodThreshold = 600;
static const size_t kDefaultSmallMethodThreshold = 60;
@@ -64,7 +53,7 @@ class CompilerOptions FINAL {
CompilerOptions();
~CompilerOptions();
- CompilerOptions(CompilerFilter compiler_filter,
+ CompilerOptions(CompilerFilter::Filter compiler_filter,
size_t huge_method_threshold,
size_t large_method_threshold,
size_t small_method_threshold,
@@ -88,40 +77,32 @@ class CompilerOptions FINAL {
bool dump_cfg_append,
bool force_determinism);
- CompilerFilter GetCompilerFilter() const {
+ CompilerFilter::Filter GetCompilerFilter() const {
return compiler_filter_;
}
- void SetCompilerFilter(CompilerFilter compiler_filter) {
+ void SetCompilerFilter(CompilerFilter::Filter compiler_filter) {
compiler_filter_ = compiler_filter;
}
bool VerifyAtRuntime() const {
- return compiler_filter_ == CompilerOptions::kVerifyAtRuntime;
+ return compiler_filter_ == CompilerFilter::kVerifyAtRuntime;
}
bool IsCompilationEnabled() const {
- return compiler_filter_ != CompilerOptions::kVerifyNone &&
- compiler_filter_ != CompilerOptions::kInterpretOnly &&
- compiler_filter_ != CompilerOptions::kVerifyAtRuntime &&
- compiler_filter_ != CompilerOptions::kVerifyProfile;
+ return CompilerFilter::IsCompilationEnabled(compiler_filter_);
}
bool IsVerificationEnabled() const {
- return compiler_filter_ != CompilerOptions::kVerifyNone &&
- compiler_filter_ != CompilerOptions::kVerifyAtRuntime;
+ return CompilerFilter::IsVerificationEnabled(compiler_filter_);
}
bool NeverVerify() const {
- return compiler_filter_ == CompilerOptions::kVerifyNone;
- }
-
- bool IsExtractOnly() const {
- return compiler_filter_ == CompilerOptions::kVerifyAtRuntime;
+ return compiler_filter_ == CompilerFilter::kVerifyNone;
}
bool VerifyOnlyProfile() const {
- return compiler_filter_ == CompilerOptions::kVerifyProfile;
+ return compiler_filter_ == CompilerFilter::kVerifyProfile;
}
size_t GetHugeMethodThreshold() const {
@@ -271,7 +252,7 @@ class CompilerOptions FINAL {
void ParseLargeMethodMax(const StringPiece& option, UsageFn Usage);
void ParseHugeMethodMax(const StringPiece& option, UsageFn Usage);
- CompilerFilter compiler_filter_;
+ CompilerFilter::Filter compiler_filter_;
size_t huge_method_threshold_;
size_t large_method_threshold_;
size_t small_method_threshold_;
@@ -317,7 +298,6 @@ class CompilerOptions FINAL {
DISALLOW_COPY_AND_ASSIGN(CompilerOptions);
};
-std::ostream& operator<<(std::ostream& os, const CompilerOptions::CompilerFilter& rhs);
} // namespace art
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index 124afbc73b..082d15961a 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -145,8 +145,8 @@ void HGraphBuilder::MaybeRecordStat(MethodCompilationStat compilation_stat) {
bool HGraphBuilder::SkipCompilation(const DexFile::CodeItem& code_item,
size_t number_of_branches) {
const CompilerOptions& compiler_options = compiler_driver_->GetCompilerOptions();
- CompilerOptions::CompilerFilter compiler_filter = compiler_options.GetCompilerFilter();
- if (compiler_filter == CompilerOptions::kEverything) {
+ CompilerFilter::Filter compiler_filter = compiler_options.GetCompilerFilter();
+ if (compiler_filter == CompilerFilter::kEverything) {
return false;
}
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index f1c5581c5b..125c00d275 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -655,7 +655,7 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* arena,
// code units is bigger than 128.
static constexpr size_t kSpaceFilterOptimizingThreshold = 128;
const CompilerOptions& compiler_options = compiler_driver->GetCompilerOptions();
- if ((compiler_options.GetCompilerFilter() == CompilerOptions::kSpace)
+ if ((compiler_options.GetCompilerFilter() == CompilerFilter::kSpace)
&& (code_item->insns_size_in_code_units_ > kSpaceFilterOptimizingThreshold)) {
MaybeRecordStat(MethodCompilationStat::kNotCompiledSpaceFilter);
return nullptr;
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index ede0bdad6a..ec6f96f599 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -257,11 +257,14 @@ NO_RETURN static void Usage(const char* fmt, ...) {
"|verify-at-runtime"
"|verify-profile"
"|interpret-only"
+ "|time"
+ "|space-profile"
"|space"
"|balanced"
+ "|speed-profile"
"|speed"
- "|everything"
- "|time):");
+ "|everything-profile"
+ "|everything):");
UsageError(" select compiler filter.");
UsageError(" verify-profile requires a --profile(-fd) to also be passed in.");
UsageError(" Example: --compiler-filter=everything");
@@ -798,10 +801,6 @@ class Dex2Oat FINAL {
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);
}
@@ -834,14 +833,14 @@ class Dex2Oat FINAL {
// time here, which is orthogonal to space.
if (compiler_options_->inline_depth_limit_ == CompilerOptions::kUnsetInlineDepthLimit) {
compiler_options_->inline_depth_limit_ =
- (compiler_options_->compiler_filter_ == CompilerOptions::kSpace)
+ (compiler_options_->compiler_filter_ == CompilerFilter::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_ == CompilerOptions::kSpace)
+ (compiler_options_->compiler_filter_ == CompilerFilter::kSpace)
// Implementation of the space filter: limit inlining max code units.
? CompilerOptions::kSpaceFilterInlineMaxCodeUnits
: CompilerOptions::kDefaultInlineMaxCodeUnits;
@@ -1029,11 +1028,8 @@ class Dex2Oat FINAL {
key_value_store_->Put(
OatHeader::kNativeDebuggableKey,
compiler_options_->GetNativeDebuggable() ? 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);
- }
+ key_value_store_->Put(OatHeader::kCompilerFilter,
+ CompilerFilter::NameOfFilter(compiler_options_->GetCompilerFilter()));
}
// Parse the arguments from the command line. In case of an unrecognized option or impossible
@@ -1322,13 +1318,7 @@ class Dex2Oat FINAL {
return false;
}
- 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 {
+ if (CompilerFilter::DependsOnImageChecksum(compiler_options_->GetCompilerFilter())) {
TimingLogger::ScopedTiming t3("Loading image checksum", timings_);
std::vector<gc::space::ImageSpace*> image_spaces =
Runtime::Current()->GetHeap()->GetBootImageSpaces();
@@ -1345,6 +1335,10 @@ class Dex2Oat FINAL {
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.
@@ -1456,7 +1450,7 @@ class Dex2Oat FINAL {
num_methods += dex_file->NumMethodIds();
}
if (num_methods <= compiler_options_->GetNumDexMethodsThreshold()) {
- compiler_options_->SetCompilerFilter(CompilerOptions::kSpeed);
+ compiler_options_->SetCompilerFilter(CompilerFilter::kSpeed);
VLOG(compiler) << "Below method threshold, compiling anyways";
}
}
@@ -1857,7 +1851,7 @@ class Dex2Oat FINAL {
}
bool UseProfileGuidedCompilation() const {
- return !profile_file_.empty() || (profile_file_fd_ != kInvalidFd);
+ return CompilerFilter::DependsOnProfile(compiler_options_->GetCompilerFilter());
}
bool LoadProfile() {
@@ -1865,7 +1859,7 @@ class Dex2Oat FINAL {
profile_compilation_info_.reset(new ProfileCompilationInfo());
ScopedFlock flock;
- bool success = false;
+ bool success = true;
std::string error;
if (profile_file_fd_ != -1) {
// The file doesn't need to be flushed so don't check the usage.
@@ -1874,7 +1868,7 @@ class Dex2Oat FINAL {
if (flock.Init(&file, &error)) {
success = profile_compilation_info_->Load(profile_file_fd_);
}
- } else {
+ } else if (profile_file_ != "") {
if (flock.Init(profile_file_.c_str(), O_RDONLY, /* block */ true, &error)) {
success = profile_compilation_info_->Load(flock.GetFile()->Fd());
}
diff --git a/runtime/Android.mk b/runtime/Android.mk
index fc96acf4b0..0c6541ebe0 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -44,6 +44,7 @@ LIBART_COMMON_SRC_FILES := \
class_table.cc \
code_simulator_container.cc \
common_throws.cc \
+ compiler_filter.cc \
debugger.cc \
dex_file.cc \
dex_file_verifier.cc \
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index 729957f318..f58af5a8da 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -72,7 +72,7 @@ ScratchFile::ScratchFile() {
filename_ = getenv("ANDROID_DATA");
filename_ += "/TmpFile-XXXXXX";
int fd = mkstemp(&filename_[0]);
- CHECK_NE(-1, fd);
+ CHECK_NE(-1, fd) << strerror(errno) << " for " << filename_;
file_.reset(new File(fd, GetFilename(), true));
}
diff --git a/runtime/compiler_filter.cc b/runtime/compiler_filter.cc
new file mode 100644
index 0000000000..31a1bc10fa
--- /dev/null
+++ b/runtime/compiler_filter.cc
@@ -0,0 +1,145 @@
+/*
+ * 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
diff --git a/runtime/compiler_filter.h b/runtime/compiler_filter.h
new file mode 100644
index 0000000000..1bea8b4f56
--- /dev/null
+++ b/runtime/compiler_filter.h
@@ -0,0 +1,88 @@
+/*
+ * 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_
diff --git a/runtime/compiler_filter_test.cc b/runtime/compiler_filter_test.cc
new file mode 100644
index 0000000000..c603be6e52
--- /dev/null
+++ b/runtime/compiler_filter_test.cc
@@ -0,0 +1,52 @@
+/*
+ * 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
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index f1e0fa7b57..3397989fdc 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -348,7 +348,8 @@ static jobjectArray DexFile_getClassNameList(JNIEnv* env, jclass, jobject cookie
static jint GetDexOptNeeded(JNIEnv* env,
const char* filename,
const char* instruction_set,
- const int target_compilation_type_mask) {
+ const char* compiler_filter_name,
+ bool profile_changed) {
if ((filename == nullptr) || !OS::FileExists(filename)) {
LOG(ERROR) << "DexFile_getDexOptNeeded file '" << filename << "' does not exist";
ScopedLocalRef<jclass> fnfe(env, env->FindClass("java/io/FileNotFoundException"));
@@ -365,17 +366,24 @@ static jint GetDexOptNeeded(JNIEnv* env,
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_compilation_type_mask,
- target_instruction_set, false);
+
+ OatFileAssistant oat_file_assistant(filename, target_instruction_set, profile_changed, false);
// Always treat elements of the bootclasspath as up-to-date.
if (oat_file_assistant.IsInBootClassPath()) {
return OatFileAssistant::kNoDexOptNeeded;
}
-
- return oat_file_assistant.GetDexOptNeeded();
+ return oat_file_assistant.GetDexOptNeeded(filter);
}
static jint DexFile_getDexOptNeeded(JNIEnv* env,
@@ -393,10 +401,18 @@ 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(),
- javaTargetCompilationTypeMask);
+ compiler_filter,
+ /*profile_changed*/false);
}
// public API
@@ -407,7 +423,8 @@ static jboolean DexFile_isDexOptNeeded(JNIEnv* env, jclass, jstring javaFilename
env,
filename.c_str(),
instruction_set,
- OatFileAssistant::kFullCompilation | OatFileAssistant::kProfileGuideCompilation);
+ "speed-profile",
+ /*profile_changed*/false);
return (status != OatFileAssistant::kNoDexOptNeeded) ? JNI_TRUE : JNI_FALSE;
}
diff --git a/runtime/oat.cc b/runtime/oat.cc
index ed99cbabbd..d13999a835 100644
--- a/runtime/oat.cc
+++ b/runtime/oat.cc
@@ -29,8 +29,6 @@ constexpr uint8_t OatHeader::kOatMagic[4];
constexpr uint8_t OatHeader::kOatVersion[4];
constexpr const char OatHeader::kTrueValue[];
constexpr const char OatHeader::kFalseValue[];
-constexpr const char OatHeader::kExtractOnlyValue[];
-constexpr const char OatHeader::kProfileGuideCompiledValue[];
static size_t ComputeOatHeaderSize(const SafeMap<std::string, std::string>* variable_data) {
size_t estimate = 0U;
@@ -472,16 +470,13 @@ bool OatHeader::IsNativeDebuggable() const {
return IsKeyEnabled(OatHeader::kNativeDebuggableKey);
}
-bool OatHeader::IsExtractOnly() const {
- return KeyHasValue(kCompilationType,
- kExtractOnlyValue,
- sizeof(kExtractOnlyValue));
-}
-
-bool OatHeader::IsProfileGuideCompiled() const {
- return KeyHasValue(kCompilationType,
- kProfileGuideCompiledValue,
- sizeof(kProfileGuideCompiledValue));
+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::KeyHasValue(const char* key, const char* value, size_t value_size) const {
diff --git a/runtime/oat.h b/runtime/oat.h
index 1d6c076c1b..0dcc52e513 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -21,6 +21,7 @@
#include "arch/instruction_set.h"
#include "base/macros.h"
+#include "compiler_filter.h"
#include "dex_file.h"
#include "safe_map.h"
@@ -31,7 +32,7 @@ class InstructionSetFeatures;
class PACKED(4) OatHeader {
public:
static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' };
- static constexpr uint8_t kOatVersion[] = { '0', '7', '5', '\0' };
+ static constexpr uint8_t kOatVersion[] = { '0', '7', '6', '\0' };
static constexpr const char* kImageLocationKey = "image-location";
static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
@@ -39,14 +40,12 @@ class PACKED(4) OatHeader {
static constexpr const char* kPicKey = "pic";
static constexpr const char* kDebuggableKey = "debuggable";
static constexpr const char* kNativeDebuggableKey = "native-debuggable";
- static constexpr const char* kCompilationType = "compilation-type";
+ static constexpr const char* kCompilerFilter = "compiler-filter";
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,
@@ -112,8 +111,7 @@ class PACKED(4) OatHeader {
bool IsPic() const;
bool IsDebuggable() const;
bool IsNativeDebuggable() const;
- bool IsExtractOnly() const;
- bool IsProfileGuideCompiled() const;
+ CompilerFilter::Filter GetCompilerFilter() const;
private:
bool KeyHasValue(const char* key, const char* value, size_t value_size) const;
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 033ea563b4..9ae033f228 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -1257,12 +1257,8 @@ bool OatFile::IsDebuggable() const {
return GetOatHeader().IsDebuggable();
}
-bool OatFile::IsExtractOnly() const {
- return GetOatHeader().IsExtractOnly();
-}
-
-bool OatFile::IsProfileGuideCompiled() const {
- return GetOatHeader().IsProfileGuideCompiled();
+CompilerFilter::Filter OatFile::GetCompilerFilter() const {
+ return GetOatHeader().GetCompilerFilter();
}
static constexpr char kDexClassPathEncodingSeparator = '*';
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 7af77aee8f..21aeab4c7a 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -92,9 +92,7 @@ class OatFile {
// Indicates whether the oat file was compiled with full debugging capability.
bool IsDebuggable() const;
- bool IsExtractOnly() const;
-
- bool IsProfileGuideCompiled() const;
+ CompilerFilter::Filter GetCompilerFilter() const;
const std::string& GetLocation() const {
return location_;
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index cbc0ec6d28..67c8e65b28 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -44,19 +44,18 @@
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, target_compilation_type_mask, isa, load_executable)
+ : OatFileAssistant(dex_location, nullptr, isa, profile_changed, 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)
- : target_compilation_type_mask_(target_compilation_type_mask), isa_(isa),
- load_executable_(load_executable) {
+ : isa_(isa), profile_changed_(profile_changed), load_executable_(load_executable) {
CHECK(dex_location != nullptr) << "OatFileAssistant: null dex location";
dex_location_.assign(dex_location);
@@ -116,42 +115,78 @@ bool OatFileAssistant::Lock(std::string* error_msg) {
return true;
}
-// 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;
+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;
}
-OatFileAssistant::DexOptNeeded OatFileAssistant::GetDexOptNeeded() {
- if (OatFileIsUpToDate() || OdexFileIsUpToDate()) {
- return kNoDexOptNeeded;
+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;
+ }
+ }
}
- if (OdexFileNeedsRelocation()) {
- return kPatchOatNeeded;
+ // 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 (OatFileNeedsRelocation()) {
- return kSelfPatchOatNeeded;
+ // 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;
+ }
}
+ // We can only run dex2oat if there are original dex files.
return HasOriginalDexFiles() ? kDex2OatNeeded : kNoDexOptNeeded;
}
-bool OatFileAssistant::MakeUpToDate(std::string* error_msg) {
- switch (GetDexOptNeeded()) {
+bool OatFileAssistant::MakeUpToDate(CompilerFilter::Filter target, std::string* error_msg) {
+ switch (GetDexOptNeeded(target)) {
case kNoDexOptNeeded: return true;
- case kDex2OatNeeded: return GenerateOatFile(error_msg);
+ case kDex2OatNeeded: return GenerateOatFile(target, error_msg);
case kPatchOatNeeded: return RelocateOatFile(OdexFileName(), error_msg);
case kSelfPatchOatNeeded: return RelocateOatFile(OatFileName(), error_msg);
}
@@ -410,11 +445,6 @@ OatFileAssistant::OatStatus OatFileAssistant::GivenOatFileStatus(const OatFile&
}
bool OatFileAssistant::GivenOatFileIsOutOfDate(const OatFile& file) {
- // Verify the file satisfies the desired compilation type.
- if ((target_compilation_type_mask_ & GetCompilationType(file)) == 0) {
- return true;
- }
-
// Verify the dex checksum.
// Note: GetOatDexFile will return null if the dex checksum doesn't match
// what we provide, which verifies the primary dex checksum for us.
@@ -457,36 +487,38 @@ bool OatFileAssistant::GivenOatFileIsOutOfDate(const OatFile& file) {
}
}
- 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;
- }
+ CompilerFilter::Filter current_compiler_filter = file.GetCompilerFilter();
+ VLOG(oat) << "Compiler filter for " << file.GetLocation() << " is " << 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;
+ 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.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;
}
- if (file.GetOatHeader().GetImageFileLocationOatChecksum() != image_info->oat_checksum) {
- VLOG(oat) << "Oat image checksum does not match image checksum.";
- 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;
}
- // The checksums are all good; the dex file is not out of date.
+ // Everything looks good; the dex file is not out of date.
return false;
}
@@ -499,40 +531,49 @@ bool OatFileAssistant::GivenOatFileIsUpToDate(const OatFile& file) {
return false;
}
- 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;
- }
+ CompilerFilter::Filter current_compiler_filter = file.GetCompilerFilter();
- const ImageInfo* image_info = GetImageInfo();
- if (image_info == nullptr) {
- VLOG(oat) << "No image to check oat relocation against.";
+ // 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;
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;
- }
+ 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_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;
+ // 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";
}
return true;
}
@@ -589,18 +630,9 @@ bool OatFileAssistant::RelocateOatFile(const std::string* input_file,
return true;
}
-bool OatFileAssistant::GenerateOatFile(std::string* error_msg) {
+bool OatFileAssistant::GenerateOatFile(CompilerFilter::Filter target, 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_
@@ -642,6 +674,7 @@ bool OatFileAssistant::GenerateOatFile(std::string* error_msg) {
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
@@ -751,8 +784,7 @@ bool OatFileAssistant::DexFilenameToOdexFilename(const std::string& location,
std::string OatFileAssistant::DalvikCacheDirectory() {
// Note: We don't cache this, because it will only be called once by
- // OatFileName, and we don't care about the performance of the profiling
- // code, which isn't used in practice.
+ // OatFileName.
// TODO: The work done in GetDalvikCache is overkill for what we need.
// Ideally a new API for getting the DalvikCacheDirectory the way we want
diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h
index 893aea2ab9..452cd84728 100644
--- a/runtime/oat_file_assistant.h
+++ b/runtime/oat_file_assistant.h
@@ -24,6 +24,7 @@
#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"
@@ -85,20 +86,6 @@ class OatFileAssistant {
kOatUpToDate,
};
- // Represents the different compilation types of oat files that OatFileAssitant
- // and external GetDexOptNeeded callers care about.
- // Note: these should be able to be used as part of a mask.
- enum CompilationType {
- // Matches Java: dalvik.system.DexFile.COMPILATION_TYPE_FULL = 1
- kFullCompilation = 1,
-
- // Matches Java: dalvik.system.DexFile.COMPILATION_TYPE_PROFILE_GUIDE = 2
- kProfileGuideCompilation = 2,
-
- // Matches Java: dalvik.system.DexFile.COMPILATION_TYPE_EXTRACT_ONLY = 4
- kExtractOnly = 4,
- };
-
// Constructs an OatFileAssistant object to assist the oat file
// corresponding to the given dex location with the target instruction set.
//
@@ -110,27 +97,26 @@ class OatFileAssistant {
// Note: Currently the dex_location must have an extension.
// TODO: Relax this restriction?
//
- // The target compilation type specifies a set of CompilationTypes that
- // should be considered up to date. An oat file compiled in a way not
- // included in the set is considered out of date. For example, to consider
- // otherwise up-to-date fully compiled and profile-guide compiled oat
- // files as up to date, but to consider extract-only files as out of date,
- // specify: (kFullCompilation | kProfileGuideCompilation).
- //
// The isa should be either the 32 bit or 64 bit variant for the current
// device. For example, on an arm device, use arm or arm64. An oat file can
// be loaded executable only if the ISA matches the current runtime.
+ //
+ // 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();
@@ -158,16 +144,18 @@ class OatFileAssistant {
bool Lock(std::string* error_msg);
// Return what action needs to be taken to produce up-to-date code for this
- // dex location.
- DexOptNeeded GetDexOptNeeded();
+ // 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);
// Attempts to generate or relocate the oat file as needed to make it up to
- // date.
+ // date with in a way that is at least as good as an oat file generated with
+ // the given compiler filter.
// 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(std::string* error_msg);
+ bool MakeUpToDate(CompilerFilter::Filter target_compiler_filter, 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.
@@ -251,7 +239,7 @@ class OatFileAssistant {
// 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.
+ // Generate the oat file from the dex file using the given compiler filter.
// This does not check the current status before attempting to generate the
// oat file.
// Returns true on success.
@@ -259,7 +247,7 @@ class OatFileAssistant {
//
// 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(std::string* error_msg);
+ bool GenerateOatFile(CompilerFilter::Filter filter, 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
@@ -315,6 +303,10 @@ class OatFileAssistant {
// 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();
@@ -327,6 +319,10 @@ class OatFileAssistant {
// 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();
@@ -346,12 +342,14 @@ class OatFileAssistant {
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;
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index 046d8ae779..e5146ae9a8 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -188,7 +188,8 @@ class OatFileAssistantTest : public CommonRuntimeTest {
// 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) {
+ const std::string& odex_location,
+ CompilerFilter::Filter filter) {
// 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.
@@ -196,11 +197,12 @@ class OatFileAssistantTest : public CommonRuntimeTest {
std::vector<std::string> args;
args.push_back("--dex-file=" + dex_location);
args.push_back("--oat-file=" + relocated_odex_location);
- args.push_back("--include-patch-information");
+ args.push_back("--compiler-filter=" + CompilerFilter::NameOfFilter(filter));
// 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;
@@ -227,21 +229,25 @@ class OatFileAssistantTest : public CommonRuntimeTest {
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());
- const std::vector<gc::space::ImageSpace*> image_spaces =
+ if (CompilerFilter::IsCompilationEnabled(filter)) {
+ 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_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());
+ 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());
+ }
}
void GeneratePicOdexForTest(const std::string& dex_location,
- const std::string& odex_location) {
+ const std::string& odex_location,
+ CompilerFilter::Filter filter) {
// Temporarily redirect the dalvik cache so dex2oat doesn't find the
// relocated image file.
std::string android_data_tmp = GetScratchDir() + "AndroidDataTmp";
@@ -249,6 +255,7 @@ class OatFileAssistantTest : public CommonRuntimeTest {
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");
@@ -267,55 +274,7 @@ class OatFileAssistantTest : public CommonRuntimeTest {
&error_msg));
ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
EXPECT_TRUE(odex_file->IsPic());
- }
-
- 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());
+ EXPECT_EQ(filter, odex_file->GetCompilerFilter());
}
private:
@@ -382,12 +341,32 @@ class OatFileAssistantNoDex2OatTest : public OatFileAssistantTest {
// Generate an oat file for the purposes of test, as opposed to testing
// generation of oat files.
-static void GenerateOatForTest(const char* dex_location) {
- OatFileAssistant oat_file_assistant(dex_location,
- OatFileAssistant::kFullCompilation, kRuntimeISA, false);
+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);
+ 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(oat_file_assistant.GenerateOatFile(&error_msg)) << 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());
}
// Case: We have a DEX file, but no OAT file for it.
@@ -396,10 +375,16 @@ TEST_F(OatFileAssistantTest, DexNoOat) {
std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
Copy(GetDexSrc1(), dex_location);
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- OatFileAssistant::kFullCompilation, kRuntimeISA, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, false);
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded, oat_file_assistant.GetDexOptNeeded());
+ 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_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_FALSE(oat_file_assistant.OdexFileExists());
@@ -420,15 +405,15 @@ TEST_F(OatFileAssistantTest, DexNoOat) {
TEST_F(OatFileAssistantTest, NoDexNoOat) {
std::string dex_location = GetScratchDir() + "/NoDexNoOat.jar";
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- OatFileAssistant::kFullCompilation, kRuntimeISA, true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, true);
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded());
+ EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
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(&error_msg));
+ EXPECT_TRUE(oat_file_assistant.MakeUpToDate(CompilerFilter::kSpeed, &error_msg));
// Trying to get the best oat file should fail, but not crash.
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
@@ -440,12 +425,19 @@ TEST_F(OatFileAssistantTest, NoDexNoOat) {
TEST_F(OatFileAssistantTest, OatUpToDate) {
std::string dex_location = GetScratchDir() + "/OatUpToDate.jar";
Copy(GetDexSrc1(), dex_location);
- GenerateOatForTest(dex_location.c_str());
+ GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- OatFileAssistant::kFullCompilation, kRuntimeISA, false);
+ 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));
- 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());
@@ -458,16 +450,68 @@ TEST_F(OatFileAssistantTest, OatUpToDate) {
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));
+
+ 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 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());
+ GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- OatFileAssistant::kFullCompilation, kRuntimeISA, true);
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded());
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, true);
+ EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
// Verify we can load both dex files.
@@ -486,15 +530,15 @@ TEST_F(OatFileAssistantTest, MultiDexSecondaryOutOfDate) {
// Compile code for GetMultiDexSrc1.
Copy(GetMultiDexSrc1(), dex_location);
- GenerateOatForTest(dex_location.c_str());
+ GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
// 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(),
- OatFileAssistant::kFullCompilation, kRuntimeISA, true);
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded, oat_file_assistant.GetDexOptNeeded());
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, true);
+ EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
}
@@ -513,6 +557,7 @@ TEST_F(OatFileAssistantTest, RelativeEncodedDexLocation) {
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;
@@ -520,8 +565,7 @@ TEST_F(OatFileAssistantTest, RelativeEncodedDexLocation) {
// Verify we can load both dex files.
OatFileAssistant oat_file_assistant(dex_location.c_str(),
oat_location.c_str(),
- OatFileAssistant::kFullCompilation,
- kRuntimeISA, true);
+ kRuntimeISA, false, true);
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
ASSERT_TRUE(oat_file.get() != nullptr);
EXPECT_TRUE(oat_file->IsExecutable());
@@ -538,12 +582,14 @@ TEST_F(OatFileAssistantTest, OatOutOfDate) {
// 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());
+ GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
Copy(GetDexSrc2(), dex_location);
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- OatFileAssistant::kFullCompilation, kRuntimeISA, false);
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded, oat_file_assistant.GetDexOptNeeded());
+ 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));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_FALSE(oat_file_assistant.OdexFileExists());
@@ -563,13 +609,15 @@ TEST_F(OatFileAssistantTest, DexOdexNoOat) {
// Create the dex and odex files
Copy(GetDexSrc1(), dex_location);
- GenerateOdexForTest(dex_location, odex_location);
+ GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
// Verify the status.
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- OatFileAssistant::kFullCompilation, kRuntimeISA, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, false);
- EXPECT_EQ(OatFileAssistant::kPatchOatNeeded, oat_file_assistant.GetDexOptNeeded());
+ EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
+ EXPECT_EQ(OatFileAssistant::kPatchOatNeeded,
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_TRUE(oat_file_assistant.OdexFileExists());
@@ -594,16 +642,16 @@ TEST_F(OatFileAssistantTest, StrippedDexOdexNoOat) {
// Create the dex and odex files
Copy(GetDexSrc1(), dex_location);
- GenerateOdexForTest(dex_location, odex_location);
+ GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
// Strip the dex file
Copy(GetStrippedDexSrc1(), dex_location);
// Verify the status.
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- OatFileAssistant::kFullCompilation, kRuntimeISA, true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, true);
- EXPECT_EQ(OatFileAssistant::kPatchOatNeeded, oat_file_assistant.GetDexOptNeeded());
+ EXPECT_EQ(OatFileAssistant::kPatchOatNeeded,
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_TRUE(oat_file_assistant.OdexFileExists());
@@ -616,9 +664,10 @@ TEST_F(OatFileAssistantTest, StrippedDexOdexNoOat) {
// Make the oat file up to date.
std::string error_msg;
- ASSERT_TRUE(oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg;
+ ASSERT_TRUE(oat_file_assistant.MakeUpToDate(CompilerFilter::kSpeed, &error_msg)) << error_msg;
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded());
+ EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_TRUE(oat_file_assistant.OdexFileExists());
@@ -646,20 +695,24 @@ TEST_F(OatFileAssistantTest, StrippedDexOdexOat) {
// Create the oat file from a different dex file so it looks out of date.
Copy(GetDexSrc2(), dex_location);
- GenerateOatForTest(dex_location.c_str());
+ GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
// Create the odex file
Copy(GetDexSrc1(), dex_location);
- GenerateOdexForTest(dex_location, odex_location);
+ GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
// Strip the dex file.
Copy(GetStrippedDexSrc1(), dex_location);
// Verify the status.
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- OatFileAssistant::kFullCompilation, kRuntimeISA, true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, true);
- EXPECT_EQ(OatFileAssistant::kPatchOatNeeded, oat_file_assistant.GetDexOptNeeded());
+ 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_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_TRUE(oat_file_assistant.OdexFileExists());
@@ -673,9 +726,12 @@ TEST_F(OatFileAssistantTest, StrippedDexOdexOat) {
// Make the oat file up to date.
std::string error_msg;
- ASSERT_TRUE(oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg;
+ ASSERT_TRUE(oat_file_assistant.MakeUpToDate(CompilerFilter::kSpeed, &error_msg)) << error_msg;
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded());
+ 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_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_TRUE(oat_file_assistant.OdexFileExists());
@@ -705,10 +761,14 @@ TEST_F(OatFileAssistantTest, ResourceOnlyDex) {
Copy(GetStrippedDexSrc1(), dex_location);
// Verify the status.
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- OatFileAssistant::kFullCompilation, kRuntimeISA, true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, true);
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded());
+ 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_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_FALSE(oat_file_assistant.OdexFileExists());
@@ -722,9 +782,10 @@ TEST_F(OatFileAssistantTest, ResourceOnlyDex) {
// Make the oat file up to date. This should have no effect.
std::string error_msg;
- EXPECT_TRUE(oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg;
+ EXPECT_TRUE(oat_file_assistant.MakeUpToDate(CompilerFilter::kSpeed, &error_msg)) << error_msg;
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded());
+ EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_FALSE(oat_file_assistant.OdexFileExists());
@@ -746,12 +807,17 @@ TEST_F(OatFileAssistantTest, SelfRelocation) {
// Create the dex and odex files
Copy(GetDexSrc1(), dex_location);
- GenerateOdexForTest(dex_location, oat_location);
+ GenerateOdexForTest(dex_location, oat_location, CompilerFilter::kSpeed);
OatFileAssistant oat_file_assistant(dex_location.c_str(),
- oat_location.c_str(), OatFileAssistant::kFullCompilation, kRuntimeISA, true);
+ oat_location.c_str(), kRuntimeISA, false, true);
- EXPECT_EQ(OatFileAssistant::kSelfPatchOatNeeded, oat_file_assistant.GetDexOptNeeded());
+ 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_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_FALSE(oat_file_assistant.OdexFileExists());
@@ -766,9 +832,10 @@ TEST_F(OatFileAssistantTest, SelfRelocation) {
// Make the oat file up to date.
std::string error_msg;
- ASSERT_TRUE(oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg;
+ ASSERT_TRUE(oat_file_assistant.MakeUpToDate(CompilerFilter::kSpeed, &error_msg)) << error_msg;
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded());
+ EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_FALSE(oat_file_assistant.OdexFileExists());
@@ -799,7 +866,7 @@ TEST_F(OatFileAssistantTest, OdexOatOverlap) {
// Create the dex and odex files
Copy(GetDexSrc1(), dex_location);
- GenerateOdexForTest(dex_location, odex_location);
+ GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
// Create the oat file by copying the odex so they are located in the same
// place in memory.
@@ -807,9 +874,10 @@ TEST_F(OatFileAssistantTest, OdexOatOverlap) {
// Verify things don't go bad.
OatFileAssistant oat_file_assistant(dex_location.c_str(),
- oat_location.c_str(), OatFileAssistant::kFullCompilation, kRuntimeISA, true);
+ oat_location.c_str(), kRuntimeISA, false, true);
- EXPECT_EQ(OatFileAssistant::kPatchOatNeeded, oat_file_assistant.GetDexOptNeeded());
+ EXPECT_EQ(OatFileAssistant::kPatchOatNeeded,
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_TRUE(oat_file_assistant.OdexFileExists());
@@ -838,13 +906,15 @@ TEST_F(OatFileAssistantTest, DexPicOdexNoOat) {
// Create the dex and odex files
Copy(GetDexSrc1(), dex_location);
- GeneratePicOdexForTest(dex_location, odex_location);
+ GeneratePicOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
// Verify the status.
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- OatFileAssistant::kFullCompilation, kRuntimeISA, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, false);
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded());
+ EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
+ EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_TRUE(oat_file_assistant.OdexFileExists());
@@ -856,27 +926,28 @@ TEST_F(OatFileAssistantTest, DexPicOdexNoOat) {
EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
}
-// 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";
+// 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";
// Create the dex and odex files
Copy(GetDexSrc1(), dex_location);
- GenerateExtractOnlyOdexForTest(dex_location, odex_location);
+ GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kVerifyAtRuntime);
// Verify the status.
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- OatFileAssistant::kFullCompilation | OatFileAssistant::kExtractOnly,
- kRuntimeISA, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, false);
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded());
+ EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
+ EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_TRUE(oat_file_assistant.OdexFileExists());
EXPECT_FALSE(oat_file_assistant.OdexFileIsOutOfDate());
- EXPECT_TRUE(oat_file_assistant.OdexFileIsUpToDate());
+ EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
EXPECT_FALSE(oat_file_assistant.OatFileExists());
EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
@@ -889,11 +960,10 @@ TEST_F(OatFileAssistantTest, LoadOatUpToDate) {
std::string dex_location = GetScratchDir() + "/LoadOatUpToDate.jar";
Copy(GetDexSrc1(), dex_location);
- GenerateOatForTest(dex_location.c_str());
+ GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
// Load the oat using an oat file assistant.
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- OatFileAssistant::kFullCompilation, kRuntimeISA, true);
+ 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);
@@ -903,17 +973,35 @@ TEST_F(OatFileAssistantTest, LoadOatUpToDate) {
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());
+ GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
// Load the oat using an oat file assistant.
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- OatFileAssistant::kFullCompilation, kRuntimeISA, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, false);
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
ASSERT_TRUE(oat_file.get() != nullptr);
@@ -933,10 +1021,9 @@ TEST_F(OatFileAssistantTest, LoadDexNoAlternateOat) {
Copy(GetDexSrc1(), dex_location);
OatFileAssistant oat_file_assistant(
- dex_location.c_str(), oat_location.c_str(),
- OatFileAssistant::kFullCompilation, kRuntimeISA, true);
+ dex_location.c_str(), oat_location.c_str(), kRuntimeISA, false, true);
std::string error_msg;
- ASSERT_TRUE(oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg;
+ ASSERT_TRUE(oat_file_assistant.MakeUpToDate(CompilerFilter::kSpeed, &error_msg)) << error_msg;
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
ASSERT_TRUE(oat_file.get() != nullptr);
@@ -948,8 +1035,7 @@ TEST_F(OatFileAssistantTest, LoadDexNoAlternateOat) {
EXPECT_TRUE(OS::FileExists(oat_location.c_str()));
// Verify it didn't create an oat in the default location.
- OatFileAssistant ofm(dex_location.c_str(),
- OatFileAssistant::kFullCompilation, kRuntimeISA, false);
+ OatFileAssistant ofm(dex_location.c_str(), kRuntimeISA, false, false);
EXPECT_FALSE(ofm.OatFileExists());
}
@@ -965,10 +1051,9 @@ TEST_F(OatFileAssistantTest, LoadDexUnwriteableAlternateOat) {
Copy(GetDexSrc1(), dex_location);
OatFileAssistant oat_file_assistant(
- dex_location.c_str(), oat_location.c_str(),
- OatFileAssistant::kFullCompilation, kRuntimeISA, true);
+ dex_location.c_str(), oat_location.c_str(), kRuntimeISA, false, true);
std::string error_msg;
- ASSERT_FALSE(oat_file_assistant.MakeUpToDate(&error_msg));
+ ASSERT_FALSE(oat_file_assistant.MakeUpToDate(CompilerFilter::kSpeed, &error_msg));
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
ASSERT_TRUE(oat_file.get() == nullptr);
@@ -981,10 +1066,9 @@ TEST_F(OatFileAssistantTest, GenNoDex) {
std::string oat_location = GetScratchDir() + "/GenNoDex.oat";
OatFileAssistant oat_file_assistant(
- dex_location.c_str(), oat_location.c_str(),
- OatFileAssistant::kFullCompilation, kRuntimeISA, true);
+ dex_location.c_str(), oat_location.c_str(), kRuntimeISA, false, true);
std::string error_msg;
- ASSERT_FALSE(oat_file_assistant.GenerateOatFile(&error_msg));
+ ASSERT_FALSE(oat_file_assistant.GenerateOatFile(CompilerFilter::kSpeed, &error_msg));
}
// Turn an absolute path into a path relative to the current working
@@ -1030,11 +1114,11 @@ TEST_F(OatFileAssistantTest, NonAbsoluteDexLocation) {
Copy(GetDexSrc1(), abs_dex_location);
std::string dex_location = MakePathRelative(abs_dex_location);
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- OatFileAssistant::kFullCompilation, kRuntimeISA, true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, true);
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded, oat_file_assistant.GetDexOptNeeded());
+ EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.OdexFileExists());
EXPECT_FALSE(oat_file_assistant.OatFileExists());
EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
@@ -1048,11 +1132,11 @@ TEST_F(OatFileAssistantTest, NonAbsoluteDexLocation) {
TEST_F(OatFileAssistantTest, ShortDexLocation) {
std::string dex_location = "/xx";
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- OatFileAssistant::kFullCompilation, kRuntimeISA, true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, true);
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded());
+ EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.OdexFileExists());
EXPECT_FALSE(oat_file_assistant.OatFileExists());
EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
@@ -1063,7 +1147,7 @@ TEST_F(OatFileAssistantTest, ShortDexLocation) {
// Trying to make it up to date should have no effect.
std::string error_msg;
- EXPECT_TRUE(oat_file_assistant.MakeUpToDate(&error_msg));
+ EXPECT_TRUE(oat_file_assistant.MakeUpToDate(CompilerFilter::kSpeed, &error_msg));
EXPECT_TRUE(error_msg.empty());
}
@@ -1073,10 +1157,10 @@ TEST_F(OatFileAssistantTest, LongDexExtension) {
std::string dex_location = GetScratchDir() + "/LongDexExtension.jarx";
Copy(GetDexSrc1(), dex_location);
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- OatFileAssistant::kFullCompilation, kRuntimeISA, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, false);
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded, oat_file_assistant.GetDexOptNeeded());
+ EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_FALSE(oat_file_assistant.OdexFileExists());
@@ -1168,11 +1252,10 @@ TEST_F(OatFileAssistantNoDex2OatTest, LoadDexOdexNoOat) {
// Create the dex and odex files
Copy(GetDexSrc1(), dex_location);
- GenerateOdexForTest(dex_location, odex_location);
+ GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
// Load the oat using an executable oat file assistant.
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- OatFileAssistant::kFullCompilation, kRuntimeISA, true);
+ 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);
@@ -1191,11 +1274,10 @@ TEST_F(OatFileAssistantNoDex2OatTest, LoadMultiDexOdexNoOat) {
// Create the dex and odex files
Copy(GetMultiDexSrc1(), dex_location);
- GenerateOdexForTest(dex_location, odex_location);
+ GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
// Load the oat using an executable oat file assistant.
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- OatFileAssistant::kFullCompilation, kRuntimeISA, true);
+ 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);
@@ -1223,45 +1305,6 @@ TEST(OatFileAssistantUtilsTest, DexFilenameToOdexFilename) {
"/foo/bar/baz_noext", kArm, &odex_file, &error_msg));
}
-// Case: We have a DEX file, extract-only ODEX, and fully compiled OAT.
-// Expect: The status depends on the target compilation type mask.
-TEST_F(OatFileAssistantTest, TargetCompilationType) {
- std::string dex_location = GetScratchDir() + "/TargetCompilationType.jar";
- std::string odex_location = GetOdexDir() + "/TargetCompilationType.odex";
- Copy(GetDexSrc1(), dex_location);
- GenerateExtractOnlyOdexForTest(dex_location, odex_location);
- GenerateOatForTest(dex_location.c_str());
-
- OatFileAssistant ofa_full(dex_location.c_str(),
- OatFileAssistant::kFullCompilation, kRuntimeISA, false);
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, ofa_full.GetDexOptNeeded());
- EXPECT_FALSE(ofa_full.IsInBootClassPath());
- EXPECT_TRUE(ofa_full.OdexFileIsOutOfDate());
- EXPECT_TRUE(ofa_full.OatFileIsUpToDate());
-
- OatFileAssistant ofa_extract(dex_location.c_str(),
- OatFileAssistant::kExtractOnly, kRuntimeISA, false);
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, ofa_extract.GetDexOptNeeded());
- EXPECT_FALSE(ofa_extract.IsInBootClassPath());
- EXPECT_TRUE(ofa_extract.OdexFileIsUpToDate());
- EXPECT_TRUE(ofa_extract.OatFileIsOutOfDate());
-
- OatFileAssistant ofa_profile(dex_location.c_str(),
- OatFileAssistant::kProfileGuideCompilation, kRuntimeISA, false);
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded, ofa_profile.GetDexOptNeeded());
- EXPECT_FALSE(ofa_profile.IsInBootClassPath());
- EXPECT_TRUE(ofa_profile.OdexFileIsOutOfDate());
- EXPECT_TRUE(ofa_profile.OatFileIsOutOfDate());
-
- OatFileAssistant ofa_extract_full(dex_location.c_str(),
- OatFileAssistant::kFullCompilation | OatFileAssistant::kExtractOnly,
- kRuntimeISA, false);
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, ofa_extract_full.GetDexOptNeeded());
- EXPECT_FALSE(ofa_extract_full.IsInBootClassPath());
- EXPECT_TRUE(ofa_extract_full.OdexFileIsUpToDate());
- EXPECT_TRUE(ofa_extract_full.OatFileIsUpToDate());
-}
-
// Verify the dexopt status values from dalvik.system.DexFile
// match the OatFileAssistant::DexOptStatus values.
TEST_F(OatFileAssistantTest, DexOptStatusValues) {
@@ -1296,28 +1339,12 @@ 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
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index 3ec3826374..34b00a0394 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -308,13 +308,10 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat(
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
@@ -330,7 +327,7 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat(
// 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(/*out*/&error_msg)) {
+ if (!oat_file_assistant.MakeUpToDate(CompilerFilter::kSpeed, /*out*/ &error_msg)) {
LOG(INFO) << error_msg;
}
@@ -484,15 +481,7 @@ void OatFileManager::DumpForSigQuit(std::ostream& os) {
if (ContainsElement(boot_oat_files, oat_file.get())) {
continue;
}
- // 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";
+ os << oat_file->GetLocation() << ": " << oat_file->GetCompilerFilter() << "\n";
}
}
diff --git a/test/117-nopatchoat/nopatchoat.cc b/test/117-nopatchoat/nopatchoat.cc
index 82e1fc8ae5..0dab4007a7 100644
--- a/test/117-nopatchoat/nopatchoat.cc
+++ b/test/117-nopatchoat/nopatchoat.cc
@@ -54,7 +54,8 @@ class NoPatchoatTest {
}
const OatFile* oat_file = oat_dex_file->GetOatFile();
- return !oat_file->IsPic() && !oat_file->IsExtractOnly();
+ return !oat_file->IsPic()
+ && CompilerFilter::IsCompilationEnabled(oat_file->GetCompilerFilter());
}
};