Add logic to eagerly resolve const-string for startup methods
Added dex2oat option --resolve-startup-const-strings=<true|false>
If true, this option causes the compiler driver to resolve all
const-strings that are referenced from methods marked as "startup" in
the profile.
Bug: 116059983
Test: test-art-host
Change-Id: I61cf9e945c125671fc4ab4b50458a911318a837f
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index a1fed5f..91b231b 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -39,6 +39,7 @@
#include "dex/dex_file_loader.h"
#include "dex2oat_environment_test.h"
#include "dex2oat_return_codes.h"
+#include "intern_table-inl.h"
#include "oat.h"
#include "oat_file.h"
#include "profile/profile_compilation_info.h"
@@ -2082,6 +2083,74 @@
EXPECT_EQ(header.GetImageSection(ImageHeader::kSectionArtFields).Size(), 0u);
}
+TEST_F(Dex2oatTest, AppImageResolveStrings) {
+ using Hotness = ProfileCompilationInfo::MethodHotness;
+ // Create a profile with the startup method marked.
+ ScratchFile profile_file;
+ std::vector<uint16_t> methods;
+ {
+ std::unique_ptr<const DexFile> dex(OpenTestDexFile("StringLiterals"));
+ for (size_t method_idx = 0; method_idx < dex->NumMethodIds(); ++method_idx) {
+ if (std::string(dex->GetMethodName(dex->GetMethodId(method_idx))) == "startUpMethod") {
+ methods.push_back(method_idx);
+ }
+ }
+ ASSERT_GT(methods.size(), 0u);
+ // Here, we build the profile from the method lists.
+ ProfileCompilationInfo info;
+ info.AddMethodsForDex(Hotness::kFlagStartup, dex.get(), methods.begin(), methods.end());
+ // Save the profile since we want to use it with dex2oat to produce an oat file.
+ ASSERT_TRUE(info.Save(profile_file.GetFd()));
+ }
+ const std::string out_dir = GetScratchDir();
+ const std::string odex_location = out_dir + "/base.odex";
+ const std::string app_image_location = out_dir + "/base.art";
+ GenerateOdexForTest(GetTestDexFileName("StringLiterals"),
+ odex_location,
+ CompilerFilter::Filter::kSpeedProfile,
+ { "--app-image-file=" + app_image_location,
+ "--resolve-startup-const-strings=true",
+ "--profile-file=" + profile_file.GetFilename()},
+ /* expect_success= */ true,
+ /* use_fd= */ false,
+ [](const OatFile&) {});
+ // Open our generated oat file.
+ std::string error_msg;
+ std::unique_ptr<OatFile> odex_file(OatFile::Open(/* zip_fd= */ -1,
+ odex_location.c_str(),
+ odex_location.c_str(),
+ /* requested_base= */ nullptr,
+ /* executable= */ false,
+ /* low_4gb= */ false,
+ odex_location.c_str(),
+ /* reservation= */ nullptr,
+ &error_msg));
+ ASSERT_TRUE(odex_file != nullptr);
+ // Check the strings in the app image intern table only contain the "startup" strigs.
+ {
+ ScopedObjectAccess soa(Thread::Current());
+ std::unique_ptr<gc::space::ImageSpace> space =
+ gc::space::ImageSpace::CreateFromAppImage(app_image_location.c_str(),
+ odex_file.get(),
+ &error_msg);
+ ASSERT_TRUE(space != nullptr) << error_msg;
+ std::set<std::string> seen;
+ InternTable intern_table;
+ intern_table.AddImageStringsToTable(space.get(), [&](InternTable::UnorderedSet& interns)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ for (const GcRoot<mirror::String>& str : interns) {
+ seen.insert(str.Read()->ToModifiedUtf8());
+ }
+ });
+ EXPECT_TRUE(seen.find("Loading ") != seen.end());
+ EXPECT_TRUE(seen.find("Starting up") != seen.end());
+ EXPECT_TRUE(seen.find("abcd.apk") != seen.end());
+ EXPECT_TRUE(seen.find("Unexpected error") == seen.end());
+ EXPECT_TRUE(seen.find("Shutting down!") == seen.end());
+ }
+}
+
+
TEST_F(Dex2oatClassLoaderContextTest, StoredClassLoaderContext) {
std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("MultiDex");
const std::string out_dir = GetScratchDir();