Create separate Android.mk for main build targets

The runtime, compiler, dex2oat, and oatdump now are in seperate trees
to prevent dependency creep.  They can now be individually built
without rebuilding the rest of the art projects. dalvikvm and jdwpspy
were already this way. Builds in the art directory should behave as
before, building everything including tests.

Change-Id: Ic6b1151e5ed0f823c3dd301afd2b13eb2d8feb81
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
new file mode 100644
index 0000000..c73c1bb
--- /dev/null
+++ b/dex2oat/dex2oat.cc
@@ -0,0 +1,1060 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#include <fstream>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "base/stl_util.h"
+#include "base/stringpiece.h"
+#include "base/timing_logger.h"
+#include "base/unix_file/fd_file.h"
+#include "class_linker.h"
+#include "dex_file-inl.h"
+#include "driver/compiler_driver.h"
+#include "elf_fixup.h"
+#include "elf_stripper.h"
+#include "gc/space/image_space.h"
+#include "gc/space/space-inl.h"
+#include "image_writer.h"
+#include "leb128.h"
+#include "mirror/abstract_method-inl.h"
+#include "mirror/class-inl.h"
+#include "mirror/class_loader.h"
+#include "mirror/object-inl.h"
+#include "mirror/object_array-inl.h"
+#include "oat_writer.h"
+#include "object_utils.h"
+#include "os.h"
+#include "runtime.h"
+#include "ScopedLocalRef.h"
+#include "scoped_thread_state_change.h"
+#include "sirt_ref.h"
+#include "vector_output_stream.h"
+#include "well_known_classes.h"
+#include "zip_archive.h"
+
+namespace art {
+
+static void UsageErrorV(const char* fmt, va_list ap) {
+  std::string error;
+  StringAppendV(&error, fmt, ap);
+  LOG(ERROR) << error;
+}
+
+static void UsageError(const char* fmt, ...) {
+  va_list ap;
+  va_start(ap, fmt);
+  UsageErrorV(fmt, ap);
+  va_end(ap);
+}
+
+static void Usage(const char* fmt, ...) {
+  va_list ap;
+  va_start(ap, fmt);
+  UsageErrorV(fmt, ap);
+  va_end(ap);
+
+  UsageError("Usage: dex2oat [options]...");
+  UsageError("");
+  UsageError("  --dex-file=<dex-file>: specifies a .dex file to compile.");
+  UsageError("      Example: --dex-file=/system/framework/core.jar");
+  UsageError("");
+  UsageError("  --zip-fd=<file-descriptor>: specifies a file descriptor of a zip file");
+  UsageError("      containing a classes.dex file to compile.");
+  UsageError("      Example: --zip-fd=5");
+  UsageError("");
+  UsageError("  --zip-location=<zip-location>: specifies a symbolic name for the file corresponding");
+  UsageError("      to the file descriptor specified by --zip-fd.");
+  UsageError("      Example: --zip-location=/system/app/Calculator.apk");
+  UsageError("");
+  UsageError("  --oat-file=<file.oat>: specifies the oat output destination via a filename.");
+  UsageError("      Example: --oat-file=/system/framework/boot.oat");
+  UsageError("");
+  UsageError("  --oat-fd=<number>: specifies the oat output destination via a file descriptor.");
+  UsageError("      Example: --oat-file=/system/framework/boot.oat");
+  UsageError("");
+  UsageError("  --oat-location=<oat-name>: specifies a symbolic name for the file corresponding");
+  UsageError("      to the file descriptor specified by --oat-fd.");
+  UsageError("      Example: --oat-location=/data/dalvik-cache/system@app@Calculator.apk.oat");
+  UsageError("");
+  UsageError("  --oat-symbols=<file.oat>: specifies the oat output destination with full symbols.");
+  UsageError("      Example: --oat-symbols=/symbols/system/framework/boot.oat");
+  UsageError("");
+  UsageError("  --bitcode=<file.bc>: specifies the optional bitcode filename.");
+  UsageError("      Example: --bitcode=/system/framework/boot.bc");
+  UsageError("");
+  UsageError("  --image=<file.art>: specifies the output image filename.");
+  UsageError("      Example: --image=/system/framework/boot.art");
+  UsageError("");
+  UsageError("  --image-classes=<classname-file>: specifies classes to include in an image.");
+  UsageError("      Example: --image=frameworks/base/preloaded-classes");
+  UsageError("");
+  UsageError("  --base=<hex-address>: specifies the base address when creating a boot image.");
+  UsageError("      Example: --base=0x50000000");
+  UsageError("");
+  UsageError("  --boot-image=<file.art>: provide the image file for the boot class path.");
+  UsageError("      Example: --boot-image=/system/framework/boot.art");
+  UsageError("      Default: <host-prefix>/system/framework/boot.art");
+  UsageError("");
+  UsageError("  --host-prefix=<path>: used to translate host paths to target paths during");
+  UsageError("      cross compilation.");
+  UsageError("      Example: --host-prefix=out/target/product/crespo");
+  UsageError("      Default: $ANDROID_PRODUCT_OUT");
+  UsageError("");
+  UsageError("  --android-root=<path>: used to locate libraries for portable linking.");
+  UsageError("      Example: --android-root=out/host/linux-x86");
+  UsageError("      Default: $ANDROID_ROOT");
+  UsageError("");
+  UsageError("  --instruction-set=(arm|mips|x86): compile for a particular instruction");
+  UsageError("      set.");
+  UsageError("      Example: --instruction-set=x86");
+  UsageError("      Default: arm");
+  UsageError("");
+  UsageError("  --compiler-backend=(Quick|QuickGBC|Portable): select compiler backend");
+  UsageError("      set.");
+  UsageError("      Example: --instruction-set=Portable");
+  UsageError("      Default: Quick");
+  UsageError("");
+  UsageError("  --host: used with Portable backend to link against host runtime libraries");
+  UsageError("");
+  UsageError("  --runtime-arg <argument>: used to specify various arguments for the runtime,");
+  UsageError("      such as initial heap size, maximum heap size, and verbose output.");
+  UsageError("      Use a separate --runtime-arg switch for each argument.");
+  UsageError("      Example: --runtime-arg -Xms256m");
+  UsageError("");
+  std::cerr << "See log for usage error information\n";
+  exit(EXIT_FAILURE);
+}
+
+class Dex2Oat {
+ public:
+  static bool Create(Dex2Oat** p_dex2oat, Runtime::Options& options, CompilerBackend compiler_backend,
+                     InstructionSet instruction_set, size_t thread_count, bool support_debugging)
+      SHARED_TRYLOCK_FUNCTION(true, Locks::mutator_lock_) {
+    if (!CreateRuntime(options, instruction_set)) {
+      *p_dex2oat = NULL;
+      return false;
+    }
+    *p_dex2oat = new Dex2Oat(Runtime::Current(), compiler_backend, instruction_set, thread_count,
+                             support_debugging);
+    return true;
+  }
+
+  ~Dex2Oat() {
+    delete runtime_;
+    LOG(INFO) << "dex2oat took " << PrettyDuration(NanoTime() - start_ns_) << " (threads: " << thread_count_ << ")";
+  }
+
+
+  // Reads the class names (java.lang.Object) and returns as set of class descriptors (Ljava/lang/Object;)
+  CompilerDriver::DescriptorSet* ReadImageClassesFromFile(const char* image_classes_filename) {
+    UniquePtr<std::ifstream> image_classes_file(new std::ifstream(image_classes_filename, std::ifstream::in));
+    if (image_classes_file.get() == NULL) {
+      LOG(ERROR) << "Failed to open image classes file " << image_classes_filename;
+      return NULL;
+    }
+    UniquePtr<CompilerDriver::DescriptorSet> result(ReadImageClasses(*image_classes_file.get()));
+    image_classes_file->close();
+    return result.release();
+  }
+
+  CompilerDriver::DescriptorSet* ReadImageClasses(std::istream& image_classes_stream) {
+    UniquePtr<CompilerDriver::DescriptorSet> image_classes(new CompilerDriver::DescriptorSet);
+    while (image_classes_stream.good()) {
+      std::string dot;
+      std::getline(image_classes_stream, dot);
+      if (StartsWith(dot, "#") || dot.empty()) {
+        continue;
+      }
+      std::string descriptor(DotToDescriptor(dot.c_str()));
+      image_classes->insert(descriptor);
+    }
+    return image_classes.release();
+  }
+
+  // Reads the class names (java.lang.Object) and returns as set of class descriptors (Ljava/lang/Object;)
+  CompilerDriver::DescriptorSet* ReadImageClassesFromZip(const std::string& zip_filename, const char* image_classes_filename) {
+    UniquePtr<ZipArchive> zip_archive(ZipArchive::Open(zip_filename));
+    if (zip_archive.get() == NULL) {
+      LOG(ERROR) << "Failed to open zip file " << zip_filename;
+      return NULL;
+    }
+    UniquePtr<ZipEntry> zip_entry(zip_archive->Find(image_classes_filename));
+    if (zip_entry.get() == NULL) {
+      LOG(ERROR) << "Failed to find " << image_classes_filename << " within " << zip_filename;
+      return NULL;
+    }
+    UniquePtr<MemMap> image_classes_file(zip_entry->ExtractToMemMap(image_classes_filename));
+    if (image_classes_file.get() == NULL) {
+      LOG(ERROR) << "Failed to extract " << image_classes_filename << " from " << zip_filename;
+      return NULL;
+    }
+    const std::string image_classes_string(reinterpret_cast<char*>(image_classes_file->Begin()),
+                                           image_classes_file->Size());
+    std::istringstream image_classes_stream(image_classes_string);
+    return ReadImageClasses(image_classes_stream);
+  }
+
+  const CompilerDriver* CreateOatFile(const std::string& boot_image_option,
+                                      const std::string* host_prefix,
+                                      const std::string& android_root,
+                                      bool is_host,
+                                      const std::vector<const DexFile*>& dex_files,
+                                      File* oat_file,
+                                      const std::string& bitcode_filename,
+                                      bool image,
+                                      UniquePtr<CompilerDriver::DescriptorSet>& image_classes,
+                                      bool dump_stats,
+                                      bool dump_timings)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    // SirtRef and ClassLoader creation needs to come after Runtime::Create
+    jobject class_loader = NULL;
+    if (!boot_image_option.empty()) {
+      ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+      std::vector<const DexFile*> class_path_files(dex_files);
+      OpenClassPathFiles(runtime_->GetClassPathString(), class_path_files);
+      for (size_t i = 0; i < class_path_files.size(); i++) {
+        class_linker->RegisterDexFile(*class_path_files[i]);
+      }
+      ScopedObjectAccessUnchecked soa(Thread::Current());
+      soa.Env()->AllocObject(WellKnownClasses::dalvik_system_PathClassLoader);
+      ScopedLocalRef<jobject> class_loader_local(soa.Env(),
+          soa.Env()->AllocObject(WellKnownClasses::dalvik_system_PathClassLoader));
+      class_loader = soa.Env()->NewGlobalRef(class_loader_local.get());
+      Runtime::Current()->SetCompileTimeClassPath(class_loader, class_path_files);
+    }
+
+    UniquePtr<CompilerDriver> driver(new CompilerDriver(compiler_backend_,
+                                                        instruction_set_,
+                                                        image,
+                                                        image_classes.release(),
+                                                        thread_count_,
+                                                        support_debugging_,
+                                                        dump_stats,
+                                                        dump_timings));
+
+    if (compiler_backend_ == kPortable) {
+      driver->SetBitcodeFileName(bitcode_filename);
+    }
+
+
+    Thread::Current()->TransitionFromRunnableToSuspended(kNative);
+
+    driver->CompileAll(class_loader, dex_files);
+
+    Thread::Current()->TransitionFromSuspendedToRunnable();
+
+    std::string image_file_location;
+    uint32_t image_file_location_oat_checksum = 0;
+    uint32_t image_file_location_oat_data_begin = 0;
+    if (!driver->IsImage()) {
+      gc::space::ImageSpace* image_space = Runtime::Current()->GetHeap()->GetImageSpace();
+      image_file_location_oat_checksum = image_space->GetImageHeader().GetOatChecksum();
+      image_file_location_oat_data_begin =
+          reinterpret_cast<uint32_t>(image_space->GetImageHeader().GetOatDataBegin());
+      image_file_location = image_space->GetImageFilename();
+      if (host_prefix != NULL && StartsWith(image_file_location, host_prefix->c_str())) {
+        image_file_location = image_file_location.substr(host_prefix->size());
+      }
+    }
+
+    std::vector<uint8_t> oat_contents;
+    // TODO: change ElfWriterQuick to not require the creation of oat_contents. The old pre-mclinker
+    //       OatWriter streamed directly to disk. The new could can be adapted to do it as follows:
+    // 1.) use first pass of OatWriter to calculate size of oat structure,
+    // 2.) call ElfWriterQuick with pointer to OatWriter instead of contents,
+    // 3.) have ElfWriterQuick call back to OatWriter to stream generate the output directly in
+    //     place in the elf file.
+    oat_contents.reserve(5 * MB);
+    VectorOutputStream vector_output_stream(oat_file->GetPath(), oat_contents);
+    if (!OatWriter::Create(vector_output_stream,
+                           dex_files,
+                           image_file_location_oat_checksum,
+                           image_file_location_oat_data_begin,
+                           image_file_location,
+                           *driver.get())) {
+      LOG(ERROR) << "Failed to create oat file " << oat_file->GetPath();
+      return NULL;
+    }
+
+    if (!driver->WriteElf(android_root, is_host, dex_files, oat_contents, oat_file)) {
+      LOG(ERROR) << "Failed to write ELF file " << oat_file->GetPath();
+      return NULL;
+    }
+
+    return driver.release();
+  }
+
+  bool CreateImageFile(const std::string& image_filename,
+                       uintptr_t image_base,
+                       const std::string& oat_filename,
+                       const std::string& oat_location,
+                       const CompilerDriver& compiler)
+      LOCKS_EXCLUDED(Locks::mutator_lock_) {
+    uintptr_t oat_data_begin;
+    {
+      // ImageWriter is scoped so it can free memory before doing FixupElf
+      ImageWriter image_writer(compiler);
+      if (!image_writer.Write(image_filename, image_base, oat_filename, oat_location)) {
+        LOG(ERROR) << "Failed to create image file " << image_filename;
+        return false;
+      }
+      oat_data_begin = image_writer.GetOatDataBegin();
+    }
+
+    UniquePtr<File> oat_file(OS::OpenFile(oat_filename.c_str(), true, false));
+    if (oat_file.get() == NULL) {
+      PLOG(ERROR) << "Failed to open ELF file: " << oat_filename;
+      return false;
+    }
+    if (!ElfFixup::Fixup(oat_file.get(), oat_data_begin)) {
+      LOG(ERROR) << "Failed to fixup ELF file " << oat_file->GetPath();
+      return false;
+    }
+    return true;
+  }
+
+ private:
+  explicit Dex2Oat(Runtime* runtime, CompilerBackend compiler_backend, InstructionSet instruction_set,
+                   size_t thread_count, bool support_debugging)
+      : compiler_backend_(compiler_backend),
+        instruction_set_(instruction_set),
+        runtime_(runtime),
+        thread_count_(thread_count),
+        support_debugging_(support_debugging),
+        start_ns_(NanoTime()) {
+  }
+
+  static bool CreateRuntime(Runtime::Options& options, InstructionSet instruction_set)
+      SHARED_TRYLOCK_FUNCTION(true, Locks::mutator_lock_) {
+    if (!Runtime::Create(options, false)) {
+      LOG(ERROR) << "Failed to create runtime";
+      return false;
+    }
+    Runtime* runtime = Runtime::Current();
+    // if we loaded an existing image, we will reuse values from the image roots.
+    if (!runtime->HasResolutionMethod()) {
+      runtime->SetResolutionMethod(runtime->CreateResolutionMethod());
+    }
+    for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
+      Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i);
+      if (!runtime->HasCalleeSaveMethod(type)) {
+        runtime->SetCalleeSaveMethod(runtime->CreateCalleeSaveMethod(instruction_set, type), type);
+      }
+    }
+    runtime->GetClassLinker()->FixupDexCaches(runtime->GetResolutionMethod());
+    return true;
+  }
+
+  // Appends to dex_files any elements of class_path that it doesn't already
+  // contain. This will open those dex files as necessary.
+  static void OpenClassPathFiles(const std::string& class_path, std::vector<const DexFile*>& dex_files) {
+    std::vector<std::string> parsed;
+    Split(class_path, ':', parsed);
+    // Take Locks::mutator_lock_ so that lock ordering on the ClassLinker::dex_lock_ is maintained.
+    ScopedObjectAccess soa(Thread::Current());
+    for (size_t i = 0; i < parsed.size(); ++i) {
+      if (DexFilesContains(dex_files, parsed[i])) {
+        continue;
+      }
+      const DexFile* dex_file = DexFile::Open(parsed[i], parsed[i]);
+      if (dex_file == NULL) {
+        LOG(WARNING) << "Failed to open dex file " << parsed[i];
+      } else {
+        dex_files.push_back(dex_file);
+      }
+    }
+  }
+
+  // Returns true if dex_files has a dex with the named location.
+  static bool DexFilesContains(const std::vector<const DexFile*>& dex_files, const std::string& location) {
+    for (size_t i = 0; i < dex_files.size(); ++i) {
+      if (dex_files[i]->GetLocation() == location) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  const CompilerBackend compiler_backend_;
+
+  const InstructionSet instruction_set_;
+
+  Runtime* runtime_;
+  size_t thread_count_;
+  bool support_debugging_;
+  uint64_t start_ns_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Dex2Oat);
+};
+
+static bool ParseInt(const char* in, int* out) {
+  char* end;
+  int result = strtol(in, &end, 10);
+  if (in == end || *end != '\0') {
+    return false;
+  }
+  *out = result;
+  return true;
+}
+
+static size_t OpenDexFiles(const std::vector<const char*>& dex_filenames,
+                           const std::vector<const char*>& dex_locations,
+                           std::vector<const DexFile*>& dex_files) {
+  size_t failure_count = 0;
+  for (size_t i = 0; i < dex_filenames.size(); i++) {
+    const char* dex_filename = dex_filenames[i];
+    const char* dex_location = dex_locations[i];
+    const DexFile* dex_file = DexFile::Open(dex_filename, dex_location);
+    if (dex_file == NULL) {
+      LOG(WARNING) << "Could not open .dex from file '" << dex_filename << "'\n";
+      ++failure_count;
+    } else {
+      dex_files.push_back(dex_file);
+    }
+  }
+  return failure_count;
+}
+
+// The primary goal of the watchdog is to prevent stuck build servers
+// during development when fatal aborts lead to a cascade of failures
+// that result in a deadlock.
+class WatchDog {
+
+// WatchDog defines its own CHECK_PTHREAD_CALL to avoid using Log which uses locks
+#undef CHECK_PTHREAD_CALL
+#define CHECK_WATCH_DOG_PTHREAD_CALL(call, args, what) \
+  do { \
+    int rc = call args; \
+    if (rc != 0) { \
+      errno = rc; \
+      std::string message(# call); \
+      message += " failed for "; \
+      message += reason; \
+      Fatal(message); \
+    } \
+  } while (false)
+
+ public:
+  WatchDog(bool is_watch_dog_enabled) {
+    is_watch_dog_enabled_ = is_watch_dog_enabled;
+    if (!is_watch_dog_enabled_) {
+      return;
+    }
+    shutting_down_ = false;
+    const char* reason = "dex2oat watch dog thread startup";
+    CHECK_WATCH_DOG_PTHREAD_CALL(pthread_mutex_init, (&mutex_, NULL), reason);
+    CHECK_WATCH_DOG_PTHREAD_CALL(pthread_cond_init, (&cond_, NULL), reason);
+    CHECK_WATCH_DOG_PTHREAD_CALL(pthread_attr_init, (&attr_), reason);
+    CHECK_WATCH_DOG_PTHREAD_CALL(pthread_create, (&pthread_, &attr_, &CallBack, this), reason);
+    CHECK_WATCH_DOG_PTHREAD_CALL(pthread_attr_destroy, (&attr_), reason);
+  }
+  ~WatchDog() {
+    if (!is_watch_dog_enabled_) {
+      return;
+    }
+    const char* reason = "dex2oat watch dog thread shutdown";
+    CHECK_WATCH_DOG_PTHREAD_CALL(pthread_mutex_lock, (&mutex_), reason);
+    shutting_down_ = true;
+    CHECK_WATCH_DOG_PTHREAD_CALL(pthread_cond_signal, (&cond_), reason);
+    CHECK_WATCH_DOG_PTHREAD_CALL(pthread_mutex_unlock, (&mutex_), reason);
+
+    CHECK_WATCH_DOG_PTHREAD_CALL(pthread_join, (pthread_, NULL), reason);
+
+    CHECK_WATCH_DOG_PTHREAD_CALL(pthread_cond_destroy, (&cond_), reason);
+    CHECK_WATCH_DOG_PTHREAD_CALL(pthread_mutex_destroy, (&mutex_), reason);
+  }
+
+ private:
+  static void* CallBack(void* arg) {
+    WatchDog* self = reinterpret_cast<WatchDog*>(arg);
+    ::art::SetThreadName("dex2oat watch dog");
+    self->Wait();
+    return NULL;
+  }
+
+  static void Message(char severity, const std::string& message) {
+    // TODO: Remove when we switch to LOG when we can guarantee it won't prevent shutdown in error
+    //       cases.
+    fprintf(stderr, "dex2oat%s %c %d %d %s\n",
+            kIsDebugBuild ? "d" : "",
+            severity,
+            getpid(),
+            GetTid(),
+            message.c_str());
+  }
+
+  static void Warn(const std::string& message) {
+    Message('W', message);
+  }
+
+  static void Fatal(const std::string& message) {
+    Message('F', message);
+    exit(1);
+  }
+
+  void Wait() {
+    bool warning = true;
+    CHECK_GT(kWatchDogTimeoutSeconds, kWatchDogWarningSeconds);
+    // TODO: tune the multiplier for GC verification, the following is just to make the timeout
+    //       large.
+    int64_t multiplier = gc::kDesiredHeapVerification > gc::kVerifyAllFast ? 100 : 1;
+    timespec warning_ts;
+    InitTimeSpec(true, CLOCK_REALTIME, multiplier * kWatchDogWarningSeconds * 1000, 0, &warning_ts);
+    timespec timeout_ts;
+    InitTimeSpec(true, CLOCK_REALTIME, multiplier * kWatchDogTimeoutSeconds * 1000, 0, &timeout_ts);
+    const char* reason = "dex2oat watch dog thread waiting";
+    CHECK_WATCH_DOG_PTHREAD_CALL(pthread_mutex_lock, (&mutex_), reason);
+    while (!shutting_down_) {
+      int rc = TEMP_FAILURE_RETRY(pthread_cond_timedwait(&cond_, &mutex_,
+                                                         warning ? &warning_ts
+                                                                 : &timeout_ts));
+      if (rc == ETIMEDOUT) {
+        std::string message(StringPrintf("dex2oat did not finish after %d seconds",
+                                         warning ? kWatchDogWarningSeconds
+                                                 : kWatchDogTimeoutSeconds));
+        if (warning) {
+          Warn(message.c_str());
+          warning = false;
+        } else {
+          Fatal(message.c_str());
+        }
+      } else if (rc != 0) {
+        std::string message(StringPrintf("pthread_cond_timedwait failed: %s",
+                                         strerror(errno)));
+        Fatal(message.c_str());
+      }
+    }
+    CHECK_WATCH_DOG_PTHREAD_CALL(pthread_mutex_unlock, (&mutex_), reason);
+  }
+
+  // When setting timeouts, keep in mind that the build server may not be as fast as your desktop.
+#if ART_USE_PORTABLE_COMPILER
+  static const unsigned int kWatchDogWarningSeconds =  2 * 60;  // 2 minutes.
+  static const unsigned int kWatchDogTimeoutSeconds = 30 * 60;  // 25 minutes + buffer.
+#else
+  static const unsigned int kWatchDogWarningSeconds =  1 * 60;  // 1 minute.
+  static const unsigned int kWatchDogTimeoutSeconds =  6 * 60;  // 5 minutes + buffer.
+#endif
+
+  bool is_watch_dog_enabled_;
+  bool shutting_down_;
+  // TODO: Switch to Mutex when we can guarantee it won't prevent shutdown in error cases.
+  pthread_mutex_t mutex_;
+  pthread_cond_t cond_;
+  pthread_attr_t attr_;
+  pthread_t pthread_;
+};
+const unsigned int WatchDog::kWatchDogWarningSeconds;
+const unsigned int WatchDog::kWatchDogTimeoutSeconds;
+
+static int dex2oat(int argc, char** argv) {
+  InitLogging(argv);
+
+  // Skip over argv[0].
+  argv++;
+  argc--;
+
+  if (argc == 0) {
+    Usage("no arguments specified");
+  }
+
+  std::vector<const char*> dex_filenames;
+  std::vector<const char*> dex_locations;
+  int zip_fd = -1;
+  std::string zip_location;
+  std::string oat_filename;
+  std::string oat_symbols;
+  std::string oat_location;
+  int oat_fd = -1;
+  std::string bitcode_filename;
+  const char* image_classes_zip_filename = NULL;
+  const char* image_classes_filename = NULL;
+  std::string image_filename;
+  std::string boot_image_filename;
+  uintptr_t image_base = 0;
+  UniquePtr<std::string> host_prefix;
+  std::string android_root;
+  std::vector<const char*> runtime_args;
+  int thread_count = sysconf(_SC_NPROCESSORS_CONF);
+  bool support_debugging = false;
+#if defined(ART_USE_PORTABLE_COMPILER)
+  CompilerBackend compiler_backend = kPortable;
+#else
+  CompilerBackend compiler_backend = kQuick;
+#endif
+#if defined(__arm__)
+  InstructionSet instruction_set = kThumb2;
+#elif defined(__i386__)
+  InstructionSet instruction_set = kX86;
+#elif defined(__mips__)
+  InstructionSet instruction_set = kMips;
+#else
+#error "Unsupported architecture"
+#endif
+  bool is_host = false;
+  bool dump_stats = kIsDebugBuild;
+  bool dump_timings = kIsDebugBuild;
+  bool watch_dog_enabled = !kIsTargetBuild;
+
+
+  for (int i = 0; i < argc; i++) {
+    const StringPiece option(argv[i]);
+    bool log_options = false;
+    if (log_options) {
+      LOG(INFO) << "dex2oat: option[" << i << "]=" << argv[i];
+    }
+    if (option.starts_with("--dex-file=")) {
+      dex_filenames.push_back(option.substr(strlen("--dex-file=")).data());
+    } else if (option.starts_with("--dex-location=")) {
+      dex_locations.push_back(option.substr(strlen("--dex-location=")).data());
+    } else if (option.starts_with("--zip-fd=")) {
+      const char* zip_fd_str = option.substr(strlen("--zip-fd=")).data();
+      if (!ParseInt(zip_fd_str, &zip_fd)) {
+        Usage("could not parse --zip-fd argument '%s' as an integer", zip_fd_str);
+      }
+    } else if (option.starts_with("--zip-location=")) {
+      zip_location = option.substr(strlen("--zip-location=")).data();
+    } else if (option.starts_with("--oat-file=")) {
+      oat_filename = option.substr(strlen("--oat-file=")).data();
+    } else if (option.starts_with("--oat-symbols=")) {
+      oat_symbols = option.substr(strlen("--oat-symbols=")).data();
+    } else if (option.starts_with("--oat-fd=")) {
+      const char* oat_fd_str = option.substr(strlen("--oat-fd=")).data();
+      if (!ParseInt(oat_fd_str, &oat_fd)) {
+        Usage("could not parse --oat-fd argument '%s' as an integer", oat_fd_str);
+      }
+    } else if (option == "-g") {
+      support_debugging = true;
+    } else if (option == "--watch-dog") {
+      watch_dog_enabled = true;
+    } else if (option == "--no-watch-dog") {
+      watch_dog_enabled = false;
+    } else if (option.starts_with("-j")) {
+      const char* thread_count_str = option.substr(strlen("-j")).data();
+      if (!ParseInt(thread_count_str, &thread_count)) {
+        Usage("could not parse -j argument '%s' as an integer", thread_count_str);
+      }
+    } else if (option.starts_with("--oat-location=")) {
+      oat_location = option.substr(strlen("--oat-location=")).data();
+    } else if (option.starts_with("--bitcode=")) {
+      bitcode_filename = option.substr(strlen("--bitcode=")).data();
+    } else if (option.starts_with("--image=")) {
+      image_filename = option.substr(strlen("--image=")).data();
+    } else if (option.starts_with("--image-classes=")) {
+      image_classes_filename = option.substr(strlen("--image-classes=")).data();
+    } else if (option.starts_with("--image-classes-zip=")) {
+      image_classes_zip_filename = option.substr(strlen("--image-classes-zip=")).data();
+    } else if (option.starts_with("--base=")) {
+      const char* image_base_str = option.substr(strlen("--base=")).data();
+      char* end;
+      image_base = strtoul(image_base_str, &end, 16);
+      if (end == image_base_str || *end != '\0') {
+        Usage("Failed to parse hexadecimal value for option %s", option.data());
+      }
+    } else if (option.starts_with("--boot-image=")) {
+      boot_image_filename = option.substr(strlen("--boot-image=")).data();
+    } else if (option.starts_with("--host-prefix=")) {
+      host_prefix.reset(new std::string(option.substr(strlen("--host-prefix=")).data()));
+    } else if (option.starts_with("--android-root=")) {
+      android_root = option.substr(strlen("--android-root=")).data();
+    } else if (option.starts_with("--instruction-set=")) {
+      StringPiece instruction_set_str = option.substr(strlen("--instruction-set=")).data();
+      if (instruction_set_str == "arm") {
+        instruction_set = kThumb2;
+      } else if (instruction_set_str == "mips") {
+        instruction_set = kMips;
+      } else if (instruction_set_str == "x86") {
+        instruction_set = kX86;
+      }
+    } else if (option.starts_with("--compiler-backend=")) {
+      StringPiece backend_str = option.substr(strlen("--compiler-backend=")).data();
+      if (backend_str == "Quick") {
+        compiler_backend = kQuick;
+      } else if (backend_str == "Portable") {
+        compiler_backend = kPortable;
+      }
+    } else if (option == "--host") {
+      is_host = true;
+    } else if (option == "--runtime-arg") {
+      if (++i >= argc) {
+        Usage("Missing required argument for --runtime-arg");
+      }
+      if (log_options) {
+        LOG(INFO) << "dex2oat: option[" << i << "]=" << argv[i];
+      }
+      runtime_args.push_back(argv[i]);
+    } else {
+      Usage("unknown argument %s", option.data());
+    }
+  }
+
+  if (oat_filename.empty() && oat_fd == -1) {
+    Usage("Output must be supplied with either --oat-file or --oat-fd");
+  }
+
+  if (!oat_filename.empty() && oat_fd != -1) {
+    Usage("--oat-file should not be used with --oat-fd");
+  }
+
+  if (!oat_symbols.empty() && oat_fd != -1) {
+    Usage("--oat-symbols should not be used with --oat-fd");
+  }
+
+  if (!oat_symbols.empty() && is_host) {
+    Usage("--oat-symbols should not be used with --host");
+  }
+
+  if (oat_fd != -1 && !image_filename.empty()) {
+    Usage("--oat-fd should not be used with --image");
+  }
+
+  if (host_prefix.get() == NULL) {
+    const char* android_product_out = getenv("ANDROID_PRODUCT_OUT");
+    if (android_product_out != NULL) {
+        host_prefix.reset(new std::string(android_product_out));
+    }
+  }
+
+  if (android_root.empty()) {
+    const char* android_root_env_var = getenv("ANDROID_ROOT");
+    if (android_root_env_var == NULL) {
+      Usage("--android-root unspecified and ANDROID_ROOT not set");
+    }
+    android_root += android_root_env_var;
+  }
+
+  bool image = (!image_filename.empty());
+  if (!image && boot_image_filename.empty()) {
+    if (host_prefix.get() == NULL) {
+      boot_image_filename += GetAndroidRoot();
+    } else {
+      boot_image_filename += *host_prefix.get();
+      boot_image_filename += "/system";
+    }
+    boot_image_filename += "/framework/boot.art";
+  }
+  std::string boot_image_option;
+  if (!boot_image_filename.empty()) {
+    boot_image_option += "-Ximage:";
+    boot_image_option += boot_image_filename;
+  }
+
+  if (image_classes_filename != NULL && !image) {
+    Usage("--image-classes should only be used with --image");
+  }
+
+  if (image_classes_filename != NULL && !boot_image_option.empty()) {
+    Usage("--image-classes should not be used with --boot-image");
+  }
+
+  if (image_classes_zip_filename != NULL && image_classes_filename == NULL) {
+    Usage("--image-classes-zip should be used with --image-classes");
+  }
+
+  if (dex_filenames.empty() && zip_fd == -1) {
+    Usage("Input must be supplied with either --dex-file or --zip-fd");
+  }
+
+  if (!dex_filenames.empty() && zip_fd != -1) {
+    Usage("--dex-file should not be used with --zip-fd");
+  }
+
+  if (!dex_filenames.empty() && !zip_location.empty()) {
+    Usage("--dex-file should not be used with --zip-location");
+  }
+
+  if (dex_locations.empty()) {
+    for (size_t i = 0; i < dex_filenames.size(); i++) {
+      dex_locations.push_back(dex_filenames[i]);
+    }
+  } else if (dex_locations.size() != dex_filenames.size()) {
+    Usage("--dex-location arguments do not match --dex-file arguments");
+  }
+
+  if (zip_fd != -1 && zip_location.empty()) {
+    Usage("--zip-location should be supplied with --zip-fd");
+  }
+
+  if (boot_image_option.empty()) {
+    if (image_base == 0) {
+      Usage("non-zero --base not specified");
+    }
+  }
+
+  std::string oat_stripped(oat_filename);
+  std::string oat_unstripped;
+  if (!oat_symbols.empty()) {
+    oat_unstripped += oat_symbols;
+  } else {
+    oat_unstripped += oat_filename;
+  }
+
+  // Done with usage checks, enable watchdog if requested
+  WatchDog watch_dog(watch_dog_enabled);
+
+  // Check early that the result of compilation can be written
+  UniquePtr<File> oat_file;
+  bool create_file = !oat_unstripped.empty();  // as opposed to using open file descriptor
+  if (create_file) {
+    oat_file.reset(OS::OpenFile(oat_unstripped.c_str(), true));
+    if (oat_location.empty()) {
+      oat_location = oat_filename;
+    }
+  } else {
+    oat_file.reset(new File(oat_fd, oat_location));
+    oat_file->DisableAutoClose();
+  }
+  if (oat_file.get() == NULL) {
+    PLOG(ERROR) << "Failed to create oat file: " << oat_location;
+    return EXIT_FAILURE;
+  }
+  if (create_file && fchmod(oat_file->Fd(), 0644) != 0) {
+    PLOG(ERROR) << "Failed to make oat file world readable: " << oat_location;
+    return EXIT_FAILURE;
+  }
+
+  LOG(INFO) << "dex2oat: " << oat_location;
+
+  Runtime::Options options;
+  options.push_back(std::make_pair("compiler", reinterpret_cast<void*>(NULL)));
+  std::vector<const DexFile*> boot_class_path;
+  if (boot_image_option.empty()) {
+    size_t failure_count = OpenDexFiles(dex_filenames, dex_locations, boot_class_path);
+    if (failure_count > 0) {
+      LOG(ERROR) << "Failed to open some dex files: " << failure_count;
+      return EXIT_FAILURE;
+    }
+    options.push_back(std::make_pair("bootclasspath", &boot_class_path));
+  } else {
+    options.push_back(std::make_pair(boot_image_option.c_str(), reinterpret_cast<void*>(NULL)));
+  }
+  if (host_prefix.get() != NULL) {
+    options.push_back(std::make_pair("host-prefix", host_prefix->c_str()));
+  }
+  for (size_t i = 0; i < runtime_args.size(); i++) {
+    options.push_back(std::make_pair(runtime_args[i], reinterpret_cast<void*>(NULL)));
+  }
+
+#if ART_SMALL_MODE
+  options.push_back(std::make_pair("-small", reinterpret_cast<void*>(NULL)));
+#endif // ART_SMALL_MODE
+
+
+#ifdef ART_SEA_IR_MODE
+  options.push_back(std::make_pair("-sea_ir", reinterpret_cast<void*>(NULL)));
+#endif
+
+
+  Dex2Oat* p_dex2oat;
+  if (!Dex2Oat::Create(&p_dex2oat, options, compiler_backend, instruction_set, thread_count,
+                       support_debugging)) {
+    LOG(ERROR) << "Failed to create dex2oat";
+    return EXIT_FAILURE;
+  }
+  UniquePtr<Dex2Oat> dex2oat(p_dex2oat);
+  // Runtime::Create acquired the mutator_lock_ that is normally given away when we Runtime::Start,
+  // give it away now and then switch to a more managable ScopedObjectAccess.
+  Thread::Current()->TransitionFromRunnableToSuspended(kNative);
+  // Whilst we're in native take the opportunity to initialize well known classes.
+  WellKnownClasses::InitClasses(Thread::Current()->GetJniEnv());
+  ScopedObjectAccess soa(Thread::Current());
+
+  // If --image-classes was specified, calculate the full list of classes to include in the image
+  UniquePtr<CompilerDriver::DescriptorSet> image_classes(NULL);
+  if (image_classes_filename != NULL) {
+    if (image_classes_zip_filename != NULL) {
+      image_classes.reset(dex2oat->ReadImageClassesFromZip(image_classes_zip_filename,
+                                                           image_classes_filename));
+    } else {
+      image_classes.reset(dex2oat->ReadImageClassesFromFile(image_classes_filename));
+    }
+    if (image_classes.get() == NULL) {
+      LOG(ERROR) << "Failed to create list of image classes from " << image_classes_filename;
+      return EXIT_FAILURE;
+    }
+  }
+
+  std::vector<const DexFile*> dex_files;
+  if (boot_image_option.empty()) {
+    dex_files = Runtime::Current()->GetClassLinker()->GetBootClassPath();
+  } else {
+    if (dex_filenames.empty()) {
+      UniquePtr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(zip_fd));
+      if (zip_archive.get() == NULL) {
+        LOG(ERROR) << "Failed to open zip from file descriptor for " << zip_location;
+        return EXIT_FAILURE;
+      }
+      const DexFile* dex_file = DexFile::Open(*zip_archive.get(), zip_location);
+      if (dex_file == NULL) {
+        LOG(ERROR) << "Failed to open dex from file descriptor for zip file: " << zip_location;
+        return EXIT_FAILURE;
+      }
+      dex_files.push_back(dex_file);
+    } else {
+      size_t failure_count = OpenDexFiles(dex_filenames, dex_locations, dex_files);
+      if (failure_count > 0) {
+        LOG(ERROR) << "Failed to open some dex files: " << failure_count;
+        return EXIT_FAILURE;
+      }
+    }
+  }
+
+  // If we're in small mode, but the program is small, turn off small mode.
+  // It doesn't make a difference for the boot image, so let's skip the check
+  // altogether.
+  if (Runtime::Current()->IsSmallMode() && !image) {
+    size_t num_methods = 0;
+    for (size_t i = 0; i != dex_files.size(); ++i) {
+      const DexFile* dex_file = dex_files[i];
+      CHECK(dex_file != NULL);
+      num_methods += dex_file->NumMethodIds();
+    }
+    if (num_methods <= Runtime::Current()->GetSmallModeMethodThreshold()) {
+      Runtime::Current()->SetSmallMode(false);
+      LOG(INFO) << "Below method threshold, compiling anyways";
+    }
+  }
+
+  UniquePtr<const CompilerDriver> compiler(dex2oat->CreateOatFile(boot_image_option,
+                                                                  host_prefix.get(),
+                                                                  android_root,
+                                                                  is_host,
+                                                                  dex_files,
+                                                                  oat_file.get(),
+                                                                  bitcode_filename,
+                                                                  image,
+                                                                  image_classes,
+                                                                  dump_stats,
+                                                                  dump_timings));
+
+  if (compiler.get() == NULL) {
+    LOG(ERROR) << "Failed to create oat file: " << oat_location;
+    return EXIT_FAILURE;
+  }
+
+  LOG(INFO) << "Oat file written successfully (unstripped): " << oat_location;
+
+  // Notes on the interleaving of creating the image and oat file to
+  // ensure the references between the two are correct.
+  //
+  // Currently we have a memory layout that looks something like this:
+  //
+  // +--------------+
+  // | image        |
+  // +--------------+
+  // | boot oat     |
+  // +--------------+
+  // | alloc spaces |
+  // +--------------+
+  //
+  // There are several constraints on the loading of the imag and boot.oat.
+  //
+  // 1. The image is expected to be loaded at an absolute address and
+  // contains Objects with absolute pointers within the image.
+  //
+  // 2. There are absolute pointers from Methods in the image to their
+  // code in the oat.
+  //
+  // 3. There are absolute pointers from the code in the oat to Methods
+  // in the image.
+  //
+  // 4. There are absolute pointers from code in the oat to other code
+  // in the oat.
+  //
+  // To get this all correct, we go through several steps.
+  //
+  // 1. We have already created that oat file above with
+  // CreateOatFile. Originally this was just our own proprietary file
+  // but now it is contained within an ELF dynamic object (aka .so
+  // file). The Compiler returned by CreateOatFile provides
+  // PatchInformation for references to oat code and Methods that need
+  // to be update once we know where the oat file will be located
+  // after the image.
+  //
+  // 2. We create the image file. It needs to know where the oat file
+  // will be loaded after itself. Originally when oat file was simply
+  // memory mapped so we could predict where its contents were based
+  // on the file size. Now that it is an ELF file, we need to inspect
+  // the ELF file to understand the in memory segment layout including
+  // where the oat header is located within. ImageWriter's
+  // PatchOatCodeAndMethods uses the PatchInformation from the
+  // Compiler to touch up absolute references in the oat file.
+  //
+  // 3. We fixup the ELF program headers so that dlopen will try to
+  // load the .so at the desired location at runtime by offsetting the
+  // Elf32_Phdr.p_vaddr values by the desired base address.
+  //
+  if (image) {
+    Thread::Current()->TransitionFromRunnableToSuspended(kNative);
+    bool image_creation_success = dex2oat->CreateImageFile(image_filename,
+                                                           image_base,
+                                                           oat_unstripped,
+                                                           oat_location,
+                                                           *compiler.get());
+    Thread::Current()->TransitionFromSuspendedToRunnable();
+    LOG(INFO) << "Image written successfully: " << image_filename;
+    if (!image_creation_success) {
+      return EXIT_FAILURE;
+    }
+  }
+
+  if (is_host) {
+    return EXIT_SUCCESS;
+  }
+
+  // If we don't want to strip in place, copy from unstripped location to stripped location.
+  // We need to strip after image creation because FixupElf needs to use .strtab.
+  if (oat_unstripped != oat_stripped) {
+    oat_file.reset();
+    UniquePtr<File> in(OS::OpenFile(oat_unstripped.c_str(), false));
+    UniquePtr<File> out(OS::OpenFile(oat_stripped.c_str(), true));
+    size_t buffer_size = 8192;
+    UniquePtr<uint8_t> buffer(new uint8_t[buffer_size]);
+    while (true) {
+      int bytes_read = TEMP_FAILURE_RETRY(read(in->Fd(), buffer.get(), buffer_size));
+      if (bytes_read <= 0) {
+        break;
+      }
+      bool write_ok = out->WriteFully(buffer.get(), bytes_read);
+      CHECK(write_ok);
+    }
+    oat_file.reset(out.release());
+    LOG(INFO) << "Oat file copied successfully (stripped): " << oat_stripped;
+  }
+
+  // Strip unneeded sections for target
+  off_t seek_actual = lseek(oat_file->Fd(), 0, SEEK_SET);
+  CHECK_EQ(0, seek_actual);
+  ElfStripper::Strip(oat_file.get());
+
+  // We wrote the oat file successfully, and want to keep it.
+  LOG(INFO) << "Oat file written successfully (stripped): " << oat_location;
+  return EXIT_SUCCESS;
+}
+
+} // namespace art
+
+int main(int argc, char** argv) {
+  return art::dex2oat(argc, argv);
+}