Use full profile in Dex2OatImageTest#TestExtension.

Test: m test-art-host-gtest-dex2oat_image_test
Bug: 119800099
Change-Id: I120f71f98b4df7fae88764e5215e06a6e151b7a2
diff --git a/dex2oat/dex2oat_image_test.cc b/dex2oat/dex2oat_image_test.cc
index 1a0a9c8..9b96494 100644
--- a/dex2oat/dex2oat_image_test.cc
+++ b/dex2oat/dex2oat_image_test.cc
@@ -74,9 +74,20 @@
                          const ClassVisitor& class_visitor,
                          size_t method_frequency = 1,
                          size_t class_frequency = 1) {
+    std::vector<std::string> dexes = GetLibCoreDexFileNames();
+    VisitDexes(dexes, method_visitor, class_visitor, method_frequency, class_frequency);
+  }
+
+  // Visitors take method and type references
+  template <typename MethodVisitor, typename ClassVisitor>
+  void VisitDexes(const std::vector<std::string>& dexes,
+                  const MethodVisitor& method_visitor,
+                  const ClassVisitor& class_visitor,
+                  size_t method_frequency = 1,
+                  size_t class_frequency = 1) {
     size_t method_counter = 0;
     size_t class_counter = 0;
-    for (const std::string& dex : GetLibCoreDexFileNames()) {
+    for (const std::string& dex : dexes) {
       std::vector<std::unique_ptr<const DexFile>> dex_files;
       std::string error_msg;
       const ArtDexFileLoader dex_file_loader;
@@ -107,19 +118,27 @@
     EXPECT_TRUE(file->WriteFully(&line[0], line.length()));
   }
 
-  void GenerateProfile(File* out_file, size_t method_frequency,  size_t type_frequency) {
+  void GenerateProfile(const std::vector<std::string>& dexes,
+                       File* out_file,
+                       size_t method_frequency,
+                       size_t type_frequency) {
     ProfileCompilationInfo profile;
-    VisitLibcoreDexes([&profile](MethodReference ref) {
-      uint32_t flags = ProfileCompilationInfo::MethodHotness::kFlagHot |
-          ProfileCompilationInfo::MethodHotness::kFlagStartup;
-      EXPECT_TRUE(profile.AddMethod(
-          ProfileMethodInfo(ref),
-          static_cast<ProfileCompilationInfo::MethodHotness::Flag>(flags)));
-    }, [&profile](TypeReference ref) {
-      std::set<dex::TypeIndex> classes;
-      classes.insert(ref.TypeIndex());
-      EXPECT_TRUE(profile.AddClassesForDex(ref.dex_file, classes.begin(), classes.end()));
-    }, method_frequency, type_frequency);
+    VisitDexes(
+        dexes,
+        [&profile](MethodReference ref) {
+          uint32_t flags = ProfileCompilationInfo::MethodHotness::kFlagHot |
+              ProfileCompilationInfo::MethodHotness::kFlagStartup;
+          EXPECT_TRUE(profile.AddMethod(
+              ProfileMethodInfo(ref),
+              static_cast<ProfileCompilationInfo::MethodHotness::Flag>(flags)));
+        },
+        [&profile](TypeReference ref) {
+          std::set<dex::TypeIndex> classes;
+          classes.insert(ref.TypeIndex());
+          EXPECT_TRUE(profile.AddClassesForDex(ref.dex_file, classes.begin(), classes.end()));
+        },
+        method_frequency,
+        type_frequency);
     ScratchFile profile_file;
     profile.Save(out_file->Fd());
     EXPECT_EQ(out_file->Flush(), 0);
@@ -241,7 +260,10 @@
   // Compile all methods and classes
   {
     ScratchFile profile_file;
-    GenerateProfile(profile_file.GetFile(), /*method_frequency=*/ 1u, /*type_frequency=*/ 1u);
+    GenerateProfile(GetLibCoreDexFileNames(),
+                    profile_file.GetFile(),
+                    /*method_frequency=*/ 1u,
+                    /*type_frequency=*/ 1u);
     everything_sizes = CompileImageAndGetSizes(
         {"--profile-file=" + profile_file.GetFilename(),
          "--compiler-filter=speed-profile"});
@@ -257,7 +279,10 @@
   // Test compiling fewer methods and classes.
   {
     ScratchFile profile_file;
-    GenerateProfile(profile_file.GetFile(), kMethodFrequency, kTypeFrequency);
+    GenerateProfile(GetLibCoreDexFileNames(),
+                    profile_file.GetFile(),
+                    kMethodFrequency,
+                    kTypeFrequency);
     filter_sizes = CompileImageAndGetSizes(
         {"--profile-file=" + profile_file.GetFilename(),
          "--compiler-filter=speed-profile"});
@@ -328,19 +353,30 @@
     dex_file = new_location;
   }
 
+  // Create a profile.
+  ScratchFile profile_file;
+  GenerateProfile(libcore_dex_files,
+                  profile_file.GetFile(),
+                  /*method_frequency=*/ 1u,
+                  /*type_frequency=*/ 1u);
+  std::vector<std::string> extra_args;
+  extra_args.push_back("--profile-file=" + profile_file.GetFilename());
+
   ArrayRef<const std::string> full_bcp(libcore_dex_files);
   size_t total_dex_files = full_bcp.size();
-  ASSERT_GE(total_dex_files, 4u);  // 2 for "head", 1 for "tail", at least one for "mid", see below.
+  ASSERT_GE(total_dex_files, 5u);  // 3 for "head", 1 for "tail", at least one for "mid", see below.
 
-  // The primary image must contain at least core-oj and core-libart to initialize the runtime.
+  // The primary image must contain at least core-oj and core-libart to initialize the runtime
+  // and we also need the core-icu4j if we want to compile these with full profile.
   ASSERT_NE(std::string::npos, full_bcp[0].find("core-oj"));
   ASSERT_NE(std::string::npos, full_bcp[1].find("core-libart"));
-  ArrayRef<const std::string> head_dex_files = full_bcp.SubArray(/*pos=*/ 0u, /*length=*/ 2u);
+  ASSERT_NE(std::string::npos, full_bcp[2].find("core-icu4j"));
+  ArrayRef<const std::string> head_dex_files = full_bcp.SubArray(/*pos=*/ 0u, /*length=*/ 3u);
   // Middle part is everything else except for conscrypt.
   ASSERT_NE(std::string::npos, full_bcp[full_bcp.size() - 1u].find("conscrypt"));
   ArrayRef<const std::string> mid_bcp =
       full_bcp.SubArray(/*pos=*/ 0u, /*length=*/ total_dex_files - 1u);
-  ArrayRef<const std::string> mid_dex_files = mid_bcp.SubArray(/*pos=*/ 2u);
+  ArrayRef<const std::string> mid_dex_files = mid_bcp.SubArray(/*pos=*/ 3u);
   // Tail is just the conscrypt.
   ArrayRef<const std::string> tail_dex_files =
       full_bcp.SubArray(/*pos=*/ total_dex_files - 1u, /*length=*/ 1u);
@@ -367,13 +403,13 @@
   std::string tail_name = tail_location.substr(tail_slash_pos + 1u);
 
   // Compile the "head", i.e. the primary boot image.
-  std::string base = android::base::StringPrintf("--base=0x%08x", kBaseAddress);
-  bool head_ok = CompileBootImage({base}, filename_prefix, head_dex_files, &error_msg);
+  extra_args.push_back(android::base::StringPrintf("--base=0x%08x", kBaseAddress));
+  bool head_ok = CompileBootImage(extra_args, filename_prefix, head_dex_files, &error_msg);
   ASSERT_TRUE(head_ok) << error_msg;
+  extra_args.pop_back();
 
   // Compile the "mid", i.e. the first extension.
   std::string mid_bcp_string = android::base::Join(mid_bcp, ':');
-  std::vector<std::string> extra_args;
   AddRuntimeArg(extra_args, "-Xbootclasspath:" + mid_bcp_string);
   AddRuntimeArg(extra_args, "-Xbootclasspath-locations:" + mid_bcp_string);
   extra_args.push_back("--boot-image=" + base_location);
diff --git a/dex2oat/driver/compiler_driver.cc b/dex2oat/driver/compiler_driver.cc
index f3c103b..c3801f4 100644
--- a/dex2oat/driver/compiler_driver.cc
+++ b/dex2oat/driver/compiler_driver.cc
@@ -1050,7 +1050,7 @@
   }
 
   TimingLogger::ScopedTiming t("LoadImageClasses", timings);
-  // Make a first class to load all classes explicitly listed in the file
+  // Make a first pass to load all classes explicitly listed in the file
   Thread* self = Thread::Current();
   ScopedObjectAccess soa(self);
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc
index 4584dd3..13f22d9 100644
--- a/dex2oat/linker/image_writer.cc
+++ b/dex2oat/linker/image_writer.cc
@@ -2181,6 +2181,16 @@
           CHECK(field->GetObject(ref) == nullptr);
           return;
         }
+        if (obj->IsString()) {
+          // Ignore interned strings. These may come from reflection interning method names.
+          // TODO: Make dex file strings weak interns and GC them before writing the image.
+          Runtime* runtime = Runtime::Current();
+          ObjPtr<mirror::String> interned =
+              runtime->GetInternTable()->LookupStrong(Thread::Current(), obj->AsString());
+          if (interned == obj) {
+            return;
+          }
+        }
         LOG(FATAL) << "Image object without assigned bin slot: "
             << mirror::Object::PrettyTypeOf(obj) << " " << obj;
       }