Clean up ImageSpace::LoadBootImage().

Do not rely on data from Runtime::Current(), pass required
parameters explicitly. Move initialization of runtime
methods to ClassLinker, remove the "uninitialization" from
ImageSpace destructor as it's performed just before the
Runtime is destroyed and it is therefore unnecessary work.

This is not a complete cleanup as we still rely on the
Runtime::Current() for zygote and boot image compilation but
it allows imgdiag to load the system boot image directly.
This shall be implemented in a follow-up change.

Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Bug: 77856493
Change-Id: Ic08c2918d726df8d2af3f8803c1673d8216a3da5
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index cf66f58..03cc658 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -973,7 +973,8 @@
     *error_msg = StringPrintf("Invalid image pointer size: %u", pointer_size_unchecked);
     return false;
   }
-  image_pointer_size_ = spaces[0]->GetImageHeader().GetPointerSize();
+  const ImageHeader& image_header = spaces[0]->GetImageHeader();
+  image_pointer_size_ = image_header.GetPointerSize();
   if (!runtime->IsAotCompiler()) {
     // Only the Aot compiler supports having an image with a different pointer size than the
     // runtime. This happens on the host for compiling 32 bit tests since we use a 64 bit libart
@@ -985,6 +986,30 @@
       return false;
     }
   }
+  DCHECK(!runtime->HasResolutionMethod());
+  runtime->SetResolutionMethod(image_header.GetImageMethod(ImageHeader::kResolutionMethod));
+  runtime->SetImtConflictMethod(image_header.GetImageMethod(ImageHeader::kImtConflictMethod));
+  runtime->SetImtUnimplementedMethod(
+      image_header.GetImageMethod(ImageHeader::kImtUnimplementedMethod));
+  runtime->SetCalleeSaveMethod(
+      image_header.GetImageMethod(ImageHeader::kSaveAllCalleeSavesMethod),
+      CalleeSaveType::kSaveAllCalleeSaves);
+  runtime->SetCalleeSaveMethod(
+      image_header.GetImageMethod(ImageHeader::kSaveRefsOnlyMethod),
+      CalleeSaveType::kSaveRefsOnly);
+  runtime->SetCalleeSaveMethod(
+      image_header.GetImageMethod(ImageHeader::kSaveRefsAndArgsMethod),
+      CalleeSaveType::kSaveRefsAndArgs);
+  runtime->SetCalleeSaveMethod(
+      image_header.GetImageMethod(ImageHeader::kSaveEverythingMethod),
+      CalleeSaveType::kSaveEverything);
+  runtime->SetCalleeSaveMethod(
+      image_header.GetImageMethod(ImageHeader::kSaveEverythingMethodForClinit),
+      CalleeSaveType::kSaveEverythingForClinit);
+  runtime->SetCalleeSaveMethod(
+      image_header.GetImageMethod(ImageHeader::kSaveEverythingMethodForSuspendCheck),
+      CalleeSaveType::kSaveEverythingForSuspendCheck);
+
   std::vector<const OatFile*> oat_files =
       runtime->GetOatFileManager().RegisterImageOatFiles(spaces);
   DCHECK(!oat_files.empty());
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 6f72740..1a611df 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -372,6 +372,9 @@
                                        image_file_name,
                                        image_instruction_set,
                                        image_space_loading_order,
+                                       runtime->ShouldRelocate(),
+                                       /*executable=*/ !runtime->IsAotCompiler(),
+                                       is_zygote,
                                        heap_reservation_size,
                                        &boot_image_spaces,
                                        &heap_reservation)) {
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 3d676ae..c5c5e8a 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -308,6 +308,7 @@
 
 static bool ImageCreationAllowed(bool is_global_cache,
                                  const InstructionSet isa,
+                                 bool is_zygote,
                                  std::string* error_msg) {
   // Anyone can write into a "local" cache.
   if (!is_global_cache) {
@@ -317,7 +318,7 @@
   // Only the zygote running as root is allowed to create the global boot image.
   // If the zygote is running as non-root (and cannot write to the dalvik-cache),
   // then image creation is not allowed..
-  if (Runtime::Current()->IsZygote()) {
+  if (is_zygote) {
     return CanWriteToDalvikCache(isa);
   }
 
@@ -1413,12 +1414,17 @@
   BootImageLoader(const std::vector<std::string>& boot_class_path,
                   const std::vector<std::string>& boot_class_path_locations,
                   const std::string& image_location,
-                  InstructionSet image_isa)
+                  InstructionSet image_isa,
+                  bool relocate,
+                  bool executable,
+                  bool is_zygote)
       : boot_class_path_(boot_class_path),
         boot_class_path_locations_(boot_class_path_locations),
         image_location_(image_location),
         image_isa_(image_isa),
-        is_zygote_(Runtime::Current()->IsZygote()),
+        relocate_(relocate),
+        executable_(executable),
+        is_zygote_(is_zygote),
         has_system_(false),
         has_cache_(false),
         is_global_cache_(true),
@@ -1585,7 +1591,6 @@
     }
 
     MaybeRelocateSpaces(spaces, logger);
-    InitRuntimeMethods(spaces);
     boot_image_spaces->swap(spaces);
     *extra_reservation = std::move(local_extra_reservation);
     return true;
@@ -1753,15 +1758,15 @@
     }
   }
 
-  static void MaybeRelocateSpaces(const std::vector<std::unique_ptr<ImageSpace>>& spaces,
-                                  TimingLogger* logger)
+  void MaybeRelocateSpaces(const std::vector<std::unique_ptr<ImageSpace>>& spaces,
+                           TimingLogger* logger)
       REQUIRES_SHARED(Locks::mutator_lock_) {
     TimingLogger::ScopedTiming timing("MaybeRelocateSpaces", logger);
     ImageSpace* first_space = spaces.front().get();
     const ImageHeader& first_space_header = first_space->GetImageHeader();
     uint32_t diff =
         static_cast<uint32_t>(first_space->Begin() - first_space_header.GetImageBegin());
-    if (!Runtime::Current()->ShouldRelocate()) {
+    if (!relocate_) {
       DCHECK_EQ(diff, 0u);
       return;
     }
@@ -1774,37 +1779,6 @@
     }
   }
 
-  static void InitRuntimeMethods(const std::vector<std::unique_ptr<ImageSpace>>& spaces)
-      REQUIRES_SHARED(Locks::mutator_lock_) {
-    Runtime* runtime = Runtime::Current();
-    DCHECK(!runtime->HasResolutionMethod());
-    DCHECK(!spaces.empty());
-    ImageSpace* space = spaces[0].get();
-    const ImageHeader& image_header = space->GetImageHeader();
-    runtime->SetResolutionMethod(image_header.GetImageMethod(ImageHeader::kResolutionMethod));
-    runtime->SetImtConflictMethod(image_header.GetImageMethod(ImageHeader::kImtConflictMethod));
-    runtime->SetImtUnimplementedMethod(
-        image_header.GetImageMethod(ImageHeader::kImtUnimplementedMethod));
-    runtime->SetCalleeSaveMethod(
-        image_header.GetImageMethod(ImageHeader::kSaveAllCalleeSavesMethod),
-        CalleeSaveType::kSaveAllCalleeSaves);
-    runtime->SetCalleeSaveMethod(
-        image_header.GetImageMethod(ImageHeader::kSaveRefsOnlyMethod),
-        CalleeSaveType::kSaveRefsOnly);
-    runtime->SetCalleeSaveMethod(
-        image_header.GetImageMethod(ImageHeader::kSaveRefsAndArgsMethod),
-        CalleeSaveType::kSaveRefsAndArgs);
-    runtime->SetCalleeSaveMethod(
-        image_header.GetImageMethod(ImageHeader::kSaveEverythingMethod),
-        CalleeSaveType::kSaveEverything);
-    runtime->SetCalleeSaveMethod(
-        image_header.GetImageMethod(ImageHeader::kSaveEverythingMethodForClinit),
-        CalleeSaveType::kSaveEverythingForClinit);
-    runtime->SetCalleeSaveMethod(
-        image_header.GetImageMethod(ImageHeader::kSaveEverythingMethodForSuspendCheck),
-        CalleeSaveType::kSaveEverythingForSuspendCheck);
-  }
-
   std::unique_ptr<ImageSpace> Load(const std::string& image_location,
                                    const std::string& image_filename,
                                    TimingLogger* logger,
@@ -1867,7 +1841,7 @@
       oat_file.reset(OatFile::Open(/*zip_fd=*/ -1,
                                    oat_filename,
                                    oat_location,
-                                   !Runtime::Current()->IsAotCompiler(),
+                                   executable_,
                                    /*low_4gb=*/ false,
                                    /*abs_dex_location=*/ dex_filename.c_str(),
                                    image_reservation,
@@ -1937,9 +1911,8 @@
     DCHECK(!image_reservation->IsValid());
     DCHECK_LT(extra_reservation_size, std::numeric_limits<uint32_t>::max() - reservation_size);
     size_t total_size = reservation_size + extra_reservation_size;
-    bool relocate = Runtime::Current()->ShouldRelocate();
     // If relocating, choose a random address for ALSR.
-    uint32_t addr = relocate ? ART_BASE_ADDRESS + ChooseRelocationOffsetDelta() : image_start;
+    uint32_t addr = relocate_ ? ART_BASE_ADDRESS + ChooseRelocationOffsetDelta() : image_start;
     *image_reservation =
         MemMap::MapAnonymous("Boot image reservation",
                              reinterpret_cast32<uint8_t*>(addr),
@@ -1983,6 +1956,8 @@
   const std::vector<std::string>& boot_class_path_locations_;
   const std::string& image_location_;
   InstructionSet image_isa_;
+  bool relocate_;
+  bool executable_;
   bool is_zygote_;
   bool has_system_;
   bool has_cache_;
@@ -2033,6 +2008,9 @@
     const std::string& image_location,
     const InstructionSet image_isa,
     ImageSpaceLoadingOrder order,
+    bool relocate,
+    bool executable,
+    bool is_zygote,
     size_t extra_reservation_size,
     /*out*/std::vector<std::unique_ptr<space::ImageSpace>>* boot_image_spaces,
     /*out*/MemMap* extra_reservation) {
@@ -2048,7 +2026,13 @@
     return false;
   }
 
-  BootImageLoader loader(boot_class_path, boot_class_path_locations, image_location, image_isa);
+  BootImageLoader loader(boot_class_path,
+                         boot_class_path_locations,
+                         image_location,
+                         image_isa,
+                         relocate,
+                         executable,
+                         is_zygote);
 
   // Step 0: Extra zygote work.
 
@@ -2065,8 +2049,7 @@
   //
   //           The advantage of doing this proactively is that the later steps are simplified,
   //           i.e., we do not need to code retries.
-  bool dex2oat_enabled = Runtime::Current()->IsImageDex2OatEnabled();
-
+  bool low_space = false;
   if (loader.IsZygote() && loader.DalvikCacheExists()) {
     // Extra checks for the zygote. These only apply when loading the first image, explained below.
     const std::string& dalvik_cache = loader.GetDalvikCache();
@@ -2079,10 +2062,9 @@
 
       // Re-evaluate the image.
       loader.FindImageFiles();
-    }
-    if (!check_space) {
+
       // Disable compilation/patching - we do not want to fill up the space again.
-      dex2oat_enabled = false;
+      low_space = true;
     }
   }
 
@@ -2130,9 +2112,12 @@
   //         so generate an image into the dalvik cache.
   if (!loader.HasSystem() && loader.DalvikCacheExists()) {
     std::string local_error_msg;
-    if (!dex2oat_enabled) {
+    if (low_space || !Runtime::Current()->IsImageDex2OatEnabled()) {
       local_error_msg = "Image compilation disabled.";
-    } else if (ImageCreationAllowed(loader.IsGlobalCache(), image_isa, &local_error_msg)) {
+    } else if (ImageCreationAllowed(loader.IsGlobalCache(),
+                                    image_isa,
+                                    is_zygote,
+                                    &local_error_msg)) {
       bool compilation_success =
           GenerateImage(loader.GetCacheFilename(), image_isa, &local_error_msg);
       if (compilation_success) {
@@ -2152,7 +2137,9 @@
 
   // We failed. Prune the cache the free up space, create a compound error message
   // and return false.
-  PruneDalvikCache(image_isa);
+  if (loader.DalvikCacheExists()) {
+    PruneDalvikCache(image_isa);
+  }
 
   std::ostringstream oss;
   bool first = true;
@@ -2170,26 +2157,7 @@
 }
 
 ImageSpace::~ImageSpace() {
-  Runtime* runtime = Runtime::Current();
-  if (runtime == nullptr) {
-    return;
-  }
-
-  if (GetImageHeader().IsAppImage()) {
-    // This image space did not modify resolution method then in Init.
-    return;
-  }
-
-  if (!runtime->HasResolutionMethod()) {
-    // Another image space has already unloaded the below methods.
-    return;
-  }
-
-  runtime->ClearInstructionSet();
-  runtime->ClearResolutionMethod();
-  runtime->ClearImtConflictMethod();
-  runtime->ClearImtUnimplementedMethod();
-  runtime->ClearCalleeSaveMethods();
+  // Everything done by member destructors. Classes forward-declared in header are now defined.
 }
 
 std::unique_ptr<ImageSpace> ImageSpace::CreateFromAppImage(const char* image,
diff --git a/runtime/gc/space/image_space.h b/runtime/gc/space/image_space.h
index 1c61f06..c7d5140 100644
--- a/runtime/gc/space/image_space.h
+++ b/runtime/gc/space/image_space.h
@@ -50,6 +50,9 @@
       const std::string& image_location,
       const InstructionSet image_isa,
       ImageSpaceLoadingOrder order,
+      bool relocate,
+      bool executable,
+      bool is_zygote,
       size_t extra_reservation_size,
       /*out*/std::vector<std::unique_ptr<space::ImageSpace>>* boot_image_spaces,
       /*out*/MemMap* extra_reservation) REQUIRES_SHARED(Locks::mutator_lock_);