Commit 29d38e77 authored by Andreas Gampe's avatar Andreas Gampe Committed by Richard Uhler
Browse files

Revert "Revert "Use compiler filter to determine oat file status.""

This reverts commit 845e5064.

Add an option to change what OatFileManager considers up-to-date.
In our tests we're allowed to write to the dalvik-cache, so it
cannot be kSpeed.

Bug: 27689078
Change-Id: I0c578705a9921114ed1fb00d360cc7448addc93a
parent 2e89e901
......@@ -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 \
......
......@@ -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;
}
......
......@@ -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") {
......
......@@ -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
......
......@@ -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;
}
......
......@@ -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;
......
......@@ -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());
}
......
......@@ -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 \
......
......@@ -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));
}
......
/*
* 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
/*
* 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_
/*
* 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
......@@ -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;
}
......
......@@ -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 {
......
......@@ -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;
......
......@@ -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 = '*';
......
......@@ -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_;
......
......@@ -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,44 @@ 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.";
return false;
}
if (CompilerFilter::IsCompilationEnabled(current_compiler_filter)) {
if (!file.IsPic()) {
const ImageInfo* image_info = GetImageInfo();
if (image_info == nullptr) {
VLOG(oat) << "No image to check oat relocation against.";
return false;
}
// Verify the oat_data_begin recorded for the image in the oat file matches
// the actual oat_data_begin for boot.oat in the image.
const OatHeader& oat_header = file.GetOatHeader();
uintptr_t oat_data_begin = oat_header.GetImageFileLocationOatDataBegin();
if (oat_data_begin != image_info->oat_data_begin) {
VLOG(oat) << file.GetLocation() <<
": Oat file image oat_data_begin (" << oat_data_begin << ")"
<< " does not match actual image oat_data_begin ("
<< image_info->oat_data_begin << ")";
return false;
}
// Verify the oat_data_begin recorded for the image in the oat file matches
// the actual oat_data_begin for boot.oat in the image.
const OatHeader& oat_header = file.GetOatHeader();
uintptr_t oat_data_begin = oat_header.GetImageFileLocationOatDataBegin();
if (oat_data_begin != image_info->oat_data_begin) {
VLOG(oat) << file.GetLocation() <<
": Oat file image oat_data_begin (" << oat_data_begin << ")"
<< " does not match actual image oat_data_begin ("
<< image_info->oat_data_begin << ")";
return false;
}
// Verify the oat_patch_delta recorded for the image in the oat file matches
// the actual oat_patch_delta for the image.
int32_t oat_patch_delta = oat_header.GetImagePatchDelta();
if (oat_patch_delta != image_info->patch_delta) {
VLOG(oat) << file.GetLocation() <<
": Oat file image patch delta (" << oat_patch_delta << ")"
<< " does not match actual image patch delta ("
<< image_info->patch_delta << ")";
return false;
// 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.
VLOG(oat) << "Oat relocation test skipped for PIC oat file";
}
} else {
VLOG(oat) << "Oat relocation test skipped for compiler filter " << current_compiler_filter;
}
return true;
}
......@@ -589,18 +625,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 +669,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 +779,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
......
......@@ -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;
......
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment