Support running without a boot image.

Bug: 17000769

Change-Id: I6404d5050c8a2f4ee6e70d58532eb25ee9de248e
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 8fc1d07..ab4bf41 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -195,10 +195,13 @@
 
 // To set a value for generic JNI. May be necessary in compiler tests.
 extern "C" void art_quick_generic_jni_trampoline(mirror::ArtMethod*);
+extern "C" void art_quick_resolution_trampoline(mirror::ArtMethod*);
+extern "C" void art_quick_imt_conflict_trampoline(mirror::ArtMethod*);
+extern "C" void art_quick_to_interpreter_bridge(mirror::ArtMethod*);
 
-void ClassLinker::InitFromCompiler(const std::vector<const DexFile*>& boot_class_path) {
+void ClassLinker::InitWithoutImage(const std::vector<const DexFile*>& boot_class_path) {
   VLOG(startup) << "ClassLinker::Init";
-  CHECK(Runtime::Current()->IsCompiler());
+  CHECK(!Runtime::Current()->GetHeap()->HasImageSpace()) << "Runtime has image. We should use it.";
 
   CHECK(!init_done_);
 
@@ -370,6 +373,12 @@
   // Set up GenericJNI entrypoint. That is mainly a hack for common_compiler_test.h so that
   // we do not need friend classes or a publicly exposed setter.
   quick_generic_jni_trampoline_ = reinterpret_cast<void*>(art_quick_generic_jni_trampoline);
+  if (!runtime->IsCompiler()) {
+    // We need to set up the generic trampolines since we don't have an image.
+    quick_resolution_trampoline_ = reinterpret_cast<void*>(art_quick_resolution_trampoline);
+    quick_imt_conflict_trampoline_ = reinterpret_cast<void*>(art_quick_imt_conflict_trampoline);
+    quick_to_interpreter_bridge_trampoline_ = reinterpret_cast<void*>(art_quick_to_interpreter_bridge);
+  }
 
   // Object, String and DexCache need to be rerun through FindSystemClass to finish init
   java_lang_Object->SetStatus(mirror::Class::kStatusNotReady, self);
@@ -589,6 +598,13 @@
 
   gc::Heap* heap = Runtime::Current()->GetHeap();
   std::string boot_image_option("--boot-image=");
+  if (heap->GetImageSpace() == nullptr) {
+    // TODO If we get a dex2dex compiler working we could maybe use that, OTOH since we are likely
+    // out of space anyway it might not matter.
+    *error_msg = StringPrintf("Cannot create oat file for '%s' because we are running "
+                              "without an image.", dex_filename);
+    return false;
+  }
   boot_image_option += heap->GetImageSpace()->GetImageLocation();
 
   std::string dex_file_option("--dex-file=");
@@ -879,16 +895,17 @@
     oat_location = cache_location.c_str();
   }
 
+  bool has_flock = true;
   // Definitely need to lock now.
   if (!scoped_flock.HasFile()) {
     std::string error_msg;
     if (!scoped_flock.Init(oat_location, &error_msg)) {
       error_msgs->push_back(error_msg);
-      return false;
+      has_flock = false;
     }
   }
 
-  if (Runtime::Current()->IsDex2OatEnabled()) {
+  if (Runtime::Current()->IsDex2OatEnabled() && has_flock && scoped_flock.HasFile()) {
     // Create the oat file.
     open_oat_file.reset(CreateOatFileForDexLocation(dex_location, scoped_flock.GetFile()->Fd(),
                                                     oat_location, error_msgs));
@@ -1003,6 +1020,9 @@
                                          const InstructionSet instruction_set) {
   Runtime* runtime = Runtime::Current();
   const gc::space::ImageSpace* image_space = runtime->GetHeap()->GetImageSpace();
+  if (image_space == nullptr) {
+    return false;
+  }
   uint32_t image_oat_checksum = 0;
   if (instruction_set == kRuntimeISA) {
     const ImageHeader& image_header = image_space->GetImageHeader();
@@ -1020,6 +1040,10 @@
                                      std::string* error_msg) {
   Runtime* runtime = Runtime::Current();
   const gc::space::ImageSpace* image_space = runtime->GetHeap()->GetImageSpace();
+  if (image_space == nullptr) {
+    *error_msg = "No image space for verification against";
+    return false;
+  }
 
   // If the requested instruction set is the same as the current runtime,
   // we can use the checksums directly. If it isn't, we'll have to read the
@@ -1270,13 +1294,15 @@
   std::string error_msg;
   if (runtime->CanRelocate()) {
     // Run relocation
-    const std::string& image_location =
-        Runtime::Current()->GetHeap()->GetImageSpace()->GetImageLocation();
-    if (odex_checksum_verified && should_patch_system) {
-      ret = PatchAndRetrieveOat(odex_filename, cache_filename, image_location, isa, &error_msg);
-    } else if (cache_checksum_verified && should_patch_cache) {
-      CHECK(have_dalvik_cache);
-      ret = PatchAndRetrieveOat(cache_filename, cache_filename, image_location, isa, &error_msg);
+    gc::space::ImageSpace* space = Runtime::Current()->GetHeap()->GetImageSpace();
+    if (space != nullptr) {
+      const std::string& image_location = space->GetImageLocation();
+      if (odex_checksum_verified && should_patch_system) {
+        ret = PatchAndRetrieveOat(odex_filename, cache_filename, image_location, isa, &error_msg);
+      } else if (cache_checksum_verified && should_patch_cache) {
+        CHECK(have_dalvik_cache);
+        ret = PatchAndRetrieveOat(cache_filename, cache_filename, image_location, isa, &error_msg);
+      }
     }
   }
   if (ret == nullptr && have_dalvik_cache && OS::FileExists(cache_filename.c_str())) {
@@ -1340,6 +1366,12 @@
                                                 const std::string& image_location,
                                                 InstructionSet isa,
                                                 std::string* error_msg) {
+  if (!Runtime::Current()->GetHeap()->HasImageSpace()) {
+    // We don't have an image space so there is no point in trying to patchoat.
+    LOG(WARNING) << "Patching of oat file '" << input_oat << "' not attempted because we are "
+                 << "running without an image. Attempting to use oat file for interpretation.";
+    return GetInterpretedOnlyOat(input_oat, isa, error_msg);
+  }
   if (!Runtime::Current()->IsDex2OatEnabled()) {
     // We don't have dex2oat so we can assume we don't have patchoat either. We should just use the
     // input_oat but make sure we only do interpretation on it's dex files.
@@ -1402,6 +1434,7 @@
   Runtime* runtime = Runtime::Current();
   int32_t real_patch_delta;
   const gc::space::ImageSpace* image_space = runtime->GetHeap()->GetImageSpace();
+  CHECK(image_space != nullptr);
   if (isa == Runtime::Current()->GetInstructionSet()) {
     const ImageHeader& image_header = image_space->GetImageHeader();
     real_patch_delta = image_header.GetPatchDelta();
@@ -1423,6 +1456,10 @@
   void* real_image_oat_offset;
   int32_t real_patch_delta;
   const gc::space::ImageSpace* image_space = runtime->GetHeap()->GetImageSpace();
+  if (image_space == nullptr) {
+    *error_msg = "No image space present";
+    return false;
+  }
   if (isa == Runtime::Current()->GetInstructionSet()) {
     const ImageHeader& image_header = image_space->GetImageHeader();
     real_image_checksum = image_header.GetOatChecksum();
@@ -2275,8 +2312,11 @@
   }
   Runtime* runtime = Runtime::Current();
   if (!runtime->IsStarted() || runtime->UseCompileTimeClassPath()) {
-    return;  // OAT file unavailable.
+    if (runtime->IsCompiler() || runtime->GetHeap()->HasImageSpace()) {
+      return;  // OAT file unavailable.
+    }
   }
+
   const DexFile& dex_file = klass->GetDexFile();
   const DexFile::ClassDef* dex_class_def = klass->GetClassDef();
   CHECK(dex_class_def != nullptr);