Separate oat from image

Change-Id: If2abdb99826ead14e3465d90ba2acffd89709389
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index 6c967ed..78d3628 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -10,6 +10,7 @@
 #include "class_loader.h"
 #include "compiler.h"
 #include "image_writer.h"
+#include "oat_writer.h"
 #include "runtime.h"
 #include "stringpiece.h"
 
@@ -25,7 +26,12 @@
           "      Example: --dex-file=/system/framework/core.jar\n"
           "\n");
   fprintf(stderr,
-          "  --image=<file>: specifies the required output image filename.\n"
+          "  --image=<file.art>: specifies the required output image filename.\n"
+          "      Example: --image=/system/framework/boot.art\n"
+          "\n");
+  // TODO: remove this by inferring from --image
+  fprintf(stderr,
+          "  --oat=<file.oat>: specifies the required oat filename.\n"
           "      Example: --image=/system/framework/boot.oat\n"
           "\n");
   fprintf(stderr,
@@ -33,10 +39,15 @@
           "      Example: --base=0x50000000\n"
           "\n");
   fprintf(stderr,
-          "  --boot=<oat-file>: provide the oat file for the boot class path.\n"
-          "      Example: --boot=/system/framework/boot.oat\n"
+          "  --boot-image=<file.art>: provide the image file for the boot class path.\n"
+          "      Example: --boot-image=/system/framework/boot.art\n"
           "\n");
-  // TODO: remove this by making boot image contain boot DexFile information?
+  // TODO: remove this by inferring from --boot-image
+  fprintf(stderr,
+          "  --boot-oat=<file.oat>: provide the oat file for the boot class path.\n"
+          "      Example: --boot-oat=/system/framework/boot.oat\n"
+          "\n");
+  // TODO: remove this by inderring from --boot-image or --boot-oat
   fprintf(stderr,
           "  --boot-dex-file=<dex-file>: specifies a .dex file that is part of the boot\n"
           "      image specified with --boot. \n"
@@ -76,8 +87,10 @@
 
   std::vector<const char*> dex_filenames;
   std::vector<const char*> method_names;
+  std::string oat_filename;
   const char* image_filename = NULL;
   std::string boot_image_option;
+  std::string boot_oat_option;
   std::vector<const char*> boot_dex_filenames;
   uintptr_t image_base = 0;
   std::string strip_location_prefix;
@@ -90,6 +103,8 @@
       dex_filenames.push_back(option.substr(strlen("--dex-file=")).data());
     } else if (option.starts_with("--method=")) {
       method_names.push_back(option.substr(strlen("--method=")).data());
+    } else if (option.starts_with("--oat=")) {
+      oat_filename = option.substr(strlen("--oat=")).data();
     } else if (option.starts_with("--image=")) {
       image_filename = option.substr(strlen("--image=")).data();
     } else if (option.starts_with("--base=")) {
@@ -100,11 +115,16 @@
         fprintf(stderr, "Failed to parse hexadecimal value for option %s\n", option.data());
         usage();
       }
-    } else if (option.starts_with("--boot=")) {
-      const char* boot_image_filename = option.substr(strlen("--boot=")).data();
+    } else if (option.starts_with("--boot-image=")) {
+      const char* boot_image_filename = option.substr(strlen("--boot-image=")).data();
       boot_image_option.clear();
       boot_image_option += "-Xbootimage:";
       boot_image_option += boot_image_filename;
+    } else if (option.starts_with("--boot-oat=")) {
+      const char* boot_oat_filename = option.substr(strlen("--boot-oat=")).data();
+      boot_oat_option.clear();
+      boot_oat_option += "-Xbootoat:";
+      boot_oat_option += boot_oat_filename;
     } else if (option.starts_with("--boot-dex-file=")) {
       boot_dex_filenames.push_back(option.substr(strlen("--boot-dex-file=")).data());
     } else if (option.starts_with("--strip-prefix=")) {
@@ -119,6 +139,11 @@
     }
   }
 
+  if (oat_filename == NULL) {
+   fprintf(stderr, "--oat file name not specified\n");
+   return EXIT_FAILURE;
+  }
+
   if (image_filename == NULL) {
    fprintf(stderr, "--image file name not specified\n");
    return EXIT_FAILURE;
@@ -129,6 +154,11 @@
    return EXIT_FAILURE;
   }
 
+  if (boot_image_option.empty() != boot_oat_option.empty()) {
+   fprintf(stderr, "--boot-image and --boat-oat must be specified together or not at all\n");
+   return EXIT_FAILURE;
+  }
+
   if (boot_image_option.empty()) {
     if (image_base == 0) {
       fprintf(stderr, "non-zero --base not specified\n");
@@ -136,7 +166,7 @@
     }
   } else {
     if (boot_dex_filenames.empty()) {
-      fprintf(stderr, "no --boot-dex-file values specified with --boot\n");
+      fprintf(stderr, "no --boot-dex-file values specified with --boot-image\n");
       return EXIT_FAILURE;
     }
   }
@@ -153,6 +183,7 @@
   } else {
     options.push_back(std::make_pair("bootclasspath", &boot_dex_files));
     options.push_back(std::make_pair(boot_image_option.c_str(), reinterpret_cast<void*>(NULL)));
+    options.push_back(std::make_pair(boot_oat_option.c_str(), reinterpret_cast<void*>(NULL)));
   }
   if (Xms != NULL) {
     options.push_back(std::make_pair(Xms, reinterpret_cast<void*>(NULL)));
@@ -167,11 +198,12 @@
   }
   ClassLinker* class_linker = runtime->GetClassLinker();
 
-  // If we have an existing boot image, position new space after it
+  // If we have an existing boot image, position new space after its oat file
   if (!boot_image_option.empty()) {
     Space* boot_space = Heap::GetBootSpace();
     CHECK(boot_space != NULL);
-    image_base = RoundUp(reinterpret_cast<uintptr_t>(boot_space->GetLimit()), kPageSize);
+    byte* oat_limit_addr = boot_space->GetImageHeader().GetOatLimitAddr();
+    image_base = RoundUp(reinterpret_cast<uintptr_t>(oat_limit_addr), kPageSize);
   }
 
   // ClassLoader creation needs to come after Runtime::Create
@@ -185,11 +217,13 @@
     class_loader = PathClassLoader::Alloc(dex_files);
   }
 
-  // if we loaded an existing image, we will reuse its stub array.
+  // if we loaded an existing image, we will reuse values from the image roots.
   if (!runtime->HasJniStubArray()) {
     runtime->SetJniStubArray(JniCompiler::CreateJniStub(kThumb2));
   }
-  // similarly for the callee save method
+  if (!runtime->HasAbstractMethodErrorStubArray()) {
+    runtime->SetAbstractMethodErrorStubArray(Compiler::CreateAbstractMethodErrorStub(kThumb2));
+  }
   if (!runtime->HasCalleeSaveMethod()) {
     runtime->SetCalleeSaveMethod(runtime->CreateCalleeSaveMethod(kThumb2));
   }
@@ -239,9 +273,14 @@
     }
   }
 
-  ImageWriter writer;
-  if (!writer.Write(image_filename, image_base)) {
-    fprintf(stderr, "could not write image %s\n", image_filename);
+  if (!OatWriter::Create(oat_filename, class_loader)) {
+    fprintf(stderr, "Failed to create oat file %s\n", oat_filename.c_str());
+    return EXIT_FAILURE;
+  }
+
+  ImageWriter image_writer;
+  if (!image_writer.Write(image_filename, image_base, oat_filename, strip_location_prefix)) {
+    fprintf(stderr, "Failed to create image file %s\n", image_filename);
     return EXIT_FAILURE;
   }