OSDN Git Service

Revert "Add basic image writer support for app images"
authorNicolas Geoffray <ngeoffray@google.com>
Thu, 5 Nov 2015 08:47:52 +0000 (08:47 +0000)
committerNicolas Geoffray <ngeoffray@google.com>
Thu, 5 Nov 2015 08:48:36 +0000 (08:48 +0000)
interpreter and jit tests fail.

Bug: 22858531

This reverts commit c033474cfbfe1e963c07fa5c38aed02e35ed6f91.

Change-Id: Ic12a3e2a1908ac0db52d21a0b44b2508c88b2585

12 files changed:
compiler/dex/quick/arm64/call_arm64.cc
compiler/driver/compiler_driver.cc
compiler/driver/compiler_driver.h
compiler/image_test.cc
compiler/image_writer.cc
compiler/image_writer.h
compiler/oat_test.cc
compiler/oat_writer.cc
compiler/oat_writer.h
dex2oat/dex2oat.cc
runtime/class_linker.cc
test/etc/run-test-jar

index b1acf5e..036da2e 100644 (file)
@@ -447,7 +447,7 @@ void Arm64Mir2Lir::GenSpecialExitForSuspend() {
 
 static bool Arm64UseRelativeCall(CompilationUnit* cu, const MethodReference& target_method) {
   // Emit relative calls anywhere in the image or within a dex file otherwise.
-  return cu->compiler_driver->IsBootImage() || cu->dex_file == target_method.dex_file;
+  return cu->compiler_driver->IsImage() || cu->dex_file == target_method.dex_file;
 }
 
 /*
index 0e73bd9..d055b37 100644 (file)
@@ -341,7 +341,7 @@ CompilerDriver::CompilerDriver(const CompilerOptions* compiler_options,
                                Compiler::Kind compiler_kind,
                                InstructionSet instruction_set,
                                const InstructionSetFeatures* instruction_set_features,
-                               bool boot_image, std::unordered_set<std::string>* image_classes,
+                               bool image, std::unordered_set<std::string>* image_classes,
                                std::unordered_set<std::string>* compiled_classes,
                                std::unordered_set<std::string>* compiled_methods,
                                size_t thread_count, bool dump_stats, bool dump_passes,
@@ -361,7 +361,7 @@ CompilerDriver::CompilerDriver(const CompilerOptions* compiler_options,
       compiled_methods_lock_("compiled method lock"),
       compiled_methods_(MethodTable::key_compare()),
       non_relative_linker_patch_count_(0u),
-      boot_image_(boot_image),
+      image_(image),
       image_classes_(image_classes),
       classes_to_compile_(compiled_classes),
       methods_to_compile_(compiled_methods),
@@ -383,7 +383,7 @@ CompilerDriver::CompilerDriver(const CompilerOptions* compiler_options,
 
   compiler_->Init();
 
-  CHECK_EQ(boot_image_, image_classes_.get() != nullptr);
+  CHECK_EQ(image_, image_classes_.get() != nullptr);
 
   // Read the profile file if one is provided.
   if (!profile_file.empty()) {
@@ -781,7 +781,7 @@ void CompilerDriver::PreCompile(jobject class_loader, const std::vector<const De
 }
 
 bool CompilerDriver::IsImageClass(const char* descriptor) const {
-  if (!IsBootImage()) {
+  if (!IsImage()) {
     // NOTE: Currently unreachable, all callers check IsImage().
     return false;
   } else {
@@ -790,7 +790,7 @@ bool CompilerDriver::IsImageClass(const char* descriptor) const {
 }
 
 bool CompilerDriver::IsClassToCompile(const char* descriptor) const {
-  if (kRestrictCompilationFiltersToImage && !IsBootImage()) {
+  if (kRestrictCompilationFiltersToImage && !IsImage()) {
     return true;
   }
 
@@ -801,7 +801,7 @@ bool CompilerDriver::IsClassToCompile(const char* descriptor) const {
 }
 
 bool CompilerDriver::IsMethodToCompile(const MethodReference& method_ref) const {
-  if (kRestrictCompilationFiltersToImage && !IsBootImage()) {
+  if (kRestrictCompilationFiltersToImage && !IsImage()) {
     return true;
   }
 
@@ -889,7 +889,7 @@ class RecordImageClassesVisitor : public ClassVisitor {
 // Make a list of descriptors for classes to include in the image
 void CompilerDriver::LoadImageClasses(TimingLogger* timings) {
   CHECK(timings != nullptr);
-  if (!IsBootImage()) {
+  if (!IsImage()) {
     return;
   }
 
@@ -1118,7 +1118,7 @@ class ClinitImageUpdate {
 };
 
 void CompilerDriver::UpdateImageClasses(TimingLogger* timings) {
-  if (IsBootImage()) {
+  if (IsImage()) {
     TimingLogger::ScopedTiming t("UpdateImageClasses", timings);
 
     Runtime* runtime = Runtime::Current();
@@ -1145,7 +1145,7 @@ bool CompilerDriver::CanAssumeClassIsLoaded(mirror::Class* klass) {
     // Having the klass reference here implies that the klass is already loaded.
     return true;
   }
-  if (!IsBootImage()) {
+  if (!IsImage()) {
     // Assume loaded only if klass is in the boot image. App classes cannot be assumed
     // loaded because we don't even know what class loader will be used to load them.
     bool class_in_image = runtime->GetHeap()->FindSpaceFromObject(klass, false)->IsImageSpace();
@@ -1157,7 +1157,7 @@ bool CompilerDriver::CanAssumeClassIsLoaded(mirror::Class* klass) {
 }
 
 bool CompilerDriver::CanAssumeTypeIsPresentInDexCache(const DexFile& dex_file, uint32_t type_idx) {
-  if (IsBootImage() &&
+  if (IsImage() &&
       IsImageClass(dex_file.StringDataByIdx(dex_file.GetTypeId(type_idx).descriptor_idx_))) {
     {
       ScopedObjectAccess soa(Thread::Current());
@@ -1183,7 +1183,7 @@ bool CompilerDriver::CanAssumeStringIsPresentInDexCache(const DexFile& dex_file,
   // See also Compiler::ResolveDexFile
 
   bool result = false;
-  if (IsBootImage()) {
+  if (IsImage()) {
     // We resolve all const-string strings when building for the image.
     ScopedObjectAccess soa(Thread::Current());
     StackHandleScope<1> hs(soa.Self());
@@ -1300,7 +1300,7 @@ bool CompilerDriver::CanEmbedTypeInCode(const DexFile& dex_file, uint32_t type_i
   if (compiling_boot) {
     // boot -> boot class pointers.
     // True if the class is in the image at boot compiling time.
-    const bool is_image_class = IsBootImage() && IsImageClass(
+    const bool is_image_class = IsImage() && IsImageClass(
         dex_file.StringDataByIdx(dex_file.GetTypeId(type_idx).descriptor_idx_));
     // True if pc relative load works.
     if (is_image_class && support_boot_image_fixup) {
@@ -1548,7 +1548,7 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType
   }
   if (!use_dex_cache && force_relocations) {
     bool is_in_image;
-    if (IsBootImage()) {
+    if (IsImage()) {
       is_in_image = IsImageClass(method->GetDeclaringClassDescriptor());
     } else {
       is_in_image = instruction_set_ != kX86 && instruction_set_ != kX86_64 &&
@@ -2019,7 +2019,7 @@ void CompilerDriver::ResolveDexFile(jobject class_loader, const DexFile& dex_fil
 
   ParallelCompilationManager context(class_linker, class_loader, this, &dex_file, dex_files,
                                      thread_pool);
-  if (IsBootImage()) {
+  if (IsImage()) {
     // For images we resolve all types, such as array, whereas for applications just those with
     // classdefs are resolved by ResolveClassFieldsAndMethods.
     TimingLogger::ScopedTiming t("Resolve Types", timings);
@@ -2101,8 +2101,8 @@ class VerifyClassVisitor : public CompilationVisitor {
       // It is *very* problematic if there are verification errors in the boot classpath. For example,
       // we rely on things working OK without verification when the decryption dialog is brought up.
       // So abort in a debug build if we find this violated.
-      DCHECK(!manager_->GetCompiler()->IsBootImage() || klass->IsVerified())
-          << "Boot classpath class " << PrettyClass(klass.Get()) << " failed to fully verify.";
+      DCHECK(!manager_->GetCompiler()->IsImage() || klass->IsVerified()) << "Boot classpath class "
+          << PrettyClass(klass.Get()) << " failed to fully verify.";
     }
     soa.Self()->AssertNoPendingException();
   }
@@ -2222,7 +2222,7 @@ class InitializeClassVisitor : public CompilationVisitor {
           if (!klass->IsInitialized()) {
             // We need to initialize static fields, we only do this for image classes that aren't
             // marked with the $NoPreloadHolder (which implies this should not be initialized early).
-            bool can_init_static_fields = manager_->GetCompiler()->IsBootImage() &&
+            bool can_init_static_fields = manager_->GetCompiler()->IsImage() &&
                 manager_->GetCompiler()->IsImageClass(descriptor) &&
                 !StringPiece(descriptor).ends_with("$NoPreloadHolder;");
             if (can_init_static_fields) {
@@ -2286,7 +2286,7 @@ void CompilerDriver::InitializeClasses(jobject jni_class_loader, const DexFile&
   ParallelCompilationManager context(class_linker, jni_class_loader, this, &dex_file, dex_files,
                                      thread_pool);
   size_t thread_count;
-  if (IsBootImage()) {
+  if (IsImage()) {
     // TODO: remove this when transactional mode supports multithreading.
     thread_count = 1U;
   } else {
@@ -2304,7 +2304,7 @@ void CompilerDriver::InitializeClasses(jobject class_loader,
     CHECK(dex_file != nullptr);
     InitializeClasses(class_loader, *dex_file, dex_files, thread_pool, timings);
   }
-  if (IsBootImage()) {
+  if (IsImage()) {
     // Prune garbage objects created during aborted transactions.
     Runtime::Current()->GetHeap()->CollectGarbage(true);
   }
index 15b6bba..4ed4dc6 100644 (file)
@@ -92,7 +92,7 @@ class CompilerDriver {
                  Compiler::Kind compiler_kind,
                  InstructionSet instruction_set,
                  const InstructionSetFeatures* instruction_set_features,
-                 bool boot_image, std::unordered_set<std::string>* image_classes,
+                 bool image, std::unordered_set<std::string>* image_classes,
                  std::unordered_set<std::string>* compiled_classes,
                  std::unordered_set<std::string>* compiled_methods,
                  size_t thread_count, bool dump_stats, bool dump_passes,
@@ -156,8 +156,8 @@ class CompilerDriver {
   }
 
   // Are we compiling and creating an image file?
-  bool IsBootImage() const {
-    return boot_image_;
+  bool IsImage() const {
+    return image_;
   }
 
   const std::unordered_set<std::string>* GetImageClasses() const {
@@ -637,7 +637,7 @@ class CompilerDriver {
   // in the .oat_patches ELF section if requested in the compiler options.
   size_t non_relative_linker_patch_count_ GUARDED_BY(compiled_methods_lock_);
 
-  const bool boot_image_;
+  const bool image_;
 
   // If image_ is true, specifies the classes that will be included in
   // the image. Note if image_classes_ is null, all classes are
index a38e1f5..fd6cd82 100644 (file)
@@ -64,10 +64,8 @@ TEST_F(ImageTest, WriteRead) {
   ScratchFile oat_file(OS::CreateEmptyFile(oat_filename.c_str()));
 
   const uintptr_t requested_image_base = ART_BASE_ADDRESS;
-  std::unique_ptr<ImageWriter> writer(new ImageWriter(*compiler_driver_,
-                                                      requested_image_base,
-                                                      /*compile_pic*/false,
-                                                      /*compile_app_image*/false));
+  std::unique_ptr<ImageWriter> writer(new ImageWriter(*compiler_driver_, requested_image_base,
+                                                      /*compile_pic*/false));
   // TODO: compile_pic should be a test argument.
   {
     {
@@ -83,15 +81,8 @@ TEST_F(ImageTest, WriteRead) {
 
       t.NewTiming("WriteElf");
       SafeMap<std::string, std::string> key_value_store;
-      OatWriter oat_writer(class_linker->GetBootClassPath(),
-                           0,
-                           0,
-                           0,
-                           compiler_driver_.get(),
-                           writer.get(),
-                           /*compiling_boot_image*/true,
-                           &timings,
-                           &key_value_store);
+      OatWriter oat_writer(class_linker->GetBootClassPath(), 0, 0, 0, compiler_driver_.get(),
+                           writer.get(), &timings, &key_value_store);
       bool success = writer->PrepareImageAddressSpace() &&
           compiler_driver_->WriteElf(GetTestAndroidRoot(),
                                      !kIsTargetBuild,
index 0c85323..af2a4f9 100644 (file)
@@ -20,7 +20,6 @@
 
 #include <memory>
 #include <numeric>
-#include <unordered_set>
 #include <vector>
 
 #include "art_field-inl.h"
@@ -73,27 +72,6 @@ namespace art {
 // Separate objects into multiple bins to optimize dirty memory use.
 static constexpr bool kBinObjects = true;
 
-// Return true if an object is already in an image space.
-bool ImageWriter::IsInBootImage(const void* obj) const {
-  if (!compile_app_image_) {
-    DCHECK(boot_image_space_ == nullptr);
-    return false;
-  }
-  const uint8_t* image_begin = boot_image_space_->Begin();
-  // Real image end including ArtMethods and ArtField sections.
-  const uint8_t* image_end = image_begin + boot_image_space_->GetImageHeader().GetImageSize();
-  return image_begin <= obj && obj < image_end;
-}
-
-bool ImageWriter::IsInBootOatFile(const void* ptr) const {
-  if (!compile_app_image_) {
-    DCHECK(boot_image_space_ == nullptr);
-    return false;
-  }
-  const ImageHeader& image_header = boot_image_space_->GetImageHeader();
-  return image_header.GetOatFileBegin() <= ptr && ptr < image_header.GetOatFileEnd();
-}
-
 static void CheckNoDexObjectsCallback(Object* obj, void* arg ATTRIBUTE_UNUSED)
     SHARED_REQUIRES(Locks::mutator_lock_) {
   Class* klass = obj->GetClass();
@@ -107,20 +85,12 @@ static void CheckNoDexObjects() {
 
 bool ImageWriter::PrepareImageAddressSpace() {
   target_ptr_size_ = InstructionSetPointerSize(compiler_driver_.GetInstructionSet());
-  gc::Heap* const heap = Runtime::Current()->GetHeap();
-  // Cache boot image space.
-    for (gc::space::ContinuousSpace* space : heap->GetContinuousSpaces()) {
-      if (space->IsImageSpace()) {
-        CHECK(compile_app_image_);
-        CHECK(boot_image_space_ == nullptr) << "Multiple image spaces";
-        boot_image_space_ = space->AsImageSpace();
-      }
-    }
   {
     ScopedObjectAccess soa(Thread::Current());
     PruneNonImageClasses();  // Remove junk
     ComputeLazyFieldsForImageClasses();  // Add useful information
   }
+  gc::Heap* heap = Runtime::Current()->GetHeap();
   heap->CollectGarbage(false);  // Remove garbage.
 
   // Dex caches must not have their dex fields set in the image. These are memory buffers of mapped
@@ -174,21 +144,21 @@ bool ImageWriter::Write(int image_fd,
   Runtime::Current()->GetOatFileManager().RegisterOatFile(
       std::unique_ptr<const OatFile>(oat_file_));
 
-  const OatHeader& oat_header = oat_file_->GetOatHeader();
-  oat_address_offsets_[kOatAddressInterpreterToInterpreterBridge] =
-      oat_header.GetInterpreterToInterpreterBridgeOffset();
-  oat_address_offsets_[kOatAddressInterpreterToCompiledCodeBridge] =
-      oat_header.GetInterpreterToCompiledCodeBridgeOffset();
-  oat_address_offsets_[kOatAddressJNIDlsymLookup] =
-      oat_header.GetJniDlsymLookupOffset();
-  oat_address_offsets_[kOatAddressQuickGenericJNITrampoline] =
-      oat_header.GetQuickGenericJniTrampolineOffset();
-  oat_address_offsets_[kOatAddressQuickIMTConflictTrampoline] =
-      oat_header.GetQuickImtConflictTrampolineOffset();
-  oat_address_offsets_[kOatAddressQuickResolutionTrampoline] =
-      oat_header.GetQuickResolutionTrampolineOffset();
-  oat_address_offsets_[kOatAddressQuickToInterpreterBridge] =
-      oat_header.GetQuickToInterpreterBridgeOffset();
+  interpreter_to_interpreter_bridge_offset_ =
+      oat_file_->GetOatHeader().GetInterpreterToInterpreterBridgeOffset();
+  interpreter_to_compiled_code_bridge_offset_ =
+      oat_file_->GetOatHeader().GetInterpreterToCompiledCodeBridgeOffset();
+
+  jni_dlsym_lookup_offset_ = oat_file_->GetOatHeader().GetJniDlsymLookupOffset();
+
+  quick_generic_jni_trampoline_offset_ =
+      oat_file_->GetOatHeader().GetQuickGenericJniTrampolineOffset();
+  quick_imt_conflict_trampoline_offset_ =
+      oat_file_->GetOatHeader().GetQuickImtConflictTrampolineOffset();
+  quick_resolution_trampoline_offset_ =
+      oat_file_->GetOatHeader().GetQuickResolutionTrampolineOffset();
+  quick_to_interpreter_bridge_offset_ =
+      oat_file_->GetOatHeader().GetQuickToInterpreterBridgeOffset();
 
   size_t oat_loaded_size = 0;
   size_t oat_data_offset = 0;
@@ -337,7 +307,7 @@ void ImageWriter::PrepareDexCacheArraySlots() {
   for (jobject weak_root : class_linker->GetDexCaches()) {
     mirror::DexCache* dex_cache =
         down_cast<mirror::DexCache*>(self->DecodeJObject(weak_root));
-    if (dex_cache == nullptr || IsInBootImage(dex_cache)) {
+    if (dex_cache == nullptr) {
       continue;
     }
     const DexFile* dex_file = dex_cache->GetDexFile();
@@ -361,7 +331,6 @@ void ImageWriter::PrepareDexCacheArraySlots() {
 
 void ImageWriter::AddDexCacheArrayRelocation(void* array, size_t offset) {
   if (array != nullptr) {
-    DCHECK(!IsInBootImage(array));
     native_object_relocations_.emplace(
         array,
         NativeObjectRelocation { offset, kNativeObjectRelocationTypeDexCacheArray });
@@ -375,8 +344,8 @@ void ImageWriter::AddMethodPointerArray(mirror::PointerArray* arr) {
       auto* method = arr->GetElementPtrSize<ArtMethod*>(i, target_ptr_size_);
       if (method != nullptr && !method->IsRuntimeMethod()) {
         auto* klass = method->GetDeclaringClass();
-        CHECK(klass == nullptr || KeepClass(klass))
-            << PrettyClass(klass) << " should be a kept class";
+        CHECK(klass == nullptr || IsImageClass(klass)) << PrettyClass(klass)
+            << " should be an image class";
       }
     }
   }
@@ -570,66 +539,10 @@ void ImageWriter::ComputeLazyFieldsForImageClasses() {
   class_linker->VisitClassesWithoutClassesLock(&visitor);
 }
 
-static bool IsBootClassLoaderClass(mirror::Class* klass) SHARED_REQUIRES(Locks::mutator_lock_) {
-  return klass->GetClassLoader() == nullptr;
-}
-
-bool ImageWriter::IsBootClassLoaderNonImageClass(mirror::Class* klass) {
-  return IsBootClassLoaderClass(klass) && !IsInBootImage(klass);
-}
-
-bool ImageWriter::ContainsBootClassLoaderNonImageClass(mirror::Class* klass) {
-  if (klass == nullptr) {
-    return false;
-  }
-  auto found = prune_class_memo_.find(klass);
-  if (found != prune_class_memo_.end()) {
-    // Already computed, return the found value.
-    return found->second;
-  }
-  // Place holder value to prevent infinite recursion.
-  prune_class_memo_.emplace(klass, false);
-  bool result = IsBootClassLoaderNonImageClass(klass);
-  if (!result) {
-    // Check interfaces since these wont be visited through VisitReferences.)
-    mirror::IfTable* if_table = klass->GetIfTable();
-    for (size_t i = 0, num_interfaces = klass->GetIfTableCount(); i < num_interfaces; ++i) {
-      result = result || ContainsBootClassLoaderNonImageClass(if_table->GetInterface(i));
-    }
-  }
-  // Check static fields and their classes.
-  size_t num_static_fields = klass->NumReferenceStaticFields();
-  if (num_static_fields != 0 && klass->IsResolved()) {
-    // Presumably GC can happen when we are cross compiling, it should not cause performance
-    // problems to do pointer size logic.
-    MemberOffset field_offset = klass->GetFirstReferenceStaticFieldOffset(
-        Runtime::Current()->GetClassLinker()->GetImagePointerSize());
-    for (size_t i = 0u; i < num_static_fields; ++i) {
-      mirror::Object* ref = klass->GetFieldObject<mirror::Object>(field_offset);
-      if (ref != nullptr) {
-        if (ref->IsClass()) {
-          result = result || ContainsBootClassLoaderNonImageClass(ref->AsClass());
-        }
-        result = result || ContainsBootClassLoaderNonImageClass(ref->GetClass());
-      }
-      field_offset = MemberOffset(field_offset.Uint32Value() +
-                                  sizeof(mirror::HeapReference<mirror::Object>));
-    }
-  }
-  result = result || ContainsBootClassLoaderNonImageClass(klass->GetSuperClass());
-  prune_class_memo_[klass] = result;
-  return result;
-}
-
-bool ImageWriter::KeepClass(Class* klass) {
+bool ImageWriter::IsImageClass(Class* klass) {
   if (klass == nullptr) {
     return false;
   }
-  if (compile_app_image_) {
-    // For app images, we need to prune boot loader classes that are not in the boot image since
-    // these may have already been loaded when the app image is loaded.
-    return !ContainsBootClassLoaderNonImageClass(klass);
-  }
   std::string temp;
   return compiler_driver_.IsImageClass(klass->GetDescriptor(&temp));
 }
@@ -639,17 +552,21 @@ class NonImageClassesVisitor : public ClassVisitor {
   explicit NonImageClassesVisitor(ImageWriter* image_writer) : image_writer_(image_writer) {}
 
   bool Visit(Class* klass) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_) {
-    if (!image_writer_->KeepClass(klass)) {
-      classes_to_prune_.insert(klass);
+    if (!image_writer_->IsImageClass(klass)) {
+      std::string temp;
+      non_image_classes_.insert(klass->GetDescriptor(&temp));
     }
     return true;
   }
 
-  std::unordered_set<mirror::Class*> classes_to_prune_;
+  std::set<std::string> non_image_classes_;
   ImageWriter* const image_writer_;
 };
 
 void ImageWriter::PruneNonImageClasses() {
+  if (compiler_driver_.GetImageClasses() == nullptr) {
+    return;
+  }
   Runtime* runtime = Runtime::Current();
   ClassLinker* class_linker = runtime->GetClassLinker();
   Thread* self = Thread::Current();
@@ -659,14 +576,8 @@ void ImageWriter::PruneNonImageClasses() {
   class_linker->VisitClasses(&visitor);
 
   // Remove the undesired classes from the class roots.
-  for (mirror::Class* klass : visitor.classes_to_prune_) {
-    std::string temp;
-    const char* name = klass->GetDescriptor(&temp);
-    VLOG(compiler) << "Pruning class " << name;
-    if (!compile_app_image_) {
-      DCHECK(IsBootClassLoaderClass(klass));
-    }
-    bool result = class_linker->RemoveClass(name, klass->GetClassLoader());
+  for (const std::string& it : visitor.non_image_classes_) {
+    bool result = class_linker->RemoveClass(it.c_str(), nullptr);
     DCHECK(result);
   }
 
@@ -683,7 +594,7 @@ void ImageWriter::PruneNonImageClasses() {
     }
     for (size_t i = 0; i < dex_cache->NumResolvedTypes(); i++) {
       Class* klass = dex_cache->GetResolvedType(i);
-      if (klass != nullptr && !KeepClass(klass)) {
+      if (klass != nullptr && !IsImageClass(klass)) {
         dex_cache->SetResolvedType(i, nullptr);
       }
     }
@@ -696,7 +607,7 @@ void ImageWriter::PruneNonImageClasses() {
         // Miranda methods may be held live by a class which was not an image class but have a
         // declaring class which is an image class. Set it to the resolution method to be safe and
         // prevent dangling pointers.
-        if (method->IsMiranda() || !KeepClass(declaring_class)) {
+        if (method->IsMiranda() || !IsImageClass(declaring_class)) {
           mirror::DexCache::SetElementPtrSize(resolved_methods,
                                               i,
                                               resolution_method,
@@ -710,7 +621,7 @@ void ImageWriter::PruneNonImageClasses() {
     }
     for (size_t i = 0; i < dex_cache->NumResolvedFields(); i++) {
       ArtField* field = dex_cache->GetResolvedField(i, target_ptr_size_);
-      if (field != nullptr && !KeepClass(field->GetDeclaringClass())) {
+      if (field != nullptr && !IsImageClass(field->GetDeclaringClass())) {
         dex_cache->SetResolvedField(i, nullptr, target_ptr_size_);
       }
     }
@@ -721,9 +632,6 @@ void ImageWriter::PruneNonImageClasses() {
 
   // Drop the array class cache in the ClassLinker, as these are roots holding those classes live.
   class_linker->DropFindArrayClassCache();
-
-  // Clear to save RAM.
-  prune_class_memo_.clear();
 }
 
 void ImageWriter::CheckNonImageClassesRemoved() {
@@ -735,13 +643,13 @@ void ImageWriter::CheckNonImageClassesRemoved() {
 
 void ImageWriter::CheckNonImageClassesRemovedCallback(Object* obj, void* arg) {
   ImageWriter* image_writer = reinterpret_cast<ImageWriter*>(arg);
-  if (obj->IsClass() && !image_writer->IsInBootImage(obj)) {
+  if (obj->IsClass()) {
     Class* klass = obj->AsClass();
-    if (!image_writer->KeepClass(klass)) {
+    if (!image_writer->IsImageClass(klass)) {
       image_writer->DumpImageClasses();
       std::string temp;
-      CHECK(image_writer->KeepClass(klass)) << klass->GetDescriptor(&temp)
-                                            << " " << PrettyDescriptor(klass);
+      CHECK(image_writer->IsImageClass(klass)) << klass->GetDescriptor(&temp)
+                                               << " " << PrettyDescriptor(klass);
     }
   }
 }
@@ -795,35 +703,25 @@ ObjectArray<Object>* ImageWriter::CreateImageRoots() const {
   // ObjectArray, we lock the dex lock twice, first to get the number
   // of dex caches first and then lock it again to copy the dex
   // caches. We check that the number of dex caches does not change.
-  size_t dex_cache_count = 0;
+  size_t dex_cache_count;
   {
     ReaderMutexLock mu(self, *class_linker->DexLock());
-    // Count number of dex caches not in the boot image.
-    for (jobject weak_root : class_linker->GetDexCaches()) {
-      mirror::DexCache* dex_cache = down_cast<mirror::DexCache*>(self->DecodeJObject(weak_root));
-      dex_cache_count += IsInBootImage(dex_cache) ? 0u : 1u;
-    }
+    dex_cache_count = class_linker->GetDexCacheCount();
   }
   Handle<ObjectArray<Object>> dex_caches(
-      hs.NewHandle(ObjectArray<Object>::Alloc(self, object_array_class.Get(), dex_cache_count)));
+      hs.NewHandle(ObjectArray<Object>::Alloc(self, object_array_class.Get(),
+                                              dex_cache_count)));
   CHECK(dex_caches.Get() != nullptr) << "Failed to allocate a dex cache array.";
   {
     ReaderMutexLock mu(self, *class_linker->DexLock());
-    size_t non_image_dex_caches = 0;
-    // Re-count number of non image dex caches.
-    for (jobject weak_root : class_linker->GetDexCaches()) {
-      mirror::DexCache* dex_cache = down_cast<mirror::DexCache*>(self->DecodeJObject(weak_root));
-      non_image_dex_caches += IsInBootImage(dex_cache) ? 0u : 1u;
-    }
-    CHECK_EQ(dex_cache_count, non_image_dex_caches)
-        << "The number of non-image dex caches changed.";
+    CHECK_EQ(dex_cache_count, class_linker->GetDexCacheCount())
+        << "The number of dex caches changed.";
     size_t i = 0;
     for (jobject weak_root : class_linker->GetDexCaches()) {
-      mirror::DexCache* dex_cache = down_cast<mirror::DexCache*>(self->DecodeJObject(weak_root));
-      if (!IsInBootImage(dex_cache)) {
-        dex_caches->Set<false>(i, dex_cache);
-        ++i;
-      }
+      mirror::DexCache* dex_cache =
+          down_cast<mirror::DexCache*>(self->DecodeJObject(weak_root));
+      dex_caches->Set<false>(i, dex_cache);
+      ++i;
     }
   }
 
@@ -863,10 +761,6 @@ void ImageWriter::WalkInstanceFields(mirror::Object* obj, mirror::Class* klass)
 
 // For an unvisited object, visit it then all its children found via fields.
 void ImageWriter::WalkFieldsInOrder(mirror::Object* obj) {
-  if (IsInBootImage(obj)) {
-    // Object is in the image, don't need to fix it up.
-    return;
-  }
   // Use our own visitor routine (instead of GC visitor) to get better locality between
   // an object and its fields
   if (!IsImageBinSlotAssigned(obj)) {
@@ -903,7 +797,6 @@ void ImageWriter::WalkFieldsInOrder(mirror::Object* obj) {
           CHECK(it == native_object_relocations_.end()) << "Field array " << cur_fields
                                                   << " already forwarded";
           size_t& offset = bin_slot_sizes_[kBinArtField];
-          DCHECK(!IsInBootImage(cur_fields));
           native_object_relocations_.emplace(
               cur_fields, NativeObjectRelocation {
                   offset, kNativeObjectRelocationTypeArtFieldArray });
@@ -915,7 +808,6 @@ void ImageWriter::WalkFieldsInOrder(mirror::Object* obj) {
             auto it2 = native_object_relocations_.find(field);
             CHECK(it2 == native_object_relocations_.end()) << "Field at index=" << i
                 << " already assigned " << PrettyField(field) << " static=" << field->IsStatic();
-            DCHECK(!IsInBootImage(field));
             native_object_relocations_.emplace(
                 field, NativeObjectRelocation {offset, kNativeObjectRelocationTypeArtField });
             offset += sizeof(ArtField);
@@ -951,7 +843,6 @@ void ImageWriter::WalkFieldsInOrder(mirror::Object* obj) {
         CHECK(it == native_object_relocations_.end()) << "Method array " << array
             << " already forwarded";
         size_t& offset = bin_slot_sizes_[bin_type];
-        DCHECK(!IsInBootImage(array));
         native_object_relocations_.emplace(array, NativeObjectRelocation { offset,
             any_dirty ? kNativeObjectRelocationTypeArtMethodArrayDirty :
                 kNativeObjectRelocationTypeArtMethodArrayClean });
@@ -976,7 +867,6 @@ void ImageWriter::WalkFieldsInOrder(mirror::Object* obj) {
 }
 
 void ImageWriter::AssignMethodOffset(ArtMethod* method, NativeObjectRelocationType type) {
-  DCHECK(!IsInBootImage(method));
   auto it = native_object_relocations_.find(method);
   CHECK(it == native_object_relocations_.end()) << "Method " << method << " already assigned "
       << PrettyMethod(method);
@@ -994,13 +884,10 @@ void ImageWriter::WalkFieldsCallback(mirror::Object* obj, void* arg) {
 void ImageWriter::UnbinObjectsIntoOffsetCallback(mirror::Object* obj, void* arg) {
   ImageWriter* writer = reinterpret_cast<ImageWriter*>(arg);
   DCHECK(writer != nullptr);
-  if (!writer->IsInBootImage(obj)) {
-    writer->UnbinObjectsIntoOffset(obj);
-  }
+  writer->UnbinObjectsIntoOffset(obj);
 }
 
 void ImageWriter::UnbinObjectsIntoOffset(mirror::Object* obj) {
-  DCHECK(!IsInBootImage(obj));
   CHECK(obj != nullptr);
 
   // We know the bin slot, and the total bin sizes for all objects by now,
@@ -1038,15 +925,13 @@ void ImageWriter::CalculateNewObjectOffsets() {
   image_methods_[ImageHeader::kRefsAndArgsSaveMethod] =
       runtime->GetCalleeSaveMethod(Runtime::kRefsAndArgs);
 
-  // Add room for fake length prefixed array for holding the image methods.
+  // Add room for fake length prefixed array.
   const auto image_method_type = kNativeObjectRelocationTypeArtMethodArrayClean;
   auto it = native_object_relocations_.find(&image_method_array_);
   CHECK(it == native_object_relocations_.end());
   size_t& offset = bin_slot_sizes_[BinTypeForNativeRelocationType(image_method_type)];
-  if (!compile_app_image_) {
-    native_object_relocations_.emplace(&image_method_array_,
-                                       NativeObjectRelocation { offset, image_method_type });
-  }
+  native_object_relocations_.emplace(&image_method_array_,
+                                     NativeObjectRelocation { offset, image_method_type });
   size_t method_alignment = ArtMethod::Alignment(target_ptr_size_);
   const size_t array_size = LengthPrefixedArray<ArtMethod>::ComputeSize(
       0, ArtMethod::Size(target_ptr_size_), method_alignment);
@@ -1055,10 +940,7 @@ void ImageWriter::CalculateNewObjectOffsets() {
   for (auto* m : image_methods_) {
     CHECK(m != nullptr);
     CHECK(m->IsRuntimeMethod());
-    DCHECK_EQ(compile_app_image_, IsInBootImage(m)) << "Trampolines should be in boot image";
-    if (!IsInBootImage(m)) {
-      AssignMethodOffset(m, kNativeObjectRelocationTypeArtMethodClean);
-    }
+    AssignMethodOffset(m, kNativeObjectRelocationTypeArtMethodClean);
   }
   // Calculate size of the dex cache arrays slot and prepare offsets.
   PrepareDexCacheArraySlots();
@@ -1208,7 +1090,6 @@ void ImageWriter::CopyAndFixupNativeData() {
     NativeObjectRelocation& relocation = pair.second;
     auto* dest = image_->Begin() + relocation.offset;
     DCHECK_GE(dest, image_->Begin() + image_end_);
-    DCHECK(!IsInBootImage(pair.first));
     switch (relocation.type) {
       case kNativeObjectRelocationTypeArtField: {
         memcpy(dest, pair.first, sizeof(ArtField));
@@ -1245,18 +1126,16 @@ void ImageWriter::CopyAndFixupNativeData() {
   auto* image_header = reinterpret_cast<ImageHeader*>(image_->Begin());
   const ImageSection& methods_section = image_header->GetMethodsSection();
   for (size_t i = 0; i < ImageHeader::kImageMethodsCount; ++i) {
-    ArtMethod* method = image_methods_[i];
-    CHECK(method != nullptr);
-    if (!IsInBootImage(method)) {
-      auto it = native_object_relocations_.find(method);
-      CHECK(it != native_object_relocations_.end()) << "No fowarding for " << PrettyMethod(method);
-      NativeObjectRelocation& relocation = it->second;
-      CHECK(methods_section.Contains(relocation.offset)) << relocation.offset << " not in "
-          << methods_section;
-      CHECK(relocation.IsArtMethodRelocation()) << relocation.type;
-      method = reinterpret_cast<ArtMethod*>(image_begin_ + it->second.offset);
-    }
-    image_header->SetImageMethod(static_cast<ImageHeader::ImageMethod>(i), method);
+    auto* m = image_methods_[i];
+    CHECK(m != nullptr);
+    auto it = native_object_relocations_.find(m);
+    CHECK(it != native_object_relocations_.end()) << "No fowarding for " << PrettyMethod(m);
+    NativeObjectRelocation& relocation = it->second;
+    CHECK(methods_section.Contains(relocation.offset)) << relocation.offset << " not in "
+        << methods_section;
+    CHECK(relocation.IsArtMethodRelocation()) << relocation.type;
+    auto* dest = reinterpret_cast<ArtMethod*>(image_begin_ + it->second.offset);
+    image_header->SetImageMethod(static_cast<ImageHeader::ImageMethod>(i), dest);
   }
   // Write the intern table into the image.
   const ImageSection& intern_table_section = image_header->GetImageSection(
@@ -1304,8 +1183,8 @@ void ImageWriter::FixupPointerArray(mirror::Object* dst, mirror::PointerArray* a
   dst->SetClass(GetImageAddress(arr->GetClass()));
   auto* dest_array = down_cast<mirror::PointerArray*>(dst);
   for (size_t i = 0, count = num_elements; i < count; ++i) {
-    void* elem = arr->GetElementPtrSize<void*>(i, target_ptr_size_);
-    if (elem != nullptr && !IsInBootImage(elem)) {
+    auto* elem = arr->GetElementPtrSize<void*>(i, target_ptr_size_);
+    if (elem != nullptr) {
       auto it = native_object_relocations_.find(elem);
       if (UNLIKELY(it == native_object_relocations_.end())) {
         if (it->second.IsArtMethodRelocation()) {
@@ -1330,9 +1209,6 @@ void ImageWriter::FixupPointerArray(mirror::Object* dst, mirror::PointerArray* a
 }
 
 void ImageWriter::CopyAndFixupObject(Object* obj) {
-  if (IsInBootImage(obj)) {
-    return;
-  }
   size_t offset = GetImageOffset(obj);
   auto* dst = reinterpret_cast<Object*>(image_->Begin() + offset);
   DCHECK_LT(offset, image_end_);
@@ -1406,19 +1282,18 @@ class FixupClassVisitor FINAL : public FixupVisitor {
 
 uintptr_t ImageWriter::NativeOffsetInImage(void* obj) {
   DCHECK(obj != nullptr);
-  DCHECK(!IsInBootImage(obj));
   auto it = native_object_relocations_.find(obj);
-  CHECK(it != native_object_relocations_.end()) << obj << " spaces "
-      << Runtime::Current()->GetHeap()->DumpSpaces();
+  CHECK(it != native_object_relocations_.end()) << obj;
   const NativeObjectRelocation& relocation = it->second;
   return relocation.offset;
 }
 
 template <typename T>
 T* ImageWriter::NativeLocationInImage(T* obj) {
-  return (obj == nullptr || IsInBootImage(obj))
-      ? obj
-      : reinterpret_cast<T*>(image_begin_ + NativeOffsetInImage(obj));
+  if (obj == nullptr) {
+    return nullptr;
+  }
+  return reinterpret_cast<T*>(image_begin_ + NativeOffsetInImage(obj));
 }
 
 void ImageWriter::FixupClass(mirror::Class* orig, mirror::Class* copy) {
@@ -1431,22 +1306,18 @@ void ImageWriter::FixupClass(mirror::Class* orig, mirror::Class* copy) {
   // Update dex cache strings.
   copy->SetDexCacheStrings(NativeLocationInImage(orig->GetDexCacheStrings()));
   // Fix up embedded tables.
-  if (!orig->IsTemp()) {
-    // TODO: Why do we have temp classes in some cases?
-    if (orig->ShouldHaveEmbeddedImtAndVTable()) {
-      for (int32_t i = 0; i < orig->GetEmbeddedVTableLength(); ++i) {
-        ArtMethod* orig_method = orig->GetEmbeddedVTableEntry(i, target_ptr_size_);
-        copy->SetEmbeddedVTableEntryUnchecked(
-            i,
-            NativeLocationInImage(orig_method),
-            target_ptr_size_);
-      }
-      for (size_t i = 0; i < mirror::Class::kImtSize; ++i) {
-        copy->SetEmbeddedImTableEntry(
-            i,
-            NativeLocationInImage(orig->GetEmbeddedImTableEntry(i, target_ptr_size_)),
-            target_ptr_size_);
-      }
+  if (orig->ShouldHaveEmbeddedImtAndVTable()) {
+    for (int32_t i = 0; i < orig->GetEmbeddedVTableLength(); ++i) {
+      auto it = native_object_relocations_.find(orig->GetEmbeddedVTableEntry(i, target_ptr_size_));
+      CHECK(it != native_object_relocations_.end()) << PrettyClass(orig);
+      copy->SetEmbeddedVTableEntryUnchecked(
+          i, reinterpret_cast<ArtMethod*>(image_begin_ + it->second.offset), target_ptr_size_);
+    }
+    for (size_t i = 0; i < mirror::Class::kImtSize; ++i) {
+      auto it = native_object_relocations_.find(orig->GetEmbeddedImTableEntry(i, target_ptr_size_));
+      CHECK(it != native_object_relocations_.end()) << PrettyClass(orig);
+      copy->SetEmbeddedImTableEntry(
+          i, reinterpret_cast<ArtMethod*>(image_begin_ + it->second.offset), target_ptr_size_);
     }
   }
   FixupClassVisitor visitor(this, copy);
@@ -1548,7 +1419,7 @@ void ImageWriter::FixupDexCache(mirror::DexCache* orig_dex_cache,
         reinterpret_cast<ArtMethod**>(image_->Begin() + copy_methods_offset);
     for (size_t i = 0, num = orig_dex_cache->NumResolvedMethods(); i != num; ++i) {
       ArtMethod* orig = mirror::DexCache::GetElementPtrSize(orig_methods, i, target_ptr_size_);
-      ArtMethod* copy = IsInBootImage(orig) ? orig : NativeLocationInImage(orig);
+      ArtMethod* copy = NativeLocationInImage(orig);
       mirror::DexCache::SetElementPtrSize(copy_methods, i, copy, target_ptr_size_);
     }
   }
@@ -1561,51 +1432,15 @@ void ImageWriter::FixupDexCache(mirror::DexCache* orig_dex_cache,
     ArtField** copy_fields = reinterpret_cast<ArtField**>(image_->Begin() + copy_fields_offset);
     for (size_t i = 0, num = orig_dex_cache->NumResolvedFields(); i != num; ++i) {
       ArtField* orig = mirror::DexCache::GetElementPtrSize(orig_fields, i, target_ptr_size_);
-      ArtField* copy = IsInBootImage(orig) ? orig : NativeLocationInImage(orig);
+      ArtField* copy = NativeLocationInImage(orig);
       mirror::DexCache::SetElementPtrSize(copy_fields, i, copy, target_ptr_size_);
     }
   }
 }
 
-const uint8_t* ImageWriter::GetOatAddress(OatAddress type) const {
-  DCHECK_LT(type, kOatAddressCount);
-  // If we are compiling an app image, we need to use the stubs of the boot image.
-  if (compile_app_image_) {
-    // Use the current image pointers.
-    gc::space::ImageSpace* image_space = Runtime::Current()->GetHeap()->GetImageSpace();
-    DCHECK(image_space != nullptr);
-    const OatFile* oat_file = image_space->GetOatFile();
-    CHECK(oat_file != nullptr);
-    const OatHeader& header = oat_file->GetOatHeader();
-    switch (type) {
-      // TODO: We could maybe clean this up if we stored them in an array in the oat header.
-      case kOatAddressQuickGenericJNITrampoline:
-        return static_cast<const uint8_t*>(header.GetQuickGenericJniTrampoline());
-      case kOatAddressInterpreterToInterpreterBridge:
-        return static_cast<const uint8_t*>(header.GetInterpreterToInterpreterBridge());
-      case kOatAddressInterpreterToCompiledCodeBridge:
-        return static_cast<const uint8_t*>(header.GetInterpreterToCompiledCodeBridge());
-      case kOatAddressJNIDlsymLookup:
-        return static_cast<const uint8_t*>(header.GetJniDlsymLookup());
-      case kOatAddressQuickIMTConflictTrampoline:
-        return static_cast<const uint8_t*>(header.GetQuickImtConflictTrampoline());
-      case kOatAddressQuickResolutionTrampoline:
-        return static_cast<const uint8_t*>(header.GetQuickResolutionTrampoline());
-      case kOatAddressQuickToInterpreterBridge:
-        return static_cast<const uint8_t*>(header.GetQuickToInterpreterBridge());
-      default:
-        UNREACHABLE();
-    }
-  }
-  return GetOatAddressForOffset(oat_address_offsets_[type]);
-}
-
 const uint8_t* ImageWriter::GetQuickCode(ArtMethod* method, bool* quick_is_interpreted) {
-  DCHECK(!method->IsResolutionMethod()) << PrettyMethod(method);
-  DCHECK(!method->IsImtConflictMethod()) << PrettyMethod(method);
-  DCHECK(!method->IsImtUnimplementedMethod()) << PrettyMethod(method);
-  DCHECK(!method->IsAbstract()) << PrettyMethod(method);
-  DCHECK(!IsInBootImage(method)) << PrettyMethod(method);
+  DCHECK(!method->IsResolutionMethod() && !method->IsImtConflictMethod() &&
+         !method->IsImtUnimplementedMethod() && !method->IsAbstract()) << PrettyMethod(method);
 
   // Use original code if it exists. Otherwise, set the code pointer to the resolution
   // trampoline.
@@ -1613,26 +1448,27 @@ const uint8_t* ImageWriter::GetQuickCode(ArtMethod* method, bool* quick_is_inter
   // Quick entrypoint:
   uint32_t quick_oat_code_offset = PointerToLowMemUInt32(
       method->GetEntryPointFromQuickCompiledCodePtrSize(target_ptr_size_));
-  const uint8_t* quick_code = GetOatAddressForOffset(quick_oat_code_offset);
+  const uint8_t* quick_code = GetOatAddress(quick_oat_code_offset);
   *quick_is_interpreted = false;
   if (quick_code != nullptr && (!method->IsStatic() || method->IsConstructor() ||
       method->GetDeclaringClass()->IsInitialized())) {
     // We have code for a non-static or initialized method, just use the code.
+    DCHECK_GE(quick_code, oat_data_begin_);
   } else if (quick_code == nullptr && method->IsNative() &&
       (!method->IsStatic() || method->GetDeclaringClass()->IsInitialized())) {
     // Non-static or initialized native method missing compiled code, use generic JNI version.
-    quick_code = GetOatAddress(kOatAddressQuickGenericJNITrampoline);
+    quick_code = GetOatAddress(quick_generic_jni_trampoline_offset_);
+    DCHECK_GE(quick_code, oat_data_begin_);
   } else if (quick_code == nullptr && !method->IsNative()) {
     // We don't have code at all for a non-native method, use the interpreter.
-    quick_code = GetOatAddress(kOatAddressQuickToInterpreterBridge);
+    quick_code = GetOatAddress(quick_to_interpreter_bridge_offset_);
     *quick_is_interpreted = true;
+    DCHECK_GE(quick_code, oat_data_begin_);
   } else {
     CHECK(!method->GetDeclaringClass()->IsInitialized());
     // We have code for a static method, but need to go through the resolution stub for class
     // initialization.
-    quick_code = GetOatAddress(kOatAddressQuickResolutionTrampoline);
-  }
-  if (!IsInBootOatFile(quick_code)) {
+    quick_code = GetOatAddress(quick_resolution_trampoline_offset_);
     DCHECK_GE(quick_code, oat_data_begin_);
   }
   return quick_code;
@@ -1643,16 +1479,16 @@ const uint8_t* ImageWriter::GetQuickEntryPoint(ArtMethod* method) {
   // The resolution method has a special trampoline to call.
   Runtime* runtime = Runtime::Current();
   if (UNLIKELY(method == runtime->GetResolutionMethod())) {
-    return GetOatAddress(kOatAddressQuickResolutionTrampoline);
+    return GetOatAddress(quick_resolution_trampoline_offset_);
   } else if (UNLIKELY(method == runtime->GetImtConflictMethod() ||
                       method == runtime->GetImtUnimplementedMethod())) {
-    return GetOatAddress(kOatAddressQuickIMTConflictTrampoline);
+    return GetOatAddress(quick_imt_conflict_trampoline_offset_);
   } else {
     // We assume all methods have code. If they don't currently then we set them to the use the
     // resolution trampoline. Abstract methods never have code and so we need to make sure their
     // use results in an AbstractMethodError. We use the interpreter to achieve this.
     if (UNLIKELY(method->IsAbstract())) {
-      return GetOatAddress(kOatAddressQuickToInterpreterBridge);
+      return GetOatAddress(quick_to_interpreter_bridge_offset_);
     } else {
       bool quick_is_interpreted;
       return GetQuickCode(method, &quick_is_interpreted);
@@ -1677,11 +1513,11 @@ void ImageWriter::CopyAndFixupMethod(ArtMethod* orig, ArtMethod* copy) {
   Runtime* runtime = Runtime::Current();
   if (UNLIKELY(orig == runtime->GetResolutionMethod())) {
     copy->SetEntryPointFromQuickCompiledCodePtrSize(
-        GetOatAddress(kOatAddressQuickResolutionTrampoline), target_ptr_size_);
+        GetOatAddress(quick_resolution_trampoline_offset_), target_ptr_size_);
   } else if (UNLIKELY(orig == runtime->GetImtConflictMethod() ||
                       orig == runtime->GetImtUnimplementedMethod())) {
     copy->SetEntryPointFromQuickCompiledCodePtrSize(
-        GetOatAddress(kOatAddressQuickIMTConflictTrampoline), target_ptr_size_);
+        GetOatAddress(quick_imt_conflict_trampoline_offset_), target_ptr_size_);
   } else if (UNLIKELY(orig->IsRuntimeMethod())) {
     bool found_one = false;
     for (size_t i = 0; i < static_cast<size_t>(Runtime::kLastCalleeSaveType); ++i) {
@@ -1699,7 +1535,7 @@ void ImageWriter::CopyAndFixupMethod(ArtMethod* orig, ArtMethod* copy) {
     // use results in an AbstractMethodError. We use the interpreter to achieve this.
     if (UNLIKELY(orig->IsAbstract())) {
       copy->SetEntryPointFromQuickCompiledCodePtrSize(
-          GetOatAddress(kOatAddressQuickToInterpreterBridge), target_ptr_size_);
+          GetOatAddress(quick_to_interpreter_bridge_offset_), target_ptr_size_);
     } else {
       bool quick_is_interpreted;
       const uint8_t* quick_code = GetQuickCode(orig, &quick_is_interpreted);
@@ -1710,7 +1546,7 @@ void ImageWriter::CopyAndFixupMethod(ArtMethod* orig, ArtMethod* copy) {
         // The native method's pointer is set to a stub to lookup via dlsym.
         // Note this is not the code_ pointer, that is handled above.
         copy->SetEntryPointFromJniPtrSize(
-            GetOatAddress(kOatAddressJNIDlsymLookup), target_ptr_size_);
+            GetOatAddress(jni_dlsym_lookup_offset_), target_ptr_size_);
       }
     }
   }
index 120de97..7a2febc 100644 (file)
 #include "utils.h"
 
 namespace art {
-namespace gc {
-namespace space {
-class ImageSpace;
-}  // namespace space
-}  // namespace gc
 
 static constexpr int kInvalidImageFd = -1;
 
 // Write a Space built during compilation for use during execution.
 class ImageWriter FINAL {
  public:
-  ImageWriter(const CompilerDriver& compiler_driver,
-              uintptr_t image_begin,
-              bool compile_pic,
-              bool compile_app_image)
-      : compiler_driver_(compiler_driver),
-        image_begin_(reinterpret_cast<uint8_t*>(image_begin)),
-        image_end_(0),
-        image_objects_offset_begin_(0),
-        image_roots_address_(0),
-        oat_file_(nullptr),
-        oat_data_begin_(nullptr),
-        compile_pic_(compile_pic),
-        compile_app_image_(compile_app_image),
-        boot_image_space_(nullptr),
+  ImageWriter(const CompilerDriver& compiler_driver, uintptr_t image_begin,
+              bool compile_pic)
+      : compiler_driver_(compiler_driver), image_begin_(reinterpret_cast<uint8_t*>(image_begin)),
+        image_end_(0), image_objects_offset_begin_(0), image_roots_address_(0), oat_file_(nullptr),
+        oat_data_begin_(nullptr), interpreter_to_interpreter_bridge_offset_(0),
+        interpreter_to_compiled_code_bridge_offset_(0), jni_dlsym_lookup_offset_(0),
+        quick_generic_jni_trampoline_offset_(0),
+        quick_imt_conflict_trampoline_offset_(0), quick_resolution_trampoline_offset_(0),
+        quick_to_interpreter_bridge_offset_(0), compile_pic_(compile_pic),
         target_ptr_size_(InstructionSetPointerSize(compiler_driver_.GetInstructionSet())),
-        bin_slot_sizes_(),
-        bin_slot_offsets_(),
-        bin_slot_count_(),
-        intern_table_bytes_(0u),
-        image_method_array_(ImageHeader::kImageMethodsCount),
-        dirty_methods_(0u),
-        clean_methods_(0u) {
+        bin_slot_sizes_(), bin_slot_offsets_(), bin_slot_count_(),
+        intern_table_bytes_(0u), image_method_array_(ImageHeader::kImageMethodsCount),
+        dirty_methods_(0u), clean_methods_(0u) {
     CHECK_NE(image_begin, 0U);
-    std::fill_n(image_methods_, arraysize(image_methods_), nullptr);
-    std::fill_n(oat_address_offsets_, arraysize(oat_address_offsets_), 0);
+    std::fill(image_methods_, image_methods_ + arraysize(image_methods_), nullptr);
   }
 
   ~ImageWriter() {
@@ -89,9 +74,8 @@ class ImageWriter FINAL {
 
   template <typename T>
   T* GetImageAddress(T* object) const SHARED_REQUIRES(Locks::mutator_lock_) {
-    return (object == nullptr || IsInBootImage(object))
-        ? object
-        : reinterpret_cast<T*>(image_begin_ + GetImageOffset(object));
+    return object == nullptr ? nullptr :
+        reinterpret_cast<T*>(image_begin_ + GetImageOffset(object));
   }
 
   ArtMethod* GetImageMethodAddress(ArtMethod* method) SHARED_REQUIRES(Locks::mutator_lock_);
@@ -166,19 +150,6 @@ class ImageWriter FINAL {
   };
   friend std::ostream& operator<<(std::ostream& stream, const NativeObjectRelocationType& type);
 
-  enum OatAddress {
-    kOatAddressInterpreterToInterpreterBridge,
-    kOatAddressInterpreterToCompiledCodeBridge,
-    kOatAddressJNIDlsymLookup,
-    kOatAddressQuickGenericJNITrampoline,
-    kOatAddressQuickIMTConflictTrampoline,
-    kOatAddressQuickResolutionTrampoline,
-    kOatAddressQuickToInterpreterBridge,
-    // Number of elements in the enum.
-    kOatAddressCount,
-  };
-  friend std::ostream& operator<<(std::ostream& stream, const OatAddress& oat_address);
-
   static constexpr size_t kBinBits = MinimumBitsToStore<uint32_t>(kBinMirrorCount - 1);
   // uint32 = typeof(lockword_)
   // Subtract read barrier bits since we want these to remain 0, or else it may result in DCHECK
@@ -244,10 +215,7 @@ class ImageWriter FINAL {
     return reinterpret_cast<mirror::Object*>(dst);
   }
 
-  // Returns the address in the boot image if we are compiling the app image.
-  const uint8_t* GetOatAddress(OatAddress type) const;
-
-  const uint8_t* GetOatAddressForOffset(uint32_t offset) const {
+  const uint8_t* GetOatAddress(uint32_t offset) const {
     // With Quick, code is within the OatFile, as there are all in one
     // .o ELF object.
     DCHECK_LE(offset, oat_file_->Size());
@@ -256,7 +224,7 @@ class ImageWriter FINAL {
   }
 
   // Returns true if the class was in the original requested image classes list.
-  bool KeepClass(mirror::Class* klass) SHARED_REQUIRES(Locks::mutator_lock_);
+  bool IsImageClass(mirror::Class* klass) SHARED_REQUIRES(Locks::mutator_lock_);
 
   // Debug aid that list of requested image classes.
   void DumpImageClasses();
@@ -331,11 +299,6 @@ class ImageWriter FINAL {
   void AssignMethodOffset(ArtMethod* method, NativeObjectRelocationType type)
       SHARED_REQUIRES(Locks::mutator_lock_);
 
-  bool IsBootClassLoaderNonImageClass(mirror::Class* klass) SHARED_REQUIRES(Locks::mutator_lock_);
-
-  bool ContainsBootClassLoaderNonImageClass(mirror::Class* klass)
-      SHARED_REQUIRES(Locks::mutator_lock_);
-
   static Bin BinTypeForNativeRelocationType(NativeObjectRelocationType type);
 
   uintptr_t NativeOffsetInImage(void* obj);
@@ -343,13 +306,6 @@ class ImageWriter FINAL {
   template <typename T>
   T* NativeLocationInImage(T* obj);
 
-  // Return true of obj is inside of the boot image space. This may only return true if we are
-  // compiling an app image.
-  bool IsInBootImage(const void* obj) const;
-
-  // Return true if ptr is within the boot oat file.
-  bool IsInBootOatFile(const void* ptr) const;
-
   const CompilerDriver& compiler_driver_;
 
   // Beginning target image address for the output image.
@@ -388,14 +344,14 @@ class ImageWriter FINAL {
   std::unique_ptr<gc::accounting::ContinuousSpaceBitmap> image_bitmap_;
 
   // Offset from oat_data_begin_ to the stubs.
-  uint32_t oat_address_offsets_[kOatAddressCount];
-
-  // Boolean flags.
+  uint32_t interpreter_to_interpreter_bridge_offset_;
+  uint32_t interpreter_to_compiled_code_bridge_offset_;
+  uint32_t jni_dlsym_lookup_offset_;
+  uint32_t quick_generic_jni_trampoline_offset_;
+  uint32_t quick_imt_conflict_trampoline_offset_;
+  uint32_t quick_resolution_trampoline_offset_;
+  uint32_t quick_to_interpreter_bridge_offset_;
   const bool compile_pic_;
-  const bool compile_app_image_;
-
-  // Boot image space for fast lookups.
-  gc::space::ImageSpace* boot_image_space_;
 
   // Size of pointers on the target architecture.
   size_t target_ptr_size_;
@@ -432,10 +388,6 @@ class ImageWriter FINAL {
   uint64_t dirty_methods_;
   uint64_t clean_methods_;
 
-  // Prune class memoization table.
-  std::unordered_map<mirror::Class*, bool> prune_class_memo_;
-
-  friend class ContainsBootClassLoaderNonImageClassVisitor;
   friend class FixupClassVisitor;
   friend class FixupRootVisitor;
   friend class FixupVisitor;
index 83d7834..ea3cb66 100644 (file)
@@ -111,7 +111,6 @@ TEST_F(OatTest, WriteRead) {
                        0,
                        compiler_driver_.get(),
                        nullptr,
-                       /*compiling_boot_image*/false,
                        &timings,
                        &key_value_store);
   bool success = compiler_driver_->WriteElf(GetTestAndroidRoot(),
index 3f2271e..c7b8884 100644 (file)
@@ -65,12 +65,10 @@ OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files,
                      int32_t image_patch_delta,
                      const CompilerDriver* compiler,
                      ImageWriter* image_writer,
-                     bool compiling_boot_image,
                      TimingLogger* timings,
                      SafeMap<std::string, std::string>* key_value_store)
   : compiler_driver_(compiler),
     image_writer_(image_writer),
-    compiling_boot_image_(compiling_boot_image),
     dex_files_(&dex_files),
     size_(0u),
     bss_size_(0u),
@@ -115,9 +113,7 @@ OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files,
     size_oat_lookup_table_(0),
     method_offset_map_() {
   CHECK(key_value_store != nullptr);
-  if (compiling_boot_image) {
-    CHECK(image_writer != nullptr);
-  }
+
   InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
   const InstructionSetFeatures* features = compiler_driver_->GetInstructionSetFeatures();
   relative_patcher_ = linker::RelativePatcher::Create(instruction_set, features,
@@ -158,7 +154,7 @@ OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files,
   }
   size_ = offset;
 
-  if (!HasBootImage()) {
+  if (!HasImage()) {
     // Allocate space for app dex cache arrays in the .bss section.
     size_t bss_start = RoundUp(size_, kPageSize);
     size_t pointer_size = GetInstructionSetPointerSize(instruction_set);
@@ -171,10 +167,9 @@ OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files,
   }
 
   CHECK_EQ(dex_files_->size(), oat_dex_files_.size());
-  if (compiling_boot_image_) {
-    CHECK_EQ(image_writer_ != nullptr,
-             key_value_store_->find(OatHeader::kImageLocationKey) == key_value_store_->end());
-  }
+  CHECK_EQ(compiler->IsImage(), image_writer_ != nullptr);
+  CHECK_EQ(compiler->IsImage(),
+           key_value_store_->find(OatHeader::kImageLocationKey) == key_value_store_->end());
   CHECK_ALIGNED(image_patch_delta_, kPageSize);
 }
 
@@ -677,7 +672,7 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor {
       class_linker_(Runtime::Current()->GetClassLinker()),
       dex_cache_(nullptr) {
     patched_code_.reserve(16 * KB);
-    if (writer_->HasBootImage()) {
+    if (writer_->HasImage()) {
       // If we're creating the image, the address space must be ready so that we can apply patches.
       CHECK(writer_->image_writer_->IsImageAddressSpaceReady());
     }
@@ -860,7 +855,7 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor {
   }
 
   uint32_t GetDexCacheOffset(const LinkerPatch& patch) SHARED_REQUIRES(Locks::mutator_lock_) {
-    if (writer_->HasBootImage()) {
+    if (writer_->HasImage()) {
       auto* element = writer_->image_writer_->GetDexCacheArrayElementImageAddress<const uint8_t*>(
               patch.TargetDexCacheDexFile(), patch.TargetDexCacheElementOffset());
       const uint8_t* oat_data = writer_->image_writer_->GetOatFileBegin() + file_offset_;
@@ -873,7 +868,7 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor {
 
   void PatchObjectAddress(std::vector<uint8_t>* code, uint32_t offset, mirror::Object* object)
       SHARED_REQUIRES(Locks::mutator_lock_) {
-    if (writer_->HasBootImage()) {
+    if (writer_->HasImage()) {
       object = writer_->image_writer_->GetImageAddress(object);
     } else {
       // NOTE: We're using linker patches for app->boot references when the image can
@@ -893,7 +888,7 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor {
 
   void PatchMethodAddress(std::vector<uint8_t>* code, uint32_t offset, ArtMethod* method)
       SHARED_REQUIRES(Locks::mutator_lock_) {
-    if (writer_->HasBootImage()) {
+    if (writer_->HasImage()) {
       method = writer_->image_writer_->GetImageMethodAddress(method);
     } else if (kIsDebugBuild) {
       // NOTE: We're using linker patches for app->boot references when the image can
@@ -916,7 +911,7 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor {
   void PatchCodeAddress(std::vector<uint8_t>* code, uint32_t offset, uint32_t target_offset)
       SHARED_REQUIRES(Locks::mutator_lock_) {
     uint32_t address = target_offset;
-    if (writer_->HasBootImage()) {
+    if (writer_->HasImage()) {
       address = PointerToLowMemUInt32(writer_->image_writer_->GetOatFileBegin() +
                                       writer_->oat_data_offset_ + target_offset);
     }
@@ -1128,7 +1123,7 @@ size_t OatWriter::InitOatCode(size_t offset) {
   offset = RoundUp(offset, kPageSize);
   oat_header_->SetExecutableOffset(offset);
   size_executable_offset_alignment_ = offset - old_offset;
-  if (compiler_driver_->IsBootImage()) {
+  if (compiler_driver_->IsImage()) {
     CHECK_EQ(image_patch_delta_, 0);
     InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
 
@@ -1169,7 +1164,7 @@ size_t OatWriter::InitOatCodeDexFiles(size_t offset) {
     } while (false)
 
   VISIT(InitCodeMethodVisitor);
-  if (compiler_driver_->IsBootImage()) {
+  if (compiler_driver_->IsImage()) {
     VISIT(InitImageMethodVisitor);
   }
 
@@ -1413,7 +1408,7 @@ size_t OatWriter::WriteMaps(OutputStream* out, const size_t file_offset, size_t
 }
 
 size_t OatWriter::WriteCode(OutputStream* out, const size_t file_offset, size_t relative_offset) {
-  if (compiler_driver_->IsBootImage()) {
+  if (compiler_driver_->IsImage()) {
     InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
 
     #define DO_TRAMPOLINE(field) \
index 7027434..f2fe048 100644 (file)
@@ -93,7 +93,6 @@ class OatWriter {
             int32_t image_patch_delta,
             const CompilerDriver* compiler,
             ImageWriter* image_writer,
-            bool compiling_boot_image,
             TimingLogger* timings,
             SafeMap<std::string, std::string>* key_value_store);
 
@@ -104,10 +103,6 @@ class OatWriter {
     return image_writer_ != nullptr;
   }
 
-  bool HasBootImage() const {
-    return compiling_boot_image_;
-  }
-
   const OatHeader& GetOatHeader() const {
     return *oat_header_;
   }
@@ -284,7 +279,6 @@ class OatWriter {
 
   const CompilerDriver* const compiler_driver_;
   ImageWriter* const image_writer_;
-  const bool compiling_boot_image_;
 
   // note OatFile does not take ownership of the DexFiles
   const std::vector<const DexFile*>* dex_files_;
index 92ed58c..2653807 100644 (file)
@@ -1355,20 +1355,9 @@ class Dex2Oat FINAL {
       uint32_t image_file_location_oat_checksum = 0;
       uintptr_t image_file_location_oat_data_begin = 0;
       int32_t image_patch_delta = 0;
-
-      if (app_image_ && image_base_ == 0) {
-        gc::space::ImageSpace* image_space = Runtime::Current()->GetHeap()->GetImageSpace();
-        image_base_ = RoundUp(
-            reinterpret_cast<uintptr_t>(image_space->GetImageHeader().GetOatFileEnd()),
-            kPageSize);
-        VLOG(compiler) << "App image base=" << reinterpret_cast<void*>(image_base_);
-      }
-
       if (IsImage()) {
         PrepareImageWriter(image_base_);
-      }
-
-      if (!IsBootImage()) {
+      } else {
         TimingLogger::ScopedTiming t3("Loading image checksum", timings_);
         gc::space::ImageSpace* image_space = Runtime::Current()->GetHeap()->GetImageSpace();
         image_file_location_oat_checksum = image_space->GetImageHeader().GetOatChecksum();
@@ -1382,13 +1371,11 @@ class Dex2Oat FINAL {
         key_value_store_->Put(OatHeader::kImageLocationKey, image_file_location);
       }
 
-      oat_writer.reset(new OatWriter(dex_files_,
-                                     image_file_location_oat_checksum,
+      oat_writer.reset(new OatWriter(dex_files_, image_file_location_oat_checksum,
                                      image_file_location_oat_data_begin,
                                      image_patch_delta,
                                      driver_.get(),
                                      image_writer_.get(),
-                                     IsBootImage(),
                                      timings_,
                                      key_value_store_.get()));
     }
@@ -1604,11 +1591,7 @@ class Dex2Oat FINAL {
   }
 
   void PrepareImageWriter(uintptr_t image_base) {
-    DCHECK(IsImage());
-    image_writer_.reset(new ImageWriter(*driver_,
-                                        image_base,
-                                        compiler_options_->GetCompilePic(),
-                                        IsAppImage()));
+    image_writer_.reset(new ImageWriter(*driver_, image_base, compiler_options_->GetCompilePic()));
   }
 
   // Let the ImageWriter write the image file. If we do not compile PIC, also fix up the oat file.
index a6eb5b2..da70456 100644 (file)
@@ -847,8 +847,8 @@ void ClassLinker::InitFromImage() {
       hs.NewHandle(dex_caches_object->AsObjectArray<mirror::DexCache>()));
 
   Handle<mirror::ObjectArray<mirror::Class>> class_roots(hs.NewHandle(
-      space->GetImageHeader().GetImageRoot(ImageHeader::kClassRoots)->
-      AsObjectArray<mirror::Class>()));
+          space->GetImageHeader().GetImageRoot(ImageHeader::kClassRoots)->
+          AsObjectArray<mirror::Class>()));
   class_roots_ = GcRoot<mirror::ObjectArray<mirror::Class>>(class_roots.Get());
 
   // Special case of setting up the String class early so that we can test arbitrary objects
@@ -857,7 +857,7 @@ void ClassLinker::InitFromImage() {
 
   mirror::Class* java_lang_Object = GetClassRoot(kJavaLangObject);
   java_lang_Object->SetObjectSize(sizeof(mirror::Object));
-  Runtime::Current()->SetSentinel(heap->AllocObject<true>(self,
+  Runtime::Current()->SetSentinel(Runtime::Current()->GetHeap()->AllocObject<true>(self,
                                                           java_lang_Object,
                                                           java_lang_Object->GetObjectSize(),
                                                           VoidFunctor()));
index e6e154e..18867fd 100755 (executable)
@@ -367,7 +367,6 @@ if [ "$PREBUILD" = "y" ]; then
                       --boot-image=${BOOT_IMAGE} \
                       --dex-file=$DEX_LOCATION/$TEST_NAME.jar \
                       --oat-file=$DEX_LOCATION/dalvik-cache/$ISA/$(echo $DEX_LOCATION/$TEST_NAME.jar/classes.dex | cut -d/ -f 2- | sed "s:/:@:g") \
-                      --app-image-file=$DEX_LOCATION/dalvik-cache/$ISA/$(echo $DEX_LOCATION/$TEST_NAME.jar/classes.dex.art | cut -d/ -f 2- | sed "s:/:@:g") \
                       --instruction-set=$ISA"
   if [ "x$INSTRUCTION_SET_FEATURES" != "x" ] ; then
     dex2oat_cmdline="${dex2oat_cmdline} --instruction-set-features=${INSTRUCTION_SET_FEATURES}"