diff options
| -rw-r--r-- | dexoptanalyzer/dexoptanalyzer.cc | 2 | ||||
| -rw-r--r-- | runtime/native/dalvik_system_DexFile.cc | 2 | ||||
| -rw-r--r-- | runtime/oat_file.cc | 4 | ||||
| -rw-r--r-- | runtime/oat_file.h | 2 | ||||
| -rw-r--r-- | runtime/oat_file_assistant.cc | 97 | ||||
| -rw-r--r-- | runtime/oat_file_assistant.h | 13 | ||||
| -rw-r--r-- | runtime/oat_file_assistant_test.cc | 62 | ||||
| -rw-r--r-- | runtime/oat_file_manager.cc | 12 |
8 files changed, 143 insertions, 51 deletions
diff --git a/dexoptanalyzer/dexoptanalyzer.cc b/dexoptanalyzer/dexoptanalyzer.cc index fc72bbdb87..51a67ca45e 100644 --- a/dexoptanalyzer/dexoptanalyzer.cc +++ b/dexoptanalyzer/dexoptanalyzer.cc @@ -229,6 +229,8 @@ class DexoptAnalyzer FINAL { if (oat_file_assistant.IsInBootClassPath()) { return kNoDexOptNeeded; } + + // TODO(calin): Pass the class loader context as an argument to dexoptanalyzer. b/62269291. int dexoptNeeded = oat_file_assistant.GetDexOptNeeded( compiler_filter_, assume_profile_changed_, downgrade_); diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc index 07dfb65972..d40e6d94c9 100644 --- a/runtime/native/dalvik_system_DexFile.cc +++ b/runtime/native/dalvik_system_DexFile.cc @@ -493,6 +493,8 @@ static jint GetDexOptNeeded(JNIEnv* env, if (oat_file_assistant.IsInBootClassPath()) { return OatFileAssistant::kNoDexOptNeeded; } + + // TODO(calin): Extend DexFile.getDexOptNeeded to accept the class loader context. b/62269291. return oat_file_assistant.GetDexOptNeeded(filter, profile_changed, downgrade); } diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index 6515cfa864..075875b3f4 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -1604,6 +1604,10 @@ CompilerFilter::Filter OatFile::GetCompilerFilter() const { return GetOatHeader().GetCompilerFilter(); } +std::string OatFile::GetClassLoaderContext() const { + return GetOatHeader().GetStoreValueByKey(OatHeader::kClassPathKey); +}; + OatFile::OatClass OatFile::FindOatClass(const DexFile& dex_file, uint16_t class_def_idx, bool* found) { diff --git a/runtime/oat_file.h b/runtime/oat_file.h index e13126bae3..04cb3a0a6e 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -115,6 +115,8 @@ class OatFile { CompilerFilter::Filter GetCompilerFilter() const; + std::string GetClassLoaderContext() const; + const std::string& GetLocation() const { return location_; } diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc index 3794f51cb7..83a8e096e4 100644 --- a/runtime/oat_file_assistant.cc +++ b/runtime/oat_file_assistant.cc @@ -190,9 +190,13 @@ bool OatFileAssistant::Lock(std::string* error_msg) { int OatFileAssistant::GetDexOptNeeded(CompilerFilter::Filter target, bool profile_changed, - bool downgrade) { + bool downgrade, + ClassLoaderContext* class_loader_context) { OatFileInfo& info = GetBestInfo(); - DexOptNeeded dexopt_needed = info.GetDexOptNeeded(target, profile_changed, downgrade); + DexOptNeeded dexopt_needed = info.GetDexOptNeeded(target, + profile_changed, + downgrade, + class_loader_context); if (info.IsOatLocation() || dexopt_needed == kDex2OatFromScratch) { return dexopt_needed; } @@ -227,7 +231,7 @@ bool OatFileAssistant::IsUpToDate() { OatFileAssistant::ResultOfAttemptToUpdate OatFileAssistant::MakeUpToDate(bool profile_changed, - const std::string& class_loader_context, + ClassLoaderContext* class_loader_context, std::string* error_msg) { CompilerFilter::Filter target; if (!GetRuntimeCompilerFilterOption(&target, error_msg)) { @@ -245,7 +249,8 @@ OatFileAssistant::MakeUpToDate(bool profile_changed, // - however, MakeUpToDate will not always succeed (e.g. for primary apks, or for dex files // loaded in other processes). So it boils down to how far do we want to complicate // the logic in order to enable the use of oat files. Maybe its time to try simplify it. - switch (info.GetDexOptNeeded(target, profile_changed, /*downgrade*/ false)) { + switch (info.GetDexOptNeeded( + target, profile_changed, /*downgrade*/ false, class_loader_context)) { case kNoDexOptNeeded: return kUpdateSucceeded; @@ -643,7 +648,7 @@ static bool PrepareOdexDirectories(const std::string& dex_location, OatFileAssistant::ResultOfAttemptToUpdate OatFileAssistant::GenerateOatFileNoChecks( OatFileAssistant::OatFileInfo& info, CompilerFilter::Filter filter, - const std::string& class_loader_context, + const ClassLoaderContext* class_loader_context, std::string* error_msg) { CHECK(error_msg != nullptr); @@ -720,7 +725,10 @@ OatFileAssistant::ResultOfAttemptToUpdate OatFileAssistant::GenerateOatFileNoChe 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(filter)); - args.push_back("--class-loader-context=" + class_loader_context); + const std::string dex2oat_context = class_loader_context == nullptr + ? OatFile::kSpecialSharedLibrary + : class_loader_context->EncodeContextForDex2oat(/*base_dir*/ ""); + args.push_back("--class-loader-context=" + dex2oat_context); if (!Dex2Oat(args, error_msg)) { // Manually delete the oat and vdex files. This ensures there is no garbage @@ -1016,31 +1024,40 @@ OatFileAssistant::OatStatus OatFileAssistant::OatFileInfo::Status() { } OatFileAssistant::DexOptNeeded OatFileAssistant::OatFileInfo::GetDexOptNeeded( - CompilerFilter::Filter target, bool profile_changed, bool downgrade) { + CompilerFilter::Filter target, + bool profile_changed, + bool downgrade, + ClassLoaderContext* context) { + bool compilation_desired = CompilerFilter::IsAotCompilationEnabled(target); bool filter_okay = CompilerFilterIsOkay(target, profile_changed, downgrade); + bool class_loader_context_okay = ClassLoaderContextIsOkay(context); + + // Only check the filter and relocation if the class loader context is ok. + // If it is not, we will return kDex2OatFromScratch as the compilation needs to be redone. + if (class_loader_context_okay) { + if (filter_okay && Status() == kOatUpToDate) { + // The oat file is in good shape as is. + return kNoDexOptNeeded; + } - if (filter_okay && Status() == kOatUpToDate) { - // The oat file is in good shape as is. - return kNoDexOptNeeded; - } - - if (filter_okay && !compilation_desired && Status() == kOatRelocationOutOfDate) { - // If no compilation is desired, then it doesn't matter if the oat - // file needs relocation. It's in good shape as is. - return kNoDexOptNeeded; - } + if (filter_okay && !compilation_desired && Status() == kOatRelocationOutOfDate) { + // If no compilation is desired, then it doesn't matter if the oat + // file needs relocation. It's in good shape as is. + return kNoDexOptNeeded; + } - if (filter_okay && Status() == kOatRelocationOutOfDate) { - return kDex2OatForRelocation; - } + if (filter_okay && Status() == kOatRelocationOutOfDate) { + return kDex2OatForRelocation; + } - if (IsUseable()) { - return kDex2OatForFilter; - } + if (IsUseable()) { + return kDex2OatForFilter; + } - if (Status() == kOatBootImageOutOfDate) { - return kDex2OatForBootImage; + if (Status() == kOatBootImageOutOfDate) { + return kDex2OatForBootImage; + } } if (oat_file_assistant_->HasOriginalDexFiles()) { @@ -1090,6 +1107,36 @@ bool OatFileAssistant::OatFileInfo::CompilerFilterIsOkay( CompilerFilter::IsAsGoodAs(current, target); } +bool OatFileAssistant::OatFileInfo::ClassLoaderContextIsOkay(ClassLoaderContext* context) { + if (context == nullptr) { + VLOG(oat) << "ClassLoaderContext check ignored: null context"; + return true; + } + + const OatFile* file = GetFile(); + if (file == nullptr) { + return false; + } + + size_t dir_index = file->GetLocation().rfind('/'); + std::string classpath_dir = (dir_index != std::string::npos) + ? file->GetLocation().substr(0, dir_index) + : ""; + + if (!context->OpenDexFiles(oat_file_assistant_->isa_, classpath_dir)) { + VLOG(oat) << "ClassLoaderContext check failed: dex files from the context could not be opened"; + return false; + } + + bool result = context->VerifyClassLoaderContextMatch(file->GetClassLoaderContext()); + if (!result) { + VLOG(oat) << "ClassLoaderContext check failed. Context was " + << file->GetClassLoaderContext() + << ". The expected context is " << context->EncodeContextForOatFile(classpath_dir); + } + return result; +} + bool OatFileAssistant::OatFileInfo::IsExecutable() { const OatFile* file = GetFile(); return (file != nullptr && file->IsExecutable()); diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h index 5eec943689..6dc3c197b2 100644 --- a/runtime/oat_file_assistant.h +++ b/runtime/oat_file_assistant.h @@ -26,6 +26,7 @@ #include "base/scoped_flock.h" #include "base/unix_file/fd_file.h" #include "compiler_filter.h" +#include "class_loader_context.h" #include "oat_file.h" #include "os.h" @@ -164,7 +165,8 @@ class OatFileAssistant { // the oat file in the odex location. int GetDexOptNeeded(CompilerFilter::Filter target_compiler_filter, bool profile_changed = false, - bool downgrade = false); + bool downgrade = false, + ClassLoaderContext* context = nullptr); // Returns true if there is up-to-date code for this dex location, // irrespective of the compiler filter of the up-to-date code. @@ -194,7 +196,7 @@ class OatFileAssistant { // to a string describing why there was a failure or the update was not // attempted. error_msg must not be null. ResultOfAttemptToUpdate MakeUpToDate(bool profile_changed, - const std::string& class_loader_context, + ClassLoaderContext* class_loader_context, std::string* error_msg); // Returns an oat file that can be used for loading dex files. @@ -330,7 +332,8 @@ class OatFileAssistant { // compiler filter. DexOptNeeded GetDexOptNeeded(CompilerFilter::Filter target_compiler_filter, bool profile_changed, - bool downgrade); + bool downgrade, + ClassLoaderContext* context); // Returns the loaded file. // Loads the file if needed. Returns null if the file failed to load. @@ -367,6 +370,8 @@ class OatFileAssistant { // compiler filter. bool CompilerFilterIsOkay(CompilerFilter::Filter target, bool profile_changed, bool downgrade); + bool ClassLoaderContextIsOkay(ClassLoaderContext* context); + // Release the loaded oat file. // Returns null if the oat file hasn't been loaded. // @@ -404,7 +409,7 @@ class OatFileAssistant { // attempted. error_msg must not be null. ResultOfAttemptToUpdate GenerateOatFileNoChecks(OatFileInfo& info, CompilerFilter::Filter target, - const std::string& class_loader_context, + const ClassLoaderContext* class_loader_context, std::string* error_msg); // Return info for the best oat file. diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc index e048177fa4..3ecd1b516d 100644 --- a/runtime/oat_file_assistant_test.cc +++ b/runtime/oat_file_assistant_test.cc @@ -40,6 +40,7 @@ namespace art { static const std::string kSpecialSharedLibrary = "&"; +static ClassLoaderContext* kSpecialSharedLibraryContext = nullptr; class OatFileAssistantTest : public DexoptTest {}; @@ -121,7 +122,7 @@ TEST_F(OatFileAssistantTest, NoDexNoOat) { // Trying to make the oat file up to date should not fail or crash. std::string error_msg; EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, - oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibrary, &error_msg)); + oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibraryContext, &error_msg)); // Trying to get the best oat file should fail, but not crash. std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile(); @@ -774,7 +775,7 @@ TEST_F(OatFileAssistantTest, ResourceOnlyDex) { std::string error_msg; Runtime::Current()->AddCompilerOption("--compiler-filter=speed"); EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, - oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibrary, &error_msg)) << + oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibraryContext, &error_msg)) << error_msg; EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, @@ -955,7 +956,7 @@ TEST_F(OatFileAssistantTest, GenNoDex) { // We should get kUpdateSucceeded from MakeUpToDate since there's nothing // that can be done in this situation. ASSERT_EQ(OatFileAssistant::kUpdateSucceeded, - oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibrary, &error_msg)); + oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibraryContext, &error_msg)); // Verify it didn't create an oat in the default location (dalvik-cache). OatFileAssistant ofm(dex_location.c_str(), kRuntimeISA, false); @@ -1034,7 +1035,7 @@ TEST_F(OatFileAssistantTest, ShortDexLocation) { std::string error_msg; Runtime::Current()->AddCompilerOption("--compiler-filter=speed"); EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, - oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibrary, &error_msg)); + oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibraryContext, &error_msg)); EXPECT_TRUE(error_msg.empty()); } @@ -1181,7 +1182,7 @@ TEST_F(OatFileAssistantTest, RuntimeCompilerFilterOptionUsed) { std::string error_msg; Runtime::Current()->AddCompilerOption("--compiler-filter=quicken"); EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, - oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibrary, &error_msg)) << + oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibraryContext, &error_msg)) << error_msg; EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken)); @@ -1190,7 +1191,7 @@ TEST_F(OatFileAssistantTest, RuntimeCompilerFilterOptionUsed) { Runtime::Current()->AddCompilerOption("--compiler-filter=speed"); EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, - oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibrary, &error_msg)) + oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibraryContext, &error_msg)) << error_msg; EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken)); @@ -1199,7 +1200,7 @@ TEST_F(OatFileAssistantTest, RuntimeCompilerFilterOptionUsed) { Runtime::Current()->AddCompilerOption("--compiler-filter=bogus"); EXPECT_EQ(OatFileAssistant::kUpdateNotAttempted, - oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibrary, &error_msg)); + oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibraryContext, &error_msg)); } TEST(OatFileAssistantUtilsTest, DexLocationToOdexFilename) { @@ -1259,7 +1260,7 @@ TEST_F(OatFileAssistantTest, DefaultMakeUpToDateFilter) { OatFileAssistant::kDefaultCompilerFilterForDexLoading; std::string error_msg; EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, - oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibrary, &error_msg)) << + oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibraryContext, &error_msg)) << error_msg; EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded(default_filter)); @@ -1277,7 +1278,7 @@ TEST_F(OatFileAssistantTest, MakeUpToDateWithSpecialSharedLibrary) { const CompilerFilter::Filter default_filter = OatFileAssistant::kDefaultCompilerFilterForDexLoading; std::string error_msg; - int status = oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibrary, &error_msg); + int status = oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibraryContext, &error_msg); EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, status) << error_msg; EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded(default_filter)); @@ -1299,19 +1300,52 @@ TEST_F(OatFileAssistantTest, MakeUpToDateWithContext) { OatFileAssistant::kDefaultCompilerFilterForDexLoading; std::string error_msg; std::string context_str = "PCL[" + context_location + "]"; - int status = oat_file_assistant.MakeUpToDate(false, context_str, &error_msg); + std::unique_ptr<ClassLoaderContext> context = ClassLoaderContext::Create(context_str); + ASSERT_TRUE(context != nullptr); + ASSERT_TRUE(context->OpenDexFiles(kRuntimeISA, "")); + + int status = oat_file_assistant.MakeUpToDate(false, context.get(), &error_msg); EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, status) << error_msg; EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded, - oat_file_assistant.GetDexOptNeeded(default_filter)); + oat_file_assistant.GetDexOptNeeded(default_filter, false, false, context.get())); + std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile(); EXPECT_NE(nullptr, oat_file.get()); - std::unique_ptr<ClassLoaderContext> context = - ClassLoaderContext::Create(context_str); - context->OpenDexFiles(kRuntimeISA, ""); EXPECT_EQ(context->EncodeContextForOatFile(""), oat_file->GetOatHeader().GetStoreValueByKey(OatHeader::kClassPathKey)); } +TEST_F(OatFileAssistantTest, GetDexOptNeededWithOutOfDateContext) { + std::string dex_location = GetScratchDir() + "/TestDex.jar"; + std::string context_location = GetScratchDir() + "/ContextDex.jar"; + Copy(GetDexSrc1(), dex_location); + Copy(GetDexSrc2(), context_location); + + OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false); + + const CompilerFilter::Filter default_filter = + OatFileAssistant::kDefaultCompilerFilterForDexLoading; + std::string error_msg; + std::string context_str = "PCL[" + context_location + "]"; + std::unique_ptr<ClassLoaderContext> context = ClassLoaderContext::Create(context_str); + ASSERT_TRUE(context != nullptr); + ASSERT_TRUE(context->OpenDexFiles(kRuntimeISA, "")); + + int status = oat_file_assistant.MakeUpToDate(false, context.get(), &error_msg); + EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, status) << error_msg; + EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded, + oat_file_assistant.GetDexOptNeeded(default_filter, false, false, context.get())); + + // Update the context by overriding the jar file. + Copy(GetMultiDexSrc2(), context_location); + std::unique_ptr<ClassLoaderContext> updated_context = ClassLoaderContext::Create(context_str); + ASSERT_TRUE(updated_context != nullptr); + // DexOptNeeded should advise compilation from scratch. + EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch, + oat_file_assistant.GetDexOptNeeded( + default_filter, false, false, updated_context.get())); +} + // TODO: More Tests: // * Test class linker falls back to unquickened dex for DexNoOat // * Test class linker falls back to unquickened dex for MultiDexNoOat diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc index 499f356a3a..516c833c6d 100644 --- a/runtime/oat_file_manager.cc +++ b/runtime/oat_file_manager.cc @@ -361,8 +361,7 @@ bool OatFileManager::HasCollisions(const OatFile* oat_file, // If the pat file loading context matches the context used during compilation then we accept // the oat file without addition checks - if (context->VerifyClassLoaderContextMatch( - oat_file->GetOatHeader().GetStoreValueByKey(OatHeader::kClassPathKey))) { + if (context->VerifyClassLoaderContextMatch(oat_file->GetClassLoaderContext())) { return false; } @@ -426,12 +425,9 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat( // Update the oat file on disk if we can, based on the --compiler-filter // option derived from the current runtime options. // This may fail, but that's okay. Best effort is all that matters here. - - const std::string& dex2oat_context = context == nullptr - ? OatFile::kSpecialSharedLibrary - : context->EncodeContextForDex2oat(/*base_dir*/ ""); - switch (oat_file_assistant.MakeUpToDate( - /*profile_changed*/false, dex2oat_context, /*out*/ &error_msg)) { + switch (oat_file_assistant.MakeUpToDate(/*profile_changed*/false, + context.get(), + /*out*/ &error_msg)) { case OatFileAssistant::kUpdateFailed: LOG(WARNING) << error_msg; break; |