[automerger skipped] Merge commit '67c932ce050e80b9bf23b15b24d9aed1a2ee209d' into art-file-create am: 7b1b6673e3 am: 89cb524ea7 -s ours
am: d55574c730 -s ours
am skip reason: change_id Ic4dae399a5bfe862aff3d8614c45b38044d805db with SHA1 d224e964bd is in history

Change-Id: I95af592d7c996a9faff51204f29e42f6913cdc0b
diff --git a/.gitignore b/.gitignore
index 4e806c6..803c297 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,6 @@
 JIT_ART
 **/__pycache__/**
+**/.idea
+**/*.iml
+**/*.pyc
+**/*.swn
diff --git a/Android.bp b/Android.bp
index d0e22fb..c1c3049 100644
--- a/Android.bp
+++ b/Android.bp
@@ -11,13 +11,17 @@
     "libbacktrace",
     "libcutils",
     "libunwindbacktrace",
+    "libunwind",
+    "libunwindstack",
     "libutils",
     "libbase",
     "liblz4",
     "liblzma",
+    "libmetricslogger_static",
 ]
 
 subdirs = [
+    "adbconnection",
     "benchmark",
     "build",
     "cmdline",
@@ -29,13 +33,25 @@
     "dexlist",
     "dexoptanalyzer",
     "disassembler",
+    "dt_fd_forward",
+    "dt_fd_forward/export",
     "imgdiag",
+    "libartbase",
+    "libdexfile",
     "oatdump",
+    "openjdkjvm",
+    "openjdkjvmti",
     "patchoat",
     "profman",
     "runtime",
     "sigchainlib",
+    "simulator",
     "test",
+    "tools",
+    "tools/breakpoint-logger",
     "tools/cpp-define-generator",
     "tools/dmtracedump",
+    "tools/hiddenapi",
+    "tools/titrace",
+    "tools/wrapagentproperties",
 ]
diff --git a/Android.mk b/Android.mk
index 8735d7c..e4f4e74 100644
--- a/Android.mk
+++ b/Android.mk
@@ -25,18 +25,6 @@
 include $(art_path)/build/Android.common_path.mk
 include $(art_path)/build/Android.oat.mk
 
-# Following the example of build's dont_bother for clean targets.
-art_dont_bother := false
-ifneq (,$(filter clean-oat%,$(MAKECMDGOALS)))
-  art_dont_bother := true
-endif
-
-# Don't bother with tests unless there is a test-art*, build-art*, or related target.
-art_test_bother := false
-ifneq (,$(filter tests test-art% valgrind-test-art% build-art% checkbuild,$(MAKECMDGOALS)))
-  art_test_bother := true
-endif
-
 .PHONY: clean-oat
 clean-oat: clean-oat-host clean-oat-target
 
@@ -66,8 +54,6 @@
 endif
 	adb shell rm -rf data/run-test/test-*/dalvik-cache/*
 
-ifneq ($(art_dont_bother),true)
-
 ########################################################################
 # cpplint rules to style check art source files
 
@@ -79,7 +65,9 @@
 include $(art_path)/oatdump/Android.mk
 include $(art_path)/tools/Android.mk
 include $(art_path)/tools/ahat/Android.mk
+include $(art_path)/tools/amm/Android.mk
 include $(art_path)/tools/dexfuzz/Android.mk
+include $(art_path)/tools/veridex/Android.mk
 include $(art_path)/libart_fake/Android.mk
 
 ART_HOST_DEPENDENCIES := \
@@ -103,8 +91,6 @@
 ########################################################################
 # test rules
 
-ifeq ($(art_test_bother),true)
-
 # All the dependencies that must be built ahead of sync-ing them onto the target device.
 TEST_ART_TARGET_SYNC_DEPS :=
 
@@ -135,11 +121,11 @@
 else
 test-art-target-sync: $(TEST_ART_TARGET_SYNC_DEPS)
 	$(TEST_ART_ADB_ROOT_AND_REMOUNT)
-	adb wait-for-device push $(ANDROID_PRODUCT_OUT)/system $(ART_TEST_ANDROID_ROOT)
+	adb wait-for-device push $(PRODUCT_OUT)/system $(ART_TEST_ANDROID_ROOT)
 # Push the contents of the `data` dir into `/data` on the device.  If
 # `/data` already exists on the device, it is not overwritten, but its
 # contents are updated.
-	adb push $(ANDROID_PRODUCT_OUT)/data /
+	adb push $(PRODUCT_OUT)/data /
 endif
 endif
 
@@ -348,7 +334,6 @@
 valgrind-test-art-target64: valgrind-test-art-target-gtest64
 	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
-endif  # art_test_bother
 
 #######################
 # Fake packages for ART
@@ -370,6 +355,7 @@
     libopenjdkjvmti \
     patchoat \
     profman \
+    libadbconnection \
 
 # For nosy apps, we provide a fake library that avoids namespace issues and gives some warnings.
 LOCAL_REQUIRED_MODULES += libart_fake
@@ -395,6 +381,7 @@
     libopenjdkjvmtid \
     patchoatd \
     profmand \
+    libadbconnectiond \
 
 endif
 endif
@@ -445,6 +432,19 @@
 include $(BUILD_PHONY_PACKAGE)
 endif
 
+# Create dummy hidden API lists which are normally generated by the framework
+# but which we do not have in the master-art manifest.
+# We need to execute this now to ensure Makefile rules depending on these files can
+# be constructed.
+define build-art-hiddenapi
+$(shell if [ ! -d frameworks/base ]; then \
+  mkdir -p ${TARGET_OUT_COMMON_INTERMEDIATES}/PACKAGING; \
+	touch ${TARGET_OUT_COMMON_INTERMEDIATES}/PACKAGING/hiddenapi-{blacklist,dark-greylist,light-greylist}.txt; \
+  fi;)
+endef
+
+$(eval $(call build-art-hiddenapi))
+
 ########################################################################
 # "m build-art" for quick minimal build
 .PHONY: build-art
@@ -457,7 +457,8 @@
 build-art-target: $(TARGET_OUT_EXECUTABLES)/art $(ART_TARGET_DEPENDENCIES) $(TARGET_CORE_IMG_OUTS)
 
 ########################################################################
-# Phony target for only building what go/lem requires on target.
+# Phony target for only building what go/lem requires for pushing ART on /data.
+
 .PHONY: build-art-target-golem
 # Also include libartbenchmark, we always include it when running golem.
 # libstdc++ is needed when building for ART_TARGET_LINUX.
@@ -470,8 +471,10 @@
                         $(ART_TARGET_SHARED_LIBRARY_BENCHMARK) \
                         $(TARGET_CORE_IMG_OUT_BASE).art \
                         $(TARGET_CORE_IMG_OUT_BASE)-interpreter.art
+	# remove libartd.so and libdexfiled.so from public.libraries.txt because golem builds
+	# won't have it.
 	sed -i '/libartd.so/d' $(TARGET_OUT)/etc/public.libraries.txt
-	# remove libartd.so from public.libraries.txt because golem builds won't have it.
+	sed -i '/libdexfiled.so/d' $(TARGET_OUT)/etc/public.libraries.txt
 
 ########################################################################
 # Phony target for building what go/lem requires on host.
@@ -482,6 +485,11 @@
                       $(ART_HOST_SHARED_LIBRARY_BENCHMARK)
 
 ########################################################################
+# Phony target for building what go/lem requires for syncing /system to target.
+.PHONY: build-art-unbundled-golem
+build-art-unbundled-golem: art-runtime linker oatdump $(TARGET_CORE_JARS) crash_dump
+
+########################################################################
 # Rules for building all dependencies for tests.
 
 .PHONY: build-art-host-tests
@@ -582,11 +590,7 @@
 
 ########################################################################
 
-endif # !art_dont_bother
-
 # Clear locally used variables.
-art_dont_bother :=
-art_test_bother :=
 TEST_ART_TARGET_SYNC_DEPS :=
 
 # Helper target that depends on boot image creation.
diff --git a/CPPLINT.cfg b/CPPLINT.cfg
new file mode 100644
index 0000000..8328842
--- /dev/null
+++ b/CPPLINT.cfg
@@ -0,0 +1,33 @@
+#
+# Copyright (C) 2017 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.
+#
+
+# Don't search for additional CPPLINT.cfg in parent directories.
+set noparent
+
+# Use 'ART_' as the cpp header guard prefix (e.g. #ifndef ART_PATH_TO_FILE_H_).
+root=..
+
+# Limit line length.
+linelength=100
+
+# Ignore the following categories of errors, as specified by the filter:
+# (the filter settings are concatenated together)
+filter=-build/c++11
+filter=-build/include
+filter=-readability/function,-readability/streams,-readability/todo
+filter=-runtime/printf,-runtime/references,-runtime/sizeof,-runtime/threadsafe_fn
+# TODO: this should be re-enabled.
+filter=-whitespace/line_length
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 8a8df36..7e492c7 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,4 +1,10 @@
 [Hook Scripts]
 check_generated_files_up_to_date = tools/cpp-define-generator/presubmit-check-files-up-to-date
 check_generated_tests_up_to_date = tools/test_presubmit.py
-check_cpplint_on_changed_files = tools/cpplint_presubmit.py
+
+[Builtin Hooks]
+cpplint = true
+
+[Builtin Hooks Options]
+# Cpplint prints nothing unless there were errors.
+cpplint = --quiet ${PREUPLOAD_FILES}
diff --git a/adbconnection/Android.bp b/adbconnection/Android.bp
new file mode 100644
index 0000000..441b706
--- /dev/null
+++ b/adbconnection/Android.bp
@@ -0,0 +1,80 @@
+//
+// Copyright (C) 2017 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.
+//
+
+// Build variants {target,host} x {debug,ndebug} x {32,64}
+
+cc_defaults {
+    name: "adbconnection-defaults",
+    host_supported: true,
+    srcs: ["adbconnection.cc"],
+    defaults: ["art_defaults"],
+
+    // Note that this tool needs to be built for both 32-bit and 64-bit since it requires
+    // to be same ISA as what it is attached to.
+    compile_multilib: "both",
+
+    shared_libs: [
+        "libbase",
+    ],
+    target: {
+        android: {
+            shared_libs: [
+                "libcutils",
+            ],
+        },
+        host: {
+        },
+        darwin: {
+            enabled: false,
+        },
+    },
+    header_libs: [
+        "libnativehelper_header_only",
+        "dt_fd_forward_export",
+    ],
+    multilib: {
+        lib32: {
+            suffix: "32",
+        },
+        lib64: {
+            suffix: "64",
+        },
+    },
+    symlink_preferred_arch: true,
+    required: [
+        "libjdwp",
+        "libdt_fd_forward",
+    ],
+}
+
+art_cc_library {
+    name: "libadbconnection",
+    defaults: ["adbconnection-defaults"],
+    shared_libs: [
+        "libart",
+    ],
+}
+
+art_cc_library {
+    name: "libadbconnectiond",
+    defaults: [
+        "art_debug_defaults",
+        "adbconnection-defaults",
+    ],
+    shared_libs: [
+        "libartd",
+    ],
+}
diff --git a/adbconnection/adbconnection.cc b/adbconnection/adbconnection.cc
new file mode 100644
index 0000000..4c2d4d7
--- /dev/null
+++ b/adbconnection/adbconnection.cc
@@ -0,0 +1,907 @@
+/*
+ * Copyright (C) 2017 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 <array>
+
+#include "adbconnection.h"
+
+#include "android-base/endian.h"
+#include "android-base/stringprintf.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/mutex.h"
+#include "java_vm_ext.h"
+#include "jni_env_ext.h"
+#include "mirror/throwable.h"
+#include "nativehelper/ScopedLocalRef.h"
+#include "runtime-inl.h"
+#include "runtime_callbacks.h"
+#include "scoped_thread_state_change-inl.h"
+#include "well_known_classes.h"
+
+#include "jdwp/jdwp_priv.h"
+
+#include "fd_transport.h"
+
+#include "poll.h"
+
+#ifdef ART_TARGET_ANDROID
+#include "cutils/sockets.h"
+#endif
+
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/eventfd.h>
+#include <jni.h>
+
+namespace adbconnection {
+
+// Messages sent from the transport
+using dt_fd_forward::kListenStartMessage;
+using dt_fd_forward::kListenEndMessage;
+using dt_fd_forward::kAcceptMessage;
+using dt_fd_forward::kCloseMessage;
+
+// Messages sent to the transport
+using dt_fd_forward::kPerformHandshakeMessage;
+using dt_fd_forward::kSkipHandshakeMessage;
+
+using android::base::StringPrintf;
+
+static constexpr const char kJdwpHandshake[14] = {
+  'J', 'D', 'W', 'P', '-', 'H', 'a', 'n', 'd', 's', 'h', 'a', 'k', 'e'
+};
+
+static constexpr int kEventfdLocked = 0;
+static constexpr int kEventfdUnlocked = 1;
+static constexpr int kControlSockSendTimeout = 10;
+
+static constexpr size_t kPacketHeaderLen = 11;
+static constexpr off_t kPacketSizeOff = 0;
+static constexpr off_t kPacketIdOff = 4;
+static constexpr off_t kPacketCommandSetOff = 9;
+static constexpr off_t kPacketCommandOff = 10;
+
+static constexpr uint8_t kDdmCommandSet = 199;
+static constexpr uint8_t kDdmChunkCommand = 1;
+
+static AdbConnectionState* gState;
+
+static bool IsDebuggingPossible() {
+  return art::Dbg::IsJdwpAllowed();
+}
+
+// Begin running the debugger.
+void AdbConnectionDebuggerController::StartDebugger() {
+  if (IsDebuggingPossible()) {
+    connection_->StartDebuggerThreads();
+  } else {
+    LOG(ERROR) << "Not starting debugger since process cannot load the jdwp agent.";
+  }
+}
+
+// The debugger should begin shutting down since the runtime is ending. We don't actually do
+// anything here. The real shutdown has already happened as far as the agent is concerned.
+void AdbConnectionDebuggerController::StopDebugger() { }
+
+bool AdbConnectionDebuggerController::IsDebuggerConfigured() {
+  return IsDebuggingPossible() && !art::Runtime::Current()->GetJdwpOptions().empty();
+}
+
+void AdbConnectionDdmCallback::DdmPublishChunk(uint32_t type,
+                                               const art::ArrayRef<const uint8_t>& data) {
+  connection_->PublishDdmData(type, data);
+}
+
+class ScopedEventFdLock {
+ public:
+  explicit ScopedEventFdLock(int fd) : fd_(fd), data_(0) {
+    TEMP_FAILURE_RETRY(read(fd_, &data_, sizeof(data_)));
+  }
+
+  ~ScopedEventFdLock() {
+    TEMP_FAILURE_RETRY(write(fd_, &data_, sizeof(data_)));
+  }
+
+ private:
+  int fd_;
+  uint64_t data_;
+};
+
+AdbConnectionState::AdbConnectionState(const std::string& agent_name)
+  : agent_name_(agent_name),
+    controller_(this),
+    ddm_callback_(this),
+    sleep_event_fd_(-1),
+    control_sock_(-1),
+    local_agent_control_sock_(-1),
+    remote_agent_control_sock_(-1),
+    adb_connection_socket_(-1),
+    adb_write_event_fd_(-1),
+    shutting_down_(false),
+    agent_loaded_(false),
+    agent_listening_(false),
+    agent_has_socket_(false),
+    sent_agent_fds_(false),
+    performed_handshake_(false),
+    notified_ddm_active_(false),
+    next_ddm_id_(1),
+    started_debugger_threads_(false) {
+  // Setup the addr.
+  control_addr_.controlAddrUn.sun_family = AF_UNIX;
+  control_addr_len_ = sizeof(control_addr_.controlAddrUn.sun_family) + sizeof(kJdwpControlName) - 1;
+  memcpy(control_addr_.controlAddrUn.sun_path, kJdwpControlName, sizeof(kJdwpControlName) - 1);
+
+  // Add the startup callback.
+  art::ScopedObjectAccess soa(art::Thread::Current());
+  art::Runtime::Current()->GetRuntimeCallbacks()->AddDebuggerControlCallback(&controller_);
+}
+
+static jobject CreateAdbConnectionThread(art::Thread* thr) {
+  JNIEnv* env = thr->GetJniEnv();
+  // Move to native state to talk with the jnienv api.
+  art::ScopedThreadStateChange stsc(thr, art::kNative);
+  ScopedLocalRef<jstring> thr_name(env, env->NewStringUTF(kAdbConnectionThreadName));
+  ScopedLocalRef<jobject> thr_group(
+      env,
+      env->GetStaticObjectField(art::WellKnownClasses::java_lang_ThreadGroup,
+                                art::WellKnownClasses::java_lang_ThreadGroup_systemThreadGroup));
+  return env->NewObject(art::WellKnownClasses::java_lang_Thread,
+                        art::WellKnownClasses::java_lang_Thread_init,
+                        thr_group.get(),
+                        thr_name.get(),
+                        /*Priority*/ 0,
+                        /*Daemon*/ true);
+}
+
+struct CallbackData {
+  AdbConnectionState* this_;
+  jobject thr_;
+};
+
+static void* CallbackFunction(void* vdata) {
+  std::unique_ptr<CallbackData> data(reinterpret_cast<CallbackData*>(vdata));
+  CHECK(data->this_ == gState);
+  art::Thread* self = art::Thread::Attach(kAdbConnectionThreadName,
+                                          true,
+                                          data->thr_);
+  CHECK(self != nullptr) << "threads_being_born_ should have ensured thread could be attached.";
+  // The name in Attach() is only for logging. Set the thread name. This is important so
+  // that the thread is no longer seen as starting up.
+  {
+    art::ScopedObjectAccess soa(self);
+    self->SetThreadName(kAdbConnectionThreadName);
+  }
+
+  // Release the peer.
+  JNIEnv* env = self->GetJniEnv();
+  env->DeleteGlobalRef(data->thr_);
+  data->thr_ = nullptr;
+  {
+    // The StartThreadBirth was called in the parent thread. We let the runtime know we are up
+    // before going into the provided code.
+    art::MutexLock mu(self, *art::Locks::runtime_shutdown_lock_);
+    art::Runtime::Current()->EndThreadBirth();
+  }
+  data->this_->RunPollLoop(self);
+  int detach_result = art::Runtime::Current()->GetJavaVM()->DetachCurrentThread();
+  CHECK_EQ(detach_result, 0);
+
+  // Get rid of the connection
+  gState = nullptr;
+  delete data->this_;
+
+  return nullptr;
+}
+
+void AdbConnectionState::StartDebuggerThreads() {
+  // First do all the final setup we need.
+  CHECK_EQ(adb_write_event_fd_.get(), -1);
+  CHECK_EQ(sleep_event_fd_.get(), -1);
+  CHECK_EQ(local_agent_control_sock_.get(), -1);
+  CHECK_EQ(remote_agent_control_sock_.get(), -1);
+
+  sleep_event_fd_.reset(eventfd(kEventfdLocked, EFD_CLOEXEC));
+  CHECK_NE(sleep_event_fd_.get(), -1) << "Unable to create wakeup eventfd.";
+  adb_write_event_fd_.reset(eventfd(kEventfdUnlocked, EFD_CLOEXEC));
+  CHECK_NE(adb_write_event_fd_.get(), -1) << "Unable to create write-lock eventfd.";
+
+  {
+    art::ScopedObjectAccess soa(art::Thread::Current());
+    art::Runtime::Current()->GetRuntimeCallbacks()->AddDdmCallback(&ddm_callback_);
+  }
+  // Setup the socketpair we use to talk to the agent.
+  bool has_sockets;
+  do {
+    has_sockets = android::base::Socketpair(AF_UNIX,
+                                            SOCK_SEQPACKET | SOCK_CLOEXEC,
+                                            0,
+                                            &local_agent_control_sock_,
+                                            &remote_agent_control_sock_);
+  } while (!has_sockets && errno == EINTR);
+  if (!has_sockets) {
+    PLOG(FATAL) << "Unable to create socketpair for agent control!";
+  }
+
+  // Next start the threads.
+  art::Thread* self = art::Thread::Current();
+  art::ScopedObjectAccess soa(self);
+  {
+    art::Runtime* runtime = art::Runtime::Current();
+    art::MutexLock mu(self, *art::Locks::runtime_shutdown_lock_);
+    if (runtime->IsShuttingDownLocked()) {
+      // The runtime is shutting down so we cannot create new threads. This shouldn't really happen.
+      LOG(ERROR) << "The runtime is shutting down when we are trying to start up the debugger!";
+      return;
+    }
+    runtime->StartThreadBirth();
+  }
+  ScopedLocalRef<jobject> thr(soa.Env(), CreateAdbConnectionThread(soa.Self()));
+  pthread_t pthread;
+  std::unique_ptr<CallbackData> data(new CallbackData { this, soa.Env()->NewGlobalRef(thr.get()) });
+  started_debugger_threads_ = true;
+  int pthread_create_result = pthread_create(&pthread,
+                                             nullptr,
+                                             &CallbackFunction,
+                                             data.get());
+  if (pthread_create_result != 0) {
+    started_debugger_threads_ = false;
+    // If the create succeeded the other thread will call EndThreadBirth.
+    art::Runtime* runtime = art::Runtime::Current();
+    soa.Env()->DeleteGlobalRef(data->thr_);
+    LOG(ERROR) << "Failed to create thread for adb-jdwp connection manager!";
+    art::MutexLock mu(art::Thread::Current(), *art::Locks::runtime_shutdown_lock_);
+    runtime->EndThreadBirth();
+    return;
+  }
+  data.release();
+}
+
+static bool FlagsSet(int16_t data, int16_t flags) {
+  return (data & flags) == flags;
+}
+
+void AdbConnectionState::CloseFds() {
+  {
+    // Lock the write_event_fd so that concurrent PublishDdms will see that the connection is
+    // closed.
+    ScopedEventFdLock lk(adb_write_event_fd_);
+    // shutdown(adb_connection_socket_, SHUT_RDWR);
+    adb_connection_socket_.reset();
+  }
+
+  // If we didn't load anything we will need to do the handshake again.
+  performed_handshake_ = false;
+
+  // If the agent isn't loaded we might need to tell ddms code the connection is closed.
+  if (!agent_loaded_ && notified_ddm_active_) {
+    NotifyDdms(/*active*/false);
+  }
+}
+
+void AdbConnectionState::NotifyDdms(bool active) {
+  art::ScopedObjectAccess soa(art::Thread::Current());
+  DCHECK_NE(notified_ddm_active_, active);
+  notified_ddm_active_ = active;
+  if (active) {
+    art::Dbg::DdmConnected();
+  } else {
+    art::Dbg::DdmDisconnected();
+  }
+}
+
+uint32_t AdbConnectionState::NextDdmId() {
+  // Just have a normal counter but always set the sign bit.
+  return (next_ddm_id_++) | 0x80000000;
+}
+
+void AdbConnectionState::PublishDdmData(uint32_t type, const art::ArrayRef<const uint8_t>& data) {
+  SendDdmPacket(NextDdmId(), DdmPacketType::kCmd, type, data);
+}
+
+void AdbConnectionState::SendDdmPacket(uint32_t id,
+                                       DdmPacketType packet_type,
+                                       uint32_t type,
+                                       art::ArrayRef<const uint8_t> data) {
+  // Get the write_event early to fail fast.
+  ScopedEventFdLock lk(adb_write_event_fd_);
+  if (adb_connection_socket_ == -1) {
+    VLOG(jdwp) << "Not sending ddms data of type "
+               << StringPrintf("%c%c%c%c",
+                               static_cast<char>(type >> 24),
+                               static_cast<char>(type >> 16),
+                               static_cast<char>(type >> 8),
+                               static_cast<char>(type)) << " due to no connection!";
+    // Adb is not connected.
+    return;
+  }
+
+  // the adb_write_event_fd_ will ensure that the adb_connection_socket_ will not go away until
+  // after we have sent our data.
+  static constexpr uint32_t kDdmPacketHeaderSize =
+      kJDWPHeaderLen       // jdwp command packet size
+      + sizeof(uint32_t)   // Type
+      + sizeof(uint32_t);  // length
+  alignas(sizeof(uint32_t)) std::array<uint8_t, kDdmPacketHeaderSize> pkt;
+  uint8_t* pkt_data = pkt.data();
+
+  // Write the length first.
+  *reinterpret_cast<uint32_t*>(pkt_data) = htonl(kDdmPacketHeaderSize + data.size());
+  pkt_data += sizeof(uint32_t);
+
+  // Write the id next;
+  *reinterpret_cast<uint32_t*>(pkt_data) = htonl(id);
+  pkt_data += sizeof(uint32_t);
+
+  // next the flags. (0 for cmd packet because DDMS).
+  *(pkt_data++) = static_cast<uint8_t>(packet_type);
+  switch (packet_type) {
+    case DdmPacketType::kCmd: {
+      // Now the cmd-set
+      *(pkt_data++) = kJDWPDdmCmdSet;
+      // Now the command
+      *(pkt_data++) = kJDWPDdmCmd;
+      break;
+    }
+    case DdmPacketType::kReply: {
+      // This is the error code bytes which are all 0
+      *(pkt_data++) = 0;
+      *(pkt_data++) = 0;
+    }
+  }
+
+  // These are at unaligned addresses so we need to do them manually.
+  // now the type.
+  uint32_t net_type = htonl(type);
+  memcpy(pkt_data, &net_type, sizeof(net_type));
+  pkt_data += sizeof(uint32_t);
+
+  // Now the data.size()
+  uint32_t net_len = htonl(data.size());
+  memcpy(pkt_data, &net_len, sizeof(net_len));
+  pkt_data += sizeof(uint32_t);
+
+  static uint32_t constexpr kIovSize = 2;
+  struct iovec iovs[kIovSize] = {
+    { pkt.data(), pkt.size() },
+    { const_cast<uint8_t*>(data.data()), data.size() },
+  };
+  // now pkt_header has the header.
+  // use writev to send the actual data.
+  ssize_t res = TEMP_FAILURE_RETRY(writev(adb_connection_socket_, iovs, kIovSize));
+  if (static_cast<size_t>(res) != (kDdmPacketHeaderSize + data.size())) {
+    PLOG(ERROR) << StringPrintf("Failed to send DDMS packet %c%c%c%c to debugger (%zd of %zu)",
+                                static_cast<char>(type >> 24),
+                                static_cast<char>(type >> 16),
+                                static_cast<char>(type >> 8),
+                                static_cast<char>(type),
+                                res, data.size() + kDdmPacketHeaderSize);
+  } else {
+    VLOG(jdwp) << StringPrintf("sent DDMS packet %c%c%c%c to debugger %zu",
+                               static_cast<char>(type >> 24),
+                               static_cast<char>(type >> 16),
+                               static_cast<char>(type >> 8),
+                               static_cast<char>(type),
+                               data.size() + kDdmPacketHeaderSize);
+  }
+}
+
+void AdbConnectionState::SendAgentFds(bool require_handshake) {
+  DCHECK(!sent_agent_fds_);
+  const char* message = require_handshake ? kPerformHandshakeMessage : kSkipHandshakeMessage;
+  union {
+    cmsghdr cm;
+    char buffer[CMSG_SPACE(dt_fd_forward::FdSet::kDataLength)];
+  } cm_un;
+  iovec iov;
+  iov.iov_base       = const_cast<char*>(message);
+  iov.iov_len        = strlen(message) + 1;
+
+  msghdr msg;
+  msg.msg_name       = nullptr;
+  msg.msg_namelen    = 0;
+  msg.msg_iov        = &iov;
+  msg.msg_iovlen     = 1;
+  msg.msg_flags      = 0;
+  msg.msg_control    = cm_un.buffer;
+  msg.msg_controllen = sizeof(cm_un.buffer);
+
+  cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
+  cmsg->cmsg_len   = CMSG_LEN(dt_fd_forward::FdSet::kDataLength);
+  cmsg->cmsg_level = SOL_SOCKET;
+  cmsg->cmsg_type  = SCM_RIGHTS;
+
+  // Duplicate the fds before sending them.
+  android::base::unique_fd read_fd(dup(adb_connection_socket_));
+  CHECK_NE(read_fd.get(), -1) << "Failed to dup read_fd_: " << strerror(errno);
+  android::base::unique_fd write_fd(dup(adb_connection_socket_));
+  CHECK_NE(write_fd.get(), -1) << "Failed to dup write_fd: " << strerror(errno);
+  android::base::unique_fd write_lock_fd(dup(adb_write_event_fd_));
+  CHECK_NE(write_lock_fd.get(), -1) << "Failed to dup write_lock_fd: " << strerror(errno);
+
+  dt_fd_forward::FdSet {
+    read_fd.get(), write_fd.get(), write_lock_fd.get()
+  }.WriteData(CMSG_DATA(cmsg));
+
+  int res = TEMP_FAILURE_RETRY(sendmsg(local_agent_control_sock_, &msg, MSG_EOR));
+  if (res < 0) {
+    PLOG(ERROR) << "Failed to send agent adb connection fds.";
+  } else {
+    sent_agent_fds_ = true;
+    VLOG(jdwp) << "Fds have been sent to jdwp agent!";
+  }
+}
+
+android::base::unique_fd AdbConnectionState::ReadFdFromAdb() {
+  // We don't actually care about the data that is sent. We do need to receive something though.
+  char dummy = '!';
+  union {
+    cmsghdr cm;
+    char buffer[CMSG_SPACE(sizeof(int))];
+  } cm_un;
+
+  iovec iov;
+  iov.iov_base       = &dummy;
+  iov.iov_len        = 1;
+
+  msghdr msg;
+  msg.msg_name       = nullptr;
+  msg.msg_namelen    = 0;
+  msg.msg_iov        = &iov;
+  msg.msg_iovlen     = 1;
+  msg.msg_flags      = 0;
+  msg.msg_control    = cm_un.buffer;
+  msg.msg_controllen = sizeof(cm_un.buffer);
+
+  cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
+  cmsg->cmsg_len   = msg.msg_controllen;
+  cmsg->cmsg_level = SOL_SOCKET;
+  cmsg->cmsg_type  = SCM_RIGHTS;
+  (reinterpret_cast<int*>(CMSG_DATA(cmsg)))[0] = -1;
+
+  int rc = TEMP_FAILURE_RETRY(recvmsg(control_sock_, &msg, 0));
+
+  if (rc <= 0) {
+    PLOG(WARNING) << "Receiving file descriptor from ADB failed (socket " << control_sock_ << ")";
+    return android::base::unique_fd(-1);
+  } else {
+    VLOG(jdwp) << "Fds have been received from ADB!";
+  }
+
+  return android::base::unique_fd((reinterpret_cast<int*>(CMSG_DATA(cmsg)))[0]);
+}
+
+bool AdbConnectionState::SetupAdbConnection() {
+  int        sleep_ms     = 500;
+  const int  sleep_max_ms = 2*1000;
+
+  android::base::unique_fd sock(socket(AF_UNIX, SOCK_SEQPACKET, 0));
+  if (sock < 0) {
+    PLOG(ERROR) << "Could not create ADB control socket";
+    return false;
+  }
+  struct timeval timeout;
+  timeout.tv_sec = kControlSockSendTimeout;
+  timeout.tv_usec = 0;
+  setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
+  int32_t pid = getpid();
+
+  while (!shutting_down_) {
+    // If adbd isn't running, because USB debugging was disabled or
+    // perhaps the system is restarting it for "adb root", the
+    // connect() will fail.  We loop here forever waiting for it
+    // to come back.
+    //
+    // Waking up and polling every couple of seconds is generally a
+    // bad thing to do, but we only do this if the application is
+    // debuggable *and* adbd isn't running.  Still, for the sake
+    // of battery life, we should consider timing out and giving
+    // up after a few minutes in case somebody ships an app with
+    // the debuggable flag set.
+    int ret = connect(sock, &control_addr_.controlAddrPlain, control_addr_len_);
+    if (ret == 0) {
+      bool trusted = sock >= 0;
+#ifdef ART_TARGET_ANDROID
+      // Needed for socket_peer_is_trusted.
+      trusted = trusted && socket_peer_is_trusted(sock);
+#endif
+      if (!trusted) {
+        LOG(ERROR) << "adb socket is not trusted. Aborting connection.";
+        if (sock >= 0 && shutdown(sock, SHUT_RDWR)) {
+          PLOG(ERROR) << "trouble shutting down socket";
+        }
+        return false;
+      }
+      /* now try to send our pid to the ADB daemon */
+      ret = TEMP_FAILURE_RETRY(send(sock, &pid, sizeof(pid), 0));
+      if (ret == sizeof(pid)) {
+        VLOG(jdwp) << "PID " << pid << " sent to adb";
+        control_sock_ = std::move(sock);
+        return true;
+      } else {
+        PLOG(ERROR) << "Weird, can't send JDWP process pid to ADB. Aborting connection.";
+        return false;
+      }
+    } else {
+      if (VLOG_IS_ON(jdwp)) {
+        PLOG(ERROR) << "Can't connect to ADB control socket. Will retry.";
+      }
+
+      usleep(sleep_ms * 1000);
+
+      sleep_ms += (sleep_ms >> 1);
+      if (sleep_ms > sleep_max_ms) {
+        sleep_ms = sleep_max_ms;
+      }
+    }
+  }
+  return false;
+}
+
+void AdbConnectionState::RunPollLoop(art::Thread* self) {
+  CHECK_NE(agent_name_, "");
+  CHECK_EQ(self->GetState(), art::kNative);
+  // TODO: Clang prebuilt for r316199 produces bogus thread safety analysis warning for holding both
+  // exclusive and shared lock in the same scope. Remove the assertion as a temporary workaround.
+  // http://b/71769596
+  // art::Locks::mutator_lock_->AssertNotHeld(self);
+  self->SetState(art::kWaitingInMainDebuggerLoop);
+  // shutting_down_ set by StopDebuggerThreads
+  while (!shutting_down_) {
+    // First get the control_sock_ from adb if we don't have one. We only need to do this once.
+    if (control_sock_ == -1 && !SetupAdbConnection()) {
+      LOG(ERROR) << "Failed to setup adb connection.";
+      return;
+    }
+    while (!shutting_down_ && control_sock_ != -1) {
+      bool should_listen_on_connection = !agent_has_socket_ && !sent_agent_fds_;
+      struct pollfd pollfds[4] = {
+        { sleep_event_fd_, POLLIN, 0 },
+        // -1 as an fd causes it to be ignored by poll
+        { (agent_loaded_ ? local_agent_control_sock_ : -1), POLLIN, 0 },
+        // Check for the control_sock_ actually going away. Only do this if we don't have an active
+        // connection.
+        { (adb_connection_socket_ == -1 ? control_sock_ : -1), POLLIN | POLLRDHUP, 0 },
+        // if we have not loaded the agent either the adb_connection_socket_ is -1 meaning we don't
+        // have a real connection yet or the socket through adb needs to be listened to for incoming
+        // data that the agent or this plugin can handle.
+        { should_listen_on_connection ? adb_connection_socket_ : -1, POLLIN | POLLRDHUP, 0 }
+      };
+      int res = TEMP_FAILURE_RETRY(poll(pollfds, 4, -1));
+      if (res < 0) {
+        PLOG(ERROR) << "Failed to poll!";
+        return;
+      }
+      // We don't actually care about doing this we just use it to wake us up.
+      // const struct pollfd& sleep_event_poll     = pollfds[0];
+      const struct pollfd& agent_control_sock_poll = pollfds[1];
+      const struct pollfd& control_sock_poll       = pollfds[2];
+      const struct pollfd& adb_socket_poll         = pollfds[3];
+      if (FlagsSet(agent_control_sock_poll.revents, POLLIN)) {
+        DCHECK(agent_loaded_);
+        char buf[257];
+        res = TEMP_FAILURE_RETRY(recv(local_agent_control_sock_, buf, sizeof(buf) - 1, 0));
+        if (res < 0) {
+          PLOG(ERROR) << "Failed to read message from agent control socket! Retrying";
+          continue;
+        } else {
+          buf[res + 1] = '\0';
+          VLOG(jdwp) << "Local agent control sock has data: " << static_cast<const char*>(buf);
+        }
+        if (memcmp(kListenStartMessage, buf, sizeof(kListenStartMessage)) == 0) {
+          agent_listening_ = true;
+          if (adb_connection_socket_ != -1) {
+            SendAgentFds(/*require_handshake*/ !performed_handshake_);
+          }
+        } else if (memcmp(kListenEndMessage, buf, sizeof(kListenEndMessage)) == 0) {
+          agent_listening_ = false;
+        } else if (memcmp(kCloseMessage, buf, sizeof(kCloseMessage)) == 0) {
+          CloseFds();
+          agent_has_socket_ = false;
+        } else if (memcmp(kAcceptMessage, buf, sizeof(kAcceptMessage)) == 0) {
+          agent_has_socket_ = true;
+          sent_agent_fds_ = false;
+          // We will only ever do the handshake once so reset this.
+          performed_handshake_ = false;
+        } else {
+          LOG(ERROR) << "Unknown message received from debugger! '" << std::string(buf) << "'";
+        }
+      } else if (FlagsSet(control_sock_poll.revents, POLLIN)) {
+        bool maybe_send_fds = false;
+        {
+          // Hold onto this lock so that concurrent ddm publishes don't try to use an illegal fd.
+          ScopedEventFdLock sefdl(adb_write_event_fd_);
+          android::base::unique_fd new_fd(ReadFdFromAdb());
+          if (new_fd == -1) {
+            // Something went wrong. We need to retry getting the control socket.
+            PLOG(ERROR) << "Something went wrong getting fds from adb. Retry!";
+            control_sock_.reset();
+            break;
+          } else if (adb_connection_socket_ != -1) {
+            // We already have a connection.
+            VLOG(jdwp) << "Ignoring second debugger. Accept then drop!";
+            if (new_fd >= 0) {
+              new_fd.reset();
+            }
+          } else {
+            VLOG(jdwp) << "Adb connection established with fd " << new_fd;
+            adb_connection_socket_ = std::move(new_fd);
+            maybe_send_fds = true;
+          }
+        }
+        if (maybe_send_fds && agent_loaded_ && agent_listening_) {
+          VLOG(jdwp) << "Sending fds as soon as we received them.";
+          // The agent was already loaded so this must be after a disconnection. Therefore have the
+          // transport perform the handshake.
+          SendAgentFds(/*require_handshake*/ true);
+        }
+      } else if (FlagsSet(control_sock_poll.revents, POLLRDHUP)) {
+        // The other end of the adb connection just dropped it.
+        // Reset the connection since we don't have an active socket through the adb server.
+        DCHECK(!agent_has_socket_) << "We shouldn't be doing anything if there is already a "
+                                   << "connection active";
+        control_sock_.reset();
+        break;
+      } else if (FlagsSet(adb_socket_poll.revents, POLLIN)) {
+        DCHECK(!agent_has_socket_);
+        if (!agent_loaded_) {
+          HandleDataWithoutAgent(self);
+        } else if (agent_listening_ && !sent_agent_fds_) {
+          VLOG(jdwp) << "Sending agent fds again on data.";
+          // Agent was already loaded so it can deal with the handshake.
+          SendAgentFds(/*require_handshake*/ true);
+        }
+      } else if (FlagsSet(adb_socket_poll.revents, POLLRDHUP)) {
+        DCHECK(!agent_has_socket_);
+        CloseFds();
+      } else {
+        VLOG(jdwp) << "Woke up poll without anything to do!";
+      }
+    }
+  }
+}
+
+static uint32_t ReadUint32AndAdvance(/*in-out*/uint8_t** in) {
+  uint32_t res;
+  memcpy(&res, *in, sizeof(uint32_t));
+  *in = (*in) + sizeof(uint32_t);
+  return ntohl(res);
+}
+
+void AdbConnectionState::HandleDataWithoutAgent(art::Thread* self) {
+  DCHECK(!agent_loaded_);
+  DCHECK(!agent_listening_);
+  // TODO Should we check in some other way if we are userdebug/eng?
+  CHECK(art::Dbg::IsJdwpAllowed());
+  // We try to avoid loading the agent which is expensive. First lets just perform the handshake.
+  if (!performed_handshake_) {
+    PerformHandshake();
+    return;
+  }
+  // Read the packet header to figure out if it is one we can handle. We only 'peek' into the stream
+  // to see if it's one we can handle. This doesn't change the state of the socket.
+  alignas(sizeof(uint32_t)) uint8_t packet_header[kPacketHeaderLen];
+  ssize_t res = TEMP_FAILURE_RETRY(recv(adb_connection_socket_.get(),
+                                        packet_header,
+                                        sizeof(packet_header),
+                                        MSG_PEEK));
+  // We want to be very careful not to change the socket state until we know we succeeded. This will
+  // let us fall-back to just loading the agent and letting it deal with everything.
+  if (res <= 0) {
+    // Close the socket. We either hit EOF or an error.
+    if (res < 0) {
+      PLOG(ERROR) << "Unable to peek into adb socket due to error. Closing socket.";
+    }
+    CloseFds();
+    return;
+  } else if (res < static_cast<int>(kPacketHeaderLen)) {
+    LOG(ERROR) << "Unable to peek into adb socket. Loading agent to handle this. Only read " << res;
+    AttachJdwpAgent(self);
+    return;
+  }
+  uint32_t full_len = ntohl(*reinterpret_cast<uint32_t*>(packet_header + kPacketSizeOff));
+  uint32_t pkt_id = ntohl(*reinterpret_cast<uint32_t*>(packet_header + kPacketIdOff));
+  uint8_t pkt_cmd_set = packet_header[kPacketCommandSetOff];
+  uint8_t pkt_cmd = packet_header[kPacketCommandOff];
+  if (pkt_cmd_set != kDdmCommandSet ||
+      pkt_cmd != kDdmChunkCommand ||
+      full_len < kPacketHeaderLen) {
+    VLOG(jdwp) << "Loading agent due to jdwp packet that cannot be handled by adbconnection.";
+    AttachJdwpAgent(self);
+    return;
+  }
+  uint32_t avail = -1;
+  res = TEMP_FAILURE_RETRY(ioctl(adb_connection_socket_.get(), FIONREAD, &avail));
+  if (res < 0) {
+    PLOG(ERROR) << "Failed to determine amount of readable data in socket! Closing connection";
+    CloseFds();
+    return;
+  } else if (avail < full_len) {
+    LOG(WARNING) << "Unable to handle ddm command in adbconnection due to insufficent data. "
+                 << "Expected " << full_len << " bytes but only " << avail << " are readable. "
+                 << "Loading jdwp agent to deal with this.";
+    AttachJdwpAgent(self);
+    return;
+  }
+  // Actually read the data.
+  std::vector<uint8_t> full_pkt;
+  full_pkt.resize(full_len);
+  res = TEMP_FAILURE_RETRY(recv(adb_connection_socket_.get(), full_pkt.data(), full_len, 0));
+  if (res < 0) {
+    PLOG(ERROR) << "Failed to recv data from adb connection. Closing connection";
+    CloseFds();
+    return;
+  }
+  DCHECK_EQ(memcmp(full_pkt.data(), packet_header, sizeof(packet_header)), 0);
+  size_t data_size = full_len - kPacketHeaderLen;
+  if (data_size < (sizeof(uint32_t) * 2)) {
+    // This is an error (the data isn't long enough) but to match historical behavior we need to
+    // ignore it.
+    return;
+  }
+  uint8_t* ddm_data = full_pkt.data() + kPacketHeaderLen;
+  uint32_t ddm_type = ReadUint32AndAdvance(&ddm_data);
+  uint32_t ddm_len = ReadUint32AndAdvance(&ddm_data);
+  if (ddm_len > data_size - (2 * sizeof(uint32_t))) {
+    // This is an error (the data isn't long enough) but to match historical behavior we need to
+    // ignore it.
+    return;
+  }
+
+  if (!notified_ddm_active_) {
+    NotifyDdms(/*active*/ true);
+  }
+  uint32_t reply_type;
+  std::vector<uint8_t> reply;
+  if (!art::Dbg::DdmHandleChunk(self->GetJniEnv(),
+                                ddm_type,
+                                art::ArrayRef<const jbyte>(reinterpret_cast<const jbyte*>(ddm_data),
+                                                           ddm_len),
+                                /*out*/&reply_type,
+                                /*out*/&reply)) {
+    // To match historical behavior we don't send any response when there is no data to reply with.
+    return;
+  }
+  SendDdmPacket(pkt_id,
+                DdmPacketType::kReply,
+                reply_type,
+                art::ArrayRef<const uint8_t>(reply));
+}
+
+void AdbConnectionState::PerformHandshake() {
+  CHECK(!performed_handshake_);
+  // Check to make sure we are able to read the whole handshake.
+  uint32_t avail = -1;
+  int res = TEMP_FAILURE_RETRY(ioctl(adb_connection_socket_.get(), FIONREAD, &avail));
+  if (res < 0 || avail < sizeof(kJdwpHandshake)) {
+    if (res < 0) {
+      PLOG(ERROR) << "Failed to determine amount of readable data for handshake!";
+    }
+    LOG(WARNING) << "Closing connection to broken client.";
+    CloseFds();
+    return;
+  }
+  // Perform the handshake.
+  char handshake_msg[sizeof(kJdwpHandshake)];
+  res = TEMP_FAILURE_RETRY(recv(adb_connection_socket_.get(),
+                                handshake_msg,
+                                sizeof(handshake_msg),
+                                MSG_DONTWAIT));
+  if (res < static_cast<int>(sizeof(kJdwpHandshake)) ||
+      strncmp(handshake_msg, kJdwpHandshake, sizeof(kJdwpHandshake)) != 0) {
+    if (res < 0) {
+      PLOG(ERROR) << "Failed to read handshake!";
+    }
+    LOG(WARNING) << "Handshake failed!";
+    CloseFds();
+    return;
+  }
+  // Send the handshake back.
+  res = TEMP_FAILURE_RETRY(send(adb_connection_socket_.get(),
+                                kJdwpHandshake,
+                                sizeof(kJdwpHandshake),
+                                0));
+  if (res < static_cast<int>(sizeof(kJdwpHandshake))) {
+    PLOG(ERROR) << "Failed to send jdwp-handshake response.";
+    CloseFds();
+    return;
+  }
+  performed_handshake_ = true;
+}
+
+void AdbConnectionState::AttachJdwpAgent(art::Thread* self) {
+  art::Runtime* runtime = art::Runtime::Current();
+  self->AssertNoPendingException();
+  runtime->AttachAgent(/* JNIEnv */ nullptr,
+                       MakeAgentArg(),
+                       /* classloader */ nullptr);
+  if (self->IsExceptionPending()) {
+    LOG(ERROR) << "Failed to load agent " << agent_name_;
+    art::ScopedObjectAccess soa(self);
+    self->GetException()->Dump();
+    self->ClearException();
+    return;
+  }
+  agent_loaded_ = true;
+}
+
+bool ContainsArgument(const std::string& opts, const char* arg) {
+  return opts.find(arg) != std::string::npos;
+}
+
+bool ValidateJdwpOptions(const std::string& opts) {
+  bool res = true;
+  // The adbconnection plugin requires that the jdwp agent be configured as a 'server' because that
+  // is what adb expects and otherwise we will hit a deadlock as the poll loop thread stops waiting
+  // for the fd's to be passed down.
+  if (ContainsArgument(opts, "server=n")) {
+    res = false;
+    LOG(ERROR) << "Cannot start jdwp debugging with server=n from adbconnection.";
+  }
+  // We don't start the jdwp agent until threads are already running. It is far too late to suspend
+  // everything.
+  if (ContainsArgument(opts, "suspend=y")) {
+    res = false;
+    LOG(ERROR) << "Cannot use suspend=y with late-init jdwp.";
+  }
+  return res;
+}
+
+std::string AdbConnectionState::MakeAgentArg() {
+  const std::string& opts = art::Runtime::Current()->GetJdwpOptions();
+  DCHECK(ValidateJdwpOptions(opts));
+  // TODO Get agent_name_ from something user settable?
+  return agent_name_ + "=" + opts + (opts.empty() ? "" : ",") +
+      "ddm_already_active=" + (notified_ddm_active_ ? "y" : "n") + "," +
+      // See the comment above for why we need to be server=y. Since the agent defaults to server=n
+      // we will add it if it wasn't already present for the convenience of the user.
+      (ContainsArgument(opts, "server=y") ? "" : "server=y,") +
+      // See the comment above for why we need to be suspend=n. Since the agent defaults to
+      // suspend=y we will add it if it wasn't already present.
+      (ContainsArgument(opts, "suspend=n") ? "" : "suspend=n") +
+      "transport=dt_fd_forward,address=" + std::to_string(remote_agent_control_sock_);
+}
+
+void AdbConnectionState::StopDebuggerThreads() {
+  // The regular agent system will take care of unloading the agent (if needed).
+  shutting_down_ = true;
+  // Wakeup the poll loop.
+  uint64_t data = 1;
+  if (sleep_event_fd_ != -1) {
+    TEMP_FAILURE_RETRY(write(sleep_event_fd_, &data, sizeof(data)));
+  }
+}
+
+// The plugin initialization function.
+extern "C" bool ArtPlugin_Initialize() REQUIRES_SHARED(art::Locks::mutator_lock_) {
+  DCHECK(art::Runtime::Current()->GetJdwpProvider() == art::JdwpProvider::kAdbConnection);
+  // TODO Provide some way for apps to set this maybe?
+  DCHECK(gState == nullptr);
+  gState = new AdbConnectionState(kDefaultJdwpAgentName);
+  return ValidateJdwpOptions(art::Runtime::Current()->GetJdwpOptions());
+}
+
+extern "C" bool ArtPlugin_Deinitialize() {
+  gState->StopDebuggerThreads();
+  if (!gState->DebuggerThreadsStarted()) {
+    // If debugger threads were started then those threads will delete the state once they are done.
+    delete gState;
+  }
+  return true;
+}
+
+}  // namespace adbconnection
diff --git a/adbconnection/adbconnection.h b/adbconnection/adbconnection.h
new file mode 100644
index 0000000..04e39bf
--- /dev/null
+++ b/adbconnection/adbconnection.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef ART_ADBCONNECTION_ADBCONNECTION_H_
+#define ART_ADBCONNECTION_ADBCONNECTION_H_
+
+#include <stdint.h>
+#include <vector>
+#include <limits>
+
+#include "android-base/unique_fd.h"
+
+#include "base/mutex.h"
+#include "base/array_ref.h"
+#include "runtime_callbacks.h"
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <jni.h>
+
+namespace adbconnection {
+
+static constexpr char kJdwpControlName[] = "\0jdwp-control";
+static constexpr char kAdbConnectionThreadName[] = "ADB-JDWP Connection Control Thread";
+
+// The default jdwp agent name.
+static constexpr char kDefaultJdwpAgentName[] = "libjdwp.so";
+
+class AdbConnectionState;
+
+struct AdbConnectionDebuggerController : public art::DebuggerControlCallback {
+  explicit AdbConnectionDebuggerController(AdbConnectionState* connection)
+      : connection_(connection) {}
+
+  // Begin running the debugger.
+  void StartDebugger() OVERRIDE;
+
+  // The debugger should begin shutting down since the runtime is ending.
+  void StopDebugger() OVERRIDE;
+
+  bool IsDebuggerConfigured() OVERRIDE;
+
+ private:
+  AdbConnectionState* connection_;
+};
+
+enum class DdmPacketType : uint8_t { kReply = 0x80, kCmd = 0x00, };
+
+struct AdbConnectionDdmCallback : public art::DdmCallback {
+  explicit AdbConnectionDdmCallback(AdbConnectionState* connection) : connection_(connection) {}
+
+  void DdmPublishChunk(uint32_t type,
+                       const art::ArrayRef<const uint8_t>& data)
+      REQUIRES_SHARED(art::Locks::mutator_lock_);
+
+ private:
+  AdbConnectionState* connection_;
+};
+
+class AdbConnectionState {
+ public:
+  explicit AdbConnectionState(const std::string& name);
+
+  // Called on the listening thread to start dealing with new input. thr is used to attach the new
+  // thread to the runtime.
+  void RunPollLoop(art::Thread* self);
+
+  // Sends ddms data over the socket, if there is one. This data is sent even if we haven't finished
+  // hand-shaking yet.
+  void PublishDdmData(uint32_t type, const art::ArrayRef<const uint8_t>& data);
+
+  // Stops debugger threads during shutdown.
+  void StopDebuggerThreads();
+
+  // If StartDebuggerThreads was called successfully.
+  bool DebuggerThreadsStarted() {
+    return started_debugger_threads_;
+  }
+
+ private:
+  uint32_t NextDdmId();
+
+  void StartDebuggerThreads();
+
+  // Tell adbd about the new runtime.
+  bool SetupAdbConnection();
+
+  std::string MakeAgentArg();
+
+  android::base::unique_fd ReadFdFromAdb();
+
+  void SendAgentFds(bool require_handshake);
+
+  void CloseFds();
+
+  void HandleDataWithoutAgent(art::Thread* self);
+
+  void PerformHandshake();
+
+  void AttachJdwpAgent(art::Thread* self);
+
+  void NotifyDdms(bool active);
+
+  void SendDdmPacket(uint32_t id,
+                     DdmPacketType type,
+                     uint32_t ddm_type,
+                     art::ArrayRef<const uint8_t> data);
+
+  std::string agent_name_;
+
+  AdbConnectionDebuggerController controller_;
+  AdbConnectionDdmCallback ddm_callback_;
+
+  // Eventfd used to allow the StopDebuggerThreads function to wake up sleeping threads
+  android::base::unique_fd sleep_event_fd_;
+
+  // Socket that we use to talk to adbd.
+  android::base::unique_fd control_sock_;
+
+  // Socket that we use to talk to the agent (if it's loaded).
+  android::base::unique_fd local_agent_control_sock_;
+
+  // The fd of the socket the agent uses to talk to us. We need to keep it around in order to clean
+  // it up when the runtime goes away.
+  android::base::unique_fd remote_agent_control_sock_;
+
+  // The fd that is forwarded through adb to the client. This is guarded by the
+  // adb_write_event_fd_.
+  android::base::unique_fd adb_connection_socket_;
+
+  // The fd we send to the agent to let us synchronize access to the shared adb_connection_socket_.
+  // This is also used as a general lock for the adb_connection_socket_ on any threads other than
+  // the poll thread.
+  android::base::unique_fd adb_write_event_fd_;
+
+  std::atomic<bool> shutting_down_;
+
+  // True if we have loaded the agent library.
+  std::atomic<bool> agent_loaded_;
+
+  // True if the dt_fd_forward transport is listening for a new communication channel.
+  std::atomic<bool> agent_listening_;
+
+  // True if the dt_fd_forward transport has the socket. If so we don't do anything to the agent or
+  // the adb connection socket until connection goes away.
+  std::atomic<bool> agent_has_socket_;
+
+  std::atomic<bool> sent_agent_fds_;
+
+  bool performed_handshake_;
+
+  bool notified_ddm_active_;
+
+  std::atomic<uint32_t> next_ddm_id_;
+
+  bool started_debugger_threads_;
+
+  socklen_t control_addr_len_;
+  union {
+    sockaddr_un controlAddrUn;
+    sockaddr controlAddrPlain;
+  } control_addr_;
+
+  friend struct AdbConnectionDebuggerController;
+};
+
+}  // namespace adbconnection
+
+#endif  // ART_ADBCONNECTION_ADBCONNECTION_H_
diff --git a/benchmark/Android.bp b/benchmark/Android.bp
index 606734b..3995ca2 100644
--- a/benchmark/Android.bp
+++ b/benchmark/Android.bp
@@ -17,7 +17,7 @@
 art_cc_library {
     name: "libartbenchmark",
     host_supported: true,
-    defaults: ["art_defaults" ],
+    defaults: ["art_defaults"],
     srcs: [
         "jni_loader.cc",
         "jobject-benchmark/jobject_benchmark.cc",
@@ -31,15 +31,6 @@
         "libbase",
         "libnativehelper",
     ],
-    clang: true,
-    target: {
-        android: {
-            shared_libs: ["libdl"],
-        },
-        host: {
-            host_ldlibs: ["-ldl", "-lpthread"],
-        },
-    },
     cflags: [
         "-Wno-frame-larger-than=",
     ],
@@ -49,7 +40,10 @@
     name: "libartbenchmark-micronative-host",
     host_supported: true,
     device_supported: false,
-    defaults: ["art_debug_defaults", "art_defaults" ],
+    defaults: [
+        "art_debug_defaults",
+        "art_defaults",
+    ],
     srcs: [
         "jni_loader.cc",
         "micro-native/micro_native.cc",
@@ -60,12 +54,6 @@
     ],
     header_libs: ["jni_headers"],
     stl: "libc++_static",
-    clang: true,
-    target: {
-        host: {
-            host_ldlibs: ["-ldl", "-lpthread"],
-        },
-    },
     cflags: [
         "-Wno-frame-larger-than=",
     ],
diff --git a/benchmark/micro-native/micro_native.cc b/benchmark/micro-native/micro_native.cc
index d366d9d..dffbf3b 100644
--- a/benchmark/micro-native/micro_native.cc
+++ b/benchmark/micro-native/micro_native.cc
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#include <stdio.h>
 #include <jni.h>
+#include <stdio.h>
 
 #ifndef NATIVE_METHOD
 #define NATIVE_METHOD(className, functionName, signature) \
diff --git a/benchmark/type-check/info.txt b/benchmark/type-check/info.txt
new file mode 100644
index 0000000..d14fb96
--- /dev/null
+++ b/benchmark/type-check/info.txt
@@ -0,0 +1 @@
+Benchmarks for repeating check-cast and instance-of instructions in a loop.
diff --git a/benchmark/type-check/src/TypeCheckBenchmark.java b/benchmark/type-check/src/TypeCheckBenchmark.java
new file mode 100644
index 0000000..96904d9
--- /dev/null
+++ b/benchmark/type-check/src/TypeCheckBenchmark.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+public class TypeCheckBenchmark {
+    public void timeCheckCastLevel1ToLevel1(int count) {
+        Object[] arr = arr1;
+        for (int i = 0; i < count; ++i) {
+            Level1 l1 = (Level1) arr[i & 1023];
+        }
+    }
+
+    public void timeCheckCastLevel2ToLevel1(int count) {
+        Object[] arr = arr2;
+        for (int i = 0; i < count; ++i) {
+            Level1 l1 = (Level1) arr[i & 1023];
+        }
+    }
+
+    public void timeCheckCastLevel3ToLevel1(int count) {
+        Object[] arr = arr3;
+        for (int i = 0; i < count; ++i) {
+            Level1 l1 = (Level1) arr[i & 1023];
+        }
+    }
+
+    public void timeCheckCastLevel9ToLevel1(int count) {
+        Object[] arr = arr9;
+        for (int i = 0; i < count; ++i) {
+            Level1 l1 = (Level1) arr[i & 1023];
+        }
+    }
+
+    public void timeCheckCastLevel9ToLevel2(int count) {
+        Object[] arr = arr9;
+        for (int i = 0; i < count; ++i) {
+            Level2 l2 = (Level2) arr[i & 1023];
+        }
+    }
+
+    public void timeInstanceOfLevel1ToLevel1(int count) {
+        int sum = 0;
+        Object[] arr = arr1;
+        for (int i = 0; i < count; ++i) {
+            if (arr[i & 1023] instanceof Level1) {
+              ++sum;
+            }
+        }
+        result = sum;
+    }
+
+    public void timeInstanceOfLevel2ToLevel1(int count) {
+        int sum = 0;
+        Object[] arr = arr2;
+        for (int i = 0; i < count; ++i) {
+            if (arr[i & 1023] instanceof Level1) {
+              ++sum;
+            }
+        }
+        result = sum;
+    }
+
+    public void timeInstanceOfLevel3ToLevel1(int count) {
+        int sum = 0;
+        Object[] arr = arr3;
+        for (int i = 0; i < count; ++i) {
+            if (arr[i & 1023] instanceof Level1) {
+              ++sum;
+            }
+        }
+        result = sum;
+    }
+
+    public void timeInstanceOfLevel9ToLevel1(int count) {
+        int sum = 0;
+        Object[] arr = arr9;
+        for (int i = 0; i < count; ++i) {
+            if (arr[i & 1023] instanceof Level1) {
+              ++sum;
+            }
+        }
+        result = sum;
+    }
+
+    public void timeInstanceOfLevel9ToLevel2(int count) {
+        int sum = 0;
+        Object[] arr = arr9;
+        for (int i = 0; i < count; ++i) {
+            if (arr[i & 1023] instanceof Level2) {
+              ++sum;
+            }
+        }
+        result = sum;
+    }
+
+    public static Object[] createArray(int level) {
+        try {
+            Class<?>[] ls = {
+                    null,
+                    Level1.class,
+                    Level2.class,
+                    Level3.class,
+                    Level4.class,
+                    Level5.class,
+                    Level6.class,
+                    Level7.class,
+                    Level8.class,
+                    Level9.class,
+            };
+            Class<?> l = ls[level];
+            Object[] array = new Object[1024];
+            for (int i = 0; i < array.length; ++i) {
+                array[i] = l.newInstance();
+            }
+            return array;
+        } catch (Exception unexpected) {
+            throw new Error("Initialization failure!");
+        }
+    }
+    Object[] arr1 = createArray(1);
+    Object[] arr2 = createArray(2);
+    Object[] arr3 = createArray(3);
+    Object[] arr9 = createArray(9);
+    int result;
+}
+
+class Level1 { }
+class Level2 extends Level1 { }
+class Level3 extends Level2 { }
+class Level4 extends Level3 { }
+class Level5 extends Level4 { }
+class Level6 extends Level5 { }
+class Level7 extends Level6 { }
+class Level8 extends Level7 { }
+class Level9 extends Level8 { }
diff --git a/build/Android.bp b/build/Android.bp
index c5ff486..2a5598f 100644
--- a/build/Android.bp
+++ b/build/Android.bp
@@ -4,6 +4,7 @@
     deps: [
         "blueprint",
         "blueprint-pathtools",
+        "blueprint-proptools",
         "soong",
         "soong-android",
         "soong-cc",
@@ -20,7 +21,6 @@
     // Additional flags are computed by art.go
 
     name: "art_defaults",
-    clang: true,
     cflags: [
         // Base set of cflags used by all things ART.
         "-fno-rtti",
@@ -68,10 +68,6 @@
             cflags: [
                 "-DART_TARGET",
 
-                // Enable missing-noreturn only on non-Mac. As lots of things are not implemented
-                // for Apple, it's a pain.
-                "-Wmissing-noreturn",
-
                 // To use oprofile_android --callgraph, uncomment this and recompile with
                 //    mmma -j art
                 // "-fno-omit-frame-pointer",
@@ -90,19 +86,21 @@
                 // Apple, it's a pain.
                 "-Wmissing-noreturn",
             ],
-            host_ldlibs: [
-                "-lrt",
-            ],
         },
         host: {
             cflags: [
                 // Bug: 15446488. We don't omit the frame pointer to work around
                 // clang/libunwind bugs that cause SEGVs in run-test-004-ThreadStress.
                 "-fno-omit-frame-pointer",
-            ],
-            host_ldlibs: [
-                "-ldl",
-                "-lpthread",
+                // The build assumes that all our x86/x86_64 hosts (such as buildbots and developer
+                // desktops) support at least sse4.2/popcount. This firstly implies that the ART
+                // runtime binary itself may exploit these features. Secondly, this implies that
+                // the ART runtime passes these feature flags to dex2oat and JIT by calling the
+                // method InstructionSetFeatures::FromCppDefines(). Since invoking dex2oat directly
+                // does not pick up these flags, cross-compiling from a x86/x86_64 host to a
+                // x86/x86_64 target should not be affected.
+                "-msse4.2",
+                "-mpopcnt",
             ],
         },
     },
@@ -129,13 +127,9 @@
     },
 
     include_dirs: [
-        "external/icu/icu4c/source/common",
-        "external/lz4/lib",
         "external/valgrind/include",
         "external/valgrind",
         "external/vixl/src",
-        "external/zlib",
-        "libnativehelper/platform_include"
     ],
 
     tidy_checks: [
diff --git a/build/Android.common_build.mk b/build/Android.common_build.mk
index f5a95fa..0896252 100644
--- a/build/Android.common_build.mk
+++ b/build/Android.common_build.mk
@@ -49,6 +49,11 @@
 # Enable the read barrier by default.
 ART_USE_READ_BARRIER ?= true
 
+# Default compact dex level to none.
+ifeq ($(ART_DEFAULT_COMPACT_DEX_LEVEL),)
+ART_DEFAULT_COMPACT_DEX_LEVEL := none
+endif
+
 ART_CPP_EXTENSION := .cc
 
 ifndef LIBART_IMG_HOST_BASE_ADDRESS
diff --git a/build/Android.common_path.mk b/build/Android.common_path.mk
index f4f8d49..3247e54 100644
--- a/build/Android.common_path.mk
+++ b/build/Android.common_path.mk
@@ -84,12 +84,6 @@
 HOST_CORE_DEX_FILES   := $(foreach jar,$(HOST_CORE_JARS),  $(call intermediates-dir-for,JAVA_LIBRARIES,$(jar),t,COMMON)/javalib.jar)
 TARGET_CORE_DEX_FILES := $(foreach jar,$(TARGET_CORE_JARS),$(call intermediates-dir-for,JAVA_LIBRARIES,$(jar), ,COMMON)/javalib.jar)
 
-# Classpath for Jack compilation: we only need core-libart.
-HOST_JACK_CLASSPATH_DEPENDENCIES   := $(call intermediates-dir-for,JAVA_LIBRARIES,core-oj-hostdex,t,COMMON)/classes.jack $(call intermediates-dir-for,JAVA_LIBRARIES,core-libart-hostdex,t,COMMON)/classes.jack
-HOST_JACK_CLASSPATH                := $(abspath $(call intermediates-dir-for,JAVA_LIBRARIES,core-oj-hostdex,t,COMMON)/classes.jack):$(abspath $(call intermediates-dir-for,JAVA_LIBRARIES,core-libart-hostdex,t,COMMON)/classes.jack)
-TARGET_JACK_CLASSPATH_DEPENDENCIES := $(call intermediates-dir-for,JAVA_LIBRARIES,core-oj, ,COMMON)/classes.jack $(call intermediates-dir-for,JAVA_LIBRARIES,core-libart, ,COMMON)/classes.jack
-TARGET_JACK_CLASSPATH              := $(abspath $(call intermediates-dir-for,JAVA_LIBRARIES,core-oj, ,COMMON)/classes.jack):$(abspath $(call intermediates-dir-for,JAVA_LIBRARIES,core-libart, ,COMMON)/classes.jack)
-
 ART_HOST_DEX_DEPENDENCIES := $(foreach jar,$(HOST_CORE_JARS),$(HOST_OUT_JAVA_LIBRARIES)/$(jar).jar)
 ART_TARGET_DEX_DEPENDENCIES := $(foreach jar,$(TARGET_CORE_JARS),$(TARGET_OUT_JAVA_LIBRARIES)/$(jar).jar)
 
diff --git a/build/Android.common_test.mk b/build/Android.common_test.mk
index 1ae79ac..c508fe7 100644
--- a/build/Android.common_test.mk
+++ b/build/Android.common_test.mk
@@ -20,26 +20,16 @@
 include art/build/Android.common_path.mk
 
 # Directory used for temporary test files on the host.
-ifneq ($(TMPDIR),)
-ART_HOST_TEST_DIR := $(TMPDIR)/test-art-$(shell echo $$PPID)
-else
-# Use a BSD checksum calculated from ANDROID_BUILD_TOP and USER as one of the
-# path components for the test output. This should allow us to run tests from multiple
-# repositories at the same time.
-ART_HOST_TEST_DIR := /tmp/test-art-$(shell echo ${ANDROID_BUILD_TOP}-${USER} | sum | cut -d ' ' -f1)
-endif
+# Use a BSD checksum calculated from CWD and USER as one of the path
+# components for the test output. This should allow us to run tests from
+# multiple repositories at the same time.
+ART_TMPDIR := $(if $(TMPDIR),$(TMPDIR),/tmp)
+ART_HOST_TEST_DIR := $(ART_TMPDIR)/test-art-$(shell echo $$CWD-${USER} | sum | cut -d ' ' -f1)
 
 # List of known broken tests that we won't attempt to execute. The test name must be the full
 # rule name such as test-art-host-oat-optimizing-HelloWorld64.
 ART_TEST_KNOWN_BROKEN :=
 
-# List of run-tests to skip running in any configuration. This needs to be the full name of the
-# run-test such as '457-regs'.
-ART_TEST_RUN_TEST_SKIP ?=
-
-# Failing valgrind tests.
-# Note: *all* 64b tests involving the runtime do not work currently. b/15170219.
-
 # List of known failing tests that when executed won't cause test execution to not finish.
 # The test name must be the full rule name such as test-art-host-oat-optimizing-HelloWorld64.
 ART_TEST_KNOWN_FAILING :=
@@ -47,85 +37,9 @@
 # Keep going after encountering a test failure?
 ART_TEST_KEEP_GOING ?= true
 
-# Do you want all tests, even those that are time consuming?
-ART_TEST_FULL ?= false
-
 # Do you want run-test to be quieter? run-tests will only show output if they fail.
 ART_TEST_QUIET ?= true
 
-# Do you want interpreter tests run?
-ART_TEST_INTERPRETER ?= true
-ART_TEST_INTERPRETER_ACCESS_CHECKS ?= true
-
-# Do you want JIT tests run?
-ART_TEST_JIT ?= true
-
-# Do you want optimizing compiler tests run?
-ART_TEST_OPTIMIZING ?= true
-
-# Do you want to test the optimizing compiler with graph coloring register allocation?
-ART_TEST_OPTIMIZING_GRAPH_COLOR ?= $(ART_TEST_FULL)
-
-# Do you want to do run-tests with profiles?
-ART_TEST_SPEED_PROFILE ?= $(ART_TEST_FULL)
-
-# Do we want to test PIC-compiled tests ("apps")?
-ART_TEST_PIC_TEST ?= $(ART_TEST_FULL)
-
-# Do you want tracing tests run?
-ART_TEST_TRACE ?= $(ART_TEST_FULL)
-
-# Do you want tracing tests (streaming mode) run?
-ART_TEST_TRACE_STREAM ?= $(ART_TEST_FULL)
-
-# Do you want tests with GC verification enabled run?
-ART_TEST_GC_VERIFY ?= $(ART_TEST_FULL)
-
-# Do you want tests with the GC stress mode enabled run?
-ART_TEST_GC_STRESS ?= $(ART_TEST_FULL)
-
-# Do you want tests with the JNI forcecopy mode enabled run?
-ART_TEST_JNI_FORCECOPY ?= $(ART_TEST_FULL)
-
-# Do you want run-tests with relocation enabled run?
-ART_TEST_RUN_TEST_RELOCATE ?= $(ART_TEST_FULL)
-
-# Do you want run-tests with prebuilding?
-ART_TEST_RUN_TEST_PREBUILD ?= true
-
-# Do you want run-tests with no prebuilding enabled run?
-ART_TEST_RUN_TEST_NO_PREBUILD ?= $(ART_TEST_FULL)
-
-# Do you want run-tests with a pregenerated core.art?
-ART_TEST_RUN_TEST_IMAGE ?= true
-
-# Do you want run-tests without a pregenerated core.art?
-ART_TEST_RUN_TEST_NO_IMAGE ?= $(ART_TEST_FULL)
-
-# Do you want run-tests with relocation enabled but patchoat failing?
-ART_TEST_RUN_TEST_RELOCATE_NO_PATCHOAT ?= $(ART_TEST_FULL)
-
-# Do you want run-tests without a dex2oat?
-ART_TEST_RUN_TEST_NO_DEX2OAT ?= $(ART_TEST_FULL)
-
-# Do you want run-tests with libartd.so?
-ART_TEST_RUN_TEST_DEBUG ?= true
-
-# Do you want run-tests with libart.so?
-ART_TEST_RUN_TEST_NDEBUG ?= $(ART_TEST_FULL)
-
-# Do you want run-tests with the host/target's second arch?
-ART_TEST_RUN_TEST_2ND_ARCH ?= true
-
-# Do you want failed tests to have their artifacts cleaned up?
-ART_TEST_RUN_TEST_ALWAYS_CLEAN ?= true
-
-# Do you want run-tests with the --debuggable flag
-ART_TEST_RUN_TEST_DEBUGGABLE ?= $(ART_TEST_FULL)
-
-# Do you want to test multi-part boot-image functionality?
-ART_TEST_RUN_TEST_MULTI_IMAGE ?= $(ART_TEST_FULL)
-
 # Define the command run on test failure. $(1) is the name of the test. Executed by the shell.
 # If the test was a top-level make target (e.g. `test-art-host-gtest-codegen_test64`), the command
 # fails with exit status 1 (returned by the last `grep` statement below).
@@ -202,9 +116,9 @@
 # $(5): a make variable used to collate target dependencies, e.g ART_TEST_TARGET_OAT_HelloWorld_DEX
 # $(6): a make variable used to collate host dependencies, e.g ART_TEST_HOST_OAT_HelloWorld_DEX
 #
-# If the input test directory contains a file called main.list and main.jpp,
+# If the input test directory contains a file called main.list,
 # then a multi-dex file is created passing main.list as the --main-dex-list
-# argument to dx and main.jpp for Jack.
+# argument to dx.
 define build-art-test-dex
   ifeq ($(ART_BUILD_TARGET),true)
     include $(CLEAR_VARS)
@@ -219,7 +133,6 @@
     LOCAL_DEX_PREOPT_IMAGE_LOCATION := $(TARGET_CORE_IMG_OUT)
     ifneq ($(wildcard $(LOCAL_PATH)/$(2)/main.list),)
       LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(LOCAL_PATH)/$(2)/main.list --minimal-main-dex
-      LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true -D jack.preprocessor.file=$(LOCAL_PATH)/$(2)/main.jpp
     endif
     include $(BUILD_JAVA_LIBRARY)
     $(5) := $$(LOCAL_INSTALLED_MODULE)
@@ -235,7 +148,6 @@
     LOCAL_DEX_PREOPT_IMAGE := $(HOST_CORE_IMG_LOCATION)
     ifneq ($(wildcard $(LOCAL_PATH)/$(2)/main.list),)
       LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(LOCAL_PATH)/$(2)/main.list --minimal-main-dex
-      LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true -D jack.preprocessor.file=$(LOCAL_PATH)/$(2)/main.jpp
     endif
     include $(BUILD_HOST_DALVIK_JAVA_LIBRARY)
     $(6) := $$(LOCAL_INSTALLED_MODULE)
diff --git a/build/Android.cpplint.mk b/build/Android.cpplint.mk
index 66ac897..964a4c8 100644
--- a/build/Android.cpplint.mk
+++ b/build/Android.cpplint.mk
@@ -16,40 +16,46 @@
 
 include art/build/Android.common_build.mk
 
-ART_CPPLINT := $(LOCAL_PATH)/tools/cpplint.py
-ART_CPPLINT_FILTER := --filter=-whitespace/line_length,-build/include,-readability/function,-readability/streams,-readability/todo,-runtime/references,-runtime/sizeof,-runtime/threadsafe_fn,-runtime/printf
-ART_CPPLINT_FLAGS := --root=$(TOP)
-ART_CPPLINT_QUIET := --quiet
-ART_CPPLINT_INGORED := \
-    runtime/elf.h \
-    runtime/openjdkjvmti/include/jvmti.h
+# Use upstream cpplint (toolpath from .repo/manifests/GLOBAL-PREUPLOAD.cfg).
+ART_CPPLINT := external/google-styleguide/cpplint/cpplint.py
 
-# This:
-#  1) Gets a list of all .h & .cc files in the art directory.
+# This file previously configured many cpplint settings.
+# Everything that could be moved to CPPLINT.cfg has moved there.
+# Please add new settings to CPPLINT.cfg over adding new flags in this file.
+
+ART_CPPLINT_FLAGS :=
+# No output when there are no errors.
+ART_CPPLINT_QUIET := --quiet
+
+#  1) Get list of all .h & .cc files in the art directory.
 #  2) Prepends 'art/' to each of them to make the full name.
-#  3) removes art/runtime/elf.h from the list.
-ART_CPPLINT_SRC := $(filter-out $(patsubst %,$(LOCAL_PATH)/%,$(ART_CPPLINT_INGORED)), $(addprefix $(LOCAL_PATH)/, $(call all-subdir-named-files,*.h) $(call all-subdir-named-files,*$(ART_CPP_EXTENSION))))
+ART_CPPLINT_SRC := $(addprefix $(LOCAL_PATH)/, $(call all-subdir-named-files,*.h) $(call all-subdir-named-files,*$(ART_CPP_EXTENSION)))
+
+#  1) Get list of all CPPLINT.cfg files in the art directory.
+#  2) Prepends 'art/' to each of them to make the full name.
+ART_CPPLINT_CFG := $(addprefix $(LOCAL_PATH)/, $(call all-subdir-named-files,CPPLINT.cfg))
 
 # "mm cpplint-art" to verify we aren't regressing
+# - files not touched since the last build are skipped (quite fast).
 .PHONY: cpplint-art
-cpplint-art:
-	$(ART_CPPLINT) $(ART_CPPLINT_FLAGS) $(ART_CPPLINT_FILTER) $(ART_CPPLINT_SRC)
+cpplint-art: cpplint-art-phony
 
-# "mm cpplint-art-all" to see all warnings
+# "mm cpplint-art-all" to manually execute cpplint.py on all files (very slow).
 .PHONY: cpplint-art-all
 cpplint-art-all:
 	$(ART_CPPLINT) $(ART_CPPLINT_FLAGS) $(ART_CPPLINT_SRC)
 
 OUT_CPPLINT := $(TARGET_COMMON_OUT_ROOT)/cpplint
 
+# Build up the list of all targets for linting the ART source files.
 ART_CPPLINT_TARGETS :=
 
 define declare-art-cpplint-target
 art_cpplint_file := $(1)
 art_cpplint_touch := $$(OUT_CPPLINT)/$$(subst /,__,$$(art_cpplint_file))
 
-$$(art_cpplint_touch): $$(art_cpplint_file) $(ART_CPPLINT) art/build/Android.cpplint.mk
-	$(hide) $(ART_CPPLINT) $(ART_CPPLINT_QUIET) $(ART_CPPLINT_FLAGS) $(ART_CPPLINT_FILTER) $$<
+$$(art_cpplint_touch): $$(art_cpplint_file) $(ART_CPPLINT) $(ART_CPPLINT_CFG) art/build/Android.cpplint.mk
+	$(hide) $(ART_CPPLINT) $(ART_CPPLINT_QUIET) $(ART_CPPLINT_FLAGS) $$<
 	$(hide) mkdir -p $$(dir $$@)
 	$(hide) touch $$@
 
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 571c91a..b483e5f 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -36,6 +36,8 @@
   ForClassLoaderD \
   ExceptionHandle \
   GetMethodSignature \
+  HiddenApi \
+  HiddenApiSignatures \
   ImageLayoutA \
   ImageLayoutB \
   IMTA \
@@ -72,6 +74,21 @@
 ART_TEST_HOST_GTEST_MainStripped_DEX := $(basename $(ART_TEST_HOST_GTEST_Main_DEX))Stripped$(suffix $(ART_TEST_HOST_GTEST_Main_DEX))
 ART_TEST_TARGET_GTEST_MainStripped_DEX := $(basename $(ART_TEST_TARGET_GTEST_Main_DEX))Stripped$(suffix $(ART_TEST_TARGET_GTEST_Main_DEX))
 
+# Create rules for MainUncompressed, a copy of Main with the classes.dex uncompressed
+# for the dex2oat tests.
+ART_TEST_HOST_GTEST_MainUncompressed_DEX := $(basename $(ART_TEST_HOST_GTEST_Main_DEX))Uncompressed$(suffix $(ART_TEST_HOST_GTEST_Main_DEX))
+ART_TEST_TARGET_GTEST_MainUncompressed_DEX := $(basename $(ART_TEST_TARGET_GTEST_Main_DEX))Uncompressed$(suffix $(ART_TEST_TARGET_GTEST_Main_DEX))
+
+# Create rules for UncompressedEmpty, a classes.dex that is empty and uncompressed
+# for the dex2oat tests.
+ART_TEST_HOST_GTEST_EmptyUncompressed_DEX := $(basename $(ART_TEST_HOST_GTEST_Main_DEX))EmptyUncompressed$(suffix $(ART_TEST_HOST_GTEST_Main_DEX))
+ART_TEST_TARGET_GTEST_EmptyUncompressed_DEX := $(basename $(ART_TEST_TARGET_GTEST_Main_DEX))EmptyUncompressed$(suffix $(ART_TEST_TARGET_GTEST_Main_DEX))
+
+# Create rules for MultiDexUncompressed, a copy of MultiDex with the classes.dex uncompressed
+# for the OatFile tests.
+ART_TEST_HOST_GTEST_MultiDexUncompressed_DEX := $(basename $(ART_TEST_HOST_GTEST_MultiDex_DEX))Uncompressed$(suffix $(ART_TEST_HOST_GTEST_MultiDex_DEX))
+ART_TEST_TARGET_GTEST_MultiDexUncompressed_DEX := $(basename $(ART_TEST_TARGET_GTEST_MultiDex_DEX))Uncompressed$(suffix $(ART_TEST_TARGET_GTEST_MultiDex_DEX))
+
 $(ART_TEST_HOST_GTEST_MainStripped_DEX): $(ART_TEST_HOST_GTEST_Main_DEX)
 	cp $< $@
 	$(call dexpreopt-remove-classes.dex,$@)
@@ -80,6 +97,36 @@
 	cp $< $@
 	$(call dexpreopt-remove-classes.dex,$@)
 
+$(ART_TEST_HOST_GTEST_MainUncompressed_DEX): $(ART_TEST_HOST_GTEST_Main_DEX) $(ZIPALIGN)
+	cp $< $@
+	$(call uncompress-dexs, $@)
+	$(call align-package, $@)
+
+$(ART_TEST_TARGET_GTEST_MainUncompressed_DEX): $(ART_TEST_TARGET_GTEST_Main_DEX) $(ZIPALIGN)
+	cp $< $@
+	$(call uncompress-dexs, $@)
+	$(call align-package, $@)
+
+$(ART_TEST_HOST_GTEST_EmptyUncompressed_DEX): $(ZIPALIGN)
+	touch $(dir $@)classes.dex
+	zip -j -qD -X -0 $@ $(dir $@)classes.dex
+	rm $(dir $@)classes.dex
+
+$(ART_TEST_TARGET_GTEST_EmptyUncompressed_DEX): $(ZIPALIGN)
+	touch $(dir $@)classes.dex
+	zip -j -qD -X -0 $@ $(dir $@)classes.dex
+	rm $(dir $@)classes.dex
+
+$(ART_TEST_HOST_GTEST_MultiDexUncompressed_DEX): $(ART_TEST_HOST_GTEST_MultiDex_DEX) $(ZIPALIGN)
+	cp $< $@
+	$(call uncompress-dexs, $@)
+	$(call align-package, $@)
+
+$(ART_TEST_TARGET_GTEST_MultiDexUncompressed_DEX): $(ART_TEST_TARGET_GTEST_MultiDex_DEX) $(ZIPALIGN)
+	cp $< $@
+	$(call uncompress-dexs, $@)
+	$(call align-package, $@)
+
 ART_TEST_GTEST_VerifierDeps_SRC := $(abspath $(wildcard $(LOCAL_PATH)/VerifierDeps/*.smali))
 ART_TEST_GTEST_VerifierDepsMulti_SRC := $(abspath $(wildcard $(LOCAL_PATH)/VerifierDepsMulti/*.smali))
 ART_TEST_HOST_GTEST_VerifierDeps_DEX := $(dir $(ART_TEST_HOST_GTEST_Main_DEX))$(subst Main,VerifierDeps,$(basename $(notdir $(ART_TEST_HOST_GTEST_Main_DEX))))$(suffix $(ART_TEST_HOST_GTEST_Main_DEX))
@@ -100,7 +147,8 @@
 	 $(HOST_OUT_EXECUTABLES)/smali assemble --output $@ $(filter %.smali,$^)
 
 # Dex file dependencies for each gtest.
-ART_GTEST_dex2oat_environment_tests_DEX_DEPS := Main MainStripped MultiDex MultiDexModifiedSecondary Nested
+ART_GTEST_art_dex_file_loader_test_DEX_DEPS := GetMethodSignature Main Nested MultiDex
+ART_GTEST_dex2oat_environment_tests_DEX_DEPS := Main MainStripped MultiDex MultiDexModifiedSecondary MyClassNatives Nested VerifierDeps VerifierDepsMulti
 
 ART_GTEST_atomic_dex_ref_map_test_DEX_DEPS := Interfaces
 ART_GTEST_class_linker_test_DEX_DEPS := AllFields ErroneousA ErroneousB ErroneousInit ForClassLoaderA ForClassLoaderB ForClassLoaderC ForClassLoaderD Interfaces MethodTypes MultiDex MyClass Nested Statics StaticsFromCode
@@ -108,11 +156,12 @@
 ART_GTEST_class_table_test_DEX_DEPS := XandY
 ART_GTEST_compiler_driver_test_DEX_DEPS := AbstractMethod StaticLeafMethods ProfileTestMultiDex
 ART_GTEST_dex_cache_test_DEX_DEPS := Main Packages MethodTypes
-ART_GTEST_dex_file_test_DEX_DEPS := GetMethodSignature Main Nested MultiDex
 ART_GTEST_dexlayout_test_DEX_DEPS := ManyMethods
-ART_GTEST_dex2oat_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS) Statics VerifierDeps
+ART_GTEST_dex2oat_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS) ManyMethods Statics VerifierDeps MainUncompressed EmptyUncompressed
 ART_GTEST_dex2oat_image_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS) Statics VerifierDeps
 ART_GTEST_exception_test_DEX_DEPS := ExceptionHandle
+ART_GTEST_hiddenapi_test_DEX_DEPS := HiddenApi
+ART_GTEST_hidden_api_test_DEX_DEPS := HiddenApiSignatures
 ART_GTEST_image_test_DEX_DEPS := ImageLayoutA ImageLayoutB DefaultMethods
 ART_GTEST_imtable_test_DEX_DEPS := IMTA IMTB
 ART_GTEST_instrumentation_test_DEX_DEPS := Instrumentation
@@ -121,9 +170,11 @@
 ART_GTEST_oat_file_assistant_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS)
 ART_GTEST_dexoptanalyzer_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS)
 ART_GTEST_image_space_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS)
-ART_GTEST_oat_file_test_DEX_DEPS := Main MultiDex
+ART_GTEST_oat_file_test_DEX_DEPS := Main MultiDex MainUncompressed MultiDexUncompressed
 ART_GTEST_oat_test_DEX_DEPS := Main
+ART_GTEST_oat_writer_test_DEX_DEPS := Main
 ART_GTEST_object_test_DEX_DEPS := ProtoCompare ProtoCompare2 StaticsFromCode XandY
+ART_GTEST_patchoat_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS)
 ART_GTEST_proxy_test_DEX_DEPS := Interfaces
 ART_GTEST_reflection_test_DEX_DEPS := Main NonStaticLeafMethods StaticLeafMethods
 ART_GTEST_profile_assistant_test_DEX_DEPS := ProfileTestMultiDex
@@ -136,6 +187,7 @@
 ART_GTEST_heap_verification_test_DEX_DEPS := ProtoCompare ProtoCompare2 StaticsFromCode XandY
 ART_GTEST_verifier_deps_test_DEX_DEPS := VerifierDeps VerifierDepsMulti MultiDex
 ART_GTEST_dex_to_dex_decompiler_test_DEX_DEPS := VerifierDeps DexToDexDecompiler
+ART_GTEST_oatdump_app_test_DEX_DEPS := ProfileTestMultiDex
 
 # The elf writer test has dependencies on core.oat.
 ART_GTEST_elf_writer_test_HOST_DEPS := $(HOST_CORE_IMAGE_DEFAULT_64) $(HOST_CORE_IMAGE_DEFAULT_32)
@@ -146,13 +198,18 @@
   $(HOST_CORE_IMAGE_optimizing_32) \
   $(HOST_CORE_IMAGE_interpreter_64) \
   $(HOST_CORE_IMAGE_interpreter_32) \
-  $(HOST_OUT_EXECUTABLES)/patchoatd
+  patchoatd-host
 ART_GTEST_dex2oat_environment_tests_TARGET_DEPS := \
   $(TARGET_CORE_IMAGE_optimizing_64) \
   $(TARGET_CORE_IMAGE_optimizing_32) \
   $(TARGET_CORE_IMAGE_interpreter_64) \
   $(TARGET_CORE_IMAGE_interpreter_32) \
-  $(TARGET_OUT_EXECUTABLES)/patchoatd
+  patchoatd-target
+
+ART_GTEST_oat_file_test_HOST_DEPS := \
+  $(ART_GTEST_dex2oat_environment_tests_HOST_DEPS)
+ART_GTEST_oat_file_test_TARGET_DEPS := \
+  $(ART_GTEST_dex2oat_environment_tests_TARGET_DEPS)
 
 ART_GTEST_oat_file_assistant_test_HOST_DEPS := \
   $(ART_GTEST_dex2oat_environment_tests_HOST_DEPS)
@@ -161,10 +218,10 @@
 
 ART_GTEST_dexoptanalyzer_test_HOST_DEPS := \
   $(ART_GTEST_dex2oat_environment_tests_HOST_DEPS) \
-  $(HOST_OUT_EXECUTABLES)/dexoptanalyzerd
+  dexoptanalyzerd-host
 ART_GTEST_dexoptanalyzer_test_TARGET_DEPS := \
   $(ART_GTEST_dex2oat_environment_tests_TARGET_DEPS) \
-  dexoptanalyzerd
+  dexoptanalyzerd-target
 
 ART_GTEST_image_space_test_HOST_DEPS := \
   $(ART_GTEST_dex2oat_environment_tests_HOST_DEPS)
@@ -172,57 +229,59 @@
   $(ART_GTEST_dex2oat_environment_tests_TARGET_DEPS)
 
 ART_GTEST_dex2oat_test_HOST_DEPS := \
-  $(ART_GTEST_dex2oat_environment_tests_HOST_DEPS)
+  $(ART_GTEST_dex2oat_environment_tests_HOST_DEPS) \
+  dex2oatd-host
 ART_GTEST_dex2oat_test_TARGET_DEPS := \
-  $(ART_GTEST_dex2oat_environment_tests_TARGET_DEPS)
+  $(ART_GTEST_dex2oat_environment_tests_TARGET_DEPS) \
+  dex2oatd-target
 
 ART_GTEST_dex2oat_image_test_HOST_DEPS := \
-  $(ART_GTEST_dex2oat_environment_tests_HOST_DEPS)
+  $(ART_GTEST_dex2oat_environment_tests_HOST_DEPS) \
+  dex2oatd-host
 ART_GTEST_dex2oat_image_test_TARGET_DEPS := \
-  $(ART_GTEST_dex2oat_environment_tests_TARGET_DEPS)
+  $(ART_GTEST_dex2oat_environment_tests_TARGET_DEPS) \
+  dex2oatd-target
 
 # TODO: document why this is needed.
 ART_GTEST_proxy_test_HOST_DEPS := $(HOST_CORE_IMAGE_DEFAULT_64) $(HOST_CORE_IMAGE_DEFAULT_32)
 
 # The dexdiag test requires the dexdiag utility.
-ART_GTEST_dexdiag_test_HOST_DEPS := \
-  $(HOST_OUT_EXECUTABLES)/dexdiag
-ART_GTEST_dexdiag_test_TARGET_DEPS := \
-  dexdiag
+ART_GTEST_dexdiag_test_HOST_DEPS := dexdiag-host
+ART_GTEST_dexdiag_test_TARGET_DEPS := dexdiag-target
 
 # The dexdump test requires an image and the dexdump utility.
 # TODO: rename into dexdump when migration completes
 ART_GTEST_dexdump_test_HOST_DEPS := \
   $(HOST_CORE_IMAGE_DEFAULT_64) \
   $(HOST_CORE_IMAGE_DEFAULT_32) \
-  $(HOST_OUT_EXECUTABLES)/dexdump2
+  dexdump2-host
 ART_GTEST_dexdump_test_TARGET_DEPS := \
   $(TARGET_CORE_IMAGE_DEFAULT_64) \
   $(TARGET_CORE_IMAGE_DEFAULT_32) \
-  dexdump2
+  dexdump2-target
 
 # The dexlayout test requires an image and the dexlayout utility.
 # TODO: rename into dexdump when migration completes
 ART_GTEST_dexlayout_test_HOST_DEPS := \
   $(HOST_CORE_IMAGE_DEFAULT_64) \
   $(HOST_CORE_IMAGE_DEFAULT_32) \
-  $(HOST_OUT_EXECUTABLES)/dexlayout \
-  $(HOST_OUT_EXECUTABLES)/dexdump2
+  dexlayoutd-host \
+  dexdump2-host
 ART_GTEST_dexlayout_test_TARGET_DEPS := \
   $(TARGET_CORE_IMAGE_DEFAULT_64) \
   $(TARGET_CORE_IMAGE_DEFAULT_32) \
-  dexlayout \
-  dexdump2
+  dexlayoutd-target \
+  dexdump2-target
 
 # The dexlist test requires an image and the dexlist utility.
 ART_GTEST_dexlist_test_HOST_DEPS := \
   $(HOST_CORE_IMAGE_DEFAULT_64) \
   $(HOST_CORE_IMAGE_DEFAULT_32) \
-  $(HOST_OUT_EXECUTABLES)/dexlist
+  dexlist-host
 ART_GTEST_dexlist_test_TARGET_DEPS := \
   $(TARGET_CORE_IMAGE_DEFAULT_64) \
   $(TARGET_CORE_IMAGE_DEFAULT_32) \
-  dexlist
+  dexlist-target
 
 # The imgdiag test has dependencies on core.oat since it needs to load it during the test.
 # For the host, also add the installed tool (in the base size, that should suffice). For the
@@ -230,30 +289,45 @@
 ART_GTEST_imgdiag_test_HOST_DEPS := \
   $(HOST_CORE_IMAGE_DEFAULT_64) \
   $(HOST_CORE_IMAGE_DEFAULT_32) \
-  $(HOST_OUT_EXECUTABLES)/imgdiagd
+  imgdiagd-host
 ART_GTEST_imgdiag_test_TARGET_DEPS := \
   $(TARGET_CORE_IMAGE_DEFAULT_64) \
   $(TARGET_CORE_IMAGE_DEFAULT_32) \
-  imgdiagd
+  imgdiagd-target
 
 # Oatdump test requires an image and oatfile to dump.
 ART_GTEST_oatdump_test_HOST_DEPS := \
   $(HOST_CORE_IMAGE_DEFAULT_64) \
   $(HOST_CORE_IMAGE_DEFAULT_32) \
-  $(HOST_OUT_EXECUTABLES)/oatdumpd \
-  $(HOST_OUT_EXECUTABLES)/oatdumpds
+  oatdumpd-host \
+  oatdumpds-host \
+  dexdump2-host
 ART_GTEST_oatdump_test_TARGET_DEPS := \
   $(TARGET_CORE_IMAGE_DEFAULT_64) \
   $(TARGET_CORE_IMAGE_DEFAULT_32) \
-  oatdump
+  oatdumpd-target \
+  dexdump2-target
 ART_GTEST_oatdump_image_test_HOST_DEPS := $(ART_GTEST_oatdump_test_HOST_DEPS)
 ART_GTEST_oatdump_image_test_TARGET_DEPS := $(ART_GTEST_oatdump_test_TARGET_DEPS)
+ART_GTEST_oatdump_app_test_HOST_DEPS := $(ART_GTEST_oatdump_test_HOST_DEPS) \
+  dex2oatd-host \
+  dex2oatds-host
+ART_GTEST_oatdump_app_test_TARGET_DEPS := $(ART_GTEST_oatdump_test_TARGET_DEPS) \
+  dex2oatd-target
+
+ART_GTEST_patchoat_test_HOST_DEPS := \
+  $(ART_GTEST_dex2oat_environment_tests_HOST_DEPS)
+ART_GTEST_patchoat_test_TARGET_DEPS := \
+  $(ART_GTEST_dex2oat_environment_tests_TARGET_DEPS)
 
 # Profile assistant tests requires profman utility.
-ART_GTEST_profile_assistant_test_HOST_DEPS := \
-  $(HOST_OUT_EXECUTABLES)/profmand
-ART_GTEST_profile_assistant_test_TARGET_DEPS := \
-  profman
+ART_GTEST_profile_assistant_test_HOST_DEPS := profmand-host
+ART_GTEST_profile_assistant_test_TARGET_DEPS := profmand-target
+
+ART_GTEST_hiddenapi_test_HOST_DEPS := \
+  $(HOST_CORE_IMAGE_DEFAULT_64) \
+  $(HOST_CORE_IMAGE_DEFAULT_32) \
+  hiddenapid-host
 
 # The path for which all the source files are relative, not actually the current directory.
 LOCAL_PATH := art
@@ -268,11 +342,16 @@
     art_dexlayout_tests \
     art_dexlist_tests \
     art_dexoptanalyzer_tests \
+    art_hiddenapi_tests \
     art_imgdiag_tests \
+    art_libartbase_tests \
+    art_libdexfile_tests \
     art_oatdump_tests \
+    art_patchoat_tests \
     art_profman_tests \
     art_runtime_tests \
     art_runtime_compiler_tests \
+    art_sigchain_tests \
 
 ART_TARGET_GTEST_FILES := $(foreach m,$(ART_TEST_MODULES),\
     $(ART_TEST_LIST_device_$(TARGET_ARCH)_$(m)))
@@ -310,19 +389,31 @@
   ART_GTEST_TARGET_ANDROID_ROOT := $(ART_TEST_ANDROID_ROOT)
 endif
 
-ART_VALGRIND_TARGET_DEPENDENCIES := \
+ART_VALGRIND_TARGET_DEPENDENCIES :=
+
+# Has to match list in external/valgrind/Android.build_one.mk
+ART_VALGRIND_SUPPORTED_ARCH := arm arm64 x86_64
+
+# Valgrind is not supported for x86
+ifneq (,$(filter $(ART_VALGRIND_SUPPORTED_ARCH),$(TARGET_ARCH)))
+art_vg_arch := $(if $(filter x86_64,$(TARGET_ARCH)),amd64,$(TARGET_ARCH))
+ART_VALGRIND_TARGET_DEPENDENCIES += \
   $(TARGET_OUT_EXECUTABLES)/valgrind \
-  $(TARGET_OUT_SHARED_LIBRARIES)/valgrind/memcheck-$(TARGET_ARCH)-linux \
-  $(TARGET_OUT_SHARED_LIBRARIES)/valgrind/vgpreload_core-$(TARGET_ARCH)-linux.so \
-  $(TARGET_OUT_SHARED_LIBRARIES)/valgrind/vgpreload_memcheck-$(TARGET_ARCH)-linux.so \
+  $(TARGET_OUT_SHARED_LIBRARIES)/valgrind/memcheck-$(art_vg_arch)-linux \
+  $(TARGET_OUT_SHARED_LIBRARIES)/valgrind/vgpreload_core-$(art_vg_arch)-linux.so \
+  $(TARGET_OUT_SHARED_LIBRARIES)/valgrind/vgpreload_memcheck-$(art_vg_arch)-linux.so \
   $(TARGET_OUT_SHARED_LIBRARIES)/valgrind/default.supp
+art_vg_arch :=
+endif
 
 ifdef TARGET_2ND_ARCH
+ifneq (,$(filter $(ART_VALGRIND_SUPPORTED_ARCH),$(TARGET_2ND_ARCH)))
 ART_VALGRIND_TARGET_DEPENDENCIES += \
   $(TARGET_OUT_SHARED_LIBRARIES)/valgrind/memcheck-$(TARGET_2ND_ARCH)-linux \
   $(TARGET_OUT_SHARED_LIBRARIES)/valgrind/vgpreload_core-$(TARGET_2ND_ARCH)-linux.so \
   $(TARGET_OUT_SHARED_LIBRARIES)/valgrind/vgpreload_memcheck-$(TARGET_2ND_ARCH)-linux.so
 endif
+endif
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := valgrind-target-suppressions.txt
@@ -362,11 +453,12 @@
 	$(hide) adb shell rm $(ART_TARGET_TEST_DIR)/$(TARGET_$(3)ARCH)/$$@-$$$$PPID
 	$(hide) adb shell chmod 755 $$(PRIVATE_TARGET_EXE)
 	$(hide) $$(call ART_TEST_SKIP,$$@) && \
-	  (adb shell "$(GCOV_ENV) LD_LIBRARY_PATH=$(4) ANDROID_ROOT=$(ART_GTEST_TARGET_ANDROID_ROOT) \
-	    $$(PRIVATE_TARGET_EXE) && touch $(ART_TARGET_TEST_DIR)/$(TARGET_$(3)ARCH)/$$@-$$$$PPID" \
-	  && (adb pull $(ART_TARGET_TEST_DIR)/$(TARGET_$(3)ARCH)/$$@-$$$$PPID /tmp/ \
-	      && $$(call ART_TEST_PASSED,$$@)) \
-	  || $$(call ART_TEST_FAILED,$$@))
+	  (adb shell "env $(GCOV_ENV) LD_LIBRARY_PATH=$(4) \
+	       ANDROID_ROOT=$(ART_GTEST_TARGET_ANDROID_ROOT) $$(PRIVATE_TARGET_EXE) \
+	     && touch $(ART_TARGET_TEST_DIR)/$(TARGET_$(3)ARCH)/$$@-$$$$PPID" \
+	   && (adb pull $(ART_TARGET_TEST_DIR)/$(TARGET_$(3)ARCH)/$$@-$$$$PPID /tmp/ \
+	       && $$(call ART_TEST_PASSED,$$@)) \
+	   || $$(call ART_TEST_FAILED,$$@))
 	$(hide) rm -f /tmp/$$@-$$$$PPID
 
   ART_TEST_TARGET_GTEST$($(3)ART_PHONY_TEST_TARGET_SUFFIX)_RULES += $$(gtest_rule)
@@ -379,17 +471,20 @@
 	$(hide) adb shell rm $(ART_TARGET_TEST_DIR)/$(TARGET_$(3)ARCH)/$$@-$$$$PPID
 	$(hide) adb shell chmod 755 $$(PRIVATE_TARGET_EXE)
 	$(hide) $$(call ART_TEST_SKIP,$$@) && \
-	  (adb shell "$(GCOV_ENV) LD_LIBRARY_PATH=$(4) ANDROID_ROOT=$(ART_GTEST_TARGET_ANDROID_ROOT) \
-	    valgrind --leak-check=full --error-exitcode=1 --workaround-gcc296-bugs=yes \
-	    --suppressions=$(ART_TARGET_TEST_DIR)/valgrind-target-suppressions.txt \
-	    --num-callers=50 --show-mismatched-frees=no \
-	    $$(PRIVATE_TARGET_EXE) && touch $(ART_TARGET_TEST_DIR)/$(TARGET_$(3)ARCH)/$$@-$$$$PPID" \
-	  && (adb pull $(ART_TARGET_TEST_DIR)/$(TARGET_$(3)ARCH)/$$@-$$$$PPID /tmp/ \
-	      && $$(call ART_TEST_PASSED,$$@)) \
-	  || $$(call ART_TEST_FAILED,$$@))
+	  (adb shell "env $(GCOV_ENV) LD_LIBRARY_PATH=$(4) \
+	       ANDROID_ROOT=$(ART_GTEST_TARGET_ANDROID_ROOT) \
+	       $$$$ANDROID_ROOT/bin/valgrind \
+	       --leak-check=full --error-exitcode=1 --workaround-gcc296-bugs=yes \
+	       --suppressions=$(ART_TARGET_TEST_DIR)/valgrind-target-suppressions.txt \
+	       --num-callers=50 --show-mismatched-frees=no $$(PRIVATE_TARGET_EXE) \
+	     && touch $(ART_TARGET_TEST_DIR)/$(TARGET_$(3)ARCH)/$$@-$$$$PPID" \
+	   && (adb pull $(ART_TARGET_TEST_DIR)/$(TARGET_$(3)ARCH)/$$@-$$$$PPID /tmp/ \
+	       && $$(call ART_TEST_PASSED,$$@)) \
+	   || $$(call ART_TEST_FAILED,$$@))
 	$(hide) rm -f /tmp/$$@-$$$$PPID
 
-  ART_TEST_TARGET_VALGRIND_GTEST$$($(3)ART_PHONY_TEST_TARGET_SUFFIX)_RULES += valgrind-$$(gtest_rule)
+  ART_TEST_TARGET_VALGRIND_GTEST$$($(3)ART_PHONY_TEST_TARGET_SUFFIX)_RULES += \
+    valgrind-$$(gtest_rule)
   ART_TEST_TARGET_VALGRIND_GTEST_RULES += valgrind-$$(gtest_rule)
   ART_TEST_TARGET_VALGRIND_GTEST_$(1)_RULES += valgrind-$$(gtest_rule)
 
@@ -424,16 +519,37 @@
     $$(gtest_exe) \
     $$(ART_GTEST_$(1)_HOST_DEPS) \
     $(foreach file,$(ART_GTEST_$(1)_DEX_DEPS),$(ART_TEST_HOST_GTEST_$(file)_DEX))
+  ifneq (,$(DIST_DIR))
+    gtest_xml_output := --gtest_output=xml:$(DIST_DIR)/gtest/$(1)$$($(3)ART_PHONY_TEST_HOST_SUFFIX).xml
+  else
+    gtest_xml_output :=
+  endif
 
   ART_TEST_HOST_GTEST_DEPENDENCIES += $$(gtest_deps)
 
+.PHONY: $$(gtest_rule)
+ifeq (,$(SANITIZE_HOST))
+$$(gtest_rule): PRIVATE_XML_OUTPUT := $$(gtest_xml_output)
+$$(gtest_rule): $$(gtest_exe) $$(gtest_deps)
+	$(hide) ($$(call ART_TEST_SKIP,$$@) && $$< $$(PRIVATE_XML_OUTPUT) && \
+		$$(call ART_TEST_PASSED,$$@)) || $$(call ART_TEST_FAILED,$$@)
+else
 # Note: envsetup currently exports ASAN_OPTIONS=detect_leaks=0 to suppress leak detection, as some
 #       build tools (e.g., ninja) intentionally leak. We want leak checks when we run our tests, so
 #       override ASAN_OPTIONS. b/37751350
-.PHONY: $$(gtest_rule)
+# Note 2: Under sanitization, also capture the output, and run it through the stack tool on failure
+# (with the x86-64 ABI, as this allows symbolization of both x86 and x86-64). We don't do this in
+# general as it loses all the color output, and we have our own symbolization step when not running
+# under ASAN.
+$$(gtest_rule): PRIVATE_XML_OUTPUT := $$(gtest_xml_output)
 $$(gtest_rule): $$(gtest_exe) $$(gtest_deps)
-	$(hide) ($$(call ART_TEST_SKIP,$$@) && ASAN_OPTIONS=detect_leaks=1 $$< && \
-		$$(call ART_TEST_PASSED,$$@)) || $$(call ART_TEST_FAILED,$$@)
+	$(hide) ($$(call ART_TEST_SKIP,$$@) && set -o pipefail && \
+		ASAN_OPTIONS=detect_leaks=1 $$< $$(PRIVATE_XML_OUTPUT) 2>&1 | tee $$<.tmp.out >&2 && \
+		{ $$(call ART_TEST_PASSED,$$@) ; rm $$<.tmp.out ; }) || \
+		( grep -q AddressSanitizer $$<.tmp.out && export ANDROID_BUILD_TOP=`pwd` && \
+			{ echo "ABI: 'x86_64'" | cat - $$<.tmp.out | development/scripts/stack | tail -n 3000 ; } ; \
+		rm $$<.tmp.out ; $$(call ART_TEST_FAILED,$$@))
+endif
 
   ART_TEST_HOST_GTEST$$($(3)ART_PHONY_TEST_HOST_SUFFIX)_RULES += $$(gtest_rule)
   ART_TEST_HOST_GTEST_RULES += $$(gtest_rule)
@@ -604,7 +720,7 @@
   endif
 
 .PHONY: $$(rule_name)
-$$(rule_name): $$(dependencies)
+$$(rule_name): $$(dependencies) dx d8-compat-dx desugar
 	$(hide) $$(call ART_TEST_PREREQ_FINISHED,$$@)
 
   # Clear locally defined variables.
@@ -679,6 +795,9 @@
 ART_GTEST_dex2oat_image_test_HOST_DEPS :=
 ART_GTEST_dex2oat_image_test_TARGET_DEPS :=
 ART_GTEST_object_test_DEX_DEPS :=
+ART_GTEST_patchoat_test_DEX_DEPS :=
+ART_GTEST_patchoat_test_HOST_DEPS :=
+ART_GTEST_patchoat_test_TARGET_DEPS :=
 ART_GTEST_proxy_test_DEX_DEPS :=
 ART_GTEST_reflection_test_DEX_DEPS :=
 ART_GTEST_stub_test_DEX_DEPS :=
@@ -692,6 +811,10 @@
 $(foreach dir,$(GTEST_DEX_DIRECTORIES), $(eval ART_TEST_HOST_GTEST_$(dir)_DEX :=))
 ART_TEST_HOST_GTEST_MainStripped_DEX :=
 ART_TEST_TARGET_GTEST_MainStripped_DEX :=
+ART_TEST_HOST_GTEST_MainUncompressed_DEX :=
+ART_TEST_TARGET_GTEST_MainUncompressed_DEX :=
+ART_TEST_HOST_GTEST_EmptyUncompressed_DEX :=
+ART_TEST_TARGET_GTEST_EmptyUncompressed_DEX :=
 ART_TEST_GTEST_VerifierDeps_SRC :=
 ART_TEST_HOST_GTEST_VerifierDeps_DEX :=
 ART_TEST_TARGET_GTEST_VerifierDeps_DEX :=
diff --git a/build/Android.oat.mk b/build/Android.oat.mk
index 3f9ea15..517ac5c 100644
--- a/build/Android.oat.mk
+++ b/build/Android.oat.mk
@@ -111,6 +111,7 @@
 	  $$(LOCAL_$(2)DEX2OAT_HOST_INSTRUCTION_SET_FEATURES_OPTION) \
 	  --host --android-root=$$(HOST_OUT) \
 	  --generate-debug-info --generate-build-id --compile-pic \
+	  --runtime-arg -XX:SlowDebug=true \
 	  $$(PRIVATE_CORE_MULTI_PARAM) $$(PRIVATE_CORE_COMPILE_OPTIONS)
 
 $$(core_oat_name): $$(core_image_name)
@@ -214,6 +215,7 @@
 	  --instruction-set-features=$$($(2)DEX2OAT_TARGET_INSTRUCTION_SET_FEATURES) \
 	  --android-root=$$(PRODUCT_OUT)/system \
 	  --generate-debug-info --generate-build-id --compile-pic \
+	  --runtime-arg -XX:SlowDebug=true \
 	  $$(PRIVATE_CORE_COMPILE_OPTIONS) || (rm $$(PRIVATE_CORE_OAT_NAME); exit 1)
 
 $$(core_oat_name): $$(core_image_name)
diff --git a/build/art.go b/build/art.go
index 6c9aa89..59480a0 100644
--- a/build/art.go
+++ b/build/art.go
@@ -19,6 +19,8 @@
 	"android/soong/cc"
 	"fmt"
 	"sync"
+
+	"github.com/google/blueprint/proptools"
 )
 
 var supportedArches = []string{"arm", "arm64", "mips", "mips64", "x86", "x86_64"}
@@ -44,10 +46,6 @@
 		cflags = append(cflags, "-DART_USE_TLAB=1")
 	}
 
-	if !envFalse(ctx, "ART_ENABLE_VDEX") {
-		cflags = append(cflags, "-DART_ENABLE_VDEX")
-	}
-
 	imtSize := envDefault(ctx, "ART_IMT_SIZE", "43")
 	cflags = append(cflags, "-DIMT_SIZE="+imtSize)
 
@@ -68,6 +66,9 @@
 			"-DART_READ_BARRIER_TYPE_IS_"+barrierType+"=1")
 	}
 
+  cdexLevel := envDefault(ctx, "ART_DEFAULT_COMPACT_DEX_LEVEL", "fast")
+  cflags = append(cflags, "-DART_DEFAULT_COMPACT_DEX_LEVEL="+cdexLevel)
+
 	// We need larger stack overflow guards for ASAN, as the compiled code will have
 	// larger frame sizes. For simplicity, just use global not-target-specific cflags.
 	// Note: We increase this for both debug and non-debug, as the overflow gap will
@@ -97,6 +98,15 @@
 		asflags = append(asflags, "-DART_ENABLE_ADDRESS_SANITIZER=1")
 	}
 
+	if envTrue(ctx, "ART_MIPS32_CHECK_ALIGNMENT") {
+		// Enable the use of MIPS32 CHECK_ALIGNMENT macro for debugging purposes
+		asflags = append(asflags, "-DART_MIPS32_CHECK_ALIGNMENT")
+	}
+
+	if envTrueOrDefault(ctx, "USE_D8_DESUGAR") {
+		cflags = append(cflags, "-DUSE_D8_DESUGAR=1")
+	}
+
 	return cflags, asflags
 }
 
@@ -153,6 +163,11 @@
 	cflags = append(cflags, "-DART_BASE_ADDRESS_MIN_DELTA="+minDelta)
 	cflags = append(cflags, "-DART_BASE_ADDRESS_MAX_DELTA="+maxDelta)
 
+	if len(ctx.AConfig().SanitizeHost()) > 0 && !envFalse(ctx, "ART_ENABLE_ADDRESS_SANITIZER") {
+		// We enable full sanitization on the host by default.
+		cflags = append(cflags, "-DART_ENABLE_ADDRESS_SANITIZER=1")
+	}
+
 	return cflags
 }
 
@@ -200,31 +215,33 @@
 
 func customLinker(ctx android.LoadHookContext) {
 	linker := envDefault(ctx, "CUSTOM_TARGET_LINKER", "")
-	if linker != "" {
-		type props struct {
-			DynamicLinker string
-		}
-
-		p := &props{}
-		p.DynamicLinker = linker
-		ctx.AppendProperties(p)
+	type props struct {
+		DynamicLinker string
 	}
+
+	p := &props{}
+	if linker != "" {
+		p.DynamicLinker = linker
+	}
+
+	ctx.AppendProperties(p)
 }
 
 func prefer32Bit(ctx android.LoadHookContext) {
-	if envTrue(ctx, "HOST_PREFER_32_BIT") {
-		type props struct {
-			Target struct {
-				Host struct {
-					Compile_multilib string
-				}
+	type props struct {
+		Target struct {
+			Host struct {
+				Compile_multilib *string
 			}
 		}
-
-		p := &props{}
-		p.Target.Host.Compile_multilib = "prefer32"
-		ctx.AppendProperties(p)
 	}
+
+	p := &props{}
+	if envTrue(ctx, "HOST_PREFER_32_BIT") {
+		p.Target.Host.Compile_multilib = proptools.StringPtr("prefer32")
+	}
+
+	ctx.AppendProperties(p)
 }
 
 func testMap(config android.Config) map[string][]string {
@@ -256,6 +273,7 @@
 
 func init() {
 	android.RegisterModuleType("art_cc_library", artLibrary)
+	android.RegisterModuleType("art_cc_static_library", artStaticLibrary)
 	android.RegisterModuleType("art_cc_binary", artBinary)
 	android.RegisterModuleType("art_cc_test", artTest)
 	android.RegisterModuleType("art_cc_test_library", artTestLibrary)
@@ -287,8 +305,18 @@
 }
 
 func artLibrary() android.Module {
-	library, _ := cc.NewLibrary(android.HostAndDeviceSupported)
-	module := library.Init()
+	m, _ := cc.NewLibrary(android.HostAndDeviceSupported)
+	module := m.Init()
+
+	installCodegenCustomizer(module, true)
+
+	return module
+}
+
+func artStaticLibrary() android.Module {
+	m, library := cc.NewLibrary(android.HostAndDeviceSupported)
+	library.BuildOnlyStatic()
+	module := m.Init()
 
 	installCodegenCustomizer(module, true)
 
@@ -342,3 +370,7 @@
 func envFalse(ctx android.BaseContext, key string) bool {
 	return ctx.AConfig().Getenv(key) == "false"
 }
+
+func envTrueOrDefault(ctx android.BaseContext, key string) bool {
+	return ctx.AConfig().Getenv(key) != "false"
+}
diff --git a/cmdline/Android.bp b/cmdline/Android.bp
index c811cbd..b46e987 100644
--- a/cmdline/Android.bp
+++ b/cmdline/Android.bp
@@ -14,6 +14,13 @@
 // limitations under the License.
 //
 
+// TODO: this header library depends on libart. Find a way to express that.
+cc_library_headers {
+    name: "art_cmdlineparser_headers",
+    host_supported: true,
+    export_include_dirs: ["."],
+}
+
 art_cc_test {
     name: "art_cmdline_tests",
     defaults: [
diff --git a/cmdline/cmdline.h b/cmdline/cmdline.h
index 18ca944..95ab123 100644
--- a/cmdline/cmdline.h
+++ b/cmdline/cmdline.h
@@ -26,7 +26,9 @@
 
 #include "android-base/stringprintf.h"
 
+#include "base/file_utils.h"
 #include "base/logging.h"
+#include "base/mutex.h"
 #include "base/stringpiece.h"
 #include "noop_compiler_callbacks.h"
 #include "runtime.h"
@@ -78,6 +80,7 @@
     *filename = cache_filename;
     return true;
   } else {
+    *filename = system_filename;
     return false;
   }
 }
@@ -146,7 +149,7 @@
       } else if (option.starts_with("--instruction-set=")) {
         StringPiece instruction_set_str = option.substr(strlen("--instruction-set=")).data();
         instruction_set_ = GetInstructionSetFromString(instruction_set_str.data());
-        if (instruction_set_ == kNone) {
+        if (instruction_set_ == InstructionSet::kNone) {
           fprintf(stderr, "Unsupported instruction set %s\n", instruction_set_str.data());
           PrintUsage();
           return false;
@@ -217,7 +220,7 @@
   // Specified by --boot-image.
   const char* boot_image_location_ = nullptr;
   // Specified by --instruction-set.
-  InstructionSet instruction_set_ = kRuntimeISA;
+  InstructionSet instruction_set_ = InstructionSet::kNone;
   // Specified by --output.
   std::ostream* os_ = &std::cout;
   std::unique_ptr<std::ofstream> out_;  // If something besides cout is used
@@ -230,6 +233,10 @@
       *error_msg = "--boot-image must be specified";
       return false;
     }
+    if (instruction_set_ == InstructionSet::kNone) {
+      LOG(WARNING) << "No instruction set given, assuming " << GetInstructionSetString(kRuntimeISA);
+      instruction_set_ = kRuntimeISA;
+    }
 
     DBG_LOG << "boot image location: " << boot_image_location_;
 
@@ -257,7 +264,7 @@
 
         DBG_LOG << "boot_image_location parent_dir_name was " << parent_dir_name;
 
-        if (GetInstructionSetFromString(parent_dir_name.c_str()) != kNone) {
+        if (GetInstructionSetFromString(parent_dir_name.c_str()) != InstructionSet::kNone) {
           *error_msg = "Do not specify the architecture as part of the boot image location";
           return false;
         }
@@ -266,8 +273,10 @@
       // Check that the boot image location points to a valid file name.
       std::string file_name;
       if (!LocationToFilename(boot_image_location, instruction_set_, &file_name)) {
-        *error_msg = android::base::StringPrintf("No corresponding file for location '%s' exists",
-                                                 boot_image_location.c_str());
+        *error_msg = android::base::StringPrintf(
+            "No corresponding file for location '%s' (filename '%s') exists",
+            boot_image_location.c_str(),
+            file_name.c_str());
         return false;
       }
 
@@ -295,6 +304,7 @@
 template <typename Args = CmdlineArgs>
 struct CmdlineMain {
   int Main(int argc, char** argv) {
+    Locks::Init();
     InitLogging(argv, Runtime::Abort);
     std::unique_ptr<Args> args = std::unique_ptr<Args>(CreateArguments());
     args_ = args.get();
diff --git a/cmdline/cmdline_parser.h b/cmdline/cmdline_parser.h
index 32480dd..82c04e7 100644
--- a/cmdline/cmdline_parser.h
+++ b/cmdline/cmdline_parser.h
@@ -19,20 +19,20 @@
 
 #define CMDLINE_NDEBUG 1  // Do not output any debugging information for parsing.
 
-#include "cmdline/detail/cmdline_parser_detail.h"
-#include "cmdline/detail/cmdline_parse_argument_detail.h"
-#include "cmdline/detail/cmdline_debug_detail.h"
+#include "detail/cmdline_debug_detail.h"
+#include "detail/cmdline_parse_argument_detail.h"
+#include "detail/cmdline_parser_detail.h"
 
-#include "cmdline_type_parser.h"
-#include "token_range.h"
-#include "cmdline_types.h"
-#include "cmdline_result.h"
 #include "cmdline_parse_result.h"
+#include "cmdline_result.h"
+#include "cmdline_type_parser.h"
+#include "cmdline_types.h"
+#include "token_range.h"
 
-#include "runtime/base/variant_map.h"
+#include "base/variant_map.h"
 
-#include <vector>
 #include <memory>
+#include <vector>
 
 namespace art {
 // Build a parser for command line arguments with a small domain specific language.
@@ -340,7 +340,7 @@
     typename std::enable_if<std::is_same<TArg, Unit>::value>::type
     InitializeTypedBuilder(ArgumentBuilder<TArg>* arg_builder) {
       // Every Unit argument implicitly maps to a runtime value of Unit{}
-      std::vector<Unit> values(names_.size(), Unit{});  // NOLINT [whitespace/braces] [5]
+      std::vector<Unit> values(names_.size(), Unit{});
       arg_builder->SetValuesInternal(std::move(values));
     }
 
diff --git a/cmdline/cmdline_parser_test.cc b/cmdline/cmdline_parser_test.cc
index d957869..235a2aa 100644
--- a/cmdline/cmdline_parser_test.cc
+++ b/cmdline/cmdline_parser_test.cc
@@ -15,14 +15,18 @@
  */
 
 #include "cmdline_parser.h"
-#include "runtime/runtime_options.h"
-#include "runtime/parsed_options.h"
 
-#include "utils.h"
 #include <numeric>
+
 #include "gtest/gtest.h"
-#include "runtime/experimental_flags.h"
-#include "runtime/runtime.h"
+
+#include "base/mutex.h"
+#include "base/utils.h"
+#include "jdwp_provider.h"
+#include "experimental_flags.h"
+#include "parsed_options.h"
+#include "runtime.h"
+#include "runtime_options.h"
 
 #define EXPECT_NULL(expected) EXPECT_EQ(reinterpret_cast<const void*>(expected), \
                                         reinterpret_cast<void*>(nullptr));
@@ -123,6 +127,7 @@
   using RuntimeParser = ParsedOptions::RuntimeParser;
 
   static void SetUpTestCase() {
+    art::Locks::Init();
     art::InitLogging(nullptr, art::Runtime::Abort);  // argv = null
   }
 
@@ -188,7 +193,7 @@
 #define EXPECT_SINGLE_PARSE_VALUE(expected, argv, key)        \
     _EXPECT_SINGLE_PARSE_EXISTS(argv, key);                   \
     EXPECT_KEY_VALUE(args, key, expected);                    \
-  } while (false)                                             // NOLINT [readability/namespace] [5]
+  } while (false)
 
 #define EXPECT_SINGLE_PARSE_VALUE_STR(expected, argv, key)    \
   EXPECT_SINGLE_PARSE_VALUE(std::string(expected), argv, key)
@@ -242,7 +247,7 @@
   {
     const char* log_args = "-verbose:"
         "class,compiler,gc,heap,jdwp,jni,monitor,profiler,signals,simulator,startup,"
-        "third-party-jni,threads,verifier";
+        "third-party-jni,threads,verifier,verifier-debug";
 
     LogVerbosity log_verbosity = LogVerbosity();
     log_verbosity.class_linker = true;
@@ -259,6 +264,7 @@
     log_verbosity.third_party_jni = true;
     log_verbosity.threads = true;
     log_verbosity.verifier = true;
+    log_verbosity.verifier_debug = true;
 
     EXPECT_SINGLE_PARSE_VALUE(log_verbosity, log_args, M::Verbose);
   }
@@ -316,7 +322,7 @@
    * Test success
    */
   {
-    XGcOption option_all_true{};  // NOLINT [readability/braces] [4]
+    XGcOption option_all_true{};
     option_all_true.collector_type_ = gc::CollectorType::kCollectorTypeCMS;
     option_all_true.verify_pre_gc_heap_ = true;
     option_all_true.verify_pre_sweeping_heap_ = true;
@@ -333,7 +339,7 @@
 
     EXPECT_SINGLE_PARSE_VALUE(option_all_true, xgc_args_all_true, M::GcOption);
 
-    XGcOption option_all_false{};  // NOLINT [readability/braces] [4]
+    XGcOption option_all_false{};
     option_all_false.collector_type_ = gc::CollectorType::kCollectorTypeMS;
     option_all_false.verify_pre_gc_heap_ = false;
     option_all_false.verify_pre_sweeping_heap_ = false;
@@ -348,7 +354,7 @@
 
     EXPECT_SINGLE_PARSE_VALUE(option_all_false, xgc_args_all_false, M::GcOption);
 
-    XGcOption option_all_default{};  // NOLINT [readability/braces] [4]
+    XGcOption option_all_default{};
 
     const char* xgc_args_blank = "-Xgc:";
     EXPECT_SINGLE_PARSE_VALUE(option_all_default, xgc_args_blank, M::GcOption);
@@ -361,48 +367,40 @@
 }  // TEST_F
 
 /*
- * {"-Xrunjdwp:_", "-agentlib:jdwp=_"}
+ * { "-XjdwpProvider:_" }
  */
-TEST_F(CmdlineParserTest, TestJdwpOptions) {
-  /*
-   * Test success
-   */
+TEST_F(CmdlineParserTest, TestJdwpProviderEmpty) {
   {
-    /*
-     * "Example: -Xrunjdwp:transport=dt_socket,address=8000,server=y\n"
-     */
-    JDWP::JdwpOptions opt = JDWP::JdwpOptions();
-    opt.transport = JDWP::JdwpTransportType::kJdwpTransportSocket;
-    opt.port = 8000;
-    opt.server = true;
-
-    const char *opt_args = "-Xrunjdwp:transport=dt_socket,address=8000,server=y";
-
-    EXPECT_SINGLE_PARSE_VALUE(opt, opt_args, M::JdwpOptions);
+    EXPECT_SINGLE_PARSE_DEFAULT_VALUE(JdwpProvider::kNone, "", M::JdwpProvider);
   }
+}  // TEST_F
 
-  {
-    /*
-     * "Example: -agentlib:jdwp=transport=dt_socket,address=localhost:6500,server=n\n");
-     */
-    JDWP::JdwpOptions opt = JDWP::JdwpOptions();
-    opt.transport = JDWP::JdwpTransportType::kJdwpTransportSocket;
-    opt.host = "localhost";
-    opt.port = 6500;
-    opt.server = false;
+TEST_F(CmdlineParserTest, TestJdwpProviderDefault) {
+  const char* opt_args = "-XjdwpProvider:default";
+  EXPECT_SINGLE_PARSE_VALUE(JdwpProvider::kDefaultJdwpProvider, opt_args, M::JdwpProvider);
+}  // TEST_F
 
-    const char *opt_args = "-agentlib:jdwp=transport=dt_socket,address=localhost:6500,server=n";
+TEST_F(CmdlineParserTest, TestJdwpProviderInternal) {
+  const char* opt_args = "-XjdwpProvider:internal";
+  EXPECT_SINGLE_PARSE_VALUE(JdwpProvider::kInternal, opt_args, M::JdwpProvider);
+}  // TEST_F
 
-    EXPECT_SINGLE_PARSE_VALUE(opt, opt_args, M::JdwpOptions);
-  }
+TEST_F(CmdlineParserTest, TestJdwpProviderNone) {
+  const char* opt_args = "-XjdwpProvider:none";
+  EXPECT_SINGLE_PARSE_VALUE(JdwpProvider::kNone, opt_args, M::JdwpProvider);
+}  // TEST_F
 
-  /*
-   * Test failures
-   */
-  EXPECT_SINGLE_PARSE_FAIL("-Xrunjdwp:help", CmdlineResult::kUsage);  // usage for help only
-  EXPECT_SINGLE_PARSE_FAIL("-Xrunjdwp:blabla", CmdlineResult::kFailure);  // invalid subarg
-  EXPECT_SINGLE_PARSE_FAIL("-agentlib:jdwp=help", CmdlineResult::kUsage);  // usage for help only
-  EXPECT_SINGLE_PARSE_FAIL("-agentlib:jdwp=blabla", CmdlineResult::kFailure);  // invalid subarg
+TEST_F(CmdlineParserTest, TestJdwpProviderAdbconnection) {
+  const char* opt_args = "-XjdwpProvider:adbconnection";
+  EXPECT_SINGLE_PARSE_VALUE(JdwpProvider::kAdbConnection, opt_args, M::JdwpProvider);
+}  // TEST_F
+
+TEST_F(CmdlineParserTest, TestJdwpProviderHelp) {
+  EXPECT_SINGLE_PARSE_FAIL("-XjdwpProvider:help", CmdlineResult::kUsage);
+}  // TEST_F
+
+TEST_F(CmdlineParserTest, TestJdwpProviderFail) {
+  EXPECT_SINGLE_PARSE_FAIL("-XjdwpProvider:blablabla", CmdlineResult::kFailure);
 }  // TEST_F
 
 /*
@@ -564,10 +562,10 @@
 
   auto&& map = parser_->ReleaseArgumentsMap();
   EXPECT_EQ(5u, map.Size());
-  EXPECT_KEY_VALUE(map, M::Help, Unit{});  // NOLINT [whitespace/braces] [5]
+  EXPECT_KEY_VALUE(map, M::Help, Unit{});
   EXPECT_KEY_VALUE(map, M::ForegroundHeapGrowthMultiplier, 0.5);
   EXPECT_KEY_VALUE(map, M::Dex2Oat, false);
-  EXPECT_KEY_VALUE(map, M::MethodTrace, Unit{});  // NOLINT [whitespace/braces] [5]
+  EXPECT_KEY_VALUE(map, M::MethodTrace, Unit{});
   EXPECT_KEY_VALUE(map, M::LargeObjectSpace, gc::space::LargeObjectSpaceType::kMap);
 }  //  TEST_F
 }  // namespace art
diff --git a/cmdline/cmdline_result.h b/cmdline/cmdline_result.h
index 963dfc1..0ae1145 100644
--- a/cmdline/cmdline_result.h
+++ b/cmdline/cmdline_result.h
@@ -18,86 +18,85 @@
 #define ART_CMDLINE_CMDLINE_RESULT_H_
 
 #include <assert.h>
-#include <utils.h>
+#include "base/utils.h"
 
 namespace art {
-  // Result of an attempt to process the command line arguments. If fails, specifies
-  // the specific error code and an error message.
-  // Use the value-carrying CmdlineParseResult<T> to get an additional value out in a success case.
-  struct CmdlineResult {
-    enum Status {
-      kSuccess,
-      // Error codes:
-      kUsage,
-      kFailure,
-      kOutOfRange,
-      kUnknown,
-    };
-
-    // Short-hand for checking if the result was successful.
-    operator bool() const {
-      return IsSuccess();
-    }
-
-    // Check if the operation has succeeded.
-    bool IsSuccess() const { return status_ == kSuccess; }
-    // Check if the operation was not a success.
-    bool IsError() const { return status_ != kSuccess; }
-    // Get the specific status, regardless of whether it's failure or success.
-    Status GetStatus() const { return status_; }
-
-    // Get the error message, *must* only be called for error status results.
-    const std::string& GetMessage() const { assert(IsError()); return message_; }
-
-    // Constructor any status. No message.
-    explicit CmdlineResult(Status status) : status_(status) {}
-
-    // Constructor with an error status, copying the message.
-    CmdlineResult(Status status, const std::string& message)
-      : status_(status), message_(message) {
-      assert(status != kSuccess);
-    }
-
-    // Constructor with an error status, taking over the message.
-    CmdlineResult(Status status, std::string&& message)
-      : status_(status), message_(message) {
-      assert(status != kSuccess);
-    }
-
-    // Make sure copying exists
-    CmdlineResult(const CmdlineResult&) = default;
-    // Make sure moving is cheap
-    CmdlineResult(CmdlineResult&&) = default;
-
-  private:
-    const Status status_;
-    const std::string message_;
+// Result of an attempt to process the command line arguments. If fails, specifies
+// the specific error code and an error message.
+// Use the value-carrying CmdlineParseResult<T> to get an additional value out in a success case.
+struct CmdlineResult {
+  enum Status {
+    kSuccess,
+    // Error codes:
+    kUsage,
+    kFailure,
+    kOutOfRange,
+    kUnknown,
   };
 
-  // TODO: code-generate this
-  static inline std::ostream& operator<<(std::ostream& stream, CmdlineResult::Status status) {
-    switch (status) {
-      case CmdlineResult::kSuccess:
-        stream << "kSuccess";
-        break;
-      case CmdlineResult::kUsage:
-        stream << "kUsage";
-        break;
-      case CmdlineResult::kFailure:
-        stream << "kFailure";
-        break;
-      case CmdlineResult::kOutOfRange:
-        stream << "kOutOfRange";
-        break;
-      case CmdlineResult::kUnknown:
-        stream << "kUnknown";
-        break;
-      default:
-        UNREACHABLE();
-    }
-    return stream;
+  // Short-hand for checking if the result was successful.
+  operator bool() const {
+    return IsSuccess();
   }
 
+  // Check if the operation has succeeded.
+  bool IsSuccess() const { return status_ == kSuccess; }
+  // Check if the operation was not a success.
+  bool IsError() const { return status_ != kSuccess; }
+  // Get the specific status, regardless of whether it's failure or success.
+  Status GetStatus() const { return status_; }
+
+  // Get the error message, *must* only be called for error status results.
+  const std::string& GetMessage() const { assert(IsError()); return message_; }
+
+  // Constructor any status. No message.
+  explicit CmdlineResult(Status status) : status_(status) {}
+
+  // Constructor with an error status, copying the message.
+  CmdlineResult(Status status, const std::string& message)
+    : status_(status), message_(message) {
+    assert(status != kSuccess);
+  }
+
+  // Constructor with an error status, taking over the message.
+  CmdlineResult(Status status, std::string&& message)
+    : status_(status), message_(message) {
+    assert(status != kSuccess);
+  }
+
+  // Make sure copying exists
+  CmdlineResult(const CmdlineResult&) = default;
+  // Make sure moving is cheap
+  CmdlineResult(CmdlineResult&&) = default;
+
+ private:
+  const Status status_;
+  const std::string message_;
+};
+
+// TODO: code-generate this
+static inline std::ostream& operator<<(std::ostream& stream, CmdlineResult::Status status) {
+  switch (status) {
+    case CmdlineResult::kSuccess:
+      stream << "kSuccess";
+      break;
+    case CmdlineResult::kUsage:
+      stream << "kUsage";
+      break;
+    case CmdlineResult::kFailure:
+      stream << "kFailure";
+      break;
+    case CmdlineResult::kOutOfRange:
+      stream << "kOutOfRange";
+      break;
+    case CmdlineResult::kUnknown:
+      stream << "kUnknown";
+      break;
+    default:
+      UNREACHABLE();
+  }
+  return stream;
+}
 }  // namespace art
 
 #endif  // ART_CMDLINE_CMDLINE_RESULT_H_
diff --git a/cmdline/cmdline_types.h b/cmdline/cmdline_types.h
index 4de8a48..cb3140a 100644
--- a/cmdline/cmdline_types.h
+++ b/cmdline/cmdline_types.h
@@ -20,9 +20,9 @@
 
 #include <list>
 
-#include "memory_representation.h"
-#include "detail/cmdline_debug_detail.h"
 #include "cmdline_type_parser.h"
+#include "detail/cmdline_debug_detail.h"
+#include "memory_representation.h"
 
 #include "android-base/strings.h"
 
@@ -34,8 +34,10 @@
 #include "gc/collector_type.h"
 #include "gc/space/large_object_space.h"
 #include "jdwp/jdwp.h"
+#include "jdwp_provider.h"
 #include "jit/profile_saver_options.h"
 #include "plugin.h"
+#include "read_barrier_config.h"
 #include "ti/agent.h"
 #include "unit.h"
 
@@ -56,130 +58,38 @@
 struct CmdlineType<Unit> : CmdlineTypeParser<Unit> {
   Result Parse(const std::string& args) {
     if (args == "") {
-      return Result::Success(Unit{});  // NOLINT [whitespace/braces] [5]
+      return Result::Success(Unit{});
     }
     return Result::Failure("Unexpected extra characters " + args);
   }
 };
 
 template <>
-struct CmdlineType<JDWP::JdwpOptions> : CmdlineTypeParser<JDWP::JdwpOptions> {
+struct CmdlineType<JdwpProvider> : CmdlineTypeParser<JdwpProvider> {
   /*
-   * Handle one of the JDWP name/value pairs.
-   *
-   * JDWP options are:
-   *  help: if specified, show help message and bail
-   *  transport: may be dt_socket or dt_shmem
-   *  address: for dt_socket, "host:port", or just "port" when listening
-   *  server: if "y", wait for debugger to attach; if "n", attach to debugger
-   *  timeout: how long to wait for debugger to connect / listen
-   *
-   * Useful with server=n (these aren't supported yet):
-   *  onthrow=<exception-name>: connect to debugger when exception thrown
-   *  onuncaught=y|n: connect to debugger when uncaught exception thrown
-   *  launch=<command-line>: launch the debugger itself
-   *
-   * The "transport" option is required, as is "address" if server=n.
+   * Handle a single JDWP provider name. Must be either 'internal', 'default', or the file name of
+   * an agent. A plugin will make use of this and the jdwpOptions to set up jdwp when appropriate.
    */
-  Result Parse(const std::string& options) {
-    VLOG(jdwp) << "ParseJdwpOptions: " << options;
-
-    if (options == "help") {
+  Result Parse(const std::string& option) {
+    if (option == "help") {
       return Result::Usage(
-          "Example: -Xrunjdwp:transport=dt_socket,address=8000,server=y\n"
-          "Example: -Xrunjdwp:transport=dt_socket,address=localhost:6500,server=n\n");
-    }
-
-    const std::string s;
-
-    std::vector<std::string> pairs;
-    Split(options, ',', &pairs);
-
-    JDWP::JdwpOptions jdwp_options;
-
-    for (const std::string& jdwp_option : pairs) {
-      std::string::size_type equals_pos = jdwp_option.find('=');
-      if (equals_pos == std::string::npos) {
-        return Result::Failure(s +
-            "Can't parse JDWP option '" + jdwp_option + "' in '" + options + "'");
-      }
-
-      Result parse_attempt = ParseJdwpOption(jdwp_option.substr(0, equals_pos),
-                                             jdwp_option.substr(equals_pos + 1),
-                                             &jdwp_options);
-      if (parse_attempt.IsError()) {
-        // We fail to parse this JDWP option.
-        return parse_attempt;
-      }
-    }
-
-    if (jdwp_options.transport == JDWP::kJdwpTransportUnknown) {
-      return Result::Failure(s + "Must specify JDWP transport: " + options);
-    }
-    if (!jdwp_options.server && (jdwp_options.host.empty() || jdwp_options.port == 0)) {
-      return Result::Failure(s + "Must specify JDWP host and port when server=n: " + options);
-    }
-
-    return Result::Success(std::move(jdwp_options));
-  }
-
-  Result ParseJdwpOption(const std::string& name, const std::string& value,
-                         JDWP::JdwpOptions* jdwp_options) {
-    if (name == "transport") {
-      if (value == "dt_socket") {
-        jdwp_options->transport = JDWP::kJdwpTransportSocket;
-      } else if (value == "dt_android_adb") {
-        jdwp_options->transport = JDWP::kJdwpTransportAndroidAdb;
-      } else {
-        return Result::Failure("JDWP transport not supported: " + value);
-      }
-    } else if (name == "server") {
-      if (value == "n") {
-        jdwp_options->server = false;
-      } else if (value == "y") {
-        jdwp_options->server = true;
-      } else {
-        return Result::Failure("JDWP option 'server' must be 'y' or 'n'");
-      }
-    } else if (name == "suspend") {
-      if (value == "n") {
-        jdwp_options->suspend = false;
-      } else if (value == "y") {
-        jdwp_options->suspend = true;
-      } else {
-        return Result::Failure("JDWP option 'suspend' must be 'y' or 'n'");
-      }
-    } else if (name == "address") {
-      /* this is either <port> or <host>:<port> */
-      std::string port_string;
-      jdwp_options->host.clear();
-      std::string::size_type colon = value.find(':');
-      if (colon != std::string::npos) {
-        jdwp_options->host = value.substr(0, colon);
-        port_string = value.substr(colon + 1);
-      } else {
-        port_string = value;
-      }
-      if (port_string.empty()) {
-        return Result::Failure("JDWP address missing port: " + value);
-      }
-      char* end;
-      uint64_t port = strtoul(port_string.c_str(), &end, 10);
-      if (*end != '\0' || port > 0xffff) {
-        return Result::Failure("JDWP address has junk in port field: " + value);
-      }
-      jdwp_options->port = port;
-    } else if (name == "launch" || name == "onthrow" || name == "oncaught" || name == "timeout") {
-      /* valid but unsupported */
-      LOG(INFO) << "Ignoring JDWP option '" << name << "'='" << value << "'";
+          "Example: -XjdwpProvider:none to disable JDWP\n"
+          "Example: -XjdwpProvider:internal for internal jdwp implementation\n"
+          "Example: -XjdwpProvider:adbconnection for adb connection mediated jdwp implementation\n"
+          "Example: -XjdwpProvider:default for the default jdwp implementation\n");
+    } else if (option == "default") {
+      return Result::Success(JdwpProvider::kDefaultJdwpProvider);
+    } else if (option == "internal") {
+      return Result::Success(JdwpProvider::kInternal);
+    } else if (option == "adbconnection") {
+      return Result::Success(JdwpProvider::kAdbConnection);
+    } else if (option == "none") {
+      return Result::Success(JdwpProvider::kNone);
     } else {
-      LOG(INFO) << "Ignoring unrecognized JDWP option '" << name << "'='" << value << "'";
+      return Result::Failure(std::string("not a valid jdwp provider: ") + option);
     }
-
-    return Result::SuccessNoValue();
   }
-
-  static const char* Name() { return "JdwpOptions"; }
+  static const char* Name() { return "JdwpProvider"; }
 };
 
 template <size_t Divisor>
@@ -289,26 +199,42 @@
   static const char* Name() { return "double"; }
 };
 
+template <typename T>
+static inline CmdlineParseResult<T> ParseNumeric(const std::string& str) {
+  static_assert(sizeof(T) < sizeof(long long int),  // NOLINT [runtime/int] [4]
+                "Current support is restricted.");
+
+  const char* begin = str.c_str();
+  char* end;
+
+  // Parse into a larger type (long long) because we can't use strtoul
+  // since it silently converts negative values into unsigned long and doesn't set errno.
+  errno = 0;
+  long long int result = strtoll(begin, &end, 10);  // NOLINT [runtime/int] [4]
+  if (begin == end || *end != '\0' || errno == EINVAL) {
+    return CmdlineParseResult<T>::Failure("Failed to parse integer from " + str);
+  } else if ((errno == ERANGE) ||  // NOLINT [runtime/int] [4]
+      result < std::numeric_limits<T>::min() || result > std::numeric_limits<T>::max()) {
+    return CmdlineParseResult<T>::OutOfRange(
+        "Failed to parse integer from " + str + "; out of range");
+  }
+
+  return CmdlineParseResult<T>::Success(static_cast<T>(result));
+}
+
 template <>
 struct CmdlineType<unsigned int> : CmdlineTypeParser<unsigned int> {
   Result Parse(const std::string& str) {
-    const char* begin = str.c_str();
-    char* end;
+    return ParseNumeric<unsigned int>(str);
+  }
 
-    // Parse into a larger type (long long) because we can't use strtoul
-    // since it silently converts negative values into unsigned long and doesn't set errno.
-    errno = 0;
-    long long int result = strtoll(begin, &end, 10);  // NOLINT [runtime/int] [4]
-    if (begin == end || *end != '\0' || errno == EINVAL) {
-      return Result::Failure("Failed to parse integer from " + str);
-    } else if ((errno == ERANGE) ||  // NOLINT [runtime/int] [4]
-        result < std::numeric_limits<int>::min()
-        || result > std::numeric_limits<unsigned int>::max() || result < 0) {
-      return Result::OutOfRange(
-          "Failed to parse integer from " + str + "; out of unsigned int range");
-    }
+  static const char* Name() { return "unsigned integer"; }
+};
 
-    return Result::Success(static_cast<unsigned int>(result));
+template <>
+struct CmdlineType<int> : CmdlineTypeParser<int> {
+  Result Parse(const std::string& str) {
+    return ParseNumeric<int>(str);
   }
 
   static const char* Name() { return "unsigned integer"; }
@@ -403,19 +329,19 @@
 };
 
 template <>
-struct CmdlineType<std::list<ti::Agent>> : CmdlineTypeParser<std::list<ti::Agent>> {
+struct CmdlineType<std::list<ti::AgentSpec>> : CmdlineTypeParser<std::list<ti::AgentSpec>> {
   Result Parse(const std::string& args) {
     assert(false && "Use AppendValues() for an Agent list type");
     return Result::Failure("Unconditional failure: Agent list must be appended: " + args);
   }
 
   Result ParseAndAppend(const std::string& args,
-                        std::list<ti::Agent>& existing_value) {
+                        std::list<ti::AgentSpec>& existing_value) {
     existing_value.emplace_back(args);
     return Result::SuccessNoValue();
   }
 
-  static const char* Name() { return "std::list<ti::Agent>"; }
+  static const char* Name() { return "std::list<ti::AgentSpec>"; }
 };
 
 template <>
@@ -515,7 +441,7 @@
 template <>
 struct CmdlineType<XGcOption> : CmdlineTypeParser<XGcOption> {
   Result Parse(const std::string& option) {  // -Xgc: already stripped
-    XGcOption xgc{};  // NOLINT [readability/braces] [4]
+    XGcOption xgc{};
 
     std::vector<std::string> gc_options;
     Split(option, ',', &gc_options);
@@ -652,6 +578,8 @@
         log_verbosity.threads = true;
       } else if (verbose_options[j] == "verifier") {
         log_verbosity.verifier = true;
+      } else if (verbose_options[j] == "verifier-debug") {
+        log_verbosity.verifier_debug = true;
       } else if (verbose_options[j] == "image") {
         log_verbosity.image = true;
       } else if (verbose_options[j] == "systrace-locks") {
@@ -717,6 +645,16 @@
       return Result::SuccessNoValue();
     }
 
+    if (option == "profile-aot-code") {
+      existing.profile_aot_code_ = true;
+      return Result::SuccessNoValue();
+    }
+
+    if (option == "save-without-jit-notifications") {
+      existing.wait_for_jit_notifications_to_save_ = false;
+      return Result::SuccessNoValue();
+    }
+
     // The rest of these options are always the wildcard from '-Xps-*'
     std::string suffix = RemovePrefix(option);
 
diff --git a/cmdline/detail/cmdline_debug_detail.h b/cmdline/detail/cmdline_debug_detail.h
index 79028f4..e69d5dc 100644
--- a/cmdline/detail/cmdline_debug_detail.h
+++ b/cmdline/detail/cmdline_debug_detail.h
@@ -25,16 +25,16 @@
 #endif
 
 namespace art {
-  // Implementation details for some template querying. Don't look inside if you hate templates.
-  namespace detail {
-    struct debug_log_ignore {
-      // Ignore most of the normal operator<< usage.
-      template <typename T>
-      debug_log_ignore& operator<<(const T&) { return *this; }
-      // Ignore std::endl and the like.
-      debug_log_ignore& operator<<(std::ostream& (*)(std::ostream&) ) { return *this; }
-    };
-  }  // namespace detail  // NOLINT [readability/namespace] [5]
+// Implementation details for some template querying. Don't look inside if you hate templates.
+namespace detail {
+struct debug_log_ignore {
+  // Ignore most of the normal operator<< usage.
+  template <typename T>
+  debug_log_ignore& operator<<(const T&) { return *this; }
+  // Ignore std::endl and the like.
+  debug_log_ignore& operator<<(std::ostream& (*)(std::ostream&) ) { return *this; }
+};
+}  // namespace detail  // NOLINT [readability/namespace] [5]
 }  // namespace art
 
 #endif  // ART_CMDLINE_DETAIL_CMDLINE_DEBUG_DETAIL_H_
diff --git a/cmdline/detail/cmdline_parse_argument_detail.h b/cmdline/detail/cmdline_parse_argument_detail.h
index da03c21..2fee27c 100644
--- a/cmdline/detail/cmdline_parse_argument_detail.h
+++ b/cmdline/detail/cmdline_parse_argument_detail.h
@@ -17,13 +17,13 @@
 #ifndef ART_CMDLINE_DETAIL_CMDLINE_PARSE_ARGUMENT_DETAIL_H_
 #define ART_CMDLINE_DETAIL_CMDLINE_PARSE_ARGUMENT_DETAIL_H_
 
-#include <type_traits>
 #include <assert.h>
-#include <functional>
-#include <vector>
 #include <algorithm>
-#include <numeric>
+#include <functional>
 #include <memory>
+#include <numeric>
+#include <type_traits>
+#include <vector>
 
 #include "android-base/strings.h"
 
@@ -33,473 +33,473 @@
 #include "unit.h"
 
 namespace art {
-  // Implementation details for the parser. Do not look inside if you hate templates.
-  namespace detail {
-    // A non-templated base class for argument parsers. Used by the general parser
-    // to parse arguments, without needing to know the argument type at compile time.
-    //
-    // This is an application of the type erasure idiom.
-    struct CmdlineParseArgumentAny {
-      virtual ~CmdlineParseArgumentAny() {}
+// Implementation details for the parser. Do not look inside if you hate templates.
+namespace detail {
+// A non-templated base class for argument parsers. Used by the general parser
+// to parse arguments, without needing to know the argument type at compile time.
+//
+// This is an application of the type erasure idiom.
+struct CmdlineParseArgumentAny {
+  virtual ~CmdlineParseArgumentAny() {}
 
-      // Attempt to parse this argument starting at arguments[position].
-      // If the parsing succeeds, the parsed value will be saved as a side-effect.
-      //
-      // In most situations, the parsing will not match by returning kUnknown. In this case,
-      // no tokens were consumed and the position variable will not be updated.
-      //
-      // At other times, parsing may fail due to validation but the initial token was still matched
-      // (for example an out of range value, or passing in a string where an int was expected).
-      // In this case the tokens are still consumed, and the position variable will get incremented
-      // by all the consumed tokens.
-      //
-      // The # of tokens consumed by the parse attempt will be set as an out-parameter into
-      // consumed_tokens. The parser should skip this many tokens before parsing the next
-      // argument.
-      virtual CmdlineResult ParseArgument(const TokenRange& arguments, size_t* consumed_tokens) = 0;
-      // How many tokens should be taken off argv for parsing this argument.
-      // For example "--help" is just 1, "-compiler-option _" would be 2 (since there's a space).
-      //
-      // A [min,max] range is returned to represent argument definitions with multiple
-      // value tokens. (e.g. {"-h", "-h " } would return [1,2]).
-      virtual std::pair<size_t, size_t> GetNumTokens() const = 0;
-      // Get the run-time typename of the argument type.
-      virtual const char* GetTypeName() const = 0;
-      // Try to do a close match, returning how many tokens were matched against this argument
-      // definition. More tokens is better.
-      //
-      // Do a quick match token-by-token, and see if they match.
-      // Any tokens with a wildcard in them are only matched up until the wildcard.
-      // If this is true, then the wildcard matching later on can still fail, so this is not
-      // a guarantee that the argument is correct, it's more of a strong hint that the
-      // user-provided input *probably* was trying to match this argument.
-      //
-      // Returns how many tokens were either matched (or ignored because there was a
-      // wildcard present). 0 means no match. If the Size() tokens are returned.
-      virtual size_t MaybeMatches(const TokenRange& tokens) = 0;
-    };
+  // Attempt to parse this argument starting at arguments[position].
+  // If the parsing succeeds, the parsed value will be saved as a side-effect.
+  //
+  // In most situations, the parsing will not match by returning kUnknown. In this case,
+  // no tokens were consumed and the position variable will not be updated.
+  //
+  // At other times, parsing may fail due to validation but the initial token was still matched
+  // (for example an out of range value, or passing in a string where an int was expected).
+  // In this case the tokens are still consumed, and the position variable will get incremented
+  // by all the consumed tokens.
+  //
+  // The # of tokens consumed by the parse attempt will be set as an out-parameter into
+  // consumed_tokens. The parser should skip this many tokens before parsing the next
+  // argument.
+  virtual CmdlineResult ParseArgument(const TokenRange& arguments, size_t* consumed_tokens) = 0;
+  // How many tokens should be taken off argv for parsing this argument.
+  // For example "--help" is just 1, "-compiler-option _" would be 2 (since there's a space).
+  //
+  // A [min,max] range is returned to represent argument definitions with multiple
+  // value tokens. (e.g. {"-h", "-h " } would return [1,2]).
+  virtual std::pair<size_t, size_t> GetNumTokens() const = 0;
+  // Get the run-time typename of the argument type.
+  virtual const char* GetTypeName() const = 0;
+  // Try to do a close match, returning how many tokens were matched against this argument
+  // definition. More tokens is better.
+  //
+  // Do a quick match token-by-token, and see if they match.
+  // Any tokens with a wildcard in them are only matched up until the wildcard.
+  // If this is true, then the wildcard matching later on can still fail, so this is not
+  // a guarantee that the argument is correct, it's more of a strong hint that the
+  // user-provided input *probably* was trying to match this argument.
+  //
+  // Returns how many tokens were either matched (or ignored because there was a
+  // wildcard present). 0 means no match. If the Size() tokens are returned.
+  virtual size_t MaybeMatches(const TokenRange& tokens) = 0;
+};
 
-    template <typename T>
-    using EnableIfNumeric = std::enable_if<std::is_arithmetic<T>::value>;
+template <typename T>
+using EnableIfNumeric = std::enable_if<std::is_arithmetic<T>::value>;
 
-    template <typename T>
-    using DisableIfNumeric = std::enable_if<!std::is_arithmetic<T>::value>;
+template <typename T>
+using DisableIfNumeric = std::enable_if<!std::is_arithmetic<T>::value>;
 
-    // Argument definition information, created by an ArgumentBuilder and an UntypedArgumentBuilder.
-    template <typename TArg>
-    struct CmdlineParserArgumentInfo {
-      // This version will only be used if TArg is arithmetic and thus has the <= operators.
-      template <typename T = TArg>  // Necessary to get SFINAE to kick in.
-      bool CheckRange(const TArg& value, typename EnableIfNumeric<T>::type* = 0) {
-        if (has_range_) {
-          return min_ <= value && value <= max_;
-        }
-        return true;
+// Argument definition information, created by an ArgumentBuilder and an UntypedArgumentBuilder.
+template <typename TArg>
+struct CmdlineParserArgumentInfo {
+  // This version will only be used if TArg is arithmetic and thus has the <= operators.
+  template <typename T = TArg>  // Necessary to get SFINAE to kick in.
+  bool CheckRange(const TArg& value, typename EnableIfNumeric<T>::type* = 0) {
+    if (has_range_) {
+      return min_ <= value && value <= max_;
+    }
+    return true;
+  }
+
+  // This version will be used at other times when TArg is not arithmetic.
+  template <typename T = TArg>
+  bool CheckRange(const TArg&, typename DisableIfNumeric<T>::type* = 0) {
+    assert(!has_range_);
+    return true;
+  }
+
+  // Do a quick match token-by-token, and see if they match.
+  // Any tokens with a wildcard in them only match the prefix up until the wildcard.
+  //
+  // If this is true, then the wildcard matching later on can still fail, so this is not
+  // a guarantee that the argument is correct, it's more of a strong hint that the
+  // user-provided input *probably* was trying to match this argument.
+  size_t MaybeMatches(const TokenRange& token_list) const {
+    auto best_match = FindClosestMatch(token_list);
+
+    return best_match.second;
+  }
+
+  // Attempt to find the closest match (see MaybeMatches).
+  //
+  // Returns the token range that was the closest match and the # of tokens that
+  // this range was matched up until.
+  std::pair<const TokenRange*, size_t> FindClosestMatch(const TokenRange& token_list) const {
+    const TokenRange* best_match_ptr = nullptr;
+
+    size_t best_match = 0;
+    for (auto&& token_range : tokenized_names_) {
+      size_t this_match = token_range.MaybeMatches(token_list, std::string("_"));
+
+      if (this_match > best_match) {
+        best_match_ptr = &token_range;
+        best_match = this_match;
+      }
+    }
+
+    return std::make_pair(best_match_ptr, best_match);
+  }
+
+  // Mark the argument definition as completed, do not mutate the object anymore after this
+  // call is done.
+  //
+  // Performs several sanity checks and token calculations.
+  void CompleteArgument() {
+    assert(names_.size() >= 1);
+    assert(!is_completed_);
+
+    is_completed_ = true;
+
+    size_t blank_count = 0;
+    size_t token_count = 0;
+
+    size_t global_blank_count = 0;
+    size_t global_token_count = 0;
+    for (auto&& name : names_) {
+      std::string s(name);
+
+      size_t local_blank_count = std::count(s.begin(), s.end(), '_');
+      size_t local_token_count = std::count(s.begin(), s.end(), ' ');
+
+      if (global_blank_count != 0) {
+        assert(local_blank_count == global_blank_count
+               && "Every argument descriptor string must have same amount of blanks (_)");
       }
 
-      // This version will be used at other times when TArg is not arithmetic.
-      template <typename T = TArg>
-      bool CheckRange(const TArg&, typename DisableIfNumeric<T>::type* = 0) {
-        assert(!has_range_);
-        return true;
+      if (local_blank_count != 0) {
+        global_blank_count = local_blank_count;
+        blank_count++;
+
+        assert(local_blank_count == 1 && "More than one blank is not supported");
+        assert(s.back() == '_' && "The blank character must only be at the end of the string");
       }
 
-      // Do a quick match token-by-token, and see if they match.
-      // Any tokens with a wildcard in them only match the prefix up until the wildcard.
-      //
-      // If this is true, then the wildcard matching later on can still fail, so this is not
-      // a guarantee that the argument is correct, it's more of a strong hint that the
-      // user-provided input *probably* was trying to match this argument.
-      size_t MaybeMatches(const TokenRange& token_list) const {
-        auto best_match = FindClosestMatch(token_list);
-
-        return best_match.second;
+      if (global_token_count != 0) {
+        assert(local_token_count == global_token_count
+               && "Every argument descriptor string must have same amount of tokens (spaces)");
       }
 
-      // Attempt to find the closest match (see MaybeMatches).
-      //
-      // Returns the token range that was the closest match and the # of tokens that
-      // this range was matched up until.
-      std::pair<const TokenRange*, size_t> FindClosestMatch(const TokenRange& token_list) const {
-        const TokenRange* best_match_ptr = nullptr;
-
-        size_t best_match = 0;
-        for (auto&& token_range : tokenized_names_) {
-          size_t this_match = token_range.MaybeMatches(token_list, std::string("_"));
-
-          if (this_match > best_match) {
-            best_match_ptr = &token_range;
-            best_match = this_match;
-          }
-        }
-
-        return std::make_pair(best_match_ptr, best_match);
+      if (local_token_count != 0) {
+        global_token_count = local_token_count;
+        token_count++;
       }
 
-      // Mark the argument definition as completed, do not mutate the object anymore after this
-      // call is done.
-      //
-      // Performs several sanity checks and token calculations.
-      void CompleteArgument() {
-        assert(names_.size() >= 1);
-        assert(!is_completed_);
-
-        is_completed_ = true;
-
-        size_t blank_count = 0;
-        size_t token_count = 0;
-
-        size_t global_blank_count = 0;
-        size_t global_token_count = 0;
-        for (auto&& name : names_) {
-          std::string s(name);
-
-          size_t local_blank_count = std::count(s.begin(), s.end(), '_');
-          size_t local_token_count = std::count(s.begin(), s.end(), ' ');
-
-          if (global_blank_count != 0) {
-            assert(local_blank_count == global_blank_count
-                   && "Every argument descriptor string must have same amount of blanks (_)");
-          }
-
-          if (local_blank_count != 0) {
-            global_blank_count = local_blank_count;
-            blank_count++;
-
-            assert(local_blank_count == 1 && "More than one blank is not supported");
-            assert(s.back() == '_' && "The blank character must only be at the end of the string");
-          }
-
-          if (global_token_count != 0) {
-            assert(local_token_count == global_token_count
-                   && "Every argument descriptor string must have same amount of tokens (spaces)");
-          }
-
-          if (local_token_count != 0) {
-            global_token_count = local_token_count;
-            token_count++;
-          }
-
-          // Tokenize every name, turning it from a string to a token list.
-          tokenized_names_.clear();
-          for (auto&& name1 : names_) {
-            // Split along ' ' only, removing any duplicated spaces.
-            tokenized_names_.push_back(
-                TokenRange::Split(name1, {' '}).RemoveToken(" "));
-          }
-
-          // remove the _ character from each of the token ranges
-          // we will often end up with an empty token (i.e. ["-XX", "_"] -> ["-XX", ""]
-          // and this is OK because we still need an empty token to simplify
-          // range comparisons
-          simple_names_.clear();
-
-          for (auto&& tokenized_name : tokenized_names_) {
-            simple_names_.push_back(tokenized_name.RemoveCharacter('_'));
-          }
-        }
-
-        if (token_count != 0) {
-          assert(("Every argument descriptor string must have equal amount of tokens (spaces)" &&
-              token_count == names_.size()));
-        }
-
-        if (blank_count != 0) {
-          assert(("Every argument descriptor string must have an equal amount of blanks (_)" &&
-              blank_count == names_.size()));
-        }
-
-        using_blanks_ = blank_count > 0;
-        {
-          size_t smallest_name_token_range_size =
-              std::accumulate(tokenized_names_.begin(), tokenized_names_.end(), ~(0u),
-                              [](size_t min, const TokenRange& cur) {
-                                return std::min(min, cur.Size());
-                              });
-          size_t largest_name_token_range_size =
-              std::accumulate(tokenized_names_.begin(), tokenized_names_.end(), 0u,
-                              [](size_t max, const TokenRange& cur) {
-                                return std::max(max, cur.Size());
-                              });
-
-          token_range_size_ = std::make_pair(smallest_name_token_range_size,
-                                             largest_name_token_range_size);
-        }
-
-        if (has_value_list_) {
-          assert(names_.size() == value_list_.size()
-                 && "Number of arg descriptors must match number of values");
-          assert(!has_value_map_);
-        }
-        if (has_value_map_) {
-          if (!using_blanks_) {
-            assert(names_.size() == value_map_.size() &&
-                   "Since no blanks were specified, each arg is mapped directly into a mapped "
-                   "value without parsing; sizes must match");
-          }
-
-          assert(!has_value_list_);
-        }
-
-        if (!using_blanks_ && !CmdlineType<TArg>::kCanParseBlankless) {
-          assert((has_value_map_ || has_value_list_) &&
-                 "Arguments without a blank (_) must provide either a value map or a value list");
-        }
-
-        TypedCheck();
+      // Tokenize every name, turning it from a string to a token list.
+      tokenized_names_.clear();
+      for (auto&& name1 : names_) {
+        // Split along ' ' only, removing any duplicated spaces.
+        tokenized_names_.push_back(
+            TokenRange::Split(name1, {' '}).RemoveToken(" "));
       }
 
-      // List of aliases for a single argument definition, e.g. {"-Xdex2oat", "-Xnodex2oat"}.
-      std::vector<const char*> names_;
-      // Is there at least 1 wildcard '_' in the argument definition?
-      bool using_blanks_ = false;
-      // [min, max] token counts in each arg def
-      std::pair<size_t, size_t> token_range_size_;
+      // remove the _ character from each of the token ranges
+      // we will often end up with an empty token (i.e. ["-XX", "_"] -> ["-XX", ""]
+      // and this is OK because we still need an empty token to simplify
+      // range comparisons
+      simple_names_.clear();
 
-      // contains all the names in a tokenized form, i.e. as a space-delimited list
-      std::vector<TokenRange> tokenized_names_;
+      for (auto&& tokenized_name : tokenized_names_) {
+        simple_names_.push_back(tokenized_name.RemoveCharacter('_'));
+      }
+    }
 
-      // contains the tokenized names, but with the _ character stripped
-      std::vector<TokenRange> simple_names_;
+    if (token_count != 0) {
+      assert(("Every argument descriptor string must have equal amount of tokens (spaces)" &&
+          token_count == names_.size()));
+    }
 
-      // For argument definitions created with '.AppendValues()'
-      // Meaning that parsing should mutate the existing value in-place if possible.
-      bool appending_values_ = false;
+    if (blank_count != 0) {
+      assert(("Every argument descriptor string must have an equal amount of blanks (_)" &&
+          blank_count == names_.size()));
+    }
 
-      // For argument definitions created with '.WithRange(min, max)'
-      bool has_range_ = false;
-      TArg min_;
-      TArg max_;
+    using_blanks_ = blank_count > 0;
+    {
+      size_t smallest_name_token_range_size =
+          std::accumulate(tokenized_names_.begin(), tokenized_names_.end(), ~(0u),
+                          [](size_t min, const TokenRange& cur) {
+                            return std::min(min, cur.Size());
+                          });
+      size_t largest_name_token_range_size =
+          std::accumulate(tokenized_names_.begin(), tokenized_names_.end(), 0u,
+                          [](size_t max, const TokenRange& cur) {
+                            return std::max(max, cur.Size());
+                          });
 
-      // For argument definitions created with '.WithValueMap'
-      bool has_value_map_ = false;
-      std::vector<std::pair<const char*, TArg>> value_map_;
+      token_range_size_ = std::make_pair(smallest_name_token_range_size,
+                                         largest_name_token_range_size);
+    }
 
-      // For argument definitions created with '.WithValues'
-      bool has_value_list_ = false;
-      std::vector<TArg> value_list_;
-
-      // Make sure there's a default constructor.
-      CmdlineParserArgumentInfo() = default;
-
-      // Ensure there's a default move constructor.
-      CmdlineParserArgumentInfo(CmdlineParserArgumentInfo&&) = default;
-
-     private:
-      // Perform type-specific checks at runtime.
-      template <typename T = TArg>
-      void TypedCheck(typename std::enable_if<std::is_same<Unit, T>::value>::type* = 0) {
-        assert(!using_blanks_ &&
-               "Blanks are not supported in Unit arguments; since a Unit has no parse-able value");
+    if (has_value_list_) {
+      assert(names_.size() == value_list_.size()
+             && "Number of arg descriptors must match number of values");
+      assert(!has_value_map_);
+    }
+    if (has_value_map_) {
+      if (!using_blanks_) {
+        assert(names_.size() == value_map_.size() &&
+               "Since no blanks were specified, each arg is mapped directly into a mapped "
+               "value without parsing; sizes must match");
       }
 
-      void TypedCheck() {}
+      assert(!has_value_list_);
+    }
 
-      bool is_completed_ = false;
-    };
+    if (!using_blanks_ && !CmdlineType<TArg>::kCanParseBlankless) {
+      assert((has_value_map_ || has_value_list_) &&
+             "Arguments without a blank (_) must provide either a value map or a value list");
+    }
 
-    // A virtual-implementation of the necessary argument information in order to
-    // be able to parse arguments.
-    template <typename TArg>
-    struct CmdlineParseArgument : CmdlineParseArgumentAny {
-      CmdlineParseArgument(CmdlineParserArgumentInfo<TArg>&& argument_info,
-                           std::function<void(TArg&)>&& save_argument,
-                           std::function<TArg&(void)>&& load_argument)
-          : argument_info_(std::forward<decltype(argument_info)>(argument_info)),
-            save_argument_(std::forward<decltype(save_argument)>(save_argument)),
-            load_argument_(std::forward<decltype(load_argument)>(load_argument)) {
-      }
+    TypedCheck();
+  }
 
-      using UserTypeInfo = CmdlineType<TArg>;
+  // List of aliases for a single argument definition, e.g. {"-Xdex2oat", "-Xnodex2oat"}.
+  std::vector<const char*> names_;
+  // Is there at least 1 wildcard '_' in the argument definition?
+  bool using_blanks_ = false;
+  // [min, max] token counts in each arg def
+  std::pair<size_t, size_t> token_range_size_;
 
-      virtual CmdlineResult ParseArgument(const TokenRange& arguments, size_t* consumed_tokens) {
-        assert(arguments.Size() > 0);
-        assert(consumed_tokens != nullptr);
+  // contains all the names in a tokenized form, i.e. as a space-delimited list
+  std::vector<TokenRange> tokenized_names_;
 
-        auto closest_match_res = argument_info_.FindClosestMatch(arguments);
-        size_t best_match_size = closest_match_res.second;
-        const TokenRange* best_match_arg_def = closest_match_res.first;
+  // contains the tokenized names, but with the _ character stripped
+  std::vector<TokenRange> simple_names_;
 
-        if (best_match_size > arguments.Size()) {
-          // The best match has more tokens than were provided.
-          // Shouldn't happen in practice since the outer parser does this check.
-          return CmdlineResult(CmdlineResult::kUnknown, "Size mismatch");
-        }
+  // For argument definitions created with '.AppendValues()'
+  // Meaning that parsing should mutate the existing value in-place if possible.
+  bool appending_values_ = false;
 
-        assert(best_match_arg_def != nullptr);
-        *consumed_tokens = best_match_arg_def->Size();
+  // For argument definitions created with '.WithRange(min, max)'
+  bool has_range_ = false;
+  TArg min_;
+  TArg max_;
 
-        if (!argument_info_.using_blanks_) {
-          return ParseArgumentSingle(arguments.Join(' '));
-        }
+  // For argument definitions created with '.WithValueMap'
+  bool has_value_map_ = false;
+  std::vector<std::pair<const char*, TArg>> value_map_;
 
-        // Extract out the blank value from arguments
-        // e.g. for a def of "foo:_" and input "foo:bar", blank_value == "bar"
-        std::string blank_value = "";
-        size_t idx = 0;
-        for (auto&& def_token : *best_match_arg_def) {
-          auto&& arg_token = arguments[idx];
+  // For argument definitions created with '.WithValues'
+  bool has_value_list_ = false;
+  std::vector<TArg> value_list_;
 
-          // Does this definition-token have a wildcard in it?
-          if (def_token.find('_') == std::string::npos) {
-            // No, regular token. Match 1:1 against the argument token.
-            bool token_match = def_token == arg_token;
+  // Make sure there's a default constructor.
+  CmdlineParserArgumentInfo() = default;
 
-            if (!token_match) {
-              return CmdlineResult(CmdlineResult::kFailure,
-                                   std::string("Failed to parse ") + best_match_arg_def->GetToken(0)
-                                   + " at token " + std::to_string(idx));
-            }
-          } else {
-            // This is a wild-carded token.
-            TokenRange def_split_wildcards = TokenRange::Split(def_token, {'_'});
+  // Ensure there's a default move constructor.
+  CmdlineParserArgumentInfo(CmdlineParserArgumentInfo&&) = default;
 
-            // Extract the wildcard contents out of the user-provided arg_token.
-            std::unique_ptr<TokenRange> arg_matches =
-                def_split_wildcards.MatchSubstrings(arg_token, "_");
-            if (arg_matches == nullptr) {
-              return CmdlineResult(CmdlineResult::kFailure,
-                                   std::string("Failed to parse ") + best_match_arg_def->GetToken(0)
-                                   + ", with a wildcard pattern " + def_token
-                                   + " at token " + std::to_string(idx));
-            }
+ private:
+  // Perform type-specific checks at runtime.
+  template <typename T = TArg>
+  void TypedCheck(typename std::enable_if<std::is_same<Unit, T>::value>::type* = 0) {
+    assert(!using_blanks_ &&
+           "Blanks are not supported in Unit arguments; since a Unit has no parse-able value");
+  }
 
-            // Get the corresponding wildcard tokens from arg_matches,
-            // and concatenate it to blank_value.
-            for (size_t sub_idx = 0;
-                sub_idx < def_split_wildcards.Size() && sub_idx < arg_matches->Size(); ++sub_idx) {
-              if (def_split_wildcards[sub_idx] == "_") {
-                blank_value += arg_matches->GetToken(sub_idx);
-              }
-            }
-          }
+  void TypedCheck() {}
 
-          ++idx;
-        }
+  bool is_completed_ = false;
+};
 
-        return ParseArgumentSingle(blank_value);
-      }
+// A virtual-implementation of the necessary argument information in order to
+// be able to parse arguments.
+template <typename TArg>
+struct CmdlineParseArgument : CmdlineParseArgumentAny {
+  CmdlineParseArgument(CmdlineParserArgumentInfo<TArg>&& argument_info,
+                       std::function<void(TArg&)>&& save_argument,
+                       std::function<TArg&(void)>&& load_argument)
+      : argument_info_(std::forward<decltype(argument_info)>(argument_info)),
+        save_argument_(std::forward<decltype(save_argument)>(save_argument)),
+        load_argument_(std::forward<decltype(load_argument)>(load_argument)) {
+  }
 
-     private:
-      virtual CmdlineResult ParseArgumentSingle(const std::string& argument) {
-        // TODO: refactor to use LookupValue for the value lists/maps
+  using UserTypeInfo = CmdlineType<TArg>;
 
-        // Handle the 'WithValueMap(...)' argument definition
-        if (argument_info_.has_value_map_) {
-          for (auto&& value_pair : argument_info_.value_map_) {
-            const char* name = value_pair.first;
+  virtual CmdlineResult ParseArgument(const TokenRange& arguments, size_t* consumed_tokens) {
+    assert(arguments.Size() > 0);
+    assert(consumed_tokens != nullptr);
 
-            if (argument == name) {
-              return SaveArgument(value_pair.second);
-            }
-          }
+    auto closest_match_res = argument_info_.FindClosestMatch(arguments);
+    size_t best_match_size = closest_match_res.second;
+    const TokenRange* best_match_arg_def = closest_match_res.first;
 
-          // Error case: Fail, telling the user what the allowed values were.
-          std::vector<std::string> allowed_values;
-          for (auto&& value_pair : argument_info_.value_map_) {
-            const char* name = value_pair.first;
-            allowed_values.push_back(name);
-          }
+    if (best_match_size > arguments.Size()) {
+      // The best match has more tokens than were provided.
+      // Shouldn't happen in practice since the outer parser does this check.
+      return CmdlineResult(CmdlineResult::kUnknown, "Size mismatch");
+    }
 
-          std::string allowed_values_flat = android::base::Join(allowed_values, ',');
+    assert(best_match_arg_def != nullptr);
+    *consumed_tokens = best_match_arg_def->Size();
+
+    if (!argument_info_.using_blanks_) {
+      return ParseArgumentSingle(arguments.Join(' '));
+    }
+
+    // Extract out the blank value from arguments
+    // e.g. for a def of "foo:_" and input "foo:bar", blank_value == "bar"
+    std::string blank_value = "";
+    size_t idx = 0;
+    for (auto&& def_token : *best_match_arg_def) {
+      auto&& arg_token = arguments[idx];
+
+      // Does this definition-token have a wildcard in it?
+      if (def_token.find('_') == std::string::npos) {
+        // No, regular token. Match 1:1 against the argument token.
+        bool token_match = def_token == arg_token;
+
+        if (!token_match) {
           return CmdlineResult(CmdlineResult::kFailure,
-                               "Argument value '" + argument + "' does not match any of known valid"
-                                "values: {" + allowed_values_flat + "}");
+                               std::string("Failed to parse ") + best_match_arg_def->GetToken(0)
+                               + " at token " + std::to_string(idx));
         }
+      } else {
+        // This is a wild-carded token.
+        TokenRange def_split_wildcards = TokenRange::Split(def_token, {'_'});
 
-        // Handle the 'WithValues(...)' argument definition
-        if (argument_info_.has_value_list_) {
-          size_t arg_def_idx = 0;
-          for (auto&& value : argument_info_.value_list_) {
-            auto&& arg_def_token = argument_info_.names_[arg_def_idx];
-
-            if (arg_def_token == argument) {
-              return SaveArgument(value);
-            }
-            ++arg_def_idx;
-          }
-
-          assert(arg_def_idx + 1 == argument_info_.value_list_.size() &&
-                 "Number of named argument definitions must match number of values defined");
-
-          // Error case: Fail, telling the user what the allowed values were.
-          std::vector<std::string> allowed_values;
-          for (auto&& arg_name : argument_info_.names_) {
-            allowed_values.push_back(arg_name);
-          }
-
-          std::string allowed_values_flat = android::base::Join(allowed_values, ',');
+        // Extract the wildcard contents out of the user-provided arg_token.
+        std::unique_ptr<TokenRange> arg_matches =
+            def_split_wildcards.MatchSubstrings(arg_token, "_");
+        if (arg_matches == nullptr) {
           return CmdlineResult(CmdlineResult::kFailure,
-                               "Argument value '" + argument + "' does not match any of known valid"
-                                "values: {" + allowed_values_flat + "}");
+                               std::string("Failed to parse ") + best_match_arg_def->GetToken(0)
+                               + ", with a wildcard pattern " + def_token
+                               + " at token " + std::to_string(idx));
         }
 
-        // Handle the regular case where we parsed an unknown value from a blank.
-        UserTypeInfo type_parser;
-
-        if (argument_info_.appending_values_) {
-          TArg& existing = load_argument_();
-          CmdlineParseResult<TArg> result = type_parser.ParseAndAppend(argument, existing);
-
-          assert(!argument_info_.has_range_);
-
-          return result;
-        }
-
-        CmdlineParseResult<TArg> result = type_parser.Parse(argument);
-
-        if (result.IsSuccess()) {
-          TArg& value = result.GetValue();
-
-          // Do a range check for 'WithRange(min,max)' argument definition.
-          if (!argument_info_.CheckRange(value)) {
-            return CmdlineParseResult<TArg>::OutOfRange(
-                value, argument_info_.min_, argument_info_.max_);
+        // Get the corresponding wildcard tokens from arg_matches,
+        // and concatenate it to blank_value.
+        for (size_t sub_idx = 0;
+            sub_idx < def_split_wildcards.Size() && sub_idx < arg_matches->Size(); ++sub_idx) {
+          if (def_split_wildcards[sub_idx] == "_") {
+            blank_value += arg_matches->GetToken(sub_idx);
           }
+        }
+      }
 
+      ++idx;
+    }
+
+    return ParseArgumentSingle(blank_value);
+  }
+
+ private:
+  virtual CmdlineResult ParseArgumentSingle(const std::string& argument) {
+    // TODO: refactor to use LookupValue for the value lists/maps
+
+    // Handle the 'WithValueMap(...)' argument definition
+    if (argument_info_.has_value_map_) {
+      for (auto&& value_pair : argument_info_.value_map_) {
+        const char* name = value_pair.first;
+
+        if (argument == name) {
+          return SaveArgument(value_pair.second);
+        }
+      }
+
+      // Error case: Fail, telling the user what the allowed values were.
+      std::vector<std::string> allowed_values;
+      for (auto&& value_pair : argument_info_.value_map_) {
+        const char* name = value_pair.first;
+        allowed_values.push_back(name);
+      }
+
+      std::string allowed_values_flat = android::base::Join(allowed_values, ',');
+      return CmdlineResult(CmdlineResult::kFailure,
+                           "Argument value '" + argument + "' does not match any of known valid"
+                            "values: {" + allowed_values_flat + "}");
+    }
+
+    // Handle the 'WithValues(...)' argument definition
+    if (argument_info_.has_value_list_) {
+      size_t arg_def_idx = 0;
+      for (auto&& value : argument_info_.value_list_) {
+        auto&& arg_def_token = argument_info_.names_[arg_def_idx];
+
+        if (arg_def_token == argument) {
           return SaveArgument(value);
         }
-
-        // Some kind of type-specific parse error. Pass the result as-is.
-        CmdlineResult raw_result = std::move(result);
-        return raw_result;
+        ++arg_def_idx;
       }
 
-     public:
-      virtual const char* GetTypeName() const {
-        // TODO: Obviate the need for each type specialization to hardcode the type name
-        return UserTypeInfo::Name();
+      assert(arg_def_idx + 1 == argument_info_.value_list_.size() &&
+             "Number of named argument definitions must match number of values defined");
+
+      // Error case: Fail, telling the user what the allowed values were.
+      std::vector<std::string> allowed_values;
+      for (auto&& arg_name : argument_info_.names_) {
+        allowed_values.push_back(arg_name);
       }
 
-      // How many tokens should be taken off argv for parsing this argument.
-      // For example "--help" is just 1, "-compiler-option _" would be 2 (since there's a space).
-      //
-      // A [min,max] range is returned to represent argument definitions with multiple
-      // value tokens. (e.g. {"-h", "-h " } would return [1,2]).
-      virtual std::pair<size_t, size_t> GetNumTokens() const {
-        return argument_info_.token_range_size_;
+      std::string allowed_values_flat = android::base::Join(allowed_values, ',');
+      return CmdlineResult(CmdlineResult::kFailure,
+                           "Argument value '" + argument + "' does not match any of known valid"
+                            "values: {" + allowed_values_flat + "}");
+    }
+
+    // Handle the regular case where we parsed an unknown value from a blank.
+    UserTypeInfo type_parser;
+
+    if (argument_info_.appending_values_) {
+      TArg& existing = load_argument_();
+      CmdlineParseResult<TArg> result = type_parser.ParseAndAppend(argument, existing);
+
+      assert(!argument_info_.has_range_);
+
+      return result;
+    }
+
+    CmdlineParseResult<TArg> result = type_parser.Parse(argument);
+
+    if (result.IsSuccess()) {
+      TArg& value = result.GetValue();
+
+      // Do a range check for 'WithRange(min,max)' argument definition.
+      if (!argument_info_.CheckRange(value)) {
+        return CmdlineParseResult<TArg>::OutOfRange(
+            value, argument_info_.min_, argument_info_.max_);
       }
 
-      // See if this token range might begin the same as the argument definition.
-      virtual size_t MaybeMatches(const TokenRange& tokens) {
-        return argument_info_.MaybeMatches(tokens);
-      }
+      return SaveArgument(value);
+    }
 
-     private:
-      CmdlineResult SaveArgument(const TArg& value) {
-        assert(!argument_info_.appending_values_
-               && "If the values are being appended, then the updated parse value is "
-                   "updated by-ref as a side effect and shouldn't be stored directly");
-        TArg val = value;
-        save_argument_(val);
-        return CmdlineResult(CmdlineResult::kSuccess);
-      }
+    // Some kind of type-specific parse error. Pass the result as-is.
+    CmdlineResult raw_result = std::move(result);
+    return raw_result;
+  }
 
-      CmdlineParserArgumentInfo<TArg> argument_info_;
-      std::function<void(TArg&)> save_argument_;
-      std::function<TArg&(void)> load_argument_;
-    };
-  }  // namespace detail  // NOLINT [readability/namespace] [5]
+ public:
+  virtual const char* GetTypeName() const {
+    // TODO: Obviate the need for each type specialization to hardcode the type name
+    return UserTypeInfo::Name();
+  }
+
+  // How many tokens should be taken off argv for parsing this argument.
+  // For example "--help" is just 1, "-compiler-option _" would be 2 (since there's a space).
+  //
+  // A [min,max] range is returned to represent argument definitions with multiple
+  // value tokens. (e.g. {"-h", "-h " } would return [1,2]).
+  virtual std::pair<size_t, size_t> GetNumTokens() const {
+    return argument_info_.token_range_size_;
+  }
+
+  // See if this token range might begin the same as the argument definition.
+  virtual size_t MaybeMatches(const TokenRange& tokens) {
+    return argument_info_.MaybeMatches(tokens);
+  }
+
+ private:
+  CmdlineResult SaveArgument(const TArg& value) {
+    assert(!argument_info_.appending_values_
+           && "If the values are being appended, then the updated parse value is "
+               "updated by-ref as a side effect and shouldn't be stored directly");
+    TArg val = value;
+    save_argument_(val);
+    return CmdlineResult(CmdlineResult::kSuccess);
+  }
+
+  CmdlineParserArgumentInfo<TArg> argument_info_;
+  std::function<void(TArg&)> save_argument_;
+  std::function<TArg&(void)> load_argument_;
+};
+}  // namespace detail  // NOLINT [readability/namespace] [5]
 }  // namespace art
 
 #endif  // ART_CMDLINE_DETAIL_CMDLINE_PARSE_ARGUMENT_DETAIL_H_
diff --git a/cmdline/detail/cmdline_parser_detail.h b/cmdline/detail/cmdline_parser_detail.h
index 24dbca2..4c26ba3 100644
--- a/cmdline/detail/cmdline_parser_detail.h
+++ b/cmdline/detail/cmdline_parser_detail.h
@@ -17,112 +17,112 @@
 #ifndef ART_CMDLINE_DETAIL_CMDLINE_PARSER_DETAIL_H_
 #define ART_CMDLINE_DETAIL_CMDLINE_PARSER_DETAIL_H_
 
-#include <string>
 #include <sstream>
+#include <string>
 #include <vector>
 
 namespace art {
-  // Implementation details for some template querying. Don't look inside if you hate templates.
-  namespace detail {
-    template <typename T>
-    typename std::remove_reference<T>::type& FakeReference();
+// Implementation details for some template querying. Don't look inside if you hate templates.
+namespace detail {
+template <typename T>
+typename std::remove_reference<T>::type& FakeReference();
 
-    // SupportsInsertionOperator<T, TStream>::value will evaluate to a boolean,
-    // whose value is true if the TStream class supports the << operator against T,
-    // and false otherwise.
-    template <typename T2, typename TStream2 = std::ostream>
-    struct SupportsInsertionOperator {
-     private:
-      template <typename TStream, typename T>
-      static std::true_type InsertionOperatorTest(TStream& os, const T& value,
-                                                  std::remove_reference<decltype(os << value)>* = 0);  // NOLINT [whitespace/operators] [3]
+// SupportsInsertionOperator<T, TStream>::value will evaluate to a boolean,
+// whose value is true if the TStream class supports the << operator against T,
+// and false otherwise.
+template <typename T2, typename TStream2 = std::ostream>
+struct SupportsInsertionOperator {
+ private:
+  template <typename TStream, typename T>
+  static std::true_type InsertionOperatorTest(TStream& os, const T& value,
+                                              std::remove_reference<decltype(os << value)>* = 0);  // NOLINT [whitespace/operators] [3]
 
-      template <typename TStream, typename ... T>
-      static std::false_type InsertionOperatorTest(TStream& os, const T& ... args);
+  template <typename TStream, typename ... T>
+  static std::false_type InsertionOperatorTest(TStream& os, const T& ... args);
 
-     public:
-      static constexpr bool value =
-          decltype(InsertionOperatorTest(FakeReference<TStream2>(), std::declval<T2>()))::value;
-    };
+ public:
+  static constexpr bool value =
+      decltype(InsertionOperatorTest(FakeReference<TStream2>(), std::declval<T2>()))::value;
+};
 
-    template <typename TLeft, typename TRight = TLeft, bool IsFloatingPoint = false>
-    struct SupportsEqualityOperatorImpl;
+template <typename TLeft, typename TRight = TLeft, bool IsFloatingPoint = false>
+struct SupportsEqualityOperatorImpl;
 
-    template <typename TLeft, typename TRight>
-    struct SupportsEqualityOperatorImpl<TLeft, TRight, false> {
-     private:
-      template <typename TL, typename TR>
-      static std::true_type EqualityOperatorTest(const TL& left, const TR& right,
-                                                 std::remove_reference<decltype(left == right)>* = 0);  // NOLINT [whitespace/operators] [3]
+template <typename TLeft, typename TRight>
+struct SupportsEqualityOperatorImpl<TLeft, TRight, false> {
+ private:
+  template <typename TL, typename TR>
+  static std::true_type EqualityOperatorTest(const TL& left, const TR& right,
+                                             std::remove_reference<decltype(left == right)>* = 0);  // NOLINT [whitespace/operators] [3]
 
-      template <typename TL, typename ... T>
-      static std::false_type EqualityOperatorTest(const TL& left, const T& ... args);
+  template <typename TL, typename ... T>
+  static std::false_type EqualityOperatorTest(const TL& left, const T& ... args);
 
-     public:
-      static constexpr bool value =
-          decltype(EqualityOperatorTest(std::declval<TLeft>(), std::declval<TRight>()))::value;
-    };
+ public:
+  static constexpr bool value =
+      decltype(EqualityOperatorTest(std::declval<TLeft>(), std::declval<TRight>()))::value;
+};
 
-    // Partial specialization when TLeft/TRight are both floating points.
-    // This is a work-around because decltype(floatvar1 == floatvar2)
-    // will not compile with clang:
-    // error: comparing floating point with == or != is unsafe [-Werror,-Wfloat-equal]
-    template <typename TLeft, typename TRight>
-    struct SupportsEqualityOperatorImpl<TLeft, TRight, true> {
-      static constexpr bool value = true;
-    };
+// Partial specialization when TLeft/TRight are both floating points.
+// This is a work-around because decltype(floatvar1 == floatvar2)
+// will not compile with clang:
+// error: comparing floating point with == or != is unsafe [-Werror,-Wfloat-equal]
+template <typename TLeft, typename TRight>
+struct SupportsEqualityOperatorImpl<TLeft, TRight, true> {
+  static constexpr bool value = true;
+};
 
-    // SupportsEqualityOperatorImpl<T1, T2>::value will evaluate to a boolean,
-    // whose value is true if T1 can be compared against T2 with ==,
-    // and false otherwise.
-    template <typename TLeft, typename TRight = TLeft>
-    struct SupportsEqualityOperator :
-        SupportsEqualityOperatorImpl<TLeft, TRight,
-                                     std::is_floating_point<TLeft>::value
-                                     && std::is_floating_point<TRight>::value> {
-    };
+// SupportsEqualityOperatorImpl<T1, T2>::value will evaluate to a boolean,
+// whose value is true if T1 can be compared against T2 with ==,
+// and false otherwise.
+template <typename TLeft, typename TRight = TLeft>
+struct SupportsEqualityOperator :  // NOLINT [whitespace/labels] [4]
+    SupportsEqualityOperatorImpl<TLeft, TRight,
+                                 std::is_floating_point<TLeft>::value
+                                 && std::is_floating_point<TRight>::value> {
+};
 
-    // Convert any kind of type to an std::string, even if there's no
-    // serialization support for it. Unknown types get converted to an
-    // an arbitrary value.
-    //
-    // Meant for printing user-visible errors or unit test failures only.
-    template <typename T>
-    std::string ToStringAny(const T& value,
-                            typename std::enable_if<
-                                SupportsInsertionOperator<T>::value>::type* = 0) {
-      std::stringstream stream;
-      stream << value;
-      return stream.str();
+// Convert any kind of type to an std::string, even if there's no
+// serialization support for it. Unknown types get converted to an
+// an arbitrary value.
+//
+// Meant for printing user-visible errors or unit test failures only.
+template <typename T>
+std::string ToStringAny(const T& value,
+                        typename std::enable_if<
+                            SupportsInsertionOperator<T>::value>::type* = 0) {
+  std::stringstream stream;
+  stream << value;
+  return stream.str();
+}
+
+template <typename T>
+std::string ToStringAny(const std::vector<T> value,
+                        typename std::enable_if<
+                            SupportsInsertionOperator<T>::value>::type* = 0) {
+  std::stringstream stream;
+  stream << "vector{";
+
+  for (size_t i = 0; i < value.size(); ++i) {
+    stream << ToStringAny(value[i]);
+
+    if (i != value.size() - 1) {
+      stream << ',';
     }
+  }
 
-    template <typename T>
-    std::string ToStringAny(const std::vector<T> value,
-                            typename std::enable_if<
-                                SupportsInsertionOperator<T>::value>::type* = 0) {
-      std::stringstream stream;
-      stream << "vector{";
+  stream << "}";
+  return stream.str();
+}
 
-      for (size_t i = 0; i < value.size(); ++i) {
-        stream << ToStringAny(value[i]);
-
-        if (i != value.size() - 1) {
-          stream << ',';
-        }
-      }
-
-      stream << "}";
-      return stream.str();
-    }
-
-    template <typename T>
-    std::string ToStringAny(const T&,
-                            typename std::enable_if<
-                                !SupportsInsertionOperator<T>::value>::type* = 0
-    ) {
-      return std::string("(unknown type [no operator<< implemented] for )");
-    }
-  }  // namespace detail  // NOLINT [readability/namespace] [5]
+template <typename T>
+std::string ToStringAny(const T&,
+                        typename std::enable_if<
+                            !SupportsInsertionOperator<T>::value>::type* = 0
+) {
+  return std::string("(unknown type [no operator<< implemented] for )");
+}
+}  // namespace detail  // NOLINT [readability/namespace] [5]
 }  // namespace art
 
 #endif  // ART_CMDLINE_DETAIL_CMDLINE_PARSER_DETAIL_H_
diff --git a/cmdline/memory_representation.h b/cmdline/memory_representation.h
index 2619c31..8db68bc 100644
--- a/cmdline/memory_representation.h
+++ b/cmdline/memory_representation.h
@@ -17,9 +17,9 @@
 #ifndef ART_CMDLINE_MEMORY_REPRESENTATION_H_
 #define ART_CMDLINE_MEMORY_REPRESENTATION_H_
 
-#include <string>
 #include <assert.h>
 #include <ostream>
+#include <string>
 
 #include "base/bit_utils.h"
 
diff --git a/cmdline/token_range.h b/cmdline/token_range.h
index c22d6c8..642bb1d 100644
--- a/cmdline/token_range.h
+++ b/cmdline/token_range.h
@@ -18,10 +18,10 @@
 #define ART_CMDLINE_TOKEN_RANGE_H_
 
 #include <assert.h>
-#include <vector>
-#include <string>
 #include <algorithm>
 #include <memory>
+#include <string>
+#include <vector>
 
 #include "android-base/strings.h"
 
diff --git a/compiler/Android.bp b/compiler/Android.bp
index b721d21..32e42bc 100644
--- a/compiler/Android.bp
+++ b/compiler/Android.bp
@@ -23,7 +23,6 @@
     name: "libart-compiler-defaults",
     defaults: ["art_defaults"],
     host_supported: true,
-    clang: true,
     srcs: [
         "compiled_method.cc",
         "debug/elf_debug_writer.cc",
@@ -38,7 +37,6 @@
         "driver/dex_compilation_unit.cc",
         "linker/buffered_output_stream.cc",
         "linker/file_output_stream.cc",
-        "linker/multi_oat_relative_patcher.cc",
         "linker/output_stream.cc",
         "linker/vector_output_stream.cc",
         "linker/relative_patcher.cc",
@@ -54,6 +52,8 @@
         "optimizing/code_generator_utils.cc",
         "optimizing/code_sinking.cc",
         "optimizing/constant_folding.cc",
+        "optimizing/constructor_fence_redundancy_elimination.cc",
+        "optimizing/data_type.cc",
         "optimizing/dead_code_elimination.cc",
         "optimizing/escape.cc",
         "optimizing/graph_checker.cc",
@@ -89,15 +89,12 @@
         "optimizing/ssa_liveness_analysis.cc",
         "optimizing/ssa_phi_elimination.cc",
         "optimizing/stack_map_stream.cc",
+        "optimizing/superblock_cloner.cc",
         "trampolines/trampoline_compiler.cc",
         "utils/assembler.cc",
         "utils/jni_macro_assembler.cc",
         "utils/swap_space.cc",
         "compiler.cc",
-        "elf_writer.cc",
-        "elf_writer_quick.cc",
-        "image_writer.cc",
-        "oat_writer.cc",
     ],
 
     codegen: {
@@ -139,6 +136,7 @@
                 "linker/mips/relative_patcher_mips.cc",
                 "optimizing/code_generator_mips.cc",
                 "optimizing/code_generator_vector_mips.cc",
+                "optimizing/instruction_simplifier_mips.cc",
                 "optimizing/intrinsics_mips.cc",
                 "optimizing/pc_relative_fixups_mips.cc",
                 "utils/mips/assembler_mips.cc",
@@ -184,45 +182,32 @@
             ],
         },
     },
-    target: {
-        host: {
-            // For compiler driver TLS.
-            host_ldlibs: ["-lpthread"],
-        },
-        android: {
-            // For atrace.
-            shared_libs: ["libcutils"],
-        },
-    },
     generated_sources: ["art_compiler_operator_srcs"],
     shared_libs: [
         "libbase",
-        "liblz4",
+        "libcutils",  // for atrace.
         "liblzma",
     ],
     include_dirs: ["art/disassembler"],
-    export_include_dirs: ["."],
+    header_libs: [
+        "art_cmdlineparser_headers",  // For compiler_options.
+        "libnativehelper_header_only",
+    ],
 
-    // For SHA-1 checksumming of build ID
-    static: {
-        whole_static_libs: ["libcrypto"],
-    },
-    shared: {
-        shared_libs: ["libcrypto"],
-    },
+    export_include_dirs: ["."],
 }
 
 gensrcs {
     name: "art_compiler_operator_srcs",
-    cmd: "$(location generate-operator-out.py) art/compiler $(in) > $(out)",
-    tool_files: ["generate-operator-out.py"],
+    cmd: "$(location generate_operator_out) art/compiler $(in) > $(out)",
+    tools: ["generate_operator_out"],
     srcs: [
-        "compiled_method.h",
         "dex/dex_to_dex_compiler.h",
         "driver/compiler_driver.h",
         "driver/compiler_options.h",
-        "image_writer.h",
+        "linker/linker_patch.h",
         "optimizing/locations.h",
+        "optimizing/optimizing_compiler_stats.h",
 
         "utils/arm/constants_arm.h",
         "utils/mips/assembler_mips.h",
@@ -233,7 +218,10 @@
 
 art_cc_library {
     name: "libart-compiler",
-    defaults: ["libart-compiler-defaults"],
+    defaults: [
+        "libart-compiler-defaults",
+        "dex2oat-pgo-defaults",
+    ],
     codegen: {
         arm: {
             // VIXL assembly support for ARM targets.
@@ -264,8 +252,16 @@
     },
     shared_libs: [
         "libart",
-        "libart-dexlayout",
+        "libdexfile",
     ],
+
+    target: {
+        android: {
+            lto: {
+                 thin: true,
+            },
+        },
+    },
 }
 
 art_cc_library {
@@ -304,7 +300,7 @@
     },
     shared_libs: [
         "libartd",
-        "libartd-dexlayout"
+        "libdexfiled",
     ],
 }
 
@@ -314,6 +310,7 @@
     srcs: ["common_compiler_test.cc"],
     shared_libs: [
         "libartd-compiler",
+        "libartd-disassembler",
         "libart-runtime-gtest",
         "libbase",
     ],
@@ -325,21 +322,18 @@
         "art_gtest_defaults",
     ],
     srcs: [
-        "compiled_method_test.cc",
         "debug/dwarf/dwarf_test.cc",
+        "debug/src_map_elem_test.cc",
         "dex/dex_to_dex_decompiler_test.cc",
         "driver/compiled_method_storage_test.cc",
         "driver/compiler_driver_test.cc",
-        "elf_writer_test.cc",
         "exception_test.cc",
-        "image_test.cc",
-        "image_write_read_test.cc",
         "jni/jni_compiler_test.cc",
-        "linker/method_bss_mapping_encoder_test.cc",
-        "linker/multi_oat_relative_patcher_test.cc",
+        "linker/linker_patch_test.cc",
         "linker/output_stream_test.cc",
-        "oat_test.cc",
         "optimizing/bounds_check_elimination_test.cc",
+        "optimizing/superblock_cloner_test.cc",
+        "optimizing/data_type_test.cc",
         "optimizing/dominator_test.cc",
         "optimizing/find_loops_test.cc",
         "optimizing/graph_checker_test.cc",
@@ -363,9 +357,7 @@
         "utils/atomic_dex_ref_map_test.cc",
         "utils/dedupe_set_test.cc",
         "utils/intrusive_forward_list_test.cc",
-        "utils/string_reference_test.cc",
         "utils/swap_space_test.cc",
-        "utils/test_dex_file_builder_test.cc",
         "verifier_deps_test.cc",
 
         "jni/jni_cfi_test.cc",
@@ -423,8 +415,14 @@
         },
     },
 
+    header_libs: [
+        "libart_simulator_headers",
+        "libnativehelper_header_only",
+    ],
+
     shared_libs: [
         "libartd-compiler",
+        "libartd-simulator-container",
         "libvixld-arm",
         "libvixld-arm64",
 
@@ -432,6 +430,10 @@
         "libnativeloader",
     ],
 
+    include_dirs: [
+        "external/zlib",
+    ],
+
     target: {
         host: {
             shared_libs: [
diff --git a/compiler/cfi_test.h b/compiler/cfi_test.h
index c754e55..29ff235 100644
--- a/compiler/cfi_test.h
+++ b/compiler/cfi_test.h
@@ -17,16 +17,16 @@
 #ifndef ART_COMPILER_CFI_TEST_H_
 #define ART_COMPILER_CFI_TEST_H_
 
-#include <vector>
 #include <memory>
 #include <sstream>
+#include <vector>
 
 #include "arch/instruction_set.h"
 #include "base/enums.h"
 #include "debug/dwarf/dwarf_constants.h"
 #include "debug/dwarf/dwarf_test.h"
 #include "debug/dwarf/headers.h"
-#include "disassembler/disassembler.h"
+#include "disassembler.h"
 #include "gtest/gtest.h"
 #include "thread.h"
 
@@ -68,7 +68,7 @@
                                              : &Thread::DumpThreadOffset<PointerSize::k32>);
     std::unique_ptr<Disassembler> disasm(Disassembler::Create(isa, opts));
     std::stringstream stream;
-    const uint8_t* base = actual_asm.data() + (isa == kThumb2 ? 1 : 0);
+    const uint8_t* base = actual_asm.data() + (isa == InstructionSet::kThumb2 ? 1 : 0);
     disasm->Dump(stream, base, base + actual_asm.size());
     ReformatAsm(&stream, &lines);
     // Print CFI and assembly interleaved.
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc
index 07bfe31..d3e3a51 100644
--- a/compiler/common_compiler_test.cc
+++ b/compiler/common_compiler_test.cc
@@ -21,21 +21,22 @@
 #include "art_method-inl.h"
 #include "base/callee_save_type.h"
 #include "base/enums.h"
+#include "base/utils.h"
 #include "class_linker.h"
-#include "compiled_method.h"
+#include "compiled_method-inl.h"
+#include "dex/descriptors_names.h"
 #include "dex/quick_compiler_callbacks.h"
 #include "dex/verification_results.h"
 #include "driver/compiler_driver.h"
 #include "driver/compiler_options.h"
 #include "interpreter/interpreter.h"
-#include "mirror/class_loader.h"
 #include "mirror/class-inl.h"
+#include "mirror/class_loader.h"
 #include "mirror/dex_cache.h"
 #include "mirror/object-inl.h"
 #include "oat_quick_method_header.h"
 #include "scoped_thread_state_change-inl.h"
 #include "thread-current-inl.h"
-#include "utils.h"
 
 namespace art {
 
@@ -95,7 +96,7 @@
     const void* method_code = CompiledMethod::CodePointer(code_ptr,
                                                           compiled_method->GetInstructionSet());
     LOG(INFO) << "MakeExecutable " << method->PrettyMethod() << " code=" << method_code;
-    class_linker_->SetEntryPointsToCompiledCode(method, method_code);
+    method->SetEntryPointFromQuickCompiledCode(method_code);
   } else {
     // No code? You must mean to go into the interpreter.
     // Or the generic JNI...
@@ -174,7 +175,6 @@
       }
     }
 
-    timer_.reset(new CumulativeLogger("Compilation times"));
     CreateCompilerDriver(compiler_kind_, instruction_set);
   }
 }
@@ -193,9 +193,6 @@
                                             GetCompiledClasses(),
                                             GetCompiledMethods(),
                                             number_of_threads,
-                                            /* dump_stats */ true,
-                                            /* dump_passes */ true,
-                                            timer_.get(),
                                             /* swap_fd */ -1,
                                             GetProfileCompilationInfo()));
   // We typically don't generate an image in unit tests, disable this optimization by default.
@@ -227,7 +224,6 @@
 }
 
 void CommonCompilerTest::TearDown() {
-  timer_.reset();
   compiler_driver_.reset();
   callbacks_.reset();
   verification_results_.reset();
diff --git a/compiler/common_compiler_test.h b/compiler/common_compiler_test.h
index 0683577..8af29d4 100644
--- a/compiler/common_compiler_test.h
+++ b/compiler/common_compiler_test.h
@@ -23,17 +23,17 @@
 
 #include "common_runtime_test.h"
 #include "compiler.h"
-#include "jit/profile_compilation_info.h"
 #include "oat_file.h"
 
 namespace art {
 namespace mirror {
-  class ClassLoader;
+class ClassLoader;
 }  // namespace mirror
 
 class CompilerDriver;
 class CompilerOptions;
 class CumulativeLogger;
+class ProfileCompilationInfo;
 class VerificationResults;
 
 template<class T> class Handle;
@@ -106,7 +106,6 @@
   std::unique_ptr<CompilerOptions> compiler_options_;
   std::unique_ptr<VerificationResults> verification_results_;
   std::unique_ptr<CompilerDriver> compiler_driver_;
-  std::unique_ptr<CumulativeLogger> timer_;
   std::unique_ptr<const InstructionSetFeatures> instruction_set_features_;
 
 
diff --git a/compiler/compiled_method-inl.h b/compiler/compiled_method-inl.h
new file mode 100644
index 0000000..c432747
--- /dev/null
+++ b/compiler/compiled_method-inl.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef ART_COMPILER_COMPILED_METHOD_INL_H_
+#define ART_COMPILER_COMPILED_METHOD_INL_H_
+
+#include "compiled_method.h"
+
+#include "base/array_ref.h"
+#include "base/length_prefixed_array.h"
+#include "linker/linker_patch.h"
+
+namespace art {
+
+inline ArrayRef<const uint8_t> CompiledCode::GetQuickCode() const {
+  return GetArray(quick_code_);
+}
+
+template <typename T>
+inline ArrayRef<const T> CompiledCode::GetArray(const LengthPrefixedArray<T>* array) {
+  if (array == nullptr) {
+    return ArrayRef<const T>();
+  }
+  DCHECK_NE(array->size(), 0u);
+  return ArrayRef<const T>(&array->At(0), array->size());
+}
+
+inline ArrayRef<const uint8_t> CompiledMethod::GetMethodInfo() const {
+  return GetArray(method_info_);
+}
+
+inline ArrayRef<const uint8_t> CompiledMethod::GetVmapTable() const {
+  return GetArray(vmap_table_);
+}
+
+inline ArrayRef<const uint8_t> CompiledMethod::GetCFIInfo() const {
+  return GetArray(cfi_info_);
+}
+
+inline ArrayRef<const linker::LinkerPatch> CompiledMethod::GetPatches() const {
+  return GetArray(patches_);
+}
+
+}  // namespace art
+
+#endif  // ART_COMPILER_COMPILED_METHOD_INL_H_
diff --git a/compiler/compiled_method.cc b/compiler/compiled_method.cc
index 0d9021f..e413718 100644
--- a/compiler/compiled_method.cc
+++ b/compiler/compiled_method.cc
@@ -22,11 +22,12 @@
 
 namespace art {
 
-CompiledCode::CompiledCode(CompilerDriver* compiler_driver, InstructionSet instruction_set,
+CompiledCode::CompiledCode(CompilerDriver* compiler_driver,
+                           InstructionSet instruction_set,
                            const ArrayRef<const uint8_t>& quick_code)
     : compiler_driver_(compiler_driver),
-      instruction_set_(instruction_set),
-      quick_code_(compiler_driver_->GetCompiledMethodStorage()->DeduplicateCode(quick_code)) {
+      quick_code_(compiler_driver_->GetCompiledMethodStorage()->DeduplicateCode(quick_code)),
+      packed_fields_(InstructionSetField::Encode(instruction_set)) {
 }
 
 CompiledCode::~CompiledCode() {
@@ -47,7 +48,7 @@
 }
 
 size_t CompiledCode::AlignCode(size_t offset) const {
-  return AlignCode(offset, instruction_set_);
+  return AlignCode(offset, GetInstructionSet());
 }
 
 size_t CompiledCode::AlignCode(size_t offset, InstructionSet instruction_set) {
@@ -55,19 +56,19 @@
 }
 
 size_t CompiledCode::CodeDelta() const {
-  return CodeDelta(instruction_set_);
+  return CodeDelta(GetInstructionSet());
 }
 
 size_t CompiledCode::CodeDelta(InstructionSet instruction_set) {
   switch (instruction_set) {
-    case kArm:
-    case kArm64:
-    case kMips:
-    case kMips64:
-    case kX86:
-    case kX86_64:
+    case InstructionSet::kArm:
+    case InstructionSet::kArm64:
+    case InstructionSet::kMips:
+    case InstructionSet::kMips64:
+    case InstructionSet::kX86:
+    case InstructionSet::kX86_64:
       return 0;
-    case kThumb2: {
+    case InstructionSet::kThumb2: {
       // +1 to set the low-order bit so a BLX will switch to Thumb mode
       return 1;
     }
@@ -77,17 +78,16 @@
   }
 }
 
-const void* CompiledCode::CodePointer(const void* code_pointer,
-                                      InstructionSet instruction_set) {
+const void* CompiledCode::CodePointer(const void* code_pointer, InstructionSet instruction_set) {
   switch (instruction_set) {
-    case kArm:
-    case kArm64:
-    case kMips:
-    case kMips64:
-    case kX86:
-    case kX86_64:
+    case InstructionSet::kArm:
+    case InstructionSet::kArm64:
+    case InstructionSet::kMips:
+    case InstructionSet::kMips64:
+    case InstructionSet::kX86:
+    case InstructionSet::kX86_64:
       return code_pointer;
-    case kThumb2: {
+    case InstructionSet::kThumb2: {
       uintptr_t address = reinterpret_cast<uintptr_t>(code_pointer);
       // Set the low-order bit so a BLX will switch to Thumb mode
       address |= 0x1;
@@ -108,7 +108,7 @@
                                const ArrayRef<const uint8_t>& method_info,
                                const ArrayRef<const uint8_t>& vmap_table,
                                const ArrayRef<const uint8_t>& cfi_info,
-                               const ArrayRef<const LinkerPatch>& patches)
+                               const ArrayRef<const linker::LinkerPatch>& patches)
     : CompiledCode(driver, instruction_set, quick_code),
       frame_size_in_bytes_(frame_size_in_bytes),
       core_spill_mask_(core_spill_mask),
@@ -129,7 +129,7 @@
     const ArrayRef<const uint8_t>& method_info,
     const ArrayRef<const uint8_t>& vmap_table,
     const ArrayRef<const uint8_t>& cfi_info,
-    const ArrayRef<const LinkerPatch>& patches) {
+    const ArrayRef<const linker::LinkerPatch>& patches) {
   SwapAllocator<CompiledMethod> alloc(driver->GetCompiledMethodStorage()->GetSwapSpaceAllocator());
   CompiledMethod* ret = alloc.allocate(1);
   alloc.construct(ret,
diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h
index 761e9e1..acdce26 100644
--- a/compiler/compiled_method.h
+++ b/compiler/compiled_method.h
@@ -18,37 +18,38 @@
 #define ART_COMPILER_COMPILED_METHOD_H_
 
 #include <memory>
-#include <iosfwd>
 #include <string>
 #include <vector>
 
 #include "arch/instruction_set.h"
-#include "base/array_ref.h"
+#include "base/bit_field.h"
 #include "base/bit_utils.h"
-#include "base/length_prefixed_array.h"
-#include "dex_file_types.h"
-#include "method_reference.h"
 
 namespace art {
 
+template <typename T> class ArrayRef;
 class CompilerDriver;
 class CompiledMethodStorage;
+template<typename T> class LengthPrefixedArray;
+
+namespace linker {
+class LinkerPatch;
+}  // namespace linker
 
 class CompiledCode {
  public:
   // For Quick to supply an code blob
-  CompiledCode(CompilerDriver* compiler_driver, InstructionSet instruction_set,
+  CompiledCode(CompilerDriver* compiler_driver,
+               InstructionSet instruction_set,
                const ArrayRef<const uint8_t>& quick_code);
 
   virtual ~CompiledCode();
 
   InstructionSet GetInstructionSet() const {
-    return instruction_set_;
+    return GetPackedField<InstructionSetField>();
   }
 
-  ArrayRef<const uint8_t> GetQuickCode() const {
-    return GetArray(quick_code_);
-  }
+  ArrayRef<const uint8_t> GetQuickCode() const;
 
   bool operator==(const CompiledCode& rhs) const;
 
@@ -66,294 +67,43 @@
   // Returns a pointer suitable for invoking the code at the argument
   // code_pointer address.  Mainly to cope with kThumb2 where the
   // lower bit must be set to indicate Thumb mode.
-  static const void* CodePointer(const void* code_pointer,
-                                 InstructionSet instruction_set);
+  static const void* CodePointer(const void* code_pointer, InstructionSet instruction_set);
 
  protected:
+  static constexpr size_t kInstructionSetFieldSize =
+      MinimumBitsToStore(static_cast<size_t>(InstructionSet::kLast));
+  static constexpr size_t kNumberOfCompiledCodePackedBits = kInstructionSetFieldSize;
+  static constexpr size_t kMaxNumberOfPackedBits = sizeof(uint32_t) * kBitsPerByte;
+
   template <typename T>
-  static ArrayRef<const T> GetArray(const LengthPrefixedArray<T>* array) {
-    if (array == nullptr) {
-      return ArrayRef<const T>();
-    }
-    DCHECK_NE(array->size(), 0u);
-    return ArrayRef<const T>(&array->At(0), array->size());
-  }
+  static ArrayRef<const T> GetArray(const LengthPrefixedArray<T>* array);
 
   CompilerDriver* GetCompilerDriver() {
     return compiler_driver_;
   }
 
+  template <typename BitFieldType>
+  typename BitFieldType::value_type GetPackedField() const {
+    return BitFieldType::Decode(packed_fields_);
+  }
+
+  template <typename BitFieldType>
+  void SetPackedField(typename BitFieldType::value_type value) {
+    DCHECK(IsUint<BitFieldType::size>(static_cast<uintptr_t>(value)));
+    packed_fields_ = BitFieldType::Update(value, packed_fields_);
+  }
+
  private:
+  using InstructionSetField = BitField<InstructionSet, 0u, kInstructionSetFieldSize>;
+
   CompilerDriver* const compiler_driver_;
 
-  const InstructionSet instruction_set_;
-
-  // Used to store the PIC code for Quick.
+  // Used to store the compiled code.
   const LengthPrefixedArray<uint8_t>* const quick_code_;
+
+  uint32_t packed_fields_;
 };
 
-class SrcMapElem {
- public:
-  uint32_t from_;
-  int32_t to_;
-};
-
-inline bool operator<(const SrcMapElem& lhs, const SrcMapElem& rhs) {
-  if (lhs.from_ != rhs.from_) {
-    return lhs.from_ < rhs.from_;
-  }
-  return lhs.to_ < rhs.to_;
-}
-
-inline bool operator==(const SrcMapElem& lhs, const SrcMapElem& rhs) {
-  return lhs.from_ == rhs.from_ && lhs.to_ == rhs.to_;
-}
-
-class LinkerPatch {
- public:
-  // Note: We explicitly specify the underlying type of the enum because GCC
-  // would otherwise select a bigger underlying type and then complain that
-  //     'art::LinkerPatch::patch_type_' is too small to hold all
-  //     values of 'enum class art::LinkerPatch::Type'
-  // which is ridiculous given we have only a handful of values here. If we
-  // choose to squeeze the Type into fewer than 8 bits, we'll have to declare
-  // patch_type_ as an uintN_t and do explicit static_cast<>s.
-  enum class Type : uint8_t {
-    kMethodRelative,          // NOTE: Actual patching is instruction_set-dependent.
-    kMethodBssEntry,          // NOTE: Actual patching is instruction_set-dependent.
-    kCall,
-    kCallRelative,            // NOTE: Actual patching is instruction_set-dependent.
-    kTypeRelative,            // NOTE: Actual patching is instruction_set-dependent.
-    kTypeBssEntry,            // NOTE: Actual patching is instruction_set-dependent.
-    kStringRelative,          // NOTE: Actual patching is instruction_set-dependent.
-    kStringBssEntry,          // NOTE: Actual patching is instruction_set-dependent.
-    kBakerReadBarrierBranch,  // NOTE: Actual patching is instruction_set-dependent.
-  };
-
-  static LinkerPatch RelativeMethodPatch(size_t literal_offset,
-                                         const DexFile* target_dex_file,
-                                         uint32_t pc_insn_offset,
-                                         uint32_t target_method_idx) {
-    LinkerPatch patch(literal_offset, Type::kMethodRelative, target_dex_file);
-    patch.method_idx_ = target_method_idx;
-    patch.pc_insn_offset_ = pc_insn_offset;
-    return patch;
-  }
-
-  static LinkerPatch MethodBssEntryPatch(size_t literal_offset,
-                                         const DexFile* target_dex_file,
-                                         uint32_t pc_insn_offset,
-                                         uint32_t target_method_idx) {
-    LinkerPatch patch(literal_offset, Type::kMethodBssEntry, target_dex_file);
-    patch.method_idx_ = target_method_idx;
-    patch.pc_insn_offset_ = pc_insn_offset;
-    return patch;
-  }
-
-  static LinkerPatch CodePatch(size_t literal_offset,
-                               const DexFile* target_dex_file,
-                               uint32_t target_method_idx) {
-    LinkerPatch patch(literal_offset, Type::kCall, target_dex_file);
-    patch.method_idx_ = target_method_idx;
-    return patch;
-  }
-
-  static LinkerPatch RelativeCodePatch(size_t literal_offset,
-                                       const DexFile* target_dex_file,
-                                       uint32_t target_method_idx) {
-    LinkerPatch patch(literal_offset, Type::kCallRelative, target_dex_file);
-    patch.method_idx_ = target_method_idx;
-    return patch;
-  }
-
-  static LinkerPatch RelativeTypePatch(size_t literal_offset,
-                                       const DexFile* target_dex_file,
-                                       uint32_t pc_insn_offset,
-                                       uint32_t target_type_idx) {
-    LinkerPatch patch(literal_offset, Type::kTypeRelative, target_dex_file);
-    patch.type_idx_ = target_type_idx;
-    patch.pc_insn_offset_ = pc_insn_offset;
-    return patch;
-  }
-
-  static LinkerPatch TypeBssEntryPatch(size_t literal_offset,
-                                       const DexFile* target_dex_file,
-                                       uint32_t pc_insn_offset,
-                                       uint32_t target_type_idx) {
-    LinkerPatch patch(literal_offset, Type::kTypeBssEntry, target_dex_file);
-    patch.type_idx_ = target_type_idx;
-    patch.pc_insn_offset_ = pc_insn_offset;
-    return patch;
-  }
-
-  static LinkerPatch RelativeStringPatch(size_t literal_offset,
-                                         const DexFile* target_dex_file,
-                                         uint32_t pc_insn_offset,
-                                         uint32_t target_string_idx) {
-    LinkerPatch patch(literal_offset, Type::kStringRelative, target_dex_file);
-    patch.string_idx_ = target_string_idx;
-    patch.pc_insn_offset_ = pc_insn_offset;
-    return patch;
-  }
-
-  static LinkerPatch StringBssEntryPatch(size_t literal_offset,
-                                         const DexFile* target_dex_file,
-                                         uint32_t pc_insn_offset,
-                                         uint32_t target_string_idx) {
-    LinkerPatch patch(literal_offset, Type::kStringBssEntry, target_dex_file);
-    patch.string_idx_ = target_string_idx;
-    patch.pc_insn_offset_ = pc_insn_offset;
-    return patch;
-  }
-
-  static LinkerPatch BakerReadBarrierBranchPatch(size_t literal_offset,
-                                                 uint32_t custom_value1 = 0u,
-                                                 uint32_t custom_value2 = 0u) {
-    LinkerPatch patch(literal_offset, Type::kBakerReadBarrierBranch, nullptr);
-    patch.baker_custom_value1_ = custom_value1;
-    patch.baker_custom_value2_ = custom_value2;
-    return patch;
-  }
-
-  LinkerPatch(const LinkerPatch& other) = default;
-  LinkerPatch& operator=(const LinkerPatch& other) = default;
-
-  size_t LiteralOffset() const {
-    return literal_offset_;
-  }
-
-  Type GetType() const {
-    return patch_type_;
-  }
-
-  bool IsPcRelative() const {
-    switch (GetType()) {
-      case Type::kMethodRelative:
-      case Type::kMethodBssEntry:
-      case Type::kCallRelative:
-      case Type::kTypeRelative:
-      case Type::kTypeBssEntry:
-      case Type::kStringRelative:
-      case Type::kStringBssEntry:
-      case Type::kBakerReadBarrierBranch:
-        return true;
-      default:
-        return false;
-    }
-  }
-
-  MethodReference TargetMethod() const {
-    DCHECK(patch_type_ == Type::kMethodRelative ||
-           patch_type_ == Type::kMethodBssEntry ||
-           patch_type_ == Type::kCall ||
-           patch_type_ == Type::kCallRelative);
-    return MethodReference(target_dex_file_, method_idx_);
-  }
-
-  const DexFile* TargetTypeDexFile() const {
-    DCHECK(patch_type_ == Type::kTypeRelative ||
-           patch_type_ == Type::kTypeBssEntry);
-    return target_dex_file_;
-  }
-
-  dex::TypeIndex TargetTypeIndex() const {
-    DCHECK(patch_type_ == Type::kTypeRelative ||
-           patch_type_ == Type::kTypeBssEntry);
-    return dex::TypeIndex(type_idx_);
-  }
-
-  const DexFile* TargetStringDexFile() const {
-    DCHECK(patch_type_ == Type::kStringRelative ||
-           patch_type_ == Type::kStringBssEntry);
-    return target_dex_file_;
-  }
-
-  dex::StringIndex TargetStringIndex() const {
-    DCHECK(patch_type_ == Type::kStringRelative ||
-           patch_type_ == Type::kStringBssEntry);
-    return dex::StringIndex(string_idx_);
-  }
-
-  uint32_t PcInsnOffset() const {
-    DCHECK(patch_type_ == Type::kMethodRelative ||
-           patch_type_ == Type::kMethodBssEntry ||
-           patch_type_ == Type::kTypeRelative ||
-           patch_type_ == Type::kTypeBssEntry ||
-           patch_type_ == Type::kStringRelative ||
-           patch_type_ == Type::kStringBssEntry);
-    return pc_insn_offset_;
-  }
-
-  uint32_t GetBakerCustomValue1() const {
-    DCHECK(patch_type_ == Type::kBakerReadBarrierBranch);
-    return baker_custom_value1_;
-  }
-
-  uint32_t GetBakerCustomValue2() const {
-    DCHECK(patch_type_ == Type::kBakerReadBarrierBranch);
-    return baker_custom_value2_;
-  }
-
- private:
-  LinkerPatch(size_t literal_offset, Type patch_type, const DexFile* target_dex_file)
-      : target_dex_file_(target_dex_file),
-        literal_offset_(literal_offset),
-        patch_type_(patch_type) {
-    cmp1_ = 0u;
-    cmp2_ = 0u;
-    // The compiler rejects methods that are too big, so the compiled code
-    // of a single method really shouln't be anywhere close to 16MiB.
-    DCHECK(IsUint<24>(literal_offset));
-  }
-
-  const DexFile* target_dex_file_;
-  // TODO: Clean up naming. Some patched locations are literals but others are not.
-  uint32_t literal_offset_ : 24;  // Method code size up to 16MiB.
-  Type patch_type_ : 8;
-  union {
-    uint32_t cmp1_;             // Used for relational operators.
-    uint32_t method_idx_;       // Method index for Call/Method patches.
-    uint32_t type_idx_;         // Type index for Type patches.
-    uint32_t string_idx_;       // String index for String patches.
-    uint32_t baker_custom_value1_;
-    static_assert(sizeof(method_idx_) == sizeof(cmp1_), "needed by relational operators");
-    static_assert(sizeof(type_idx_) == sizeof(cmp1_), "needed by relational operators");
-    static_assert(sizeof(string_idx_) == sizeof(cmp1_), "needed by relational operators");
-    static_assert(sizeof(baker_custom_value1_) == sizeof(cmp1_), "needed by relational operators");
-  };
-  union {
-    // Note: To avoid uninitialized padding on 64-bit systems, we use `size_t` for `cmp2_`.
-    // This allows a hashing function to treat an array of linker patches as raw memory.
-    size_t cmp2_;             // Used for relational operators.
-    // Literal offset of the insn loading PC (same as literal_offset if it's the same insn,
-    // may be different if the PC-relative addressing needs multiple insns).
-    uint32_t pc_insn_offset_;
-    uint32_t baker_custom_value2_;
-    static_assert(sizeof(pc_insn_offset_) <= sizeof(cmp2_), "needed by relational operators");
-    static_assert(sizeof(baker_custom_value2_) <= sizeof(cmp2_), "needed by relational operators");
-  };
-
-  friend bool operator==(const LinkerPatch& lhs, const LinkerPatch& rhs);
-  friend bool operator<(const LinkerPatch& lhs, const LinkerPatch& rhs);
-};
-std::ostream& operator<<(std::ostream& os, const LinkerPatch::Type& type);
-
-inline bool operator==(const LinkerPatch& lhs, const LinkerPatch& rhs) {
-  return lhs.literal_offset_ == rhs.literal_offset_ &&
-      lhs.patch_type_ == rhs.patch_type_ &&
-      lhs.target_dex_file_ == rhs.target_dex_file_ &&
-      lhs.cmp1_ == rhs.cmp1_ &&
-      lhs.cmp2_ == rhs.cmp2_;
-}
-
-inline bool operator<(const LinkerPatch& lhs, const LinkerPatch& rhs) {
-  return (lhs.literal_offset_ != rhs.literal_offset_) ? lhs.literal_offset_ < rhs.literal_offset_
-      : (lhs.patch_type_ != rhs.patch_type_) ? lhs.patch_type_ < rhs.patch_type_
-      : (lhs.target_dex_file_ != rhs.target_dex_file_) ? lhs.target_dex_file_ < rhs.target_dex_file_
-      : (lhs.cmp1_ != rhs.cmp1_) ? lhs.cmp1_ < rhs.cmp1_
-      : lhs.cmp2_ < rhs.cmp2_;
-}
-
 class CompiledMethod FINAL : public CompiledCode {
  public:
   // Constructs a CompiledMethod.
@@ -368,7 +118,7 @@
                  const ArrayRef<const uint8_t>& method_info,
                  const ArrayRef<const uint8_t>& vmap_table,
                  const ArrayRef<const uint8_t>& cfi_info,
-                 const ArrayRef<const LinkerPatch>& patches);
+                 const ArrayRef<const linker::LinkerPatch>& patches);
 
   virtual ~CompiledMethod();
 
@@ -382,10 +132,22 @@
       const ArrayRef<const uint8_t>& method_info,
       const ArrayRef<const uint8_t>& vmap_table,
       const ArrayRef<const uint8_t>& cfi_info,
-      const ArrayRef<const LinkerPatch>& patches);
+      const ArrayRef<const linker::LinkerPatch>& patches);
 
   static void ReleaseSwapAllocatedCompiledMethod(CompilerDriver* driver, CompiledMethod* m);
 
+  bool IsIntrinsic() const {
+    return GetPackedField<IsIntrinsicField>();
+  }
+
+  // Marks the compiled method as being generated using an intrinsic codegen.
+  // Such methods have no relationships to their code items.
+  // This affects debug information generated at link time.
+  void MarkAsIntrinsic() {
+    DCHECK(!IsIntrinsic());
+    SetPackedField<IsIntrinsicField>(/* value */ true);
+  }
+
   size_t GetFrameSizeInBytes() const {
     return frame_size_in_bytes_;
   }
@@ -398,23 +160,23 @@
     return fp_spill_mask_;
   }
 
-  ArrayRef<const uint8_t> GetMethodInfo() const {
-    return GetArray(method_info_);
-  }
+  ArrayRef<const uint8_t> GetMethodInfo() const;
 
-  ArrayRef<const uint8_t> GetVmapTable() const {
-    return GetArray(vmap_table_);
-  }
+  ArrayRef<const uint8_t> GetVmapTable() const;
 
-  ArrayRef<const uint8_t> GetCFIInfo() const {
-    return GetArray(cfi_info_);
-  }
+  ArrayRef<const uint8_t> GetCFIInfo() const;
 
-  ArrayRef<const LinkerPatch> GetPatches() const {
-    return GetArray(patches_);
-  }
+  ArrayRef<const linker::LinkerPatch> GetPatches() const;
 
  private:
+  static constexpr size_t kIsIntrinsicLsb = kNumberOfCompiledCodePackedBits;
+  static constexpr size_t kIsIntrinsicSize = 1u;
+  static constexpr size_t kNumberOfCompiledMethodPackedBits = kIsIntrinsicLsb + kIsIntrinsicSize;
+  static_assert(kNumberOfCompiledMethodPackedBits <= CompiledCode::kMaxNumberOfPackedBits,
+                "Too many packed fields.");
+
+  using IsIntrinsicField = BitField<bool, kIsIntrinsicLsb, kIsIntrinsicSize>;
+
   // For quick code, the size of the activation used by the code.
   const size_t frame_size_in_bytes_;
   // For quick code, a bit mask describing spilled GPR callee-save registers.
@@ -428,7 +190,7 @@
   // For quick code, a FDE entry for the debug_frame section.
   const LengthPrefixedArray<uint8_t>* const cfi_info_;
   // For quick code, linker patches needed by the method.
-  const LengthPrefixedArray<LinkerPatch>* const patches_;
+  const LengthPrefixedArray<linker::LinkerPatch>* const patches_;
 };
 
 }  // namespace art
diff --git a/compiler/compiled_method_test.cc b/compiler/compiled_method_test.cc
deleted file mode 100644
index f4a72cf..0000000
--- a/compiler/compiled_method_test.cc
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Copyright (C) 2015 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 <gtest/gtest.h>
-
-#include "compiled_method.h"
-
-namespace art {
-
-TEST(CompiledMethod, SrcMapElemOperators) {
-  SrcMapElem elems[] = {
-      { 1u, -1 },
-      { 1u, 0 },
-      { 1u, 1 },
-      { 2u, -1 },
-      { 2u, 0 },    // Index 4.
-      { 2u, 1 },
-      { 2u, 0u },   // Index 6: Arbitrarily add identical SrcMapElem with index 4.
-  };
-
-  for (size_t i = 0; i != arraysize(elems); ++i) {
-    for (size_t j = 0; j != arraysize(elems); ++j) {
-      bool expected = (i != 6u ? i : 4u) == (j != 6u ? j : 4u);
-      EXPECT_EQ(expected, elems[i] == elems[j]) << i << " " << j;
-    }
-  }
-
-  for (size_t i = 0; i != arraysize(elems); ++i) {
-    for (size_t j = 0; j != arraysize(elems); ++j) {
-      bool expected = (i != 6u ? i : 4u) < (j != 6u ? j : 4u);
-      EXPECT_EQ(expected, elems[i] < elems[j]) << i << " " << j;
-    }
-  }
-}
-
-TEST(CompiledMethod, LinkerPatchOperators) {
-  const DexFile* dex_file1 = reinterpret_cast<const DexFile*>(1);
-  const DexFile* dex_file2 = reinterpret_cast<const DexFile*>(2);
-  LinkerPatch patches[] = {
-      LinkerPatch::RelativeMethodPatch(16u, dex_file1, 3000u, 1000u),
-      LinkerPatch::RelativeMethodPatch(16u, dex_file1, 3001u, 1000u),
-      LinkerPatch::RelativeMethodPatch(16u, dex_file1, 3000u, 1001u),
-      LinkerPatch::RelativeMethodPatch(16u, dex_file1, 3001u, 1001u),  // Index 3.
-      LinkerPatch::RelativeMethodPatch(16u, dex_file2, 3000u, 1000u),
-      LinkerPatch::RelativeMethodPatch(16u, dex_file2, 3001u, 1000u),
-      LinkerPatch::RelativeMethodPatch(16u, dex_file2, 3000u, 1001u),
-      LinkerPatch::RelativeMethodPatch(16u, dex_file2, 3001u, 1001u),
-      LinkerPatch::MethodBssEntryPatch(16u, dex_file1, 3000u, 1000u),
-      LinkerPatch::MethodBssEntryPatch(16u, dex_file1, 3001u, 1000u),
-      LinkerPatch::MethodBssEntryPatch(16u, dex_file1, 3000u, 1001u),
-      LinkerPatch::MethodBssEntryPatch(16u, dex_file1, 3001u, 1001u),
-      LinkerPatch::MethodBssEntryPatch(16u, dex_file2, 3000u, 1000u),
-      LinkerPatch::MethodBssEntryPatch(16u, dex_file2, 3001u, 1000u),
-      LinkerPatch::MethodBssEntryPatch(16u, dex_file2, 3000u, 1001u),
-      LinkerPatch::MethodBssEntryPatch(16u, dex_file2, 3001u, 1001u),
-      LinkerPatch::CodePatch(16u, dex_file1, 1000u),
-      LinkerPatch::CodePatch(16u, dex_file1, 1001u),
-      LinkerPatch::CodePatch(16u, dex_file2, 1000u),
-      LinkerPatch::CodePatch(16u, dex_file2, 1001u),
-      LinkerPatch::RelativeCodePatch(16u, dex_file1, 1000u),
-      LinkerPatch::RelativeCodePatch(16u, dex_file1, 1001u),
-      LinkerPatch::RelativeCodePatch(16u, dex_file2, 1000u),
-      LinkerPatch::RelativeCodePatch(16u, dex_file2, 1001u),
-      LinkerPatch::RelativeTypePatch(16u, dex_file1, 3000u, 1000u),
-      LinkerPatch::RelativeTypePatch(16u, dex_file1, 3001u, 1000u),
-      LinkerPatch::RelativeTypePatch(16u, dex_file1, 3000u, 1001u),
-      LinkerPatch::RelativeTypePatch(16u, dex_file1, 3001u, 1001u),
-      LinkerPatch::RelativeTypePatch(16u, dex_file2, 3000u, 1000u),
-      LinkerPatch::RelativeTypePatch(16u, dex_file2, 3001u, 1000u),
-      LinkerPatch::RelativeTypePatch(16u, dex_file2, 3000u, 1001u),
-      LinkerPatch::RelativeTypePatch(16u, dex_file2, 3001u, 1001u),
-      LinkerPatch::TypeBssEntryPatch(16u, dex_file1, 3000u, 1000u),
-      LinkerPatch::TypeBssEntryPatch(16u, dex_file1, 3001u, 1000u),
-      LinkerPatch::TypeBssEntryPatch(16u, dex_file1, 3000u, 1001u),
-      LinkerPatch::TypeBssEntryPatch(16u, dex_file1, 3001u, 1001u),
-      LinkerPatch::TypeBssEntryPatch(16u, dex_file2, 3000u, 1000u),
-      LinkerPatch::TypeBssEntryPatch(16u, dex_file2, 3001u, 1000u),
-      LinkerPatch::TypeBssEntryPatch(16u, dex_file2, 3000u, 1001u),
-      LinkerPatch::TypeBssEntryPatch(16u, dex_file2, 3001u, 1001u),
-      LinkerPatch::RelativeStringPatch(16u, dex_file1, 3000u, 1000u),
-      LinkerPatch::RelativeStringPatch(16u, dex_file1, 3001u, 1000u),
-      LinkerPatch::RelativeStringPatch(16u, dex_file1, 3000u, 1001u),
-      LinkerPatch::RelativeStringPatch(16u, dex_file1, 3001u, 1001u),
-      LinkerPatch::RelativeStringPatch(16u, dex_file2, 3000u, 1000u),
-      LinkerPatch::RelativeStringPatch(16u, dex_file2, 3001u, 1000u),
-      LinkerPatch::RelativeStringPatch(16u, dex_file2, 3000u, 1001u),
-      LinkerPatch::RelativeStringPatch(16u, dex_file2, 3001u, 1001u),
-      LinkerPatch::StringBssEntryPatch(16u, dex_file1, 3000u, 1000u),
-      LinkerPatch::StringBssEntryPatch(16u, dex_file1, 3001u, 1000u),
-      LinkerPatch::StringBssEntryPatch(16u, dex_file1, 3000u, 1001u),
-      LinkerPatch::StringBssEntryPatch(16u, dex_file1, 3001u, 1001u),
-      LinkerPatch::StringBssEntryPatch(16u, dex_file2, 3000u, 1000u),
-      LinkerPatch::StringBssEntryPatch(16u, dex_file2, 3001u, 1000u),
-      LinkerPatch::StringBssEntryPatch(16u, dex_file2, 3000u, 1001u),
-      LinkerPatch::StringBssEntryPatch(16u, dex_file2, 3001u, 1001u),
-      LinkerPatch::BakerReadBarrierBranchPatch(16u, 0u, 0u),
-      LinkerPatch::BakerReadBarrierBranchPatch(16u, 0u, 1u),
-      LinkerPatch::BakerReadBarrierBranchPatch(16u, 1u, 0u),
-      LinkerPatch::BakerReadBarrierBranchPatch(16u, 1u, 1u),
-
-      LinkerPatch::RelativeMethodPatch(32u, dex_file1, 3000u, 1000u),
-      LinkerPatch::RelativeMethodPatch(32u, dex_file1, 3001u, 1000u),
-      LinkerPatch::RelativeMethodPatch(32u, dex_file1, 3000u, 1001u),
-      LinkerPatch::RelativeMethodPatch(32u, dex_file1, 3001u, 1001u),
-      LinkerPatch::RelativeMethodPatch(32u, dex_file2, 3000u, 1000u),
-      LinkerPatch::RelativeMethodPatch(32u, dex_file2, 3001u, 1000u),
-      LinkerPatch::RelativeMethodPatch(32u, dex_file2, 3000u, 1001u),
-      LinkerPatch::RelativeMethodPatch(32u, dex_file2, 3001u, 1001u),
-      LinkerPatch::MethodBssEntryPatch(32u, dex_file1, 3000u, 1000u),
-      LinkerPatch::MethodBssEntryPatch(32u, dex_file1, 3001u, 1000u),
-      LinkerPatch::MethodBssEntryPatch(32u, dex_file1, 3000u, 1001u),
-      LinkerPatch::MethodBssEntryPatch(32u, dex_file1, 3001u, 1001u),
-      LinkerPatch::MethodBssEntryPatch(32u, dex_file2, 3000u, 1000u),
-      LinkerPatch::MethodBssEntryPatch(32u, dex_file2, 3001u, 1000u),
-      LinkerPatch::MethodBssEntryPatch(32u, dex_file2, 3000u, 1001u),
-      LinkerPatch::MethodBssEntryPatch(32u, dex_file2, 3001u, 1001u),
-      LinkerPatch::CodePatch(32u, dex_file1, 1000u),
-      LinkerPatch::CodePatch(32u, dex_file1, 1001u),
-      LinkerPatch::CodePatch(32u, dex_file2, 1000u),
-      LinkerPatch::CodePatch(32u, dex_file2, 1001u),
-      LinkerPatch::RelativeCodePatch(32u, dex_file1, 1000u),
-      LinkerPatch::RelativeCodePatch(32u, dex_file1, 1001u),
-      LinkerPatch::RelativeCodePatch(32u, dex_file2, 1000u),
-      LinkerPatch::RelativeCodePatch(32u, dex_file2, 1001u),
-      LinkerPatch::RelativeTypePatch(32u, dex_file1, 3000u, 1000u),
-      LinkerPatch::RelativeTypePatch(32u, dex_file1, 3001u, 1000u),
-      LinkerPatch::RelativeTypePatch(32u, dex_file1, 3000u, 1001u),
-      LinkerPatch::RelativeTypePatch(32u, dex_file1, 3001u, 1001u),
-      LinkerPatch::RelativeTypePatch(32u, dex_file2, 3000u, 1000u),
-      LinkerPatch::RelativeTypePatch(32u, dex_file2, 3001u, 1000u),
-      LinkerPatch::RelativeTypePatch(32u, dex_file2, 3000u, 1001u),
-      LinkerPatch::RelativeTypePatch(32u, dex_file2, 3001u, 1001u),
-      LinkerPatch::TypeBssEntryPatch(32u, dex_file1, 3000u, 1000u),
-      LinkerPatch::TypeBssEntryPatch(32u, dex_file1, 3001u, 1000u),
-      LinkerPatch::TypeBssEntryPatch(32u, dex_file1, 3000u, 1001u),
-      LinkerPatch::TypeBssEntryPatch(32u, dex_file1, 3001u, 1001u),
-      LinkerPatch::TypeBssEntryPatch(32u, dex_file2, 3000u, 1000u),
-      LinkerPatch::TypeBssEntryPatch(32u, dex_file2, 3001u, 1000u),
-      LinkerPatch::TypeBssEntryPatch(32u, dex_file2, 3000u, 1001u),
-      LinkerPatch::TypeBssEntryPatch(32u, dex_file2, 3001u, 1001u),
-      LinkerPatch::RelativeStringPatch(32u, dex_file1, 3000u, 1000u),
-      LinkerPatch::RelativeStringPatch(32u, dex_file1, 3001u, 1000u),
-      LinkerPatch::RelativeStringPatch(32u, dex_file1, 3000u, 1001u),
-      LinkerPatch::RelativeStringPatch(32u, dex_file1, 3001u, 1001u),
-      LinkerPatch::RelativeStringPatch(32u, dex_file2, 3000u, 1000u),
-      LinkerPatch::RelativeStringPatch(32u, dex_file2, 3001u, 1000u),
-      LinkerPatch::RelativeStringPatch(32u, dex_file2, 3000u, 1001u),
-      LinkerPatch::RelativeStringPatch(32u, dex_file2, 3001u, 1001u),
-      LinkerPatch::StringBssEntryPatch(32u, dex_file1, 3000u, 1000u),
-      LinkerPatch::StringBssEntryPatch(32u, dex_file1, 3001u, 1000u),
-      LinkerPatch::StringBssEntryPatch(32u, dex_file1, 3000u, 1001u),
-      LinkerPatch::StringBssEntryPatch(32u, dex_file1, 3001u, 1001u),
-      LinkerPatch::StringBssEntryPatch(32u, dex_file2, 3000u, 1000u),
-      LinkerPatch::StringBssEntryPatch(32u, dex_file2, 3001u, 1000u),
-      LinkerPatch::StringBssEntryPatch(32u, dex_file2, 3000u, 1001u),
-      LinkerPatch::StringBssEntryPatch(32u, dex_file2, 3001u, 1001u),
-      LinkerPatch::BakerReadBarrierBranchPatch(32u, 0u, 0u),
-      LinkerPatch::BakerReadBarrierBranchPatch(32u, 0u, 1u),
-      LinkerPatch::BakerReadBarrierBranchPatch(32u, 1u, 0u),
-      LinkerPatch::BakerReadBarrierBranchPatch(32u, 1u, 1u),
-
-      LinkerPatch::RelativeMethodPatch(16u, dex_file1, 3001u, 1001u),  // Same as patch at index 3.
-  };
-  constexpr size_t last_index = arraysize(patches) - 1u;
-
-  for (size_t i = 0; i != arraysize(patches); ++i) {
-    for (size_t j = 0; j != arraysize(patches); ++j) {
-      bool expected = (i != last_index ? i : 3u) == (j != last_index ? j : 3u);
-      EXPECT_EQ(expected, patches[i] == patches[j]) << i << " " << j;
-    }
-  }
-
-  for (size_t i = 0; i != arraysize(patches); ++i) {
-    for (size_t j = 0; j != arraysize(patches); ++j) {
-      bool expected = (i != last_index ? i : 3u) < (j != last_index ? j : 3u);
-      EXPECT_EQ(expected, patches[i] < patches[j]) << i << " " << j;
-    }
-  }
-}
-
-}  // namespace art
diff --git a/compiler/compiler.cc b/compiler/compiler.cc
index c500921..646040f 100644
--- a/compiler/compiler.cc
+++ b/compiler/compiler.cc
@@ -16,10 +16,13 @@
 
 #include "compiler.h"
 
-#include "base/logging.h"
+#include <android-base/logging.h>
+
+#include "base/macros.h"
+#include "base/utils.h"
+#include "dex/code_item_accessors-inl.h"
 #include "driver/compiler_driver.h"
 #include "optimizing/optimizing_compiler.h"
-#include "utils.h"
 
 namespace art {
 
@@ -44,15 +47,16 @@
    * Dalvik uses 16-bit uints for instruction and register counts.  We'll limit to a quarter
    * of that, which also guarantees we cannot overflow our 16-bit internal Quick SSA name space.
    */
-  if (code_item.insns_size_in_code_units_ >= UINT16_MAX / 4) {
+  CodeItemDataAccessor accessor(dex_file, &code_item);
+  if (accessor.InsnsSizeInCodeUnits() >= UINT16_MAX / 4) {
     LOG(INFO) << "Method exceeds compiler instruction limit: "
-              << code_item.insns_size_in_code_units_
+              << accessor.InsnsSizeInCodeUnits()
               << " in " << dex_file.PrettyMethod(method_idx);
     return true;
   }
-  if (code_item.registers_size_ >= UINT16_MAX / 4) {
+  if (accessor.RegistersSize() >= UINT16_MAX / 4) {
     LOG(INFO) << "Method exceeds compiler virtual register limit: "
-              << code_item.registers_size_ << " in " << dex_file.PrettyMethod(method_idx);
+              << accessor.RegistersSize() << " in " << dex_file.PrettyMethod(method_idx);
     return true;
   }
   return false;
diff --git a/compiler/compiler.h b/compiler/compiler.h
index ba89cb1..f2ec3a9 100644
--- a/compiler/compiler.h
+++ b/compiler/compiler.h
@@ -17,19 +17,19 @@
 #ifndef ART_COMPILER_COMPILER_H_
 #define ART_COMPILER_COMPILER_H_
 
-#include "dex_file.h"
 #include "base/mutex.h"
-#include "os.h"
+#include "base/os.h"
+#include "dex/dex_file.h"
 
 namespace art {
 
 namespace jit {
-  class JitCodeCache;
-  class JitLogger;
+class JitCodeCache;
+class JitLogger;
 }  // namespace jit
 namespace mirror {
-  class ClassLoader;
-  class DexCache;
+class ClassLoader;
+class DexCache;
 }  // namespace mirror
 
 class ArtMethod;
@@ -39,6 +39,12 @@
 class OatWriter;
 class Thread;
 
+enum class CopyOption {
+  kNever,
+  kAlways,
+  kOnlyIfCompressed
+};
+
 class Compiler {
  public:
   enum Kind {
@@ -46,12 +52,6 @@
     kOptimizing
   };
 
-  enum JniOptimizationFlags {
-    kNone                       = 0x0,
-    kFastNative                 = 0x1,
-    kCriticalNative             = 0x2,
-  };
-
   static Compiler* Create(CompilerDriver* driver, Kind kind);
 
   virtual void Init() = 0;
@@ -72,7 +72,7 @@
   virtual CompiledMethod* JniCompile(uint32_t access_flags,
                                      uint32_t method_idx,
                                      const DexFile& dex_file,
-                                     JniOptimizationFlags optimization_flags) const = 0;
+                                     Handle<mirror::DexCache> dex_cache) const = 0;
 
   virtual bool JitCompile(Thread* self ATTRIBUTE_UNUSED,
                           jit::JitCodeCache* code_cache ATTRIBUTE_UNUSED,
diff --git a/compiler/debug/debug_info.h b/compiler/debug/debug_info.h
new file mode 100644
index 0000000..04c6991
--- /dev/null
+++ b/compiler/debug/debug_info.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef ART_COMPILER_DEBUG_DEBUG_INFO_H_
+#define ART_COMPILER_DEBUG_DEBUG_INFO_H_
+
+#include <map>
+
+#include "base/array_ref.h"
+#include "method_debug_info.h"
+
+namespace art {
+class DexFile;
+
+namespace debug {
+
+// References inputs for all debug information which can be written into the ELF file.
+struct DebugInfo {
+  // Describes compiled code in the .text section.
+  ArrayRef<const MethodDebugInfo> compiled_methods;
+
+  // Describes dex-files in the .dex section.
+  std::map<uint32_t, const DexFile*> dex_files;  // Offset in section -> dex file content.
+
+  bool Empty() const {
+    return compiled_methods.empty() && dex_files.empty();
+  }
+};
+
+}  // namespace debug
+}  // namespace art
+
+#endif  // ART_COMPILER_DEBUG_DEBUG_INFO_H_
diff --git a/compiler/debug/dwarf/debug_abbrev_writer.h b/compiler/debug/dwarf/debug_abbrev_writer.h
index 0fc843c..cccca25 100644
--- a/compiler/debug/dwarf/debug_abbrev_writer.h
+++ b/compiler/debug/dwarf/debug_abbrev_writer.h
@@ -22,10 +22,10 @@
 #include <unordered_map>
 
 #include "base/casts.h"
+#include "base/leb128.h"
 #include "base/stl_util.h"
 #include "debug/dwarf/dwarf_constants.h"
 #include "debug/dwarf/writer.h"
-#include "leb128.h"
 
 namespace art {
 namespace dwarf {
diff --git a/compiler/debug/dwarf/debug_info_entry_writer.h b/compiler/debug/dwarf/debug_info_entry_writer.h
index 85f021e..89d16f2 100644
--- a/compiler/debug/dwarf/debug_info_entry_writer.h
+++ b/compiler/debug/dwarf/debug_info_entry_writer.h
@@ -21,11 +21,11 @@
 #include <unordered_map>
 
 #include "base/casts.h"
+#include "base/leb128.h"
 #include "debug/dwarf/debug_abbrev_writer.h"
 #include "debug/dwarf/dwarf_constants.h"
 #include "debug/dwarf/expression.h"
 #include "debug/dwarf/writer.h"
-#include "leb128.h"
 
 namespace art {
 namespace dwarf {
diff --git a/compiler/debug/dwarf/dwarf_test.cc b/compiler/debug/dwarf/dwarf_test.cc
index 866bf4394..933034f 100644
--- a/compiler/debug/dwarf/dwarf_test.cc
+++ b/compiler/debug/dwarf/dwarf_test.cc
@@ -125,7 +125,7 @@
   WriteCIE(is64bit, Reg(is64bit ? 16 : 8),
            initial_opcodes, kCFIFormat, &debug_frame_data_);
   std::vector<uintptr_t> debug_frame_patches;
-  std::vector<uintptr_t> expected_patches { 28 };  // NOLINT
+  std::vector<uintptr_t> expected_patches = { 28 };
   WriteFDE(is64bit, 0, 0, 0x01000000, 0x01000000, ArrayRef<const uint8_t>(*opcodes.data()),
            kCFIFormat, 0, &debug_frame_data_, &debug_frame_patches);
 
@@ -140,7 +140,7 @@
            initial_opcodes, kCFIFormat, &debug_frame_data_);
   DebugFrameOpCodeWriter<> opcodes;
   std::vector<uintptr_t> debug_frame_patches;
-  std::vector<uintptr_t> expected_patches { 32 };  // NOLINT
+  std::vector<uintptr_t> expected_patches = { 32 };
   WriteFDE(is64bit, 0, 0, 0x0100000000000000, 0x0200000000000000,
            ArrayRef<const uint8_t>(*opcodes.data()),
                      kCFIFormat, 0, &debug_frame_data_, &debug_frame_patches);
@@ -237,7 +237,7 @@
   DW_CHECK_NEXT("1\t0\t1000\t2000\tfile.c");
 
   std::vector<uintptr_t> debug_line_patches;
-  std::vector<uintptr_t> expected_patches { 87 };  // NOLINT
+  std::vector<uintptr_t> expected_patches = { 87 };
   WriteDebugLineTable(include_directories, files, opcodes,
                       0, &debug_line_data_, &debug_line_patches);
 
@@ -275,7 +275,7 @@
   EXPECT_LT(opcodes.data()->size(), num_rows * 3);
 
   std::vector<std::string> directories;
-  std::vector<FileEntry> files { { "file.c", 0, 1000, 2000 } };  // NOLINT
+  std::vector<FileEntry> files = { { "file.c", 0, 1000, 2000 } };
   std::vector<uintptr_t> debug_line_patches;
   WriteDebugLineTable(directories, files, opcodes,
                       0, &debug_line_data_, &debug_line_patches);
@@ -333,7 +333,7 @@
   DW_CHECK("3      DW_TAG_compile_unit    [no children]");
 
   std::vector<uintptr_t> debug_info_patches;
-  std::vector<uintptr_t> expected_patches { 16, 20, 29, 33, 42, 46 };  // NOLINT
+  std::vector<uintptr_t> expected_patches = { 16, 20, 29, 33, 42, 46 };
   dwarf::WriteDebugInfoCU(0 /* debug_abbrev_offset */, info,
                           0, &debug_info_data_, &debug_info_patches);
 
diff --git a/compiler/debug/dwarf/dwarf_test.h b/compiler/debug/dwarf/dwarf_test.h
index e2f0a65..9a7c604 100644
--- a/compiler/debug/dwarf/dwarf_test.h
+++ b/compiler/debug/dwarf/dwarf_test.h
@@ -17,20 +17,21 @@
 #ifndef ART_COMPILER_DEBUG_DWARF_DWARF_TEST_H_
 #define ART_COMPILER_DEBUG_DWARF_DWARF_TEST_H_
 
-#include <cstring>
 #include <dirent.h>
-#include <memory>
-#include <set>
 #include <stdio.h>
-#include <string>
 #include <sys/types.h>
 
+#include <cstring>
+#include <memory>
+#include <set>
+#include <string>
+
+#include "base/os.h"
 #include "base/unix_file/fd_file.h"
 #include "common_runtime_test.h"
-#include "elf_builder.h"
 #include "gtest/gtest.h"
+#include "linker/elf_builder.h"
 #include "linker/file_output_stream.h"
-#include "os.h"
 
 namespace art {
 namespace dwarf {
@@ -59,10 +60,11 @@
   template<typename ElfTypes>
   std::vector<std::string> Objdump(const char* args) {
     // Write simple elf file with just the DWARF sections.
-    InstructionSet isa = (sizeof(typename ElfTypes::Addr) == 8) ? kX86_64 : kX86;
+    InstructionSet isa =
+        (sizeof(typename ElfTypes::Addr) == 8) ? InstructionSet::kX86_64 : InstructionSet::kX86;
     ScratchFile file;
-    FileOutputStream output_stream(file.GetFile());
-    ElfBuilder<ElfTypes> builder(isa, nullptr, &output_stream);
+    linker::FileOutputStream output_stream(file.GetFile());
+    linker::ElfBuilder<ElfTypes> builder(isa, nullptr, &output_stream);
     builder.Start();
     if (!debug_info_data_.empty()) {
       builder.WriteSection(".debug_info", &debug_info_data_);
diff --git a/compiler/debug/dwarf/writer.h b/compiler/debug/dwarf/writer.h
index 95912ad..c09d97a 100644
--- a/compiler/debug/dwarf/writer.h
+++ b/compiler/debug/dwarf/writer.h
@@ -19,9 +19,11 @@
 
 #include <type_traits>
 #include <vector>
+
+#include <android-base/logging.h>
+
 #include "base/bit_utils.h"
-#include "base/logging.h"
-#include "leb128.h"
+#include "base/leb128.h"
 
 namespace art {
 namespace dwarf {
diff --git a/compiler/debug/elf_debug_frame_writer.h b/compiler/debug/elf_debug_frame_writer.h
index f9d33c1..27b70c8 100644
--- a/compiler/debug/elf_debug_frame_writer.h
+++ b/compiler/debug/elf_debug_frame_writer.h
@@ -24,7 +24,7 @@
 #include "debug/dwarf/dwarf_constants.h"
 #include "debug/dwarf/headers.h"
 #include "debug/method_debug_info.h"
-#include "elf_builder.h"
+#include "linker/elf_builder.h"
 
 namespace art {
 namespace debug {
@@ -37,8 +37,8 @@
   // debugger that its value in the previous frame is not recoverable.
   bool is64bit = Is64BitInstructionSet(isa);
   switch (isa) {
-    case kArm:
-    case kThumb2: {
+    case InstructionSet::kArm:
+    case InstructionSet::kThumb2: {
       dwarf::DebugFrameOpCodeWriter<> opcodes;
       opcodes.DefCFA(Reg::ArmCore(13), 0);  // R13(SP).
       // core registers.
@@ -61,7 +61,7 @@
       WriteCIE(is64bit, return_reg, opcodes, format, buffer);
       return;
     }
-    case kArm64: {
+    case InstructionSet::kArm64: {
       dwarf::DebugFrameOpCodeWriter<> opcodes;
       opcodes.DefCFA(Reg::Arm64Core(31), 0);  // R31(SP).
       // core registers.
@@ -84,8 +84,8 @@
       WriteCIE(is64bit, return_reg, opcodes, format, buffer);
       return;
     }
-    case kMips:
-    case kMips64: {
+    case InstructionSet::kMips:
+    case InstructionSet::kMips64: {
       dwarf::DebugFrameOpCodeWriter<> opcodes;
       opcodes.DefCFA(Reg::MipsCore(29), 0);  // R29(SP).
       // core registers.
@@ -108,7 +108,7 @@
       WriteCIE(is64bit, return_reg, opcodes, format, buffer);
       return;
     }
-    case kX86: {
+    case InstructionSet::kX86: {
       // FIXME: Add fp registers once libunwind adds support for them. Bug: 20491296
       constexpr bool generate_opcodes_for_x86_fp = false;
       dwarf::DebugFrameOpCodeWriter<> opcodes;
@@ -134,7 +134,7 @@
       WriteCIE(is64bit, return_reg, opcodes, format, buffer);
       return;
     }
-    case kX86_64: {
+    case InstructionSet::kX86_64: {
       dwarf::DebugFrameOpCodeWriter<> opcodes;
       opcodes.DefCFA(Reg::X86_64Core(4), 8);  // R4(RSP).
       opcodes.Offset(Reg::X86_64Core(16), -8);  // R16(RIP).
@@ -160,7 +160,7 @@
       WriteCIE(is64bit, return_reg, opcodes, format, buffer);
       return;
     }
-    case kNone:
+    case InstructionSet::kNone:
       break;
   }
   LOG(FATAL) << "Cannot write CIE frame for ISA " << isa;
@@ -168,7 +168,7 @@
 }
 
 template<typename ElfTypes>
-void WriteCFISection(ElfBuilder<ElfTypes>* builder,
+void WriteCFISection(linker::ElfBuilder<ElfTypes>* builder,
                      const ArrayRef<const MethodDebugInfo>& method_infos,
                      dwarf::CFIFormat format,
                      bool write_oat_patches) {
@@ -207,13 +207,12 @@
   }
 
   // Write .eh_frame/.debug_frame section.
-  auto* cfi_section = (format == dwarf::DW_DEBUG_FRAME_FORMAT
-                       ? builder->GetDebugFrame()
-                       : builder->GetEhFrame());
+  const bool is_debug_frame = format == dwarf::DW_DEBUG_FRAME_FORMAT;
+  auto* cfi_section = (is_debug_frame ? builder->GetDebugFrame() : builder->GetEhFrame());
   {
     cfi_section->Start();
     const bool is64bit = Is64BitInstructionSet(builder->GetIsa());
-    const Elf_Addr cfi_address = cfi_section->GetAddress();
+    const Elf_Addr cfi_address = (is_debug_frame ? 0 : cfi_section->GetAddress());
     const Elf_Addr cie_address = cfi_address;
     Elf_Addr buffer_address = cfi_address;
     std::vector<uint8_t> buffer;  // Small temporary buffer.
diff --git a/compiler/debug/elf_debug_info_writer.h b/compiler/debug/elf_debug_info_writer.h
index de32351..893cad2 100644
--- a/compiler/debug/elf_debug_info_writer.h
+++ b/compiler/debug/elf_debug_info_writer.h
@@ -27,13 +27,16 @@
 #include "debug/elf_compilation_unit.h"
 #include "debug/elf_debug_loc_writer.h"
 #include "debug/method_debug_info.h"
-#include "dex_file-inl.h"
-#include "dex_file.h"
-#include "elf_builder.h"
+#include "dex/code_item_accessors-inl.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file.h"
+#include "heap_poisoning.h"
 #include "linear_alloc.h"
+#include "linker/elf_builder.h"
 #include "mirror/array.h"
 #include "mirror/class-inl.h"
 #include "mirror/class.h"
+#include "oat_file.h"
 
 namespace art {
 namespace debug {
@@ -46,9 +49,10 @@
 
 static std::vector<const char*> GetParamNames(const MethodDebugInfo* mi) {
   std::vector<const char*> names;
-  if (mi->code_item != nullptr) {
+  CodeItemDebugInfoAccessor accessor(*mi->dex_file, mi->code_item, mi->dex_method_index);
+  if (accessor.HasCodeItem()) {
     DCHECK(mi->dex_file != nullptr);
-    const uint8_t* stream = mi->dex_file->GetDebugInfoStream(mi->code_item);
+    const uint8_t* stream = mi->dex_file->GetDebugInfoStream(accessor.DebugInfoOffset());
     if (stream != nullptr) {
       DecodeUnsignedLeb128(&stream);  // line.
       uint32_t parameters_size = DecodeUnsignedLeb128(&stream);
@@ -67,7 +71,7 @@
   using Elf_Addr = typename ElfTypes::Addr;
 
  public:
-  explicit ElfDebugInfoWriter(ElfBuilder<ElfTypes>* builder)
+  explicit ElfDebugInfoWriter(linker::ElfBuilder<ElfTypes>* builder)
       : builder_(builder),
         debug_abbrev_(&debug_abbrev_buffer_) {
   }
@@ -92,7 +96,7 @@
   }
 
  private:
-  ElfBuilder<ElfTypes>* builder_;
+  linker::ElfBuilder<ElfTypes>* builder_;
   std::vector<uintptr_t> debug_info_patches_;
   std::vector<uint8_t> debug_abbrev_buffer_;
   dwarf::DebugAbbrevWriter<> debug_abbrev_;
@@ -122,22 +126,44 @@
     const Elf_Addr base_address = compilation_unit.is_code_address_text_relative
         ? owner_->builder_->GetText()->GetAddress()
         : 0;
-    const uint64_t cu_size = compilation_unit.code_end - compilation_unit.code_address;
+    const bool is64bit = Is64BitInstructionSet(owner_->builder_->GetIsa());
     using namespace dwarf;  // NOLINT. For easy access to DWARF constants.
 
     info_.StartTag(DW_TAG_compile_unit);
     info_.WriteString(DW_AT_producer, "Android dex2oat");
     info_.WriteData1(DW_AT_language, DW_LANG_Java);
     info_.WriteString(DW_AT_comp_dir, "$JAVA_SRC_ROOT");
+    // The low_pc acts as base address for several other addresses/ranges.
     info_.WriteAddr(DW_AT_low_pc, base_address + compilation_unit.code_address);
-    info_.WriteUdata(DW_AT_high_pc, dchecked_integral_cast<uint32_t>(cu_size));
     info_.WriteSecOffset(DW_AT_stmt_list, compilation_unit.debug_line_offset);
 
+    // Write .debug_ranges entries covering code ranges of the whole compilation unit.
+    dwarf::Writer<> debug_ranges(&owner_->debug_ranges_);
+    info_.WriteSecOffset(DW_AT_ranges, owner_->debug_ranges_.size());
+    for (auto mi : compilation_unit.methods) {
+      uint64_t low_pc = mi->code_address - compilation_unit.code_address;
+      uint64_t high_pc = low_pc + mi->code_size;
+      if (is64bit) {
+        debug_ranges.PushUint64(low_pc);
+        debug_ranges.PushUint64(high_pc);
+      } else {
+        debug_ranges.PushUint32(low_pc);
+        debug_ranges.PushUint32(high_pc);
+      }
+    }
+    if (is64bit) {
+      debug_ranges.PushUint64(0);  // End of list.
+      debug_ranges.PushUint64(0);
+    } else {
+      debug_ranges.PushUint32(0);  // End of list.
+      debug_ranges.PushUint32(0);
+    }
+
     const char* last_dex_class_desc = nullptr;
     for (auto mi : compilation_unit.methods) {
       DCHECK(mi->dex_file != nullptr);
       const DexFile* dex = mi->dex_file;
-      const DexFile::CodeItem* dex_code = mi->code_item;
+      CodeItemDebugInfoAccessor accessor(*dex, mi->code_item, mi->dex_method_index);
       const DexFile::MethodId& dex_method = dex->GetMethodId(mi->dex_method_index);
       const DexFile::ProtoId& dex_proto = dex->GetMethodPrototype(dex_method);
       const DexFile::TypeList* dex_params = dex->GetProtoParameters(dex_proto);
@@ -179,13 +205,13 @@
       // Decode dex register locations for all stack maps.
       // It might be expensive, so do it just once and reuse the result.
       std::vector<DexRegisterMap> dex_reg_maps;
-      if (mi->code_info != nullptr) {
+      if (accessor.HasCodeItem() && mi->code_info != nullptr) {
         const CodeInfo code_info(mi->code_info);
         CodeInfoEncoding encoding = code_info.ExtractEncoding();
         for (size_t s = 0; s < code_info.GetNumberOfStackMaps(encoding); ++s) {
           const StackMap& stack_map = code_info.GetStackMapAt(s, encoding);
           dex_reg_maps.push_back(code_info.GetDexRegisterMapOf(
-              stack_map, encoding, dex_code->registers_size_));
+              stack_map, encoding, accessor.RegistersSize()));
         }
       }
 
@@ -199,9 +225,9 @@
         WriteName("this");
         info_.WriteFlagPresent(DW_AT_artificial);
         WriteLazyType(dex_class_desc);
-        if (dex_code != nullptr) {
+        if (accessor.HasCodeItem()) {
           // Write the stack location of the parameter.
-          const uint32_t vreg = dex_code->registers_size_ - dex_code->ins_size_ + arg_reg;
+          const uint32_t vreg = accessor.RegistersSize() - accessor.InsSize() + arg_reg;
           const bool is64bitValue = false;
           WriteRegLocation(mi, dex_reg_maps, vreg, is64bitValue, compilation_unit.code_address);
         }
@@ -219,28 +245,27 @@
           const char* type_desc = dex->StringByTypeIdx(dex_params->GetTypeItem(i).type_idx_);
           WriteLazyType(type_desc);
           const bool is64bitValue = type_desc[0] == 'D' || type_desc[0] == 'J';
-          if (dex_code != nullptr) {
+          if (accessor.HasCodeItem()) {
             // Write the stack location of the parameter.
-            const uint32_t vreg = dex_code->registers_size_ - dex_code->ins_size_ + arg_reg;
+            const uint32_t vreg = accessor.RegistersSize() - accessor.InsSize() + arg_reg;
             WriteRegLocation(mi, dex_reg_maps, vreg, is64bitValue, compilation_unit.code_address);
           }
           arg_reg += is64bitValue ? 2 : 1;
           info_.EndTag();
         }
-        if (dex_code != nullptr) {
-          DCHECK_EQ(arg_reg, dex_code->ins_size_);
+        if (accessor.HasCodeItem()) {
+          DCHECK_EQ(arg_reg, accessor.InsSize());
         }
       }
 
       // Write local variables.
       LocalInfos local_infos;
-      if (dex->DecodeDebugLocalInfo(dex_code,
-                                    is_static,
-                                    mi->dex_method_index,
-                                    LocalInfoCallback,
-                                    &local_infos)) {
+      if (accessor.DecodeDebugLocalInfo(is_static,
+                                        mi->dex_method_index,
+                                        LocalInfoCallback,
+                                        &local_infos)) {
         for (const DexFile::LocalInfo& var : local_infos) {
-          if (var.reg_ < dex_code->registers_size_ - dex_code->ins_size_) {
+          if (var.reg_ < accessor.RegistersSize() - accessor.InsSize()) {
             info_.StartTag(DW_TAG_variable);
             WriteName(var.name_);
             WriteLazyType(var.descriptor_);
@@ -269,7 +294,7 @@
     CHECK_EQ(info_.Depth(), 0);
     std::vector<uint8_t> buffer;
     buffer.reserve(info_.data()->size() + KB);
-    const size_t offset = owner_->builder_->GetDebugInfo()->GetSize();
+    const size_t offset = owner_->builder_->GetDebugInfo()->GetPosition();
     // All compilation units share single table which is at the start of .debug_abbrev.
     const size_t debug_abbrev_offset = 0;
     WriteDebugInfoCU(debug_abbrev_offset, info_, offset, &buffer, &owner_->debug_info_patches_);
@@ -434,7 +459,7 @@
     CHECK_EQ(info_.Depth(), 0);
     std::vector<uint8_t> buffer;
     buffer.reserve(info_.data()->size() + KB);
-    const size_t offset = owner_->builder_->GetDebugInfo()->GetSize();
+    const size_t offset = owner_->builder_->GetDebugInfo()->GetPosition();
     // All compilation units share single table which is at the start of .debug_abbrev.
     const size_t debug_abbrev_offset = 0;
     WriteDebugInfoCU(debug_abbrev_offset, info_, offset, &buffer, &owner_->debug_info_patches_);
diff --git a/compiler/debug/elf_debug_line_writer.h b/compiler/debug/elf_debug_line_writer.h
index cdd1e53..44504c1 100644
--- a/compiler/debug/elf_debug_line_writer.h
+++ b/compiler/debug/elf_debug_line_writer.h
@@ -20,12 +20,13 @@
 #include <unordered_set>
 #include <vector>
 
-#include "compiled_method.h"
 #include "debug/dwarf/debug_line_opcode_writer.h"
 #include "debug/dwarf/headers.h"
 #include "debug/elf_compilation_unit.h"
-#include "dex_file-inl.h"
-#include "elf_builder.h"
+#include "debug/src_map_elem.h"
+#include "dex/dex_file-inl.h"
+#include "linker/elf_builder.h"
+#include "oat_file.h"
 #include "stack_map.h"
 
 namespace art {
@@ -43,7 +44,7 @@
   using Elf_Addr = typename ElfTypes::Addr;
 
  public:
-  explicit ElfDebugLineWriter(ElfBuilder<ElfTypes>* builder) : builder_(builder) {
+  explicit ElfDebugLineWriter(linker::ElfBuilder<ElfTypes>* builder) : builder_(builder) {
   }
 
   void Start() {
@@ -59,7 +60,7 @@
         ? builder_->GetText()->GetAddress()
         : 0;
 
-    compilation_unit.debug_line_offset = builder_->GetDebugLine()->GetSize();
+    compilation_unit.debug_line_offset = builder_->GetDebugLine()->GetPosition();
 
     std::vector<dwarf::FileEntry> files;
     std::unordered_map<std::string, size_t> files_map;
@@ -68,19 +69,19 @@
     int code_factor_bits_ = 0;
     int dwarf_isa = -1;
     switch (isa) {
-      case kArm:  // arm actually means thumb2.
-      case kThumb2:
+      case InstructionSet::kArm:  // arm actually means thumb2.
+      case InstructionSet::kThumb2:
         code_factor_bits_ = 1;  // 16-bit instuctions
         dwarf_isa = 1;  // DW_ISA_ARM_thumb.
         break;
-      case kArm64:
-      case kMips:
-      case kMips64:
+      case InstructionSet::kArm64:
+      case InstructionSet::kMips:
+      case InstructionSet::kMips64:
         code_factor_bits_ = 2;  // 32-bit instructions
         break;
-      case kNone:
-      case kX86:
-      case kX86_64:
+      case InstructionSet::kNone:
+      case InstructionSet::kX86:
+      case InstructionSet::kX86_64:
         break;
     }
     std::unordered_set<uint64_t> seen_addresses(compilation_unit.methods.size());
@@ -158,7 +159,9 @@
       PositionInfos dex2line_map;
       DCHECK(mi->dex_file != nullptr);
       const DexFile* dex = mi->dex_file;
-      if (!dex->DecodeDebugPositionInfo(mi->code_item, PositionInfoCallback, &dex2line_map)) {
+      CodeItemDebugInfoAccessor accessor(*dex, mi->code_item, mi->dex_method_index);
+      const uint32_t debug_info_offset = accessor.DebugInfoOffset();
+      if (!dex->DecodeDebugPositionInfo(debug_info_offset, PositionInfoCallback, &dex2line_map)) {
         continue;
       }
 
@@ -265,7 +268,7 @@
     }
     std::vector<uint8_t> buffer;
     buffer.reserve(opcodes.data()->size() + KB);
-    size_t offset = builder_->GetDebugLine()->GetSize();
+    size_t offset = builder_->GetDebugLine()->GetPosition();
     WriteDebugLineTable(directories, files, opcodes, offset, &buffer, &debug_line_patches_);
     builder_->GetDebugLine()->WriteFully(buffer.data(), buffer.size());
     return buffer.size();
@@ -280,7 +283,7 @@
   }
 
  private:
-  ElfBuilder<ElfTypes>* builder_;
+  linker::ElfBuilder<ElfTypes>* builder_;
   std::vector<uintptr_t> debug_line_patches_;
 };
 
diff --git a/compiler/debug/elf_debug_loc_writer.h b/compiler/debug/elf_debug_loc_writer.h
index bf47e8f..9ea9f01 100644
--- a/compiler/debug/elf_debug_loc_writer.h
+++ b/compiler/debug/elf_debug_loc_writer.h
@@ -33,20 +33,20 @@
 
 static Reg GetDwarfCoreReg(InstructionSet isa, int machine_reg) {
   switch (isa) {
-    case kArm:
-    case kThumb2:
+    case InstructionSet::kArm:
+    case InstructionSet::kThumb2:
       return Reg::ArmCore(machine_reg);
-    case kArm64:
+    case InstructionSet::kArm64:
       return Reg::Arm64Core(machine_reg);
-    case kX86:
+    case InstructionSet::kX86:
       return Reg::X86Core(machine_reg);
-    case kX86_64:
+    case InstructionSet::kX86_64:
       return Reg::X86_64Core(machine_reg);
-    case kMips:
+    case InstructionSet::kMips:
       return Reg::MipsCore(machine_reg);
-    case kMips64:
+    case InstructionSet::kMips64:
       return Reg::Mips64Core(machine_reg);
-    case kNone:
+    case InstructionSet::kNone:
       LOG(FATAL) << "No instruction set";
   }
   UNREACHABLE();
@@ -54,20 +54,20 @@
 
 static Reg GetDwarfFpReg(InstructionSet isa, int machine_reg) {
   switch (isa) {
-    case kArm:
-    case kThumb2:
+    case InstructionSet::kArm:
+    case InstructionSet::kThumb2:
       return Reg::ArmFp(machine_reg);
-    case kArm64:
+    case InstructionSet::kArm64:
       return Reg::Arm64Fp(machine_reg);
-    case kX86:
+    case InstructionSet::kX86:
       return Reg::X86Fp(machine_reg);
-    case kX86_64:
+    case InstructionSet::kX86_64:
       return Reg::X86_64Fp(machine_reg);
-    case kMips:
+    case InstructionSet::kMips:
       return Reg::MipsFp(machine_reg);
-    case kMips64:
+    case InstructionSet::kMips64:
       return Reg::Mips64Fp(machine_reg);
-    case kNone:
+    case InstructionSet::kNone:
       LOG(FATAL) << "No instruction set";
   }
   UNREACHABLE();
@@ -149,11 +149,12 @@
     DCHECK_LT(stack_map_index, dex_register_maps.size());
     DexRegisterMap dex_register_map = dex_register_maps[stack_map_index];
     DCHECK(dex_register_map.IsValid());
+    CodeItemDataAccessor accessor(*method_info->dex_file, method_info->code_item);
     reg_lo = dex_register_map.GetDexRegisterLocation(
-        vreg, method_info->code_item->registers_size_, code_info, encoding);
+        vreg, accessor.RegistersSize(), code_info, encoding);
     if (is64bitValue) {
       reg_hi = dex_register_map.GetDexRegisterLocation(
-          vreg + 1, method_info->code_item->registers_size_, code_info, encoding);
+          vreg + 1, accessor.RegistersSize(), code_info, encoding);
     }
 
     // Add location entry for this address range.
@@ -230,7 +231,7 @@
           break;  // the high word is correctly implied by the low word.
         }
       } else if (kind == Kind::kInFpuRegister) {
-        if ((isa == kArm || isa == kThumb2) &&
+        if ((isa == InstructionSet::kArm || isa == InstructionSet::kThumb2) &&
             piece == 0 && reg_hi.GetKind() == Kind::kInFpuRegister &&
             reg_hi.GetValue() == value + 1 && value % 2 == 0) {
           // Translate S register pair to D register (e.g. S4+S5 to D2).
@@ -251,7 +252,10 @@
         // kInStackLargeOffset and kConstantLargeValue are hidden by GetKind().
         // kInRegisterHigh and kInFpuRegisterHigh should be handled by
         // the special cases above and they should not occur alone.
-        LOG(ERROR) << "Unexpected register location kind: " << kind;
+        LOG(WARNING) << "Unexpected register location: " << kind
+                     << " (This can indicate either a bug in the dexer when generating"
+                     << " local variable information, or a bug in ART compiler."
+                     << " Please file a bug at go/art-bug)";
         break;
       }
       if (is64bitValue) {
diff --git a/compiler/debug/elf_debug_writer.cc b/compiler/debug/elf_debug_writer.cc
index 7fa6e14..59a080f 100644
--- a/compiler/debug/elf_debug_writer.cc
+++ b/compiler/debug/elf_debug_writer.cc
@@ -17,6 +17,7 @@
 #include "elf_debug_writer.h"
 
 #include <vector>
+#include <unordered_map>
 
 #include "base/array_ref.h"
 #include "debug/dwarf/dwarf_constants.h"
@@ -28,7 +29,7 @@
 #include "debug/elf_gnu_debugdata_writer.h"
 #include "debug/elf_symtab_writer.h"
 #include "debug/method_debug_info.h"
-#include "elf_builder.h"
+#include "linker/elf_builder.h"
 #include "linker/vector_output_stream.h"
 #include "oat.h"
 
@@ -36,37 +37,52 @@
 namespace debug {
 
 template <typename ElfTypes>
-void WriteDebugInfo(ElfBuilder<ElfTypes>* builder,
-                    const ArrayRef<const MethodDebugInfo>& method_infos,
+void WriteDebugInfo(linker::ElfBuilder<ElfTypes>* builder,
+                    const DebugInfo& debug_info,
                     dwarf::CFIFormat cfi_format,
                     bool write_oat_patches) {
   // Write .strtab and .symtab.
-  WriteDebugSymbols(builder, method_infos, true /* with_signature */);
+  WriteDebugSymbols(builder, false /* mini-debug-info */, debug_info);
 
   // Write .debug_frame.
-  WriteCFISection(builder, method_infos, cfi_format, write_oat_patches);
+  WriteCFISection(builder, debug_info.compiled_methods, cfi_format, write_oat_patches);
 
-  // Group the methods into compilation units based on source file.
-  std::vector<ElfCompilationUnit> compilation_units;
-  const char* last_source_file = nullptr;
-  for (const MethodDebugInfo& mi : method_infos) {
+  // Group the methods into compilation units based on class.
+  std::unordered_map<const DexFile::ClassDef*, ElfCompilationUnit> class_to_compilation_unit;
+  for (const MethodDebugInfo& mi : debug_info.compiled_methods) {
     if (mi.dex_file != nullptr) {
       auto& dex_class_def = mi.dex_file->GetClassDef(mi.class_def_index);
-      const char* source_file = mi.dex_file->GetSourceFile(dex_class_def);
-      if (compilation_units.empty() || source_file != last_source_file) {
-        compilation_units.push_back(ElfCompilationUnit());
-      }
-      ElfCompilationUnit& cu = compilation_units.back();
+      ElfCompilationUnit& cu = class_to_compilation_unit[&dex_class_def];
       cu.methods.push_back(&mi);
       // All methods must have the same addressing mode otherwise the min/max below does not work.
       DCHECK_EQ(cu.methods.front()->is_code_address_text_relative, mi.is_code_address_text_relative);
       cu.is_code_address_text_relative = mi.is_code_address_text_relative;
       cu.code_address = std::min(cu.code_address, mi.code_address);
       cu.code_end = std::max(cu.code_end, mi.code_address + mi.code_size);
-      last_source_file = source_file;
     }
   }
 
+  // Sort compilation units to make the compiler output deterministic.
+  std::vector<ElfCompilationUnit> compilation_units;
+  compilation_units.reserve(class_to_compilation_unit.size());
+  for (auto& it : class_to_compilation_unit) {
+    // The .debug_line section requires the methods to be sorted by code address.
+    std::stable_sort(it.second.methods.begin(),
+                     it.second.methods.end(),
+                     [](const MethodDebugInfo* a, const MethodDebugInfo* b) {
+                         return a->code_address < b->code_address;
+                     });
+    compilation_units.push_back(std::move(it.second));
+  }
+  std::sort(compilation_units.begin(),
+            compilation_units.end(),
+            [](ElfCompilationUnit& a, ElfCompilationUnit& b) {
+                // Sort by index of the first method within the method_infos array.
+                // This assumes that the order of method_infos is deterministic.
+                // Code address is not good for sorting due to possible duplicates.
+                return a.methods.front() < b.methods.front();
+            });
+
   // Write .debug_line section.
   if (!compilation_units.empty()) {
     ElfDebugLineWriter<ElfTypes> line_writer(builder);
@@ -92,52 +108,94 @@
 std::vector<uint8_t> MakeMiniDebugInfo(
     InstructionSet isa,
     const InstructionSetFeatures* features,
-    size_t rodata_size,
-    size_t text_size,
-    const ArrayRef<const MethodDebugInfo>& method_infos) {
+    uint64_t text_section_address,
+    size_t text_section_size,
+    uint64_t dex_section_address,
+    size_t dex_section_size,
+    const DebugInfo& debug_info) {
   if (Is64BitInstructionSet(isa)) {
     return MakeMiniDebugInfoInternal<ElfTypes64>(isa,
                                                  features,
-                                                 rodata_size,
-                                                 text_size,
-                                                 method_infos);
+                                                 text_section_address,
+                                                 text_section_size,
+                                                 dex_section_address,
+                                                 dex_section_size,
+                                                 debug_info);
   } else {
     return MakeMiniDebugInfoInternal<ElfTypes32>(isa,
                                                  features,
-                                                 rodata_size,
-                                                 text_size,
-                                                 method_infos);
+                                                 text_section_address,
+                                                 text_section_size,
+                                                 dex_section_address,
+                                                 dex_section_size,
+                                                 debug_info);
   }
 }
 
 template <typename ElfTypes>
-static std::vector<uint8_t> WriteDebugElfFileForMethodsInternal(
+static std::vector<uint8_t> MakeElfFileForJITInternal(
     InstructionSet isa,
     const InstructionSetFeatures* features,
-    const ArrayRef<const MethodDebugInfo>& method_infos) {
+    bool mini_debug_info,
+    ArrayRef<const MethodDebugInfo> method_infos) {
+  CHECK_GT(method_infos.size(), 0u);
+  uint64_t min_address = std::numeric_limits<uint64_t>::max();
+  uint64_t max_address = 0;
+  for (const MethodDebugInfo& mi : method_infos) {
+    CHECK_EQ(mi.is_code_address_text_relative, false);
+    min_address = std::min(min_address, mi.code_address);
+    max_address = std::max(max_address, mi.code_address + mi.code_size);
+  }
+  DebugInfo debug_info{};
+  debug_info.compiled_methods = method_infos;
   std::vector<uint8_t> buffer;
   buffer.reserve(KB);
-  VectorOutputStream out("Debug ELF file", &buffer);
-  std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, features, &out));
+  linker::VectorOutputStream out("Debug ELF file", &buffer);
+  std::unique_ptr<linker::ElfBuilder<ElfTypes>> builder(
+      new linker::ElfBuilder<ElfTypes>(isa, features, &out));
   // No program headers since the ELF file is not linked and has no allocated sections.
   builder->Start(false /* write_program_headers */);
-  WriteDebugInfo(builder.get(),
-                 method_infos,
-                 dwarf::DW_DEBUG_FRAME_FORMAT,
-                 false /* write_oat_patches */);
+  if (mini_debug_info) {
+    if (method_infos.size() > 1) {
+      std::vector<uint8_t> mdi = MakeMiniDebugInfo(isa,
+                                                   features,
+                                                   min_address,
+                                                   max_address - min_address,
+                                                   /* dex_section_address */ 0,
+                                                   /* dex_section_size */ 0,
+                                                   debug_info);
+      builder->WriteSection(".gnu_debugdata", &mdi);
+    } else {
+      // The compression is great help for multiple methods but it is not worth it for a
+      // single method due to the overheads so skip the compression here for performance.
+      builder->GetText()->AllocateVirtualMemory(min_address, max_address - min_address);
+      WriteDebugSymbols(builder.get(), true /* mini-debug-info */, debug_info);
+      WriteCFISection(builder.get(),
+                      debug_info.compiled_methods,
+                      dwarf::DW_DEBUG_FRAME_FORMAT,
+                      false /* write_oat_paches */);
+    }
+  } else {
+    builder->GetText()->AllocateVirtualMemory(min_address, max_address - min_address);
+    WriteDebugInfo(builder.get(),
+                   debug_info,
+                   dwarf::DW_DEBUG_FRAME_FORMAT,
+                   false /* write_oat_patches */);
+  }
   builder->End();
   CHECK(builder->Good());
   return buffer;
 }
 
-std::vector<uint8_t> WriteDebugElfFileForMethods(
+std::vector<uint8_t> MakeElfFileForJIT(
     InstructionSet isa,
     const InstructionSetFeatures* features,
-    const ArrayRef<const MethodDebugInfo>& method_infos) {
+    bool mini_debug_info,
+    ArrayRef<const MethodDebugInfo> method_infos) {
   if (Is64BitInstructionSet(isa)) {
-    return WriteDebugElfFileForMethodsInternal<ElfTypes64>(isa, features, method_infos);
+    return MakeElfFileForJITInternal<ElfTypes64>(isa, features, mini_debug_info, method_infos);
   } else {
-    return WriteDebugElfFileForMethodsInternal<ElfTypes32>(isa, features, method_infos);
+    return MakeElfFileForJITInternal<ElfTypes32>(isa, features, mini_debug_info, method_infos);
   }
 }
 
@@ -149,8 +207,9 @@
     REQUIRES_SHARED(Locks::mutator_lock_) {
   std::vector<uint8_t> buffer;
   buffer.reserve(KB);
-  VectorOutputStream out("Debug ELF file", &buffer);
-  std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, features, &out));
+  linker::VectorOutputStream out("Debug ELF file", &buffer);
+  std::unique_ptr<linker::ElfBuilder<ElfTypes>> builder(
+      new linker::ElfBuilder<ElfTypes>(isa, features, &out));
   // No program headers since the ELF file is not linked and has no allocated sections.
   builder->Start(false /* write_program_headers */);
   ElfDebugInfoWriter<ElfTypes> info_writer(builder.get());
@@ -174,40 +233,15 @@
   }
 }
 
-std::vector<MethodDebugInfo> MakeTrampolineInfos(const OatHeader& header) {
-  std::map<const char*, uint32_t> trampolines = {
-    { "interpreterToInterpreterBridge", header.GetInterpreterToInterpreterBridgeOffset() },
-    { "interpreterToCompiledCodeBridge", header.GetInterpreterToCompiledCodeBridgeOffset() },
-    { "jniDlsymLookup", header.GetJniDlsymLookupOffset() },
-    { "quickGenericJniTrampoline", header.GetQuickGenericJniTrampolineOffset() },
-    { "quickImtConflictTrampoline", header.GetQuickImtConflictTrampolineOffset() },
-    { "quickResolutionTrampoline", header.GetQuickResolutionTrampolineOffset() },
-    { "quickToInterpreterBridge", header.GetQuickToInterpreterBridgeOffset() },
-  };
-  std::vector<MethodDebugInfo> result;
-  for (const auto& it : trampolines) {
-    if (it.second != 0) {
-      MethodDebugInfo info = MethodDebugInfo();
-      info.trampoline_name = it.first;
-      info.isa = header.GetInstructionSet();
-      info.is_code_address_text_relative = true;
-      info.code_address = it.second - header.GetExecutableOffset();
-      info.code_size = 0;  // The symbol lasts until the next symbol.
-      result.push_back(std::move(info));
-    }
-  }
-  return result;
-}
-
 // Explicit instantiations
 template void WriteDebugInfo<ElfTypes32>(
-    ElfBuilder<ElfTypes32>* builder,
-    const ArrayRef<const MethodDebugInfo>& method_infos,
+    linker::ElfBuilder<ElfTypes32>* builder,
+    const DebugInfo& debug_info,
     dwarf::CFIFormat cfi_format,
     bool write_oat_patches);
 template void WriteDebugInfo<ElfTypes64>(
-    ElfBuilder<ElfTypes64>* builder,
-    const ArrayRef<const MethodDebugInfo>& method_infos,
+    linker::ElfBuilder<ElfTypes64>* builder,
+    const DebugInfo& debug_info,
     dwarf::CFIFormat cfi_format,
     bool write_oat_patches);
 
diff --git a/compiler/debug/elf_debug_writer.h b/compiler/debug/elf_debug_writer.h
index 5d68810..e442e00 100644
--- a/compiler/debug/elf_debug_writer.h
+++ b/compiler/debug/elf_debug_writer.h
@@ -23,7 +23,8 @@
 #include "base/macros.h"
 #include "base/mutex.h"
 #include "debug/dwarf/dwarf_constants.h"
-#include "elf_builder.h"
+#include "debug/debug_info.h"
+#include "linker/elf_builder.h"
 
 namespace art {
 class OatHeader;
@@ -35,22 +36,25 @@
 
 template <typename ElfTypes>
 void WriteDebugInfo(
-    ElfBuilder<ElfTypes>* builder,
-    const ArrayRef<const MethodDebugInfo>& method_infos,
+    linker::ElfBuilder<ElfTypes>* builder,
+    const DebugInfo& debug_info,
     dwarf::CFIFormat cfi_format,
     bool write_oat_patches);
 
 std::vector<uint8_t> MakeMiniDebugInfo(
     InstructionSet isa,
     const InstructionSetFeatures* features,
-    size_t rodata_section_size,
+    uint64_t text_section_address,
     size_t text_section_size,
-    const ArrayRef<const MethodDebugInfo>& method_infos);
+    uint64_t dex_section_address,
+    size_t dex_section_size,
+    const DebugInfo& debug_info);
 
-std::vector<uint8_t> WriteDebugElfFileForMethods(
+std::vector<uint8_t> MakeElfFileForJIT(
     InstructionSet isa,
     const InstructionSetFeatures* features,
-    const ArrayRef<const MethodDebugInfo>& method_infos);
+    bool mini_debug_info,
+    ArrayRef<const MethodDebugInfo> method_infos);
 
 std::vector<uint8_t> WriteDebugElfFileForClasses(
     InstructionSet isa,
@@ -58,8 +62,6 @@
     const ArrayRef<mirror::Class*>& types)
     REQUIRES_SHARED(Locks::mutator_lock_);
 
-std::vector<MethodDebugInfo> MakeTrampolineInfos(const OatHeader& oat_header);
-
 }  // namespace debug
 }  // namespace art
 
diff --git a/compiler/debug/elf_gnu_debugdata_writer.h b/compiler/debug/elf_gnu_debugdata_writer.h
index fb63d62..a88c5cb 100644
--- a/compiler/debug/elf_gnu_debugdata_writer.h
+++ b/compiler/debug/elf_gnu_debugdata_writer.h
@@ -20,7 +20,7 @@
 #include <vector>
 
 #include "arch/instruction_set.h"
-#include "elf_builder.h"
+#include "linker/elf_builder.h"
 #include "linker/vector_output_stream.h"
 
 // liblzma.
@@ -80,21 +80,25 @@
 static std::vector<uint8_t> MakeMiniDebugInfoInternal(
     InstructionSet isa,
     const InstructionSetFeatures* features,
-    size_t rodata_section_size,
+    typename ElfTypes::Addr text_section_address,
     size_t text_section_size,
-    const ArrayRef<const MethodDebugInfo>& method_infos) {
+    typename ElfTypes::Addr dex_section_address,
+    size_t dex_section_size,
+    const DebugInfo& debug_info) {
   std::vector<uint8_t> buffer;
   buffer.reserve(KB);
-  VectorOutputStream out("Mini-debug-info ELF file", &buffer);
-  std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, features, &out));
-  builder->Start();
-  // Mirror .rodata and .text as NOBITS sections.
-  // It is needed to detected relocations after compression.
-  builder->GetRoData()->WriteNoBitsSection(rodata_section_size);
-  builder->GetText()->WriteNoBitsSection(text_section_size);
-  WriteDebugSymbols(builder.get(), method_infos, false /* with_signature */);
+  linker::VectorOutputStream out("Mini-debug-info ELF file", &buffer);
+  std::unique_ptr<linker::ElfBuilder<ElfTypes>> builder(
+      new linker::ElfBuilder<ElfTypes>(isa, features, &out));
+  builder->Start(false /* write_program_headers */);
+  // Mirror ELF sections as NOBITS since the added symbols will reference them.
+  builder->GetText()->AllocateVirtualMemory(text_section_address, text_section_size);
+  if (dex_section_size != 0) {
+    builder->GetDex()->AllocateVirtualMemory(dex_section_address, dex_section_size);
+  }
+  WriteDebugSymbols(builder.get(), true /* mini-debug-info */, debug_info);
   WriteCFISection(builder.get(),
-                  method_infos,
+                  debug_info.compiled_methods,
                   dwarf::DW_DEBUG_FRAME_FORMAT,
                   false /* write_oat_paches */);
   builder->End();
diff --git a/compiler/debug/elf_symtab_writer.h b/compiler/debug/elf_symtab_writer.h
index af9f091..7a8e291 100644
--- a/compiler/debug/elf_symtab_writer.h
+++ b/compiler/debug/elf_symtab_writer.h
@@ -17,11 +17,15 @@
 #ifndef ART_COMPILER_DEBUG_ELF_SYMTAB_WRITER_H_
 #define ART_COMPILER_DEBUG_ELF_SYMTAB_WRITER_H_
 
+#include <map>
 #include <unordered_set>
 
+#include "base/utils.h"
+#include "debug/debug_info.h"
 #include "debug/method_debug_info.h"
-#include "elf_builder.h"
-#include "utils.h"
+#include "dex/dex_file-inl.h"
+#include "dex/code_item_accessors.h"
+#include "linker/elf_builder.h"
 
 namespace art {
 namespace debug {
@@ -33,76 +37,83 @@
 // exist, but it will still work well without them.
 // However, these extra symbols take space, so let's just generate
 // one symbol which marks the whole .text section as code.
-constexpr bool kGenerateSingleArmMappingSymbol = true;
+// Note that ARM's Streamline requires it to match function symbol.
+constexpr bool kGenerateArmMappingSymbol = true;
+
+// Magic name for .symtab symbols which enumerate dex files used
+// by this ELF file (currently mmapped inside the .dex section).
+constexpr const char* kDexFileSymbolName = "$dexfile";
 
 template <typename ElfTypes>
-static void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder,
-                              const ArrayRef<const MethodDebugInfo>& method_infos,
-                              bool with_signature) {
+static void WriteDebugSymbols(linker::ElfBuilder<ElfTypes>* builder,
+                              bool mini_debug_info,
+                              const DebugInfo& debug_info) {
   uint64_t mapping_symbol_address = std::numeric_limits<uint64_t>::max();
+  const auto* text = builder->GetText();
   auto* strtab = builder->GetStrTab();
   auto* symtab = builder->GetSymTab();
 
-  if (method_infos.empty()) {
+  if (debug_info.Empty()) {
     return;
   }
 
   // Find all addresses which contain deduped methods.
   // The first instance of method is not marked deduped_, but the rest is.
   std::unordered_set<uint64_t> deduped_addresses;
-  for (const MethodDebugInfo& info : method_infos) {
+  for (const MethodDebugInfo& info : debug_info.compiled_methods) {
     if (info.deduped) {
       deduped_addresses.insert(info.code_address);
     }
+    if (kGenerateArmMappingSymbol && info.isa == InstructionSet::kThumb2) {
+      uint64_t address = info.code_address;
+      address += info.is_code_address_text_relative ? text->GetAddress() : 0;
+      mapping_symbol_address = std::min(mapping_symbol_address, address);
+    }
   }
 
   strtab->Start();
   strtab->Write("");  // strtab should start with empty string.
-  std::string last_name;
-  size_t last_name_offset = 0;
-  for (const MethodDebugInfo& info : method_infos) {
+  // Generate ARM mapping symbols. ELF local symbols must be added first.
+  if (mapping_symbol_address != std::numeric_limits<uint64_t>::max()) {
+    symtab->Add(strtab->Write("$t"), text, mapping_symbol_address, 0, STB_LOCAL, STT_NOTYPE);
+  }
+  // Add symbols for compiled methods.
+  for (const MethodDebugInfo& info : debug_info.compiled_methods) {
     if (info.deduped) {
       continue;  // Add symbol only for the first instance.
     }
     size_t name_offset;
-    if (info.trampoline_name != nullptr) {
-      name_offset = strtab->Write(info.trampoline_name);
+    if (!info.custom_name.empty()) {
+      name_offset = strtab->Write(info.custom_name);
     } else {
       DCHECK(info.dex_file != nullptr);
-      std::string name = info.dex_file->PrettyMethod(info.dex_method_index, with_signature);
+      std::string name = info.dex_file->PrettyMethod(info.dex_method_index, !mini_debug_info);
       if (deduped_addresses.find(info.code_address) != deduped_addresses.end()) {
         name += " [DEDUPED]";
       }
-      // If we write method names without signature, we might see the same name multiple times.
-      name_offset = (name == last_name ? last_name_offset : strtab->Write(name));
-      last_name = std::move(name);
-      last_name_offset = name_offset;
+      name_offset = strtab->Write(name);
     }
 
-    const auto* text = info.is_code_address_text_relative ? builder->GetText() : nullptr;
-    uint64_t address = info.code_address + (text != nullptr ? text->GetAddress() : 0);
+    uint64_t address = info.code_address;
+    address += info.is_code_address_text_relative ? text->GetAddress() : 0;
     // Add in code delta, e.g., thumb bit 0 for Thumb2 code.
     address += CompiledMethod::CodeDelta(info.isa);
     symtab->Add(name_offset, text, address, info.code_size, STB_GLOBAL, STT_FUNC);
-
-    // Conforming to aaelf, add $t mapping symbol to indicate start of a sequence of thumb2
-    // instructions, so that disassembler tools can correctly disassemble.
-    // Note that even if we generate just a single mapping symbol, ARM's Streamline
-    // requires it to match function symbol.  Just address 0 does not work.
-    if (info.isa == kThumb2) {
-      if (address < mapping_symbol_address || !kGenerateSingleArmMappingSymbol) {
-        symtab->Add(strtab->Write("$t"), text, address & ~1, 0, STB_LOCAL, STT_NOTYPE);
-        mapping_symbol_address = address;
-      }
+  }
+  // Add symbols for dex files.
+  if (!debug_info.dex_files.empty() && builder->GetDex()->Exists()) {
+    auto dex = builder->GetDex();
+    for (auto it : debug_info.dex_files) {
+      uint64_t dex_address = dex->GetAddress() + it.first /* offset within the section */;
+      const DexFile* dex_file = it.second;
+      typename ElfTypes::Word dex_name = strtab->Write(kDexFileSymbolName);
+      symtab->Add(dex_name, dex, dex_address, dex_file->Size(), STB_GLOBAL, STT_FUNC);
     }
   }
   strtab->End();
 
   // Symbols are buffered and written after names (because they are smaller).
-  // We could also do two passes in this function to avoid the buffering.
-  symtab->Start();
-  symtab->Write();
-  symtab->End();
+  symtab->WriteCachedSection();
 }
 
 }  // namespace debug
diff --git a/compiler/debug/method_debug_info.h b/compiler/debug/method_debug_info.h
index ed1da2c..d0b03ec 100644
--- a/compiler/debug/method_debug_info.h
+++ b/compiler/debug/method_debug_info.h
@@ -17,14 +17,17 @@
 #ifndef ART_COMPILER_DEBUG_METHOD_DEBUG_INFO_H_
 #define ART_COMPILER_DEBUG_METHOD_DEBUG_INFO_H_
 
-#include "compiled_method.h"
-#include "dex_file.h"
+#include <string>
+
+#include "arch/instruction_set.h"
+#include "base/array_ref.h"
+#include "dex/dex_file.h"
 
 namespace art {
 namespace debug {
 
 struct MethodDebugInfo {
-  const char* trampoline_name;
+  std::string custom_name;
   const DexFile* dex_file;  // Native methods (trampolines) do not reference dex file.
   size_t class_def_index;
   uint32_t dex_method_index;
diff --git a/compiler/debug/src_map_elem.h b/compiler/debug/src_map_elem.h
new file mode 100644
index 0000000..5286b8c
--- /dev/null
+++ b/compiler/debug/src_map_elem.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef ART_COMPILER_DEBUG_SRC_MAP_ELEM_H_
+#define ART_COMPILER_DEBUG_SRC_MAP_ELEM_H_
+
+#include <stdint.h>
+
+namespace art {
+
+class SrcMapElem {
+ public:
+  uint32_t from_;
+  int32_t to_;
+};
+
+inline bool operator<(const SrcMapElem& lhs, const SrcMapElem& rhs) {
+  if (lhs.from_ != rhs.from_) {
+    return lhs.from_ < rhs.from_;
+  }
+  return lhs.to_ < rhs.to_;
+}
+
+inline bool operator==(const SrcMapElem& lhs, const SrcMapElem& rhs) {
+  return lhs.from_ == rhs.from_ && lhs.to_ == rhs.to_;
+}
+
+}  // namespace art
+
+#endif  // ART_COMPILER_DEBUG_SRC_MAP_ELEM_H_
diff --git a/compiler/debug/src_map_elem_test.cc b/compiler/debug/src_map_elem_test.cc
new file mode 100644
index 0000000..ceaa53f
--- /dev/null
+++ b/compiler/debug/src_map_elem_test.cc
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2017 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 <gtest/gtest.h>
+
+#include "src_map_elem.h"
+
+#include "base/macros.h"
+
+namespace art {
+namespace debug {
+
+TEST(SrcMapElem, Operators) {
+  SrcMapElem elems[] = {
+      { 1u, -1 },
+      { 1u, 0 },
+      { 1u, 1 },
+      { 2u, -1 },
+      { 2u, 0 },    // Index 4.
+      { 2u, 1 },
+      { 2u, 0u },   // Index 6: Arbitrarily add identical SrcMapElem with index 4.
+  };
+
+  for (size_t i = 0; i != arraysize(elems); ++i) {
+    for (size_t j = 0; j != arraysize(elems); ++j) {
+      bool expected = (i != 6u ? i : 4u) == (j != 6u ? j : 4u);
+      EXPECT_EQ(expected, elems[i] == elems[j]) << i << " " << j;
+    }
+  }
+
+  for (size_t i = 0; i != arraysize(elems); ++i) {
+    for (size_t j = 0; j != arraysize(elems); ++j) {
+      bool expected = (i != 6u ? i : 4u) < (j != 6u ? j : 4u);
+      EXPECT_EQ(expected, elems[i] < elems[j]) << i << " " << j;
+    }
+  }
+}
+
+}  // namespace debug
+}  // namespace art
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index 9d57b96..be8641f 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -16,16 +16,19 @@
 
 #include "dex_to_dex_compiler.h"
 
-#include "android-base/stringprintf.h"
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
 
 #include "art_field-inl.h"
 #include "art_method-inl.h"
-#include "base/logging.h"
+#include "base/logging.h"  // For VLOG
+#include "base/macros.h"
 #include "base/mutex.h"
-#include "bytecode_utils.h"
 #include "compiled_method.h"
-#include "dex_file-inl.h"
-#include "dex_instruction-inl.h"
+#include "dex/bytecode_utils.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_instruction-inl.h"
+#include "dex_to_dex_decompiler.h"
 #include "driver/compiler_driver.h"
 #include "driver/dex_compilation_unit.h"
 #include "mirror/dex_cache.h"
@@ -42,34 +45,30 @@
 // Control check-cast elision.
 const bool kEnableCheckCastEllision = true;
 
-struct QuickenedInfo {
-  QuickenedInfo(uint32_t pc, uint16_t index) : dex_pc(pc), dex_member_index(index) {}
+// Holds the state for compiling a single method.
+struct DexToDexCompiler::CompilationState {
+  struct QuickenedInfo {
+    QuickenedInfo(uint32_t pc, uint16_t index) : dex_pc(pc), dex_member_index(index) {}
 
-  uint32_t dex_pc;
-  uint16_t dex_member_index;
-};
+    uint32_t dex_pc;
+    uint16_t dex_member_index;
+  };
 
-class DexCompiler {
- public:
-  DexCompiler(art::CompilerDriver& compiler,
-              const DexCompilationUnit& unit,
-              DexToDexCompilationLevel dex_to_dex_compilation_level)
-    : driver_(compiler),
-      unit_(unit),
-      dex_to_dex_compilation_level_(dex_to_dex_compilation_level) {}
-
-  ~DexCompiler() {}
-
-  void Compile();
+  CompilationState(DexToDexCompiler* compiler,
+                   const DexCompilationUnit& unit,
+                   const CompilationLevel compilation_level,
+                   const std::vector<uint8_t>* quicken_data);
 
   const std::vector<QuickenedInfo>& GetQuickenedInfo() const {
     return quickened_info_;
   }
 
- private:
-  const DexFile& GetDexFile() const {
-    return *unit_.GetDexFile();
-  }
+  // Returns the quickening info, or an empty array if it was not quickened.
+  // If already_quickened is true, then don't change anything but still return what the quicken
+  // data would have been.
+  std::vector<uint8_t> Compile();
+
+  const DexFile& GetDexFile() const;
 
   // Compiles a RETURN-VOID into a RETURN-VOID-BARRIER within a constructor where
   // a barrier is required.
@@ -91,30 +90,133 @@
 
   // Compiles a virtual method invocation into a quick virtual method invocation.
   // The method index is replaced by the vtable index where the corresponding
-  // Executable can be found. Therefore, this does not involve any resolution
+  // executable can be found. Therefore, this does not involve any resolution
   // at runtime.
   // Since the method index is encoded with 16 bits, we can replace it only if the
   // vtable index can be encoded with 16 bits too.
   void CompileInvokeVirtual(Instruction* inst, uint32_t dex_pc,
                             Instruction::Code new_opcode, bool is_range);
 
+  // Return the next index.
+  uint16_t NextIndex();
+
+  // Returns the dequickened index if an instruction is quickened, otherwise return index.
+  uint16_t GetIndexForInstruction(const Instruction* inst, uint32_t index);
+
+  DexToDexCompiler* const compiler_;
   CompilerDriver& driver_;
   const DexCompilationUnit& unit_;
-  const DexToDexCompilationLevel dex_to_dex_compilation_level_;
+  const CompilationLevel compilation_level_;
 
   // Filled by the compiler when quickening, in order to encode that information
   // in the .oat file. The runtime will use that information to get to the original
   // opcodes.
   std::vector<QuickenedInfo> quickened_info_;
 
-  DISALLOW_COPY_AND_ASSIGN(DexCompiler);
+  // True if we optimized a return void to a return void no barrier.
+  bool optimized_return_void_ = false;
+
+  // If the code item was already quickened previously.
+  const bool already_quickened_;
+  const QuickenInfoTable existing_quicken_info_;
+  uint32_t quicken_index_ = 0u;
+
+  DISALLOW_COPY_AND_ASSIGN(CompilationState);
 };
 
-void DexCompiler::Compile() {
-  DCHECK_EQ(dex_to_dex_compilation_level_, DexToDexCompilationLevel::kOptimize);
-  for (CodeItemIterator it(*unit_.GetCodeItem()); !it.Done(); it.Advance()) {
-    Instruction* inst = const_cast<Instruction*>(&it.CurrentInstruction());
-    const uint32_t dex_pc = it.CurrentDexPc();
+DexToDexCompiler::DexToDexCompiler(CompilerDriver* driver)
+    : driver_(driver),
+      lock_("Quicken lock", kDexToDexCompilerLock) {
+  DCHECK(driver != nullptr);
+}
+
+void DexToDexCompiler::ClearState() {
+  MutexLock lock(Thread::Current(), lock_);
+  active_dex_file_ = nullptr;
+  active_bit_vector_ = nullptr;
+  should_quicken_.clear();
+  shared_code_item_quicken_info_.clear();
+}
+
+size_t DexToDexCompiler::NumCodeItemsToQuicken(Thread* self) const {
+  MutexLock lock(self, lock_);
+  return num_code_items_;
+}
+
+BitVector* DexToDexCompiler::GetOrAddBitVectorForDex(const DexFile* dex_file) {
+  if (active_dex_file_ != dex_file) {
+    active_dex_file_ = dex_file;
+    auto inserted = should_quicken_.emplace(dex_file,
+                                            BitVector(dex_file->NumMethodIds(),
+                                                      /*expandable*/ false,
+                                                      Allocator::GetMallocAllocator()));
+    active_bit_vector_ = &inserted.first->second;
+  }
+  return active_bit_vector_;
+}
+
+void DexToDexCompiler::MarkForCompilation(Thread* self,
+                                          const MethodReference& method_ref) {
+  MutexLock lock(self, lock_);
+  BitVector* const bitmap = GetOrAddBitVectorForDex(method_ref.dex_file);
+  DCHECK(bitmap != nullptr);
+  DCHECK(!bitmap->IsBitSet(method_ref.index));
+  bitmap->SetBit(method_ref.index);
+  ++num_code_items_;
+}
+
+DexToDexCompiler::CompilationState::CompilationState(DexToDexCompiler* compiler,
+                                                     const DexCompilationUnit& unit,
+                                                     const CompilationLevel compilation_level,
+                                                     const std::vector<uint8_t>* quicken_data)
+    : compiler_(compiler),
+      driver_(*compiler->GetDriver()),
+      unit_(unit),
+      compilation_level_(compilation_level),
+      already_quickened_(quicken_data != nullptr),
+      existing_quicken_info_(already_quickened_
+          ? ArrayRef<const uint8_t>(*quicken_data) : ArrayRef<const uint8_t>()) {}
+
+uint16_t DexToDexCompiler::CompilationState::NextIndex() {
+  DCHECK(already_quickened_);
+  if (kIsDebugBuild && quicken_index_ >= existing_quicken_info_.NumIndices()) {
+    for (const DexInstructionPcPair& pair : unit_.GetCodeItemAccessor()) {
+      LOG(ERROR) << pair->DumpString(nullptr);
+    }
+    LOG(FATAL) << "Mismatched number of quicken slots.";
+  }
+  const uint16_t ret = existing_quicken_info_.GetData(quicken_index_);
+  quicken_index_++;
+  return ret;
+}
+
+uint16_t DexToDexCompiler::CompilationState::GetIndexForInstruction(const Instruction* inst,
+                                                                    uint32_t index) {
+  if (UNLIKELY(already_quickened_)) {
+    return inst->IsQuickened() ? NextIndex() : index;
+  }
+  DCHECK(!inst->IsQuickened());
+  return index;
+}
+
+bool DexToDexCompiler::ShouldCompileMethod(const MethodReference& ref) {
+  // TODO: It's probably safe to avoid the lock here if the active_dex_file_ matches since we only
+  // only call ShouldCompileMethod on one dex at a time.
+  MutexLock lock(Thread::Current(), lock_);
+  return GetOrAddBitVectorForDex(ref.dex_file)->IsBitSet(ref.index);
+}
+
+std::vector<uint8_t> DexToDexCompiler::CompilationState::Compile() {
+  DCHECK_EQ(compilation_level_, CompilationLevel::kOptimize);
+  const CodeItemDataAccessor& instructions = unit_.GetCodeItemAccessor();
+  for (DexInstructionIterator it = instructions.begin(); it != instructions.end(); ++it) {
+    const uint32_t dex_pc = it.DexPc();
+    Instruction* inst = const_cast<Instruction*>(&it.Inst());
+
+    if (!already_quickened_) {
+      DCHECK(!inst->IsQuickened());
+    }
+
     switch (inst->Opcode()) {
       case Instruction::RETURN_VOID:
         CompileReturnVoid(inst, dex_pc);
@@ -125,89 +227,150 @@
         if (inst->Opcode() == Instruction::NOP) {
           // We turned the CHECK_CAST into two NOPs, avoid visiting the second NOP twice since this
           // would add 2 quickening info entries.
-          it.Advance();
+          ++it;
         }
         break;
 
       case Instruction::IGET:
+      case Instruction::IGET_QUICK:
         CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_QUICK, false);
         break;
 
       case Instruction::IGET_WIDE:
+      case Instruction::IGET_WIDE_QUICK:
         CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_WIDE_QUICK, false);
         break;
 
       case Instruction::IGET_OBJECT:
+      case Instruction::IGET_OBJECT_QUICK:
         CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_OBJECT_QUICK, false);
         break;
 
       case Instruction::IGET_BOOLEAN:
+      case Instruction::IGET_BOOLEAN_QUICK:
         CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_BOOLEAN_QUICK, false);
         break;
 
       case Instruction::IGET_BYTE:
+      case Instruction::IGET_BYTE_QUICK:
         CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_BYTE_QUICK, false);
         break;
 
       case Instruction::IGET_CHAR:
+      case Instruction::IGET_CHAR_QUICK:
         CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_CHAR_QUICK, false);
         break;
 
       case Instruction::IGET_SHORT:
+      case Instruction::IGET_SHORT_QUICK:
         CompileInstanceFieldAccess(inst, dex_pc, Instruction::IGET_SHORT_QUICK, false);
         break;
 
       case Instruction::IPUT:
+      case Instruction::IPUT_QUICK:
         CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_QUICK, true);
         break;
 
       case Instruction::IPUT_BOOLEAN:
+      case Instruction::IPUT_BOOLEAN_QUICK:
         CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_BOOLEAN_QUICK, true);
         break;
 
       case Instruction::IPUT_BYTE:
+      case Instruction::IPUT_BYTE_QUICK:
         CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_BYTE_QUICK, true);
         break;
 
       case Instruction::IPUT_CHAR:
+      case Instruction::IPUT_CHAR_QUICK:
         CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_CHAR_QUICK, true);
         break;
 
       case Instruction::IPUT_SHORT:
+      case Instruction::IPUT_SHORT_QUICK:
         CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_SHORT_QUICK, true);
         break;
 
       case Instruction::IPUT_WIDE:
+      case Instruction::IPUT_WIDE_QUICK:
         CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_WIDE_QUICK, true);
         break;
 
       case Instruction::IPUT_OBJECT:
+      case Instruction::IPUT_OBJECT_QUICK:
         CompileInstanceFieldAccess(inst, dex_pc, Instruction::IPUT_OBJECT_QUICK, true);
         break;
 
       case Instruction::INVOKE_VIRTUAL:
+      case Instruction::INVOKE_VIRTUAL_QUICK:
         CompileInvokeVirtual(inst, dex_pc, Instruction::INVOKE_VIRTUAL_QUICK, false);
         break;
 
       case Instruction::INVOKE_VIRTUAL_RANGE:
+      case Instruction::INVOKE_VIRTUAL_RANGE_QUICK:
         CompileInvokeVirtual(inst, dex_pc, Instruction::INVOKE_VIRTUAL_RANGE_QUICK, true);
         break;
 
       case Instruction::NOP:
-        // We need to differentiate between check cast inserted NOP and normal NOP, put an invalid
-        // index in the map for normal nops. This should be rare in real code.
-        quickened_info_.push_back(QuickenedInfo(dex_pc, DexFile::kDexNoIndex16));
+        if (already_quickened_) {
+          const uint16_t reference_index = NextIndex();
+          quickened_info_.push_back(QuickenedInfo(dex_pc, reference_index));
+          if (reference_index == DexFile::kDexNoIndex16) {
+            // This means it was a normal nop and not a check-cast.
+            break;
+          }
+          const uint16_t type_index = NextIndex();
+          if (driver_.IsSafeCast(&unit_, dex_pc)) {
+            quickened_info_.push_back(QuickenedInfo(dex_pc, type_index));
+          }
+          ++it;
+        } else {
+          // We need to differentiate between check cast inserted NOP and normal NOP, put an invalid
+          // index in the map for normal nops. This should be rare in real code.
+          quickened_info_.push_back(QuickenedInfo(dex_pc, DexFile::kDexNoIndex16));
+        }
         break;
 
       default:
-        DCHECK(!inst->IsQuickened());
         // Nothing to do.
         break;
     }
   }
+
+  if (already_quickened_) {
+    DCHECK_EQ(quicken_index_, existing_quicken_info_.NumIndices());
+  }
+
+  // Even if there are no indicies, generate an empty quicken info so that we know the method was
+  // quickened.
+
+  std::vector<uint8_t> quicken_data;
+  if (kIsDebugBuild) {
+    // Double check that the counts line up with the size of the quicken info.
+    size_t quicken_count = 0;
+    for (const DexInstructionPcPair& pair : instructions) {
+      if (QuickenInfoTable::NeedsIndexForInstruction(&pair.Inst())) {
+        ++quicken_count;
+      }
+    }
+    CHECK_EQ(quicken_count, GetQuickenedInfo().size());
+  }
+
+  QuickenInfoTable::Builder builder(&quicken_data, GetQuickenedInfo().size());
+  // Length is encoded by the constructor.
+  for (const CompilationState::QuickenedInfo& info : GetQuickenedInfo()) {
+    // Dex pc is not serialized, only used for checking the instructions. Since we access the
+    // array based on the index of the quickened instruction, the indexes must line up perfectly.
+    // The reader side uses the NeedsIndexForInstruction function too.
+    const Instruction& inst = instructions.InstructionAt(info.dex_pc);
+    CHECK(QuickenInfoTable::NeedsIndexForInstruction(&inst)) << inst.Opcode();
+    builder.AddIndex(info.dex_member_index);
+  }
+  DCHECK(!quicken_data.empty());
+  return quicken_data;
 }
 
-void DexCompiler::CompileReturnVoid(Instruction* inst, uint32_t dex_pc) {
+void DexToDexCompiler::CompilationState::CompileReturnVoid(Instruction* inst, uint32_t dex_pc) {
   DCHECK_EQ(inst->Opcode(), Instruction::RETURN_VOID);
   if (unit_.IsConstructor()) {
     // Are we compiling a non clinit constructor which needs a barrier ?
@@ -223,9 +386,11 @@
                  << " at dex pc " << StringPrintf("0x%x", dex_pc) << " in method "
                  << GetDexFile().PrettyMethod(unit_.GetDexMethodIndex(), true);
   inst->SetOpcode(Instruction::RETURN_VOID_NO_BARRIER);
+  optimized_return_void_ = true;
 }
 
-Instruction* DexCompiler::CompileCheckCast(Instruction* inst, uint32_t dex_pc) {
+Instruction* DexToDexCompiler::CompilationState::CompileCheckCast(Instruction* inst,
+                                                                  uint32_t dex_pc) {
   if (!kEnableCheckCastEllision) {
     return inst;
   }
@@ -242,27 +407,30 @@
                  << " by replacing it with 2 NOPs at dex pc "
                  << StringPrintf("0x%x", dex_pc) << " in method "
                  << GetDexFile().PrettyMethod(unit_.GetDexMethodIndex(), true);
-  quickened_info_.push_back(QuickenedInfo(dex_pc, inst->VRegA_21c()));
-  quickened_info_.push_back(QuickenedInfo(dex_pc, inst->VRegB_21c()));
-  // We are modifying 4 consecutive bytes.
-  inst->SetOpcode(Instruction::NOP);
-  inst->SetVRegA_10x(0u);  // keep compliant with verifier.
-  // Get to next instruction which is the second half of check-cast and replace
-  // it by a NOP.
-  inst = const_cast<Instruction*>(inst->Next());
-  inst->SetOpcode(Instruction::NOP);
-  inst->SetVRegA_10x(0u);  // keep compliant with verifier.
+  if (!already_quickened_) {
+    quickened_info_.push_back(QuickenedInfo(dex_pc, inst->VRegA_21c()));
+    quickened_info_.push_back(QuickenedInfo(dex_pc, inst->VRegB_21c()));
+
+    // We are modifying 4 consecutive bytes.
+    inst->SetOpcode(Instruction::NOP);
+    inst->SetVRegA_10x(0u);  // keep compliant with verifier.
+    // Get to next instruction which is the second half of check-cast and replace
+    // it by a NOP.
+    inst = const_cast<Instruction*>(inst->Next());
+    inst->SetOpcode(Instruction::NOP);
+    inst->SetVRegA_10x(0u);  // keep compliant with verifier.
+  }
   return inst;
 }
 
-void DexCompiler::CompileInstanceFieldAccess(Instruction* inst,
-                                             uint32_t dex_pc,
-                                             Instruction::Code new_opcode,
-                                             bool is_put) {
+void DexToDexCompiler::CompilationState::CompileInstanceFieldAccess(Instruction* inst,
+                                                                    uint32_t dex_pc,
+                                                                    Instruction::Code new_opcode,
+                                                                    bool is_put) {
   if (!kEnableQuickening) {
     return;
   }
-  uint32_t field_idx = inst->VRegC_22c();
+  uint32_t field_idx = GetIndexForInstruction(inst, inst->VRegC_22c());
   MemberOffset field_offset(0u);
   bool is_volatile;
   bool fast_path = driver_.ComputeInstanceFieldInfo(field_idx, &unit_, is_put,
@@ -274,26 +442,34 @@
                    << " by field offset " << field_offset.Int32Value()
                    << " at dex pc " << StringPrintf("0x%x", dex_pc) << " in method "
                    << GetDexFile().PrettyMethod(unit_.GetDexMethodIndex(), true);
-    // We are modifying 4 consecutive bytes.
-    inst->SetOpcode(new_opcode);
-    // Replace field index by field offset.
-    inst->SetVRegC_22c(static_cast<uint16_t>(field_offset.Int32Value()));
+    if (!already_quickened_) {
+      // We are modifying 4 consecutive bytes.
+      inst->SetOpcode(new_opcode);
+      // Replace field index by field offset.
+      inst->SetVRegC_22c(static_cast<uint16_t>(field_offset.Int32Value()));
+    }
     quickened_info_.push_back(QuickenedInfo(dex_pc, field_idx));
   }
 }
 
-void DexCompiler::CompileInvokeVirtual(Instruction* inst, uint32_t dex_pc,
-                                       Instruction::Code new_opcode, bool is_range) {
+const DexFile& DexToDexCompiler::CompilationState::GetDexFile() const {
+  return *unit_.GetDexFile();
+}
+
+void DexToDexCompiler::CompilationState::CompileInvokeVirtual(Instruction* inst,
+                                                              uint32_t dex_pc,
+                                                              Instruction::Code new_opcode,
+                                                              bool is_range) {
   if (!kEnableQuickening) {
     return;
   }
-  uint32_t method_idx = is_range ? inst->VRegB_3rc() : inst->VRegB_35c();
+  uint32_t method_idx = GetIndexForInstruction(inst,
+                                               is_range ? inst->VRegB_3rc() : inst->VRegB_35c());
   ScopedObjectAccess soa(Thread::Current());
 
   ClassLinker* class_linker = unit_.GetClassLinker();
   ArtMethod* resolved_method =
       class_linker->ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>(
-          GetDexFile(),
           method_idx,
           unit_.GetDexCache(),
           unit_.GetClassLoader(),
@@ -315,19 +491,20 @@
                  << " by vtable index " << vtable_idx
                  << " at dex pc " << StringPrintf("0x%x", dex_pc) << " in method "
                  << GetDexFile().PrettyMethod(unit_.GetDexMethodIndex(), true);
-  // We are modifying 4 consecutive bytes.
-  inst->SetOpcode(new_opcode);
-  // Replace method index by vtable index.
-  if (is_range) {
-    inst->SetVRegB_3rc(static_cast<uint16_t>(vtable_idx));
-  } else {
-    inst->SetVRegB_35c(static_cast<uint16_t>(vtable_idx));
+  if (!already_quickened_) {
+    // We are modifying 4 consecutive bytes.
+    inst->SetOpcode(new_opcode);
+    // Replace method index by vtable index.
+    if (is_range) {
+      inst->SetVRegB_3rc(static_cast<uint16_t>(vtable_idx));
+    } else {
+      inst->SetVRegB_35c(static_cast<uint16_t>(vtable_idx));
+    }
   }
   quickened_info_.push_back(QuickenedInfo(dex_pc, method_idx));
 }
 
-CompiledMethod* ArtCompileDEX(
-    CompilerDriver* driver,
+CompiledMethod* DexToDexCompiler::CompileMethod(
     const DexFile::CodeItem* code_item,
     uint32_t access_flags,
     InvokeType invoke_type ATTRIBUTE_UNUSED,
@@ -335,69 +512,175 @@
     uint32_t method_idx,
     Handle<mirror::ClassLoader> class_loader,
     const DexFile& dex_file,
-    DexToDexCompilationLevel dex_to_dex_compilation_level) {
-  DCHECK(driver != nullptr);
-  if (dex_to_dex_compilation_level != DexToDexCompilationLevel::kDontDexToDexCompile) {
-    ScopedObjectAccess soa(Thread::Current());
-    StackHandleScope<1> hs(soa.Self());
-    ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
-    art::DexCompilationUnit unit(
-        class_loader,
-        class_linker,
-        dex_file,
-        code_item,
-        class_def_idx,
-        method_idx,
-        access_flags,
-        driver->GetVerifiedMethod(&dex_file, method_idx),
-        hs.NewHandle(class_linker->FindDexCache(soa.Self(), dex_file)));
-    art::optimizer::DexCompiler dex_compiler(*driver, unit, dex_to_dex_compilation_level);
-    dex_compiler.Compile();
-    if (dex_compiler.GetQuickenedInfo().empty()) {
-      // No need to create a CompiledMethod if there are no quickened opcodes.
+    CompilationLevel compilation_level) {
+  if (compilation_level == CompilationLevel::kDontDexToDexCompile) {
+    return nullptr;
+  }
+
+  ScopedObjectAccess soa(Thread::Current());
+  StackHandleScope<1> hs(soa.Self());
+  ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
+  art::DexCompilationUnit unit(
+      class_loader,
+      class_linker,
+      dex_file,
+      code_item,
+      class_def_idx,
+      method_idx,
+      access_flags,
+      driver_->GetVerifiedMethod(&dex_file, method_idx),
+      hs.NewHandle(class_linker->FindDexCache(soa.Self(), dex_file)));
+
+  std::vector<uint8_t> quicken_data;
+  // If the code item is shared with multiple different method ids, make sure that we quicken only
+  // once and verify that all the dequicken maps match.
+  if (UNLIKELY(shared_code_items_.find(code_item) != shared_code_items_.end())) {
+    // Avoid quickening the shared code items for now because the existing conflict detection logic
+    // does not currently handle cases where the code item is quickened in one place but
+    // compiled in another.
+    static constexpr bool kAvoidQuickeningSharedCodeItems = true;
+    if (kAvoidQuickeningSharedCodeItems) {
       return nullptr;
     }
+    // For shared code items, use a lock to prevent races.
+    MutexLock mu(soa.Self(), lock_);
+    auto existing = shared_code_item_quicken_info_.find(code_item);
+    QuickenState* existing_data = nullptr;
+    std::vector<uint8_t>* existing_quicken_data = nullptr;
+    if (existing != shared_code_item_quicken_info_.end()) {
+      existing_data = &existing->second;
+      if (existing_data->conflict_) {
+        return nullptr;
+      }
+      existing_quicken_data = &existing_data->quicken_data_;
+    }
+    bool optimized_return_void;
+    {
+      CompilationState state(this, unit, compilation_level, existing_quicken_data);
+      quicken_data = state.Compile();
+      optimized_return_void = state.optimized_return_void_;
+    }
 
-    // Create a `CompiledMethod`, with the quickened information in the vmap table.
+    // Already quickened, check that the data matches what was previously seen.
+    MethodReference method_ref(&dex_file, method_idx);
+    if (existing_data != nullptr) {
+      if (*existing_quicken_data != quicken_data ||
+          existing_data->optimized_return_void_ != optimized_return_void) {
+        VLOG(compiler) << "Quicken data mismatch, for method "
+                       << dex_file.PrettyMethod(method_idx);
+        // Mark the method as a conflict to never attempt to quicken it in the future.
+        existing_data->conflict_ = true;
+      }
+      existing_data->methods_.push_back(method_ref);
+    } else {
+      QuickenState new_state;
+      new_state.methods_.push_back(method_ref);
+      new_state.quicken_data_ = quicken_data;
+      new_state.optimized_return_void_ = optimized_return_void;
+      bool inserted = shared_code_item_quicken_info_.emplace(code_item, new_state).second;
+      CHECK(inserted) << "Failed to insert " << dex_file.PrettyMethod(method_idx);
+    }
+
+    // Easy sanity check is to check that the existing stuff matches by re-quickening using the
+    // newly produced quicken data.
+    // Note that this needs to be behind the lock for this case since we may unquicken in another
+    // thread.
     if (kIsDebugBuild) {
-      // Double check that the counts line up with the size of the quicken info.
-      size_t quicken_count = 0;
-      for (CodeItemIterator it(*code_item); !it.Done(); it.Advance()) {
-        if (QuickenInfoTable::NeedsIndexForInstruction(&it.CurrentInstruction())) {
-          ++quicken_count;
+      CompilationState state2(this, unit, compilation_level, &quicken_data);
+      std::vector<uint8_t> new_data = state2.Compile();
+      CHECK(new_data == quicken_data) << "Mismatch producing new quicken data";
+    }
+  } else {
+    CompilationState state(this, unit, compilation_level, /*quicken_data*/ nullptr);
+    quicken_data = state.Compile();
+
+    // Easy sanity check is to check that the existing stuff matches by re-quickening using the
+    // newly produced quicken data.
+    if (kIsDebugBuild) {
+      CompilationState state2(this, unit, compilation_level, &quicken_data);
+      std::vector<uint8_t> new_data = state2.Compile();
+      CHECK(new_data == quicken_data) << "Mismatch producing new quicken data";
+    }
+  }
+
+  if (quicken_data.empty()) {
+    return nullptr;
+  }
+
+  // Create a `CompiledMethod`, with the quickened information in the vmap table.
+  InstructionSet instruction_set = driver_->GetInstructionSet();
+  if (instruction_set == InstructionSet::kThumb2) {
+    // Don't use the thumb2 instruction set to avoid the one off code delta.
+    instruction_set = InstructionSet::kArm;
+  }
+  CompiledMethod* ret = CompiledMethod::SwapAllocCompiledMethod(
+      driver_,
+      instruction_set,
+      ArrayRef<const uint8_t>(),                   // no code
+      0,
+      0,
+      0,
+      ArrayRef<const uint8_t>(),                   // method_info
+      ArrayRef<const uint8_t>(quicken_data),       // vmap_table
+      ArrayRef<const uint8_t>(),                   // cfi data
+      ArrayRef<const linker::LinkerPatch>());
+  DCHECK(ret != nullptr);
+  return ret;
+}
+
+void DexToDexCompiler::SetDexFiles(const std::vector<const DexFile*>& dex_files) {
+  // Record what code items are already seen to detect when multiple methods have the same code
+  // item.
+  std::unordered_set<const DexFile::CodeItem*> seen_code_items;
+  for (const DexFile* dex_file : dex_files) {
+    for (size_t i = 0; i < dex_file->NumClassDefs(); ++i) {
+      const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
+      const uint8_t* class_data = dex_file->GetClassData(class_def);
+      if (class_data == nullptr) {
+        continue;
+      }
+      ClassDataItemIterator it(*dex_file, class_data);
+      it.SkipAllFields();
+      for (; it.HasNextMethod(); it.Next()) {
+        const DexFile::CodeItem* code_item = it.GetMethodCodeItem();
+        // Detect the shared code items.
+        if (!seen_code_items.insert(code_item).second) {
+          shared_code_items_.insert(code_item);
         }
       }
-      CHECK_EQ(quicken_count, dex_compiler.GetQuickenedInfo().size());
     }
-    std::vector<uint8_t> quicken_data;
-    for (QuickenedInfo info : dex_compiler.GetQuickenedInfo()) {
-      // Dex pc is not serialized, only used for checking the instructions. Since we access the
-      // array based on the index of the quickened instruction, the indexes must line up perfectly.
-      // The reader side uses the NeedsIndexForInstruction function too.
-      const Instruction* inst = Instruction::At(code_item->insns_ + info.dex_pc);
-      CHECK(QuickenInfoTable::NeedsIndexForInstruction(inst)) << inst->Opcode();
-      // Add the index.
-      quicken_data.push_back(static_cast<uint8_t>(info.dex_member_index >> 0));
-      quicken_data.push_back(static_cast<uint8_t>(info.dex_member_index >> 8));
-    }
-    InstructionSet instruction_set = driver->GetInstructionSet();
-    if (instruction_set == kThumb2) {
-      // Don't use the thumb2 instruction set to avoid the one off code delta.
-      instruction_set = kArm;
-    }
-    return CompiledMethod::SwapAllocCompiledMethod(
-        driver,
-        instruction_set,
-        ArrayRef<const uint8_t>(),                   // no code
-        0,
-        0,
-        0,
-        ArrayRef<const uint8_t>(),                   // method_info
-        ArrayRef<const uint8_t>(quicken_data),       // vmap_table
-        ArrayRef<const uint8_t>(),                   // cfi data
-        ArrayRef<const LinkerPatch>());
   }
-  return nullptr;
+  VLOG(compiler) << "Shared code items " << shared_code_items_.size();
+}
+
+void DexToDexCompiler::UnquickenConflictingMethods() {
+  MutexLock mu(Thread::Current(), lock_);
+  size_t unquicken_count = 0;
+  for (const auto& pair : shared_code_item_quicken_info_) {
+    const DexFile::CodeItem* code_item = pair.first;
+    const QuickenState& state = pair.second;
+    CHECK_GE(state.methods_.size(), 1u);
+    if (state.conflict_) {
+      // Unquicken using the existing quicken data.
+      // TODO: Do we really need to pass a dex file in?
+      optimizer::ArtDecompileDEX(*state.methods_[0].dex_file,
+                                 *code_item,
+                                 ArrayRef<const uint8_t>(state.quicken_data_),
+                                 /* decompile_return_instruction*/ true);
+      ++unquicken_count;
+      // Go clear the vmaps for all the methods that were already quickened to avoid writing them
+      // out during oat writing.
+      for (const MethodReference& ref : state.methods_) {
+        CompiledMethod* method = driver_->RemoveCompiledMethod(ref);
+        if (method != nullptr) {
+          // There is up to one compiled method for each method ref. Releasing it leaves the
+          // deduped data intact, this means its safe to do even when other threads might be
+          // compiling.
+          CompiledMethod::ReleaseSwapAllocatedCompiledMethod(driver_, method);
+        }
+      }
+    }
+  }
 }
 
 }  // namespace optimizer
diff --git a/compiler/dex/dex_to_dex_compiler.h b/compiler/dex/dex_to_dex_compiler.h
index 87ddb39..7536c31 100644
--- a/compiler/dex/dex_to_dex_compiler.h
+++ b/compiler/dex/dex_to_dex_compiler.h
@@ -17,14 +17,22 @@
 #ifndef ART_COMPILER_DEX_DEX_TO_DEX_COMPILER_H_
 #define ART_COMPILER_DEX_DEX_TO_DEX_COMPILER_H_
 
-#include "dex_file.h"
+#include <set>
+#include <unordered_map>
+#include <unordered_set>
+
+#include "base/bit_vector.h"
+#include "dex/dex_file.h"
+#include "dex/invoke_type.h"
+#include "dex/method_reference.h"
 #include "handle.h"
-#include "invoke_type.h"
+#include "quicken_info.h"
 
 namespace art {
 
 class CompiledMethod;
 class CompilerDriver;
+class DexCompilationUnit;
 
 namespace mirror {
 class ClassLoader;
@@ -32,21 +40,79 @@
 
 namespace optimizer {
 
-enum class DexToDexCompilationLevel {
-  kDontDexToDexCompile,   // Only meaning wrt image time interpretation.
-  kOptimize               // Perform peep-hole optimizations.
-};
-std::ostream& operator<<(std::ostream& os, const DexToDexCompilationLevel& rhs);
+class DexToDexCompiler {
+ public:
+  enum class CompilationLevel {
+    kDontDexToDexCompile,   // Only meaning wrt image time interpretation.
+    kOptimize               // Perform peep-hole optimizations.
+  };
 
-CompiledMethod* ArtCompileDEX(CompilerDriver* driver,
-                              const DexFile::CodeItem* code_item,
-                              uint32_t access_flags,
-                              InvokeType invoke_type,
-                              uint16_t class_def_idx,
-                              uint32_t method_idx,
-                              Handle<mirror::ClassLoader> class_loader,
-                              const DexFile& dex_file,
-                              DexToDexCompilationLevel dex_to_dex_compilation_level);
+  explicit DexToDexCompiler(CompilerDriver* driver);
+
+  CompiledMethod* CompileMethod(const DexFile::CodeItem* code_item,
+                                uint32_t access_flags,
+                                InvokeType invoke_type,
+                                uint16_t class_def_idx,
+                                uint32_t method_idx,
+                                Handle<mirror::ClassLoader> class_loader,
+                                const DexFile& dex_file,
+                                const CompilationLevel compilation_level) WARN_UNUSED;
+
+  void MarkForCompilation(Thread* self,
+                          const MethodReference& method_ref);
+
+  void ClearState();
+
+  // Unquicken all methods that have conflicting quicken info. This is not done during the
+  // quickening process to avoid race conditions.
+  void UnquickenConflictingMethods();
+
+  CompilerDriver* GetDriver() {
+    return driver_;
+  }
+
+  bool ShouldCompileMethod(const MethodReference& ref);
+
+  // Return the number of code items to quicken.
+  size_t NumCodeItemsToQuicken(Thread* self) const;
+
+  void SetDexFiles(const std::vector<const DexFile*>& dex_files);
+
+ private:
+  // Holds the state for compiling a single method.
+  struct CompilationState;
+
+  // Quicken state for a code item, may be referenced by multiple methods.
+  struct QuickenState {
+    std::vector<MethodReference> methods_;
+    std::vector<uint8_t> quicken_data_;
+    bool optimized_return_void_ = false;
+    bool conflict_ = false;
+  };
+
+  BitVector* GetOrAddBitVectorForDex(const DexFile* dex_file) REQUIRES(lock_);
+
+  CompilerDriver* const driver_;
+
+  // State for adding methods (should this be in its own class?).
+  const DexFile* active_dex_file_ = nullptr;
+  BitVector* active_bit_vector_ = nullptr;
+
+  // Lock that guards duplicate code items and the bitmap.
+  mutable Mutex lock_;
+  // Record what method references are going to get quickened.
+  std::unordered_map<const DexFile*, BitVector> should_quicken_;
+  // Guarded by lock_ during writing, accessed without a lock during quickening.
+  // This is safe because no thread is adding to the shared code items during the quickening phase.
+  std::unordered_set<const DexFile::CodeItem*> shared_code_items_;
+  // Blacklisted code items are unquickened in UnquickenConflictingMethods.
+  std::unordered_map<const DexFile::CodeItem*, QuickenState> shared_code_item_quicken_info_
+      GUARDED_BY(lock_);
+  // Number of added code items.
+  size_t num_code_items_ GUARDED_BY(lock_) = 0u;
+};
+
+std::ostream& operator<<(std::ostream& os, const DexToDexCompiler::CompilationLevel& rhs);
 
 }  // namespace optimizer
 
diff --git a/compiler/dex/dex_to_dex_decompiler_test.cc b/compiler/dex/dex_to_dex_decompiler_test.cc
index 8e416b0..19b1900 100644
--- a/compiler/dex/dex_to_dex_decompiler_test.cc
+++ b/compiler/dex/dex_to_dex_decompiler_test.cc
@@ -17,14 +17,13 @@
 #include "dex_to_dex_decompiler.h"
 
 #include "class_linker.h"
-#include "compiler/common_compiler_test.h"
-#include "compiler/compiled_method.h"
-#include "compiler/driver/compiler_options.h"
-#include "compiler/driver/compiler_driver.h"
+#include "common_compiler_test.h"
+#include "compiled_method-inl.h"
 #include "compiler_callbacks.h"
-#include "dex_file.h"
+#include "dex/dex_file.h"
+#include "driver/compiler_driver.h"
+#include "driver/compiler_options.h"
 #include "handle_scope-inl.h"
-#include "verifier/method_verifier-inl.h"
 #include "mirror/class_loader.h"
 #include "runtime.h"
 #include "scoped_thread_state_change-inl.h"
@@ -92,7 +91,7 @@
       it.SkipAllFields();
 
       // Unquicken each method.
-      while (it.HasNextDirectMethod()) {
+      while (it.HasNextMethod()) {
         uint32_t method_idx = it.GetMemberIndex();
         CompiledMethod* compiled_method =
             compiler_driver_->GetCompiledMethod(MethodReference(updated_dex_file, method_idx));
@@ -100,20 +99,10 @@
         if (compiled_method != nullptr) {
           table = compiled_method->GetVmapTable();
         }
-        optimizer::ArtDecompileDEX(
-            *it.GetMethodCodeItem(), table, /* decompile_return_instruction */ true);
-        it.Next();
-      }
-      while (it.HasNextVirtualMethod()) {
-        uint32_t method_idx = it.GetMemberIndex();
-        CompiledMethod* compiled_method =
-            compiler_driver_->GetCompiledMethod(MethodReference(updated_dex_file, method_idx));
-        ArrayRef<const uint8_t> table;
-        if (compiled_method != nullptr) {
-          table = compiled_method->GetVmapTable();
-        }
-        optimizer::ArtDecompileDEX(
-            *it.GetMethodCodeItem(), table, /* decompile_return_instruction */ true);
+        optimizer::ArtDecompileDEX(*updated_dex_file,
+                                   *it.GetMethodCodeItem(),
+                                   table,
+                                   /* decompile_return_instruction */ true);
         it.Next();
       }
       DCHECK(!it.HasNext());
diff --git a/compiler/dex/inline_method_analyser.cc b/compiler/dex/inline_method_analyser.cc
index e5ff7fc..dc044c1 100644
--- a/compiler/dex/inline_method_analyser.cc
+++ b/compiler/dex/inline_method_analyser.cc
@@ -20,10 +20,11 @@
 #include "art_method-inl.h"
 #include "base/enums.h"
 #include "class_linker-inl.h"
-#include "dex_file-inl.h"
-#include "dex_instruction.h"
-#include "dex_instruction-inl.h"
-#include "dex_instruction_utils.h"
+#include "dex/code_item_accessors-inl.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_instruction-inl.h"
+#include "dex/dex_instruction.h"
+#include "dex/dex_instruction_utils.h"
 #include "mirror/class-inl.h"
 #include "mirror/dex_cache-inl.h"
 
@@ -43,7 +44,7 @@
   typedef bool MatchFn(Matcher* matcher);
 
   template <size_t size>
-  static bool Match(const DexFile::CodeItem* code_item, MatchFn* const (&pattern)[size]);
+  static bool Match(const CodeItemDataAccessor* code_item, MatchFn* const (&pattern)[size]);
 
   // Match and advance.
 
@@ -62,22 +63,20 @@
   bool IPutOnThis();
 
  private:
-  explicit Matcher(const DexFile::CodeItem* code_item)
+  explicit Matcher(const CodeItemDataAccessor* code_item)
       : code_item_(code_item),
-        instruction_(Instruction::At(code_item->insns_)),
-        pos_(0u),
-        mark_(0u) { }
+        instruction_(code_item->begin()) {}
 
-  static bool DoMatch(const DexFile::CodeItem* code_item, MatchFn* const* pattern, size_t size);
+  static bool DoMatch(const CodeItemDataAccessor* code_item, MatchFn* const* pattern, size_t size);
 
-  const DexFile::CodeItem* const code_item_;
-  const Instruction* instruction_;
-  size_t pos_;
-  size_t mark_;
+  const CodeItemDataAccessor* const code_item_;
+  DexInstructionIterator instruction_;
+  size_t pos_ = 0u;
+  size_t mark_ = 0u;
 };
 
 template <size_t size>
-bool Matcher::Match(const DexFile::CodeItem* code_item, MatchFn* const (&pattern)[size]) {
+bool Matcher::Match(const CodeItemDataAccessor* code_item, MatchFn* const (&pattern)[size]) {
   return DoMatch(code_item, pattern, size);
 }
 
@@ -93,7 +92,7 @@
     return false;
   }
   matcher->pos_ += 1u;
-  matcher->instruction_ = matcher->instruction_->Next();
+  ++matcher->instruction_;
   return true;
 }
 
@@ -105,7 +104,7 @@
     return true;
   }
   matcher->pos_ = matcher->mark_;
-  matcher->instruction_ = matcher->instruction_->Next();
+  ++matcher->instruction_;
   return true;
 }
 
@@ -122,12 +121,12 @@
 }
 
 bool Matcher::IPutOnThis() {
-  DCHECK_NE(code_item_->ins_size_, 0u);
+  DCHECK_NE(code_item_->InsSize(), 0u);
   return IsInstructionIPut(instruction_->Opcode()) &&
-      instruction_->VRegB_22c() == code_item_->registers_size_ - code_item_->ins_size_;
+      instruction_->VRegB_22c() == code_item_->RegistersSize() - code_item_->InsSize();
 }
 
-bool Matcher::DoMatch(const DexFile::CodeItem* code_item, MatchFn* const* pattern, size_t size) {
+bool Matcher::DoMatch(const CodeItemDataAccessor* code_item, MatchFn* const* pattern, size_t size) {
   Matcher matcher(code_item);
   while (matcher.pos_ != size) {
     if (!pattern[matcher.pos_](&matcher)) {
@@ -142,8 +141,11 @@
 ArtMethod* GetTargetConstructor(ArtMethod* method, const Instruction* invoke_direct)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   DCHECK_EQ(invoke_direct->Opcode(), Instruction::INVOKE_DIRECT);
-  DCHECK_EQ(invoke_direct->VRegC_35c(),
-            method->GetCodeItem()->registers_size_ - method->GetCodeItem()->ins_size_);
+  if (kIsDebugBuild) {
+    CodeItemDataAccessor accessor(method->DexInstructionData());
+    DCHECK_EQ(invoke_direct->VRegC_35c(),
+              accessor.RegistersSize() - accessor.InsSize());
+  }
   uint32_t method_index = invoke_direct->VRegB_35c();
   ArtMethod* target_method = Runtime::Current()->GetClassLinker()->LookupResolvedMethod(
       method_index, method->GetDexCache(), method->GetClassLoader());
@@ -158,7 +160,7 @@
 
 // Return the forwarded arguments and check that all remaining arguments are zero.
 // If the check fails, return static_cast<size_t>(-1).
-size_t CountForwardedConstructorArguments(const DexFile::CodeItem* code_item,
+size_t CountForwardedConstructorArguments(const CodeItemDataAccessor* code_item,
                                           const Instruction* invoke_direct,
                                           uint16_t zero_vreg_mask) {
   DCHECK_EQ(invoke_direct->Opcode(), Instruction::INVOKE_DIRECT);
@@ -167,7 +169,7 @@
   uint32_t args[Instruction::kMaxVarArgRegs];
   invoke_direct->GetVarArgs(args);
   uint16_t this_vreg = args[0];
-  DCHECK_EQ(this_vreg, code_item->registers_size_ - code_item->ins_size_);  // Checked by verifier.
+  DCHECK_EQ(this_vreg, code_item->RegistersSize() - code_item->InsSize());  // Checked by verifier.
   size_t forwarded = 1u;
   while (forwarded < number_of_args &&
       args[forwarded] == this_vreg + forwarded &&
@@ -249,7 +251,7 @@
   return true;
 }
 
-bool DoAnalyseConstructor(const DexFile::CodeItem* code_item,
+bool DoAnalyseConstructor(const CodeItemDataAccessor* code_item,
                           ArtMethod* method,
                           /*inout*/ ConstructorIPutData (&iputs)[kMaxConstructorIPuts])
     REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -292,42 +294,43 @@
   DCHECK(method->IsConstructor());
   DCHECK(code_item != nullptr);
   if (!method->GetDeclaringClass()->IsVerified() ||
-      code_item->insns_size_in_code_units_ > kMaxCodeUnits ||
-      code_item->registers_size_ > kMaxVRegs ||
+      code_item->InsnsSizeInCodeUnits() > kMaxCodeUnits ||
+      code_item->RegistersSize() > kMaxVRegs ||
       !Matcher::Match(code_item, kConstructorPattern)) {
     return false;
   }
 
   // Verify the invoke, prevent a few odd cases and collect IPUTs.
-  uint16_t this_vreg = code_item->registers_size_ - code_item->ins_size_;
+  uint16_t this_vreg = code_item->RegistersSize() - code_item->InsSize();
   uint16_t zero_vreg_mask = 0u;
-  for (const Instruction* instruction = Instruction::At(code_item->insns_);
-      instruction->Opcode() != Instruction::RETURN_VOID;
-      instruction = instruction->Next()) {
-    if (instruction->Opcode() == Instruction::INVOKE_DIRECT) {
-      ArtMethod* target_method = GetTargetConstructor(method, instruction);
+
+  for (const DexInstructionPcPair& pair : *code_item) {
+    const Instruction& instruction = pair.Inst();
+    if (instruction.Opcode() == Instruction::RETURN_VOID) {
+      break;
+    } else if (instruction.Opcode() == Instruction::INVOKE_DIRECT) {
+      ArtMethod* target_method = GetTargetConstructor(method, &instruction);
       if (target_method == nullptr) {
         return false;
       }
       // We allow forwarding constructors only if they pass more arguments
       // to prevent infinite recursion.
       if (target_method->GetDeclaringClass() == method->GetDeclaringClass() &&
-          instruction->VRegA_35c() <= code_item->ins_size_) {
+          instruction.VRegA_35c() <= code_item->InsSize()) {
         return false;
       }
-      size_t forwarded = CountForwardedConstructorArguments(code_item, instruction, zero_vreg_mask);
+      size_t forwarded = CountForwardedConstructorArguments(code_item, &instruction, zero_vreg_mask);
       if (forwarded == static_cast<size_t>(-1)) {
         return false;
       }
       if (target_method->GetDeclaringClass()->IsObjectClass()) {
-        DCHECK_EQ(Instruction::At(target_method->GetCodeItem()->insns_)->Opcode(),
-                  Instruction::RETURN_VOID);
+        DCHECK_EQ(target_method->DexInstructionData().begin()->Opcode(), Instruction::RETURN_VOID);
       } else {
-        const DexFile::CodeItem* target_code_item = target_method->GetCodeItem();
-        if (target_code_item == nullptr) {
+        CodeItemDataAccessor target_code_item(target_method->DexInstructionData());
+        if (!target_code_item.HasCodeItem()) {
           return false;  // Native constructor?
         }
-        if (!DoAnalyseConstructor(target_code_item, target_method, iputs)) {
+        if (!DoAnalyseConstructor(&target_code_item, target_method, iputs)) {
           return false;
         }
         // Prune IPUTs with zero input.
@@ -345,15 +348,15 @@
           return false;
         }
       }
-    } else if (IsInstructionDirectConst(instruction->Opcode())) {
-      zero_vreg_mask |= GetZeroVRegMask(instruction);
+    } else if (IsInstructionDirectConst(instruction.Opcode())) {
+      zero_vreg_mask |= GetZeroVRegMask(&instruction);
       if ((zero_vreg_mask & (1u << this_vreg)) != 0u) {
         return false;  // Overwriting `this` is unsupported.
       }
     } else {
-      DCHECK(IsInstructionIPut(instruction->Opcode()));
-      DCHECK_EQ(instruction->VRegB_22c(), this_vreg);
-      if (!RecordConstructorIPut(method, instruction, this_vreg, zero_vreg_mask, iputs)) {
+      DCHECK(IsInstructionIPut(instruction.Opcode()));
+      DCHECK_EQ(instruction.VRegB_22c(), this_vreg);
+      if (!RecordConstructorIPut(method, &instruction, this_vreg, zero_vreg_mask, iputs)) {
         return false;
       }
     }
@@ -363,7 +366,7 @@
 
 }  // anonymous namespace
 
-bool AnalyseConstructor(const DexFile::CodeItem* code_item,
+bool AnalyseConstructor(const CodeItemDataAccessor* code_item,
                         ArtMethod* method,
                         InlineMethod* result)
     REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -427,28 +430,27 @@
     InlineMethodAnalyser::IPutVariant(Instruction::IPUT_SHORT), "iget/iput_short variant");
 
 bool InlineMethodAnalyser::AnalyseMethodCode(ArtMethod* method, InlineMethod* result) {
-  const DexFile::CodeItem* code_item = method->GetCodeItem();
-  if (code_item == nullptr) {
+  CodeItemDataAccessor code_item(method->DexInstructionData());
+  if (!code_item.HasCodeItem()) {
     // Native or abstract.
     return false;
   }
-  return AnalyseMethodCode(code_item,
+  return AnalyseMethodCode(&code_item,
                            MethodReference(method->GetDexFile(), method->GetDexMethodIndex()),
                            method->IsStatic(),
                            method,
                            result);
 }
 
-bool InlineMethodAnalyser::AnalyseMethodCode(const DexFile::CodeItem* code_item,
+bool InlineMethodAnalyser::AnalyseMethodCode(const CodeItemDataAccessor* code_item,
                                              const MethodReference& method_ref,
                                              bool is_static,
                                              ArtMethod* method,
                                              InlineMethod* result) {
   // We currently support only plain return or 2-instruction methods.
 
-  DCHECK_NE(code_item->insns_size_in_code_units_, 0u);
-  const Instruction* instruction = Instruction::At(code_item->insns_);
-  Instruction::Code opcode = instruction->Opcode();
+  DCHECK_NE(code_item->InsnsSizeInCodeUnits(), 0u);
+  Instruction::Code opcode = code_item->begin()->Opcode();
 
   switch (opcode) {
     case Instruction::RETURN_VOID:
@@ -509,7 +511,7 @@
 }
 
 bool InlineMethodAnalyser::IsSyntheticAccessor(MethodReference ref) {
-  const DexFile::MethodId& method_id = ref.dex_file->GetMethodId(ref.dex_method_index);
+  const DexFile::MethodId& method_id = ref.dex_file->GetMethodId(ref.index);
   const char* method_name = ref.dex_file->GetMethodName(method_id);
   // javac names synthetic accessors "access$nnn",
   // jack names them "-getN", "-putN", "-wrapN".
@@ -517,15 +519,15 @@
       strncmp(method_name, "-", strlen("-")) == 0;
 }
 
-bool InlineMethodAnalyser::AnalyseReturnMethod(const DexFile::CodeItem* code_item,
+bool InlineMethodAnalyser::AnalyseReturnMethod(const CodeItemDataAccessor* code_item,
                                                InlineMethod* result) {
-  const Instruction* return_instruction = Instruction::At(code_item->insns_);
+  DexInstructionIterator return_instruction = code_item->begin();
   Instruction::Code return_opcode = return_instruction->Opcode();
   uint32_t reg = return_instruction->VRegA_11x();
-  uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_;
+  uint32_t arg_start = code_item->RegistersSize() - code_item->InsSize();
   DCHECK_GE(reg, arg_start);
   DCHECK_LT((return_opcode == Instruction::RETURN_WIDE) ? reg + 1 : reg,
-      code_item->registers_size_);
+      code_item->RegistersSize());
 
   if (result != nullptr) {
     result->opcode = kInlineOpReturnArg;
@@ -539,9 +541,9 @@
   return true;
 }
 
-bool InlineMethodAnalyser::AnalyseConstMethod(const DexFile::CodeItem* code_item,
+bool InlineMethodAnalyser::AnalyseConstMethod(const CodeItemDataAccessor* code_item,
                                               InlineMethod* result) {
-  const Instruction* instruction = Instruction::At(code_item->insns_);
+  DexInstructionIterator instruction = code_item->begin();
   const Instruction* return_instruction = instruction->Next();
   Instruction::Code return_opcode = return_instruction->Opcode();
   if (return_opcode != Instruction::RETURN &&
@@ -550,13 +552,13 @@
   }
 
   int32_t return_reg = return_instruction->VRegA_11x();
-  DCHECK_LT(return_reg, code_item->registers_size_);
+  DCHECK_LT(return_reg, code_item->RegistersSize());
 
   int32_t const_value = instruction->VRegB();
   if (instruction->Opcode() == Instruction::CONST_HIGH16) {
     const_value <<= 16;
   }
-  DCHECK_LT(instruction->VRegA(), code_item->registers_size_);
+  DCHECK_LT(instruction->VRegA(), code_item->RegistersSize());
   if (instruction->VRegA() != return_reg) {
     return false;  // Not returning the value set by const?
   }
@@ -570,12 +572,12 @@
   return true;
 }
 
-bool InlineMethodAnalyser::AnalyseIGetMethod(const DexFile::CodeItem* code_item,
+bool InlineMethodAnalyser::AnalyseIGetMethod(const CodeItemDataAccessor* code_item,
                                              const MethodReference& method_ref,
                                              bool is_static,
                                              ArtMethod* method,
                                              InlineMethod* result) {
-  const Instruction* instruction = Instruction::At(code_item->insns_);
+  DexInstructionIterator instruction = code_item->begin();
   Instruction::Code opcode = instruction->Opcode();
   DCHECK(IsInstructionIGet(opcode));
 
@@ -590,17 +592,17 @@
 
   uint32_t return_reg = return_instruction->VRegA_11x();
   DCHECK_LT(return_opcode == Instruction::RETURN_WIDE ? return_reg + 1 : return_reg,
-            code_item->registers_size_);
+            code_item->RegistersSize());
 
   uint32_t dst_reg = instruction->VRegA_22c();
   uint32_t object_reg = instruction->VRegB_22c();
   uint32_t field_idx = instruction->VRegC_22c();
-  uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_;
+  uint32_t arg_start = code_item->RegistersSize() - code_item->InsSize();
   DCHECK_GE(object_reg, arg_start);
-  DCHECK_LT(object_reg, code_item->registers_size_);
+  DCHECK_LT(object_reg, code_item->RegistersSize());
   uint32_t object_arg = object_reg - arg_start;
 
-  DCHECK_LT(opcode == Instruction::IGET_WIDE ? dst_reg + 1 : dst_reg, code_item->registers_size_);
+  DCHECK_LT(opcode == Instruction::IGET_WIDE ? dst_reg + 1 : dst_reg, code_item->RegistersSize());
   if (dst_reg != return_reg) {
     return false;  // Not returning the value retrieved by IGET?
   }
@@ -634,18 +636,18 @@
   return true;
 }
 
-bool InlineMethodAnalyser::AnalyseIPutMethod(const DexFile::CodeItem* code_item,
+bool InlineMethodAnalyser::AnalyseIPutMethod(const CodeItemDataAccessor* code_item,
                                              const MethodReference& method_ref,
                                              bool is_static,
                                              ArtMethod* method,
                                              InlineMethod* result) {
-  const Instruction* instruction = Instruction::At(code_item->insns_);
+  DexInstructionIterator instruction = code_item->begin();
   Instruction::Code opcode = instruction->Opcode();
   DCHECK(IsInstructionIPut(opcode));
 
   const Instruction* return_instruction = instruction->Next();
   Instruction::Code return_opcode = return_instruction->Opcode();
-  uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_;
+  uint32_t arg_start = code_item->RegistersSize() - code_item->InsSize();
   uint16_t return_arg_plus1 = 0u;
   if (return_opcode != Instruction::RETURN_VOID) {
     if (return_opcode != Instruction::RETURN &&
@@ -657,7 +659,7 @@
     uint32_t return_reg = return_instruction->VRegA_11x();
     DCHECK_GE(return_reg, arg_start);
     DCHECK_LT(return_opcode == Instruction::RETURN_WIDE ? return_reg + 1u : return_reg,
-              code_item->registers_size_);
+              code_item->RegistersSize());
     return_arg_plus1 = return_reg - arg_start + 1u;
   }
 
@@ -665,9 +667,9 @@
   uint32_t object_reg = instruction->VRegB_22c();
   uint32_t field_idx = instruction->VRegC_22c();
   DCHECK_GE(object_reg, arg_start);
-  DCHECK_LT(object_reg, code_item->registers_size_);
+  DCHECK_LT(object_reg, code_item->RegistersSize());
   DCHECK_GE(src_reg, arg_start);
-  DCHECK_LT(opcode == Instruction::IPUT_WIDE ? src_reg + 1 : src_reg, code_item->registers_size_);
+  DCHECK_LT(opcode == Instruction::IPUT_WIDE ? src_reg + 1 : src_reg, code_item->RegistersSize());
   uint32_t object_arg = object_reg - arg_start;
   uint32_t src_arg = src_reg - arg_start;
 
diff --git a/compiler/dex/inline_method_analyser.h b/compiler/dex/inline_method_analyser.h
index a35e97f..e1d652a 100644
--- a/compiler/dex/inline_method_analyser.h
+++ b/compiler/dex/inline_method_analyser.h
@@ -19,9 +19,9 @@
 
 #include "base/macros.h"
 #include "base/mutex.h"
-#include "dex_file.h"
-#include "dex_instruction.h"
-#include "method_reference.h"
+#include "dex/dex_file.h"
+#include "dex/dex_instruction.h"
+#include "dex/method_reference.h"
 
 /*
  * NOTE: This code is part of the quick compiler. It lives in the runtime
@@ -30,6 +30,8 @@
 
 namespace art {
 
+class CodeItemDataAccessor;
+
 namespace verifier {
 class MethodVerifier;
 }  // namespace verifier
@@ -121,21 +123,21 @@
   static bool IsSyntheticAccessor(MethodReference ref);
 
  private:
-  static bool AnalyseMethodCode(const DexFile::CodeItem* code_item,
+  static bool AnalyseMethodCode(const CodeItemDataAccessor* code_item,
                                 const MethodReference& method_ref,
                                 bool is_static,
                                 ArtMethod* method,
                                 InlineMethod* result)
       REQUIRES_SHARED(Locks::mutator_lock_);
-  static bool AnalyseReturnMethod(const DexFile::CodeItem* code_item, InlineMethod* result);
-  static bool AnalyseConstMethod(const DexFile::CodeItem* code_item, InlineMethod* result);
-  static bool AnalyseIGetMethod(const DexFile::CodeItem* code_item,
+  static bool AnalyseReturnMethod(const CodeItemDataAccessor* code_item, InlineMethod* result);
+  static bool AnalyseConstMethod(const CodeItemDataAccessor* code_item, InlineMethod* result);
+  static bool AnalyseIGetMethod(const CodeItemDataAccessor* code_item,
                                 const MethodReference& method_ref,
                                 bool is_static,
                                 ArtMethod* method,
                                 InlineMethod* result)
       REQUIRES_SHARED(Locks::mutator_lock_);
-  static bool AnalyseIPutMethod(const DexFile::CodeItem* code_item,
+  static bool AnalyseIPutMethod(const CodeItemDataAccessor* code_item,
                                 const MethodReference& method_ref,
                                 bool is_static,
                                 ArtMethod* method,
diff --git a/compiler/dex/quick_compiler_callbacks.cc b/compiler/dex/quick_compiler_callbacks.cc
index 1a240bd..baf97a8 100644
--- a/compiler/dex/quick_compiler_callbacks.cc
+++ b/compiler/dex/quick_compiler_callbacks.cc
@@ -17,8 +17,12 @@
 #include "quick_compiler_callbacks.h"
 
 #include "driver/compiler_driver.h"
-#include "verifier/method_verifier-inl.h"
+#include "mirror/class-inl.h"
+#include "mirror/object.h"
+#include "obj_ptr-inl.h"
+#include "thread-current-inl.h"
 #include "verification_results.h"
+#include "verifier/method_verifier-inl.h"
 
 namespace art {
 
@@ -34,17 +38,35 @@
   }
 }
 
-bool QuickCompilerCallbacks::CanAssumeVerified(ClassReference ref) {
+ClassStatus QuickCompilerCallbacks::GetPreviousClassState(ClassReference ref) {
   // If we don't have class unloading enabled in the compiler, we will never see class that were
   // previously verified. Return false to avoid overhead from the lookup in the compiler driver.
   if (!does_class_unloading_) {
-    return false;
+    return ClassStatus::kNotReady;
   }
   DCHECK(compiler_driver_ != nullptr);
   // In the case of the quicken filter: avoiding verification of quickened instructions, which the
   // verifier doesn't currently support.
   // In the case of the verify filter, avoiding verifiying twice.
-  return compiler_driver_->CanAssumeVerified(ref);
+  return compiler_driver_->GetClassStatus(ref);
+}
+
+void QuickCompilerCallbacks::UpdateClassState(ClassReference ref, ClassStatus status) {
+  // Driver is null when bootstrapping the runtime.
+  if (compiler_driver_ != nullptr) {
+    compiler_driver_->RecordClassStatus(ref, status);
+  }
+}
+
+bool QuickCompilerCallbacks::CanUseOatStatusForVerification(mirror::Class* klass) {
+  // No dex files: conservatively false.
+  if (dex_files_ == nullptr) {
+    return false;
+  }
+
+  // If the class isn't from one of the dex files, accept oat file data.
+  const DexFile* dex_file = &klass->GetDexFile();
+  return std::find(dex_files_->begin(), dex_files_->end(), dex_file) == dex_files_->end();
 }
 
 }  // namespace art
diff --git a/compiler/dex/quick_compiler_callbacks.h b/compiler/dex/quick_compiler_callbacks.h
index 578aff4..8a07e9c 100644
--- a/compiler/dex/quick_compiler_callbacks.h
+++ b/compiler/dex/quick_compiler_callbacks.h
@@ -23,51 +23,62 @@
 namespace art {
 
 class CompilerDriver;
+class DexFile;
 class VerificationResults;
 
 class QuickCompilerCallbacks FINAL : public CompilerCallbacks {
-  public:
-    explicit QuickCompilerCallbacks(CompilerCallbacks::CallbackMode mode)
-        : CompilerCallbacks(mode) {}
+ public:
+  explicit QuickCompilerCallbacks(CompilerCallbacks::CallbackMode mode)
+      : CompilerCallbacks(mode), dex_files_(nullptr) {}
 
-    ~QuickCompilerCallbacks() { }
+  ~QuickCompilerCallbacks() { }
 
-    void MethodVerified(verifier::MethodVerifier* verifier)
-        REQUIRES_SHARED(Locks::mutator_lock_) OVERRIDE;
+  void MethodVerified(verifier::MethodVerifier* verifier)
+      REQUIRES_SHARED(Locks::mutator_lock_) OVERRIDE;
 
-    void ClassRejected(ClassReference ref) OVERRIDE;
+  void ClassRejected(ClassReference ref) OVERRIDE;
 
-    // We are running in an environment where we can call patchoat safely so we should.
-    bool IsRelocationPossible() OVERRIDE {
-      return true;
-    }
+  // We are running in an environment where we can call patchoat safely so we should.
+  bool IsRelocationPossible() OVERRIDE {
+    return true;
+  }
 
-    verifier::VerifierDeps* GetVerifierDeps() const OVERRIDE {
-      return verifier_deps_.get();
-    }
+  verifier::VerifierDeps* GetVerifierDeps() const OVERRIDE {
+    return verifier_deps_.get();
+  }
 
-    void SetVerifierDeps(verifier::VerifierDeps* deps) OVERRIDE {
-      verifier_deps_.reset(deps);
-    }
+  void SetVerifierDeps(verifier::VerifierDeps* deps) OVERRIDE {
+    verifier_deps_.reset(deps);
+  }
 
-    void SetVerificationResults(VerificationResults* verification_results) {
-      verification_results_ = verification_results;
-    }
+  void SetVerificationResults(VerificationResults* verification_results) {
+    verification_results_ = verification_results;
+  }
 
-    bool CanAssumeVerified(ClassReference ref) OVERRIDE;
+  ClassStatus GetPreviousClassState(ClassReference ref) OVERRIDE;
 
-    void SetDoesClassUnloading(bool does_class_unloading, CompilerDriver* compiler_driver)
-        OVERRIDE {
-      does_class_unloading_ = does_class_unloading;
-      compiler_driver_ = compiler_driver;
-      DCHECK(!does_class_unloading || compiler_driver_ != nullptr);
-    }
+  void SetDoesClassUnloading(bool does_class_unloading, CompilerDriver* compiler_driver)
+      OVERRIDE {
+    does_class_unloading_ = does_class_unloading;
+    compiler_driver_ = compiler_driver;
+    DCHECK(!does_class_unloading || compiler_driver_ != nullptr);
+  }
 
-  private:
-    VerificationResults* verification_results_ = nullptr;
-    bool does_class_unloading_ = false;
-    CompilerDriver* compiler_driver_ = nullptr;
-    std::unique_ptr<verifier::VerifierDeps> verifier_deps_;
+  void UpdateClassState(ClassReference ref, ClassStatus state) OVERRIDE;
+
+  bool CanUseOatStatusForVerification(mirror::Class* klass) OVERRIDE
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
+  void SetDexFiles(const std::vector<const DexFile*>* dex_files) {
+    dex_files_ = dex_files;
+  }
+
+ private:
+  VerificationResults* verification_results_ = nullptr;
+  bool does_class_unloading_ = false;
+  CompilerDriver* compiler_driver_ = nullptr;
+  std::unique_ptr<verifier::VerifierDeps> verifier_deps_;
+  const std::vector<const DexFile*>* dex_files_;
 };
 
 }  // namespace art
diff --git a/compiler/dex/verification_results.cc b/compiler/dex/verification_results.cc
index beb3439..1e0b94d 100644
--- a/compiler/dex/verification_results.cc
+++ b/compiler/dex/verification_results.cc
@@ -16,14 +16,15 @@
 
 #include "verification_results.h"
 
-#include "base/logging.h"
+#include <android-base/logging.h>
+
 #include "base/mutex-inl.h"
 #include "base/stl_util.h"
 #include "driver/compiler_driver.h"
 #include "driver/compiler_options.h"
 #include "runtime.h"
-#include "thread.h"
 #include "thread-current-inl.h"
+#include "thread.h"
 #include "utils/atomic_dex_ref_map-inl.h"
 #include "verified_method.h"
 #include "verifier/method_verifier-inl.h"
@@ -46,28 +47,22 @@
 
 void VerificationResults::ProcessVerifiedMethod(verifier::MethodVerifier* method_verifier) {
   DCHECK(method_verifier != nullptr);
-  if (!compiler_options_->IsAnyCompilationEnabled()) {
-    // Verified methods are only required for quickening and compilation.
-    return;
-  }
   MethodReference ref = method_verifier->GetMethodReference();
   std::unique_ptr<const VerifiedMethod> verified_method(VerifiedMethod::Create(method_verifier));
   if (verified_method == nullptr) {
     // We'll punt this later.
     return;
   }
-  AtomicMap::InsertResult result = atomic_verified_methods_.Insert(
-      DexFileReference(ref.dex_file, ref.dex_method_index),
-      /*expected*/ nullptr,
-      verified_method.get());
+  AtomicMap::InsertResult result = atomic_verified_methods_.Insert(ref,
+                                                                   /*expected*/ nullptr,
+                                                                   verified_method.get());
   const VerifiedMethod* existing = nullptr;
   bool inserted;
   if (result != AtomicMap::kInsertResultInvalidDexFile) {
     inserted = (result == AtomicMap::kInsertResultSuccess);
     if (!inserted) {
       // Rare case.
-      CHECK(atomic_verified_methods_.Get(DexFileReference(ref.dex_file, ref.dex_method_index),
-                                         &existing));
+      CHECK(atomic_verified_methods_.Get(ref, &existing));
       CHECK_NE(verified_method.get(), existing);
     }
   } else {
@@ -104,8 +99,7 @@
 
 const VerifiedMethod* VerificationResults::GetVerifiedMethod(MethodReference ref) {
   const VerifiedMethod* ret = nullptr;
-  DCHECK(compiler_options_->IsAnyCompilationEnabled());
-  if (atomic_verified_methods_.Get(DexFileReference(ref.dex_file, ref.dex_method_index), &ret)) {
+  if (atomic_verified_methods_.Get(ref, &ret)) {
     return ret;
   }
   ReaderMutexLock mu(Thread::Current(), verified_methods_lock_);
@@ -119,7 +113,7 @@
   // at runtime.
   std::unique_ptr<VerifiedMethod> verified_method = std::make_unique<VerifiedMethod>(
       /* encountered_error_types */ 0, /* has_runtime_throw */ false);
-  if (atomic_verified_methods_.Insert(DexFileReference(ref.dex_file, ref.dex_method_index),
+  if (atomic_verified_methods_.Insert(ref,
                                       /*expected*/ nullptr,
                                       verified_method.get()) ==
           AtomicMap::InsertResult::kInsertResultSuccess) {
@@ -154,7 +148,7 @@
 }
 
 void VerificationResults::AddDexFile(const DexFile* dex_file) {
-  atomic_verified_methods_.AddDexFile(dex_file, dex_file->NumMethodIds());
+  atomic_verified_methods_.AddDexFile(dex_file);
   WriterMutexLock mu(Thread::Current(), verified_methods_lock_);
   // There can be some verified methods that are already registered for the dex_file since we set
   // up well known classes earlier. Remove these and put them in the array so that we don't
@@ -162,9 +156,7 @@
   for (auto it = verified_methods_.begin(); it != verified_methods_.end(); ) {
     MethodReference ref = it->first;
     if (ref.dex_file == dex_file) {
-      CHECK(atomic_verified_methods_.Insert(DexFileReference(ref.dex_file, ref.dex_method_index),
-                                            nullptr,
-                                            it->second) ==
+      CHECK(atomic_verified_methods_.Insert(ref, nullptr, it->second) ==
           AtomicMap::kInsertResultSuccess);
       it = verified_methods_.erase(it);
     } else {
diff --git a/compiler/dex/verification_results.h b/compiler/dex/verification_results.h
index 5a03599..56f0030 100644
--- a/compiler/dex/verification_results.h
+++ b/compiler/dex/verification_results.h
@@ -23,9 +23,9 @@
 #include "base/dchecked_vector.h"
 #include "base/macros.h"
 #include "base/mutex.h"
-#include "class_reference.h"
-#include "method_reference.h"
-#include "safe_map.h"
+#include "base/safe_map.h"
+#include "dex/class_reference.h"
+#include "dex/method_reference.h"
 #include "utils/atomic_dex_ref_map.h"
 
 namespace art {
@@ -64,10 +64,8 @@
 
  private:
   // Verified methods. The method array is fixed to avoid needing a lock to extend it.
-  using AtomicMap = AtomicDexRefMap<const VerifiedMethod*>;
-  using VerifiedMethodMap = SafeMap<MethodReference,
-                                    const VerifiedMethod*,
-                                    MethodReferenceComparator>;
+  using AtomicMap = AtomicDexRefMap<MethodReference, const VerifiedMethod*>;
+  using VerifiedMethodMap = SafeMap<MethodReference, const VerifiedMethod*>;
 
   VerifiedMethodMap verified_methods_ GUARDED_BY(verified_methods_lock_);
   const CompilerOptions* const compiler_options_;
diff --git a/compiler/dex/verified_method.cc b/compiler/dex/verified_method.cc
index e46dc59..f2da3ff 100644
--- a/compiler/dex/verified_method.cc
+++ b/compiler/dex/verified_method.cc
@@ -19,9 +19,11 @@
 #include <algorithm>
 #include <memory>
 
-#include "base/logging.h"
-#include "dex_file.h"
-#include "dex_instruction-inl.h"
+#include <android-base/logging.h>
+
+#include "dex/code_item_accessors-inl.h"
+#include "dex/dex_file.h"
+#include "dex/dex_instruction-inl.h"
 #include "runtime.h"
 #include "verifier/method_verifier-inl.h"
 #include "verifier/reg_type-inl.h"
@@ -64,24 +66,20 @@
   if (method_verifier->HasFailures()) {
     return;
   }
-  const DexFile::CodeItem* code_item = method_verifier->CodeItem();
-  const Instruction* inst = Instruction::At(code_item->insns_);
-  const Instruction* end = Instruction::At(code_item->insns_ +
-                                           code_item->insns_size_in_code_units_);
-
-  for (; inst < end; inst = inst->Next()) {
-    Instruction::Code code = inst->Opcode();
+  for (const DexInstructionPcPair& pair : method_verifier->CodeItem()) {
+    const Instruction& inst = pair.Inst();
+    const Instruction::Code code = inst.Opcode();
     if (code == Instruction::CHECK_CAST) {
-      uint32_t dex_pc = inst->GetDexPc(code_item->insns_);
+      const uint32_t dex_pc = pair.DexPc();
       if (!method_verifier->GetInstructionFlags(dex_pc).IsVisited()) {
         // Do not attempt to quicken this instruction, it's unreachable anyway.
         continue;
       }
       const verifier::RegisterLine* line = method_verifier->GetRegLine(dex_pc);
       const verifier::RegType& reg_type(line->GetRegisterType(method_verifier,
-                                                              inst->VRegA_21c()));
+                                                              inst.VRegA_21c()));
       const verifier::RegType& cast_type =
-          method_verifier->ResolveCheckedClass(dex::TypeIndex(inst->VRegB_21c()));
+          method_verifier->ResolveCheckedClass(dex::TypeIndex(inst.VRegB_21c()));
       // Pass null for the method verifier to not record the VerifierDeps dependency
       // if the types are not assignable.
       if (cast_type.IsStrictlyAssignableFrom(reg_type, /* method_verifier */ nullptr)) {
diff --git a/compiler/dex/verified_method.h b/compiler/dex/verified_method.h
index 64b3f44..f04392d 100644
--- a/compiler/dex/verified_method.h
+++ b/compiler/dex/verified_method.h
@@ -20,9 +20,9 @@
 #include <vector>
 
 #include "base/mutex.h"
-#include "dex_file.h"
-#include "method_reference.h"
-#include "safe_map.h"
+#include "base/safe_map.h"
+#include "dex/dex_file.h"
+#include "dex/method_reference.h"
 
 namespace art {
 
diff --git a/compiler/driver/compiled_method_storage.cc b/compiler/driver/compiled_method_storage.cc
index 528b0a2..a26a985 100644
--- a/compiler/driver/compiled_method_storage.cc
+++ b/compiler/driver/compiled_method_storage.cc
@@ -19,10 +19,12 @@
 
 #include "compiled_method_storage.h"
 
-#include "base/logging.h"
+#include <android-base/logging.h>
+
+#include "base/utils.h"
 #include "compiled_method.h"
+#include "linker/linker_patch.h"
 #include "thread-current-inl.h"
-#include "utils.h"
 #include "utils/dedupe_set-inl.h"
 #include "utils/swap_space.h"
 
@@ -135,16 +137,7 @@
 
       return hash;
     } else {
-      size_t hash = 0x811c9dc5;
-      for (uint32_t i = 0; i < len; ++i) {
-        hash = (hash * 16777619) ^ data[i];
-      }
-      hash += hash << 13;
-      hash ^= hash >> 7;
-      hash += hash << 3;
-      hash ^= hash >> 17;
-      hash += hash << 5;
-      return hash;
+      return HashBytes(data, len);
     }
   }
 };
@@ -178,7 +171,7 @@
                          LengthPrefixedArrayAlloc<uint8_t>(swap_space_.get())),
       dedupe_cfi_info_("dedupe cfi info", LengthPrefixedArrayAlloc<uint8_t>(swap_space_.get())),
       dedupe_linker_patches_("dedupe cfi info",
-                             LengthPrefixedArrayAlloc<LinkerPatch>(swap_space_.get())) {
+                             LengthPrefixedArrayAlloc<linker::LinkerPatch>(swap_space_.get())) {
 }
 
 CompiledMethodStorage::~CompiledMethodStorage() {
@@ -234,13 +227,13 @@
   ReleaseArrayIfNotDeduplicated(cfi_info);
 }
 
-const LengthPrefixedArray<LinkerPatch>* CompiledMethodStorage::DeduplicateLinkerPatches(
-    const ArrayRef<const LinkerPatch>& linker_patches) {
+const LengthPrefixedArray<linker::LinkerPatch>* CompiledMethodStorage::DeduplicateLinkerPatches(
+    const ArrayRef<const linker::LinkerPatch>& linker_patches) {
   return AllocateOrDeduplicateArray(linker_patches, &dedupe_linker_patches_);
 }
 
 void CompiledMethodStorage::ReleaseLinkerPatches(
-    const LengthPrefixedArray<LinkerPatch>* linker_patches) {
+    const LengthPrefixedArray<linker::LinkerPatch>* linker_patches) {
   ReleaseArrayIfNotDeduplicated(linker_patches);
 }
 
diff --git a/compiler/driver/compiled_method_storage.h b/compiler/driver/compiled_method_storage.h
index 27011e8..249f06c 100644
--- a/compiler/driver/compiled_method_storage.h
+++ b/compiler/driver/compiled_method_storage.h
@@ -28,7 +28,9 @@
 
 namespace art {
 
+namespace linker {
 class LinkerPatch;
+}  // namespace linker
 
 class CompiledMethodStorage {
  public:
@@ -61,9 +63,9 @@
   const LengthPrefixedArray<uint8_t>* DeduplicateCFIInfo(const ArrayRef<const uint8_t>& cfi_info);
   void ReleaseCFIInfo(const LengthPrefixedArray<uint8_t>* cfi_info);
 
-  const LengthPrefixedArray<LinkerPatch>* DeduplicateLinkerPatches(
-      const ArrayRef<const LinkerPatch>& linker_patches);
-  void ReleaseLinkerPatches(const LengthPrefixedArray<LinkerPatch>* linker_patches);
+  const LengthPrefixedArray<linker::LinkerPatch>* DeduplicateLinkerPatches(
+      const ArrayRef<const linker::LinkerPatch>& linker_patches);
+  void ReleaseLinkerPatches(const LengthPrefixedArray<linker::LinkerPatch>* linker_patches);
 
  private:
   template <typename T, typename DedupeSetType>
@@ -98,7 +100,7 @@
   ArrayDedupeSet<uint8_t> dedupe_method_info_;
   ArrayDedupeSet<uint8_t> dedupe_vmap_table_;
   ArrayDedupeSet<uint8_t> dedupe_cfi_info_;
-  ArrayDedupeSet<LinkerPatch> dedupe_linker_patches_;
+  ArrayDedupeSet<linker::LinkerPatch> dedupe_linker_patches_;
 
   DISALLOW_COPY_AND_ASSIGN(CompiledMethodStorage);
 };
diff --git a/compiler/driver/compiled_method_storage_test.cc b/compiler/driver/compiled_method_storage_test.cc
index bbd28b2..0769561 100644
--- a/compiler/driver/compiled_method_storage_test.cc
+++ b/compiler/driver/compiled_method_storage_test.cc
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
+#include "compiled_method_storage.h"
+
 #include <gtest/gtest.h>
 
-#include "compiled_method_storage.h"
-#include "compiled_method.h"
+#include "compiled_method-inl.h"
 #include "compiler_driver.h"
 #include "compiler_options.h"
 #include "dex/verification_results.h"
@@ -30,15 +31,12 @@
   CompilerDriver driver(&compiler_options,
                         &verification_results,
                         Compiler::kOptimizing,
-                        /* instruction_set_ */ kNone,
+                        /* instruction_set_ */ InstructionSet::kNone,
                         /* instruction_set_features */ nullptr,
                         /* image_classes */ nullptr,
                         /* compiled_classes */ nullptr,
                         /* compiled_methods */ nullptr,
                         /* thread_count */ 1u,
-                        /* dump_stats */ false,
-                        /* dump_passes */ false,
-                        /* timer */ nullptr,
                         /* swap_fd */ -1,
                         /* profile_compilation_info */ nullptr);
   CompiledMethodStorage* storage = driver.GetCompiledMethodStorage();
@@ -69,17 +67,17 @@
       ArrayRef<const uint8_t>(raw_cfi_info1),
       ArrayRef<const uint8_t>(raw_cfi_info2),
   };
-  const LinkerPatch raw_patches1[] = {
-      LinkerPatch::CodePatch(0u, nullptr, 1u),
-      LinkerPatch::RelativeMethodPatch(4u, nullptr, 0u, 1u),
+  const linker::LinkerPatch raw_patches1[] = {
+      linker::LinkerPatch::CodePatch(0u, nullptr, 1u),
+      linker::LinkerPatch::RelativeMethodPatch(4u, nullptr, 0u, 1u),
   };
-  const LinkerPatch raw_patches2[] = {
-      LinkerPatch::CodePatch(0u, nullptr, 1u),
-      LinkerPatch::RelativeMethodPatch(4u, nullptr, 0u, 2u),
+  const linker::LinkerPatch raw_patches2[] = {
+      linker::LinkerPatch::CodePatch(0u, nullptr, 1u),
+      linker::LinkerPatch::RelativeMethodPatch(4u, nullptr, 0u, 2u),
   };
-  ArrayRef<const LinkerPatch> patches[] = {
-      ArrayRef<const LinkerPatch>(raw_patches1),
-      ArrayRef<const LinkerPatch>(raw_patches2),
+  ArrayRef<const linker::LinkerPatch> patches[] = {
+      ArrayRef<const linker::LinkerPatch>(raw_patches1),
+      ArrayRef<const linker::LinkerPatch>(raw_patches2),
   };
 
   std::vector<CompiledMethod*> compiled_methods;
@@ -90,7 +88,7 @@
         for (auto&& f : cfi_info) {
           for (auto&& p : patches) {
             compiled_methods.push_back(CompiledMethod::SwapAllocCompiledMethod(
-                &driver, kNone, c, 0u, 0u, 0u, s, v, f, p));
+                &driver, InstructionSet::kNone, c, 0u, 0u, 0u, s, v, f, p));
           }
         }
       }
diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h
index b043929..294072d 100644
--- a/compiler/driver/compiler_driver-inl.h
+++ b/compiler/driver/compiler_driver-inl.h
@@ -32,14 +32,16 @@
 
 namespace art {
 
-inline mirror::Class* CompilerDriver::ResolveClass(
-    const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
-    Handle<mirror::ClassLoader> class_loader, dex::TypeIndex cls_index,
+inline ObjPtr<mirror::Class> CompilerDriver::ResolveClass(
+    const ScopedObjectAccess& soa,
+    Handle<mirror::DexCache> dex_cache,
+    Handle<mirror::ClassLoader> class_loader,
+    dex::TypeIndex cls_index,
     const DexCompilationUnit* mUnit) {
   DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile());
   DCHECK_EQ(class_loader.Get(), mUnit->GetClassLoader().Get());
-  mirror::Class* cls = mUnit->GetClassLinker()->ResolveType(
-      *mUnit->GetDexFile(), cls_index, dex_cache, class_loader);
+  ObjPtr<mirror::Class> cls =
+      mUnit->GetClassLinker()->ResolveType(cls_index, dex_cache, class_loader);
   DCHECK_EQ(cls == nullptr, soa.Self()->IsExceptionPending());
   if (UNLIKELY(cls == nullptr)) {
     // Clean up any exception left by type resolution.
@@ -48,9 +50,11 @@
   return cls;
 }
 
-inline mirror::Class* CompilerDriver::ResolveCompilingMethodsClass(
-    const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
-    Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit) {
+inline ObjPtr<mirror::Class> CompilerDriver::ResolveCompilingMethodsClass(
+    const ScopedObjectAccess& soa,
+    Handle<mirror::DexCache> dex_cache,
+    Handle<mirror::ClassLoader> class_loader,
+    const DexCompilationUnit* mUnit) {
   DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile());
   DCHECK_EQ(class_loader.Get(), mUnit->GetClassLoader().Get());
   const DexFile::MethodId& referrer_method_id =
@@ -58,13 +62,13 @@
   return ResolveClass(soa, dex_cache, class_loader, referrer_method_id.class_idx_, mUnit);
 }
 
-inline ArtField* CompilerDriver::ResolveFieldWithDexFile(
-    const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
-    Handle<mirror::ClassLoader> class_loader, const DexFile* dex_file,
-    uint32_t field_idx, bool is_static) {
-  DCHECK_EQ(dex_cache->GetDexFile(), dex_file);
+inline ArtField* CompilerDriver::ResolveField(const ScopedObjectAccess& soa,
+                                              Handle<mirror::DexCache> dex_cache,
+                                              Handle<mirror::ClassLoader> class_loader,
+                                              uint32_t field_idx,
+                                              bool is_static) {
   ArtField* resolved_field = Runtime::Current()->GetClassLinker()->ResolveField(
-      *dex_file, field_idx, dex_cache, class_loader, is_static);
+      field_idx, dex_cache, class_loader, is_static);
   DCHECK_EQ(resolved_field == nullptr, soa.Self()->IsExceptionPending());
   if (UNLIKELY(resolved_field == nullptr)) {
     // Clean up any exception left by type resolution.
@@ -79,18 +83,11 @@
   return resolved_field;
 }
 
-inline ArtField* CompilerDriver::ResolveField(
-    const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
-    Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit,
-    uint32_t field_idx, bool is_static) {
-  DCHECK_EQ(class_loader.Get(), mUnit->GetClassLoader().Get());
-  return ResolveFieldWithDexFile(soa, dex_cache, class_loader, mUnit->GetDexFile(), field_idx,
-                                 is_static);
-}
-
 inline std::pair<bool, bool> CompilerDriver::IsFastInstanceField(
-    mirror::DexCache* dex_cache, mirror::Class* referrer_class,
-    ArtField* resolved_field, uint16_t field_idx) {
+    ObjPtr<mirror::DexCache> dex_cache,
+    ObjPtr<mirror::Class> referrer_class,
+    ArtField* resolved_field,
+    uint16_t field_idx) {
   DCHECK(!resolved_field->IsStatic());
   ObjPtr<mirror::Class> fields_class = resolved_field->GetDeclaringClass();
   bool fast_get = referrer_class != nullptr &&
@@ -112,7 +109,7 @@
   DCHECK_EQ(class_loader.Get(), mUnit->GetClassLoader().Get());
   ArtMethod* resolved_method =
       mUnit->GetClassLinker()->ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>(
-          *dex_cache->GetDexFile(), method_idx, dex_cache, class_loader, nullptr, invoke_type);
+          method_idx, dex_cache, class_loader, /* referrer */ nullptr, invoke_type);
   if (UNLIKELY(resolved_method == nullptr)) {
     DCHECK(soa.Self()->IsExceptionPending());
     // Clean up any exception left by type resolution.
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index e48b82d..5360476 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -16,9 +16,9 @@
 
 #include "compiler_driver.h"
 
+#include <unistd.h>
 #include <unordered_set>
 #include <vector>
-#include <unistd.h>
 
 #ifndef __APPLE__
 #include <malloc.h>  // For mallinfo
@@ -32,21 +32,24 @@
 #include "base/array_ref.h"
 #include "base/bit_vector.h"
 #include "base/enums.h"
+#include "base/logging.h"  // For VLOG
 #include "base/stl_util.h"
 #include "base/systrace.h"
 #include "base/time_utils.h"
 #include "base/timing_logger.h"
 #include "class_linker-inl.h"
-#include "compiled_method.h"
+#include "compiled_method-inl.h"
 #include "compiler.h"
 #include "compiler_callbacks.h"
 #include "compiler_driver-inl.h"
+#include "dex/descriptors_names.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_annotations.h"
+#include "dex/dex_instruction-inl.h"
 #include "dex/dex_to_dex_compiler.h"
 #include "dex/verification_results.h"
 #include "dex/verified_method.h"
 #include "dex_compilation_unit.h"
-#include "dex_file-inl.h"
-#include "dex_instruction-inl.h"
 #include "driver/compiler_options.h"
 #include "gc/accounting/card_table-inl.h"
 #include "gc/accounting/heap_bitmap.h"
@@ -54,7 +57,9 @@
 #include "gc/space/space.h"
 #include "handle_scope-inl.h"
 #include "intrinsics_enum.h"
+#include "jit/profile_compilation_info.h"
 #include "jni_internal.h"
+#include "linker/linker_patch.h"
 #include "mirror/class-inl.h"
 #include "mirror/class_loader.h"
 #include "mirror/dex_cache-inl.h"
@@ -65,6 +70,7 @@
 #include "nativehelper/ScopedLocalRef.h"
 #include "object_lock.h"
 #include "runtime.h"
+#include "runtime_intrinsics.h"
 #include "scoped_thread_state_change-inl.h"
 #include "thread.h"
 #include "thread_list.h"
@@ -251,24 +257,6 @@
   DISALLOW_COPY_AND_ASSIGN(AOTCompilationStats);
 };
 
-class CompilerDriver::DexFileMethodSet {
- public:
-  explicit DexFileMethodSet(const DexFile& dex_file)
-    : dex_file_(dex_file),
-      method_indexes_(dex_file.NumMethodIds(), false, Allocator::GetMallocAllocator()) {
-  }
-  DexFileMethodSet(DexFileMethodSet&& other) = default;
-
-  const DexFile& GetDexFile() const { return dex_file_; }
-
-  BitVector& GetMethodIndexes() { return method_indexes_; }
-  const BitVector& GetMethodIndexes() const { return method_indexes_; }
-
- private:
-  const DexFile& dex_file_;
-  BitVector method_indexes_;
-};
-
 CompilerDriver::CompilerDriver(
     const CompilerOptions* compiler_options,
     VerificationResults* verification_results,
@@ -279,36 +267,30 @@
     std::unordered_set<std::string>* compiled_classes,
     std::unordered_set<std::string>* compiled_methods,
     size_t thread_count,
-    bool dump_stats,
-    bool dump_passes,
-    CumulativeLogger* timer,
     int swap_fd,
     const ProfileCompilationInfo* profile_compilation_info)
     : compiler_options_(compiler_options),
       verification_results_(verification_results),
       compiler_(Compiler::Create(this, compiler_kind)),
       compiler_kind_(compiler_kind),
-      instruction_set_(instruction_set == kArm ? kThumb2 : instruction_set),
+      instruction_set_(
+          instruction_set == InstructionSet::kArm ? InstructionSet::kThumb2 : instruction_set),
       instruction_set_features_(instruction_set_features),
       requires_constructor_barrier_lock_("constructor barrier lock"),
       non_relative_linker_patch_count_(0u),
       image_classes_(image_classes),
       classes_to_compile_(compiled_classes),
       methods_to_compile_(compiled_methods),
+      number_of_soft_verifier_failures_(0),
       had_hard_verifier_failure_(false),
       parallel_thread_count_(thread_count),
       stats_(new AOTCompilationStats),
-      dump_stats_(dump_stats),
-      dump_passes_(dump_passes),
-      timings_logger_(timer),
       compiler_context_(nullptr),
       support_boot_image_fixup_(true),
       compiled_method_storage_(swap_fd),
       profile_compilation_info_(profile_compilation_info),
       max_arena_alloc_(0),
-      dex_to_dex_references_lock_("dex-to-dex references lock"),
-      dex_to_dex_references_(),
-      current_dex_to_dex_methods_(nullptr) {
+      dex_to_dex_compiler_(this) {
   DCHECK(compiler_options_ != nullptr);
 
   compiler_->Init();
@@ -316,6 +298,8 @@
   if (GetCompilerOptions().IsBootImage()) {
     CHECK(image_classes_.get() != nullptr) << "Expected image classes for boot image";
   }
+
+  compiled_method_storage_.SetDedupeEnabled(compiler_options_->DeduplicateCode());
 }
 
 CompilerDriver::~CompilerDriver() {
@@ -363,28 +347,6 @@
 }
 #undef CREATE_TRAMPOLINE
 
-static void SetupIntrinsic(Thread* self,
-                           Intrinsics intrinsic,
-                           InvokeType invoke_type,
-                           const char* class_name,
-                           const char* method_name,
-                           const char* signature)
-      REQUIRES_SHARED(Locks::mutator_lock_) {
-  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  PointerSize image_size = class_linker->GetImagePointerSize();
-  ObjPtr<mirror::Class> cls = class_linker->FindSystemClass(self, class_name);
-  if (cls == nullptr) {
-    LOG(FATAL) << "Could not find class of intrinsic " << class_name;
-  }
-  ArtMethod* method = cls->FindClassMethod(method_name, signature, image_size);
-  if (method == nullptr || method->GetDeclaringClass() != cls) {
-    LOG(FATAL) << "Could not find method of intrinsic "
-               << class_name << " " << method_name << " " << signature;
-  }
-  DCHECK_EQ(method->GetInvokeType(), invoke_type);
-  method->SetIntrinsic(static_cast<uint32_t>(intrinsic));
-}
-
 void CompilerDriver::CompileAll(jobject class_loader,
                                 const std::vector<const DexFile*>& dex_files,
                                 TimingLogger* timings) {
@@ -403,14 +365,7 @@
     // We don't need to setup the intrinsics for non boot image compilation, as
     // those compilations will pick up a boot image that have the ArtMethod already
     // set with the intrinsics flag.
-    ScopedObjectAccess soa(Thread::Current());
-#define SETUP_INTRINSICS(Name, InvokeType, NeedsEnvironmentOrCache, SideEffects, Exceptions, \
-                         ClassName, MethodName, Signature) \
-  SetupIntrinsic(soa.Self(), Intrinsics::k##Name, InvokeType, ClassName, MethodName, Signature);
-#include "intrinsics_list.h"
-INTRINSICS_LIST(SETUP_INTRINSICS)
-#undef INTRINSICS_LIST
-#undef SETUP_INTRINSICS
+    InitializeIntrinsics();
   }
   // Compile:
   // 1) Compile all classes and methods enabled for compilation. May fall back to dex-to-dex
@@ -418,17 +373,23 @@
   if (GetCompilerOptions().IsAnyCompilationEnabled()) {
     Compile(class_loader, dex_files, timings);
   }
-  if (dump_stats_) {
+  if (GetCompilerOptions().GetDumpStats()) {
     stats_->Dump();
   }
 
   FreeThreadPools();
 }
 
-static optimizer::DexToDexCompilationLevel GetDexToDexCompilationLevel(
+static optimizer::DexToDexCompiler::CompilationLevel GetDexToDexCompilationLevel(
     Thread* self, const CompilerDriver& driver, Handle<mirror::ClassLoader> class_loader,
     const DexFile& dex_file, const DexFile::ClassDef& class_def)
     REQUIRES_SHARED(Locks::mutator_lock_) {
+  // When the dex file is uncompressed in the APK, we do not generate a copy in the .vdex
+  // file. As a result, dex2oat will map the dex file read-only, and we only need to check
+  // that to know if we can do quickening.
+  if (dex_file.GetContainer() != nullptr && dex_file.GetContainer()->IsReadOnly()) {
+    return optimizer::DexToDexCompiler::CompilationLevel::kDontDexToDexCompile;
+  }
   auto* const runtime = Runtime::Current();
   DCHECK(driver.GetCompilerOptions().IsQuickeningCompilationEnabled());
   const char* descriptor = dex_file.GetClassDescriptor(class_def);
@@ -437,7 +398,7 @@
   if (klass == nullptr) {
     CHECK(self->IsExceptionPending());
     self->ClearException();
-    return optimizer::DexToDexCompilationLevel::kDontDexToDexCompile;
+    return optimizer::DexToDexCompiler::CompilationLevel::kDontDexToDexCompile;
   }
   // DexToDex at the kOptimize level may introduce quickened opcodes, which replace symbolic
   // references with actual offsets. We cannot re-verify such instructions.
@@ -445,22 +406,23 @@
   // We store the verification information in the class status in the oat file, which the linker
   // can validate (checksums) and use to skip load-time verification. It is thus safe to
   // optimize when a class has been fully verified before.
-  optimizer::DexToDexCompilationLevel max_level = optimizer::DexToDexCompilationLevel::kOptimize;
+  optimizer::DexToDexCompiler::CompilationLevel max_level =
+      optimizer::DexToDexCompiler::CompilationLevel::kOptimize;
   if (driver.GetCompilerOptions().GetDebuggable()) {
     // We are debuggable so definitions of classes might be changed. We don't want to do any
     // optimizations that could break that.
-    max_level = optimizer::DexToDexCompilationLevel::kDontDexToDexCompile;
+    max_level = optimizer::DexToDexCompiler::CompilationLevel::kDontDexToDexCompile;
   }
   if (klass->IsVerified()) {
     // Class is verified so we can enable DEX-to-DEX compilation for performance.
     return max_level;
   } else {
     // Class verification has failed: do not run DEX-to-DEX optimizations.
-    return optimizer::DexToDexCompilationLevel::kDontDexToDexCompile;
+    return optimizer::DexToDexCompiler::CompilationLevel::kDontDexToDexCompile;
   }
 }
 
-static optimizer::DexToDexCompilationLevel GetDexToDexCompilationLevel(
+static optimizer::DexToDexCompiler::CompilationLevel GetDexToDexCompilationLevel(
     Thread* self,
     const CompilerDriver& driver,
     jobject jclass_loader,
@@ -477,136 +439,50 @@
 // GetQuickGenericJniStub allowing down calls that aren't compiled using a JNI compiler?
 static bool InstructionSetHasGenericJniStub(InstructionSet isa) {
   switch (isa) {
-    case kArm:
-    case kArm64:
-    case kThumb2:
-    case kMips:
-    case kMips64:
-    case kX86:
-    case kX86_64: return true;
+    case InstructionSet::kArm:
+    case InstructionSet::kArm64:
+    case InstructionSet::kThumb2:
+    case InstructionSet::kMips:
+    case InstructionSet::kMips64:
+    case InstructionSet::kX86:
+    case InstructionSet::kX86_64: return true;
     default: return false;
   }
 }
 
-static void CompileMethod(Thread* self,
-                          CompilerDriver* driver,
-                          const DexFile::CodeItem* code_item,
-                          uint32_t access_flags,
-                          InvokeType invoke_type,
-                          uint16_t class_def_idx,
-                          uint32_t method_idx,
-                          Handle<mirror::ClassLoader> class_loader,
-                          const DexFile& dex_file,
-                          optimizer::DexToDexCompilationLevel dex_to_dex_compilation_level,
-                          bool compilation_enabled,
-                          Handle<mirror::DexCache> dex_cache) {
+template <typename CompileFn>
+static void CompileMethodHarness(
+    Thread* self,
+    CompilerDriver* driver,
+    const DexFile::CodeItem* code_item,
+    uint32_t access_flags,
+    InvokeType invoke_type,
+    uint16_t class_def_idx,
+    uint32_t method_idx,
+    Handle<mirror::ClassLoader> class_loader,
+    const DexFile& dex_file,
+    optimizer::DexToDexCompiler::CompilationLevel dex_to_dex_compilation_level,
+    bool compilation_enabled,
+    Handle<mirror::DexCache> dex_cache,
+    CompileFn compile_fn) {
   DCHECK(driver != nullptr);
-  CompiledMethod* compiled_method = nullptr;
+  CompiledMethod* compiled_method;
   uint64_t start_ns = kTimeCompileMethod ? NanoTime() : 0;
   MethodReference method_ref(&dex_file, method_idx);
 
-  if (driver->GetCurrentDexToDexMethods() != nullptr) {
-    // This is the second pass when we dex-to-dex compile previously marked methods.
-    // TODO: Refactor the compilation to avoid having to distinguish the two passes
-    // here. That should be done on a higher level. http://b/29089975
-    if (driver->GetCurrentDexToDexMethods()->IsBitSet(method_idx)) {
-      VerificationResults* results = driver->GetVerificationResults();
-      DCHECK(results != nullptr);
-      const VerifiedMethod* verified_method = results->GetVerifiedMethod(method_ref);
-      // Do not optimize if a VerifiedMethod is missing. SafeCast elision,
-      // for example, relies on it.
-      compiled_method = optimizer::ArtCompileDEX(
-          driver,
-          code_item,
-          access_flags,
-          invoke_type,
-          class_def_idx,
-          method_idx,
-          class_loader,
-          dex_file,
-          (verified_method != nullptr)
-              ? dex_to_dex_compilation_level
-              : optimizer::DexToDexCompilationLevel::kDontDexToDexCompile);
-    }
-  } else if ((access_flags & kAccNative) != 0) {
-    // Are we extracting only and have support for generic JNI down calls?
-    if (!driver->GetCompilerOptions().IsJniCompilationEnabled() &&
-        InstructionSetHasGenericJniStub(driver->GetInstructionSet())) {
-      // Leaving this empty will trigger the generic JNI version
-    } else {
-      // Look-up the ArtMethod associated with this code_item (if any)
-      // -- It is later used to lookup any [optimization] annotations for this method.
-      ScopedObjectAccess soa(self);
+  compiled_method = compile_fn(self,
+                               driver,
+                               code_item,
+                               access_flags,
+                               invoke_type,
+                               class_def_idx,
+                               method_idx,
+                               class_loader,
+                               dex_file,
+                               dex_to_dex_compilation_level,
+                               compilation_enabled,
+                               dex_cache);
 
-      // TODO: Lookup annotation from DexFile directly without resolving method.
-      ArtMethod* method =
-          Runtime::Current()->GetClassLinker()->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
-              dex_file,
-              method_idx,
-              dex_cache,
-              class_loader,
-              /* referrer */ nullptr,
-              invoke_type);
-
-      // Query any JNI optimization annotations such as @FastNative or @CriticalNative.
-      Compiler::JniOptimizationFlags optimization_flags = Compiler::kNone;
-      if (UNLIKELY(method == nullptr)) {
-        // Failed method resolutions happen very rarely, e.g. ancestor class cannot be resolved.
-        DCHECK(self->IsExceptionPending());
-        self->ClearException();
-      } else if (method->IsAnnotatedWithFastNative()) {
-        // TODO: Will no longer need this CHECK once we have verifier checking this.
-        CHECK(!method->IsAnnotatedWithCriticalNative());
-        optimization_flags = Compiler::kFastNative;
-      } else if (method->IsAnnotatedWithCriticalNative()) {
-        // TODO: Will no longer need this CHECK once we have verifier checking this.
-        CHECK(!method->IsAnnotatedWithFastNative());
-        optimization_flags = Compiler::kCriticalNative;
-      }
-
-      compiled_method = driver->GetCompiler()->JniCompile(access_flags,
-                                                          method_idx,
-                                                          dex_file,
-                                                          optimization_flags);
-      CHECK(compiled_method != nullptr);
-    }
-  } else if ((access_flags & kAccAbstract) != 0) {
-    // Abstract methods don't have code.
-  } else {
-    VerificationResults* results = driver->GetVerificationResults();
-    DCHECK(results != nullptr);
-    const VerifiedMethod* verified_method = results->GetVerifiedMethod(method_ref);
-    bool compile = compilation_enabled &&
-        // Basic checks, e.g., not <clinit>.
-        results->IsCandidateForCompilation(method_ref, access_flags) &&
-        // Did not fail to create VerifiedMethod metadata.
-        verified_method != nullptr &&
-        // Do not have failures that should punt to the interpreter.
-        !verified_method->HasRuntimeThrow() &&
-        (verified_method->GetEncounteredVerificationFailures() &
-            (verifier::VERIFY_ERROR_FORCE_INTERPRETER | verifier::VERIFY_ERROR_LOCKING)) == 0 &&
-        // Is eligable for compilation by methods-to-compile filter.
-        driver->IsMethodToCompile(method_ref) &&
-        driver->ShouldCompileBasedOnProfile(method_ref);
-
-    if (compile) {
-      // NOTE: if compiler declines to compile this method, it will return null.
-      compiled_method = driver->GetCompiler()->Compile(code_item,
-                                                       access_flags,
-                                                       invoke_type,
-                                                       class_def_idx,
-                                                       method_idx,
-                                                       class_loader,
-                                                       dex_file,
-                                                       dex_cache);
-    }
-    if (compiled_method == nullptr &&
-        dex_to_dex_compilation_level != optimizer::DexToDexCompilationLevel::kDontDexToDexCompile) {
-      DCHECK(!Runtime::Current()->UseJitCompilation());
-      // TODO: add a command-line option to disable DEX-to-DEX compilation ?
-      driver->MarkForDexToDexCompilation(self, method_ref);
-    }
-  }
   if (kTimeCompileMethod) {
     uint64_t duration_ns = NanoTime() - start_ns;
     if (duration_ns > MsToNs(driver->GetCompiler()->GetMaximumCompilationTimeBeforeWarning())) {
@@ -618,7 +494,7 @@
   if (compiled_method != nullptr) {
     // Count non-relative linker patches.
     size_t non_relative_linker_patch_count = 0u;
-    for (const LinkerPatch& patch : compiled_method->GetPatches()) {
+    for (const linker::LinkerPatch& patch : compiled_method->GetPatches()) {
       if (!patch.IsPcRelative()) {
         ++non_relative_linker_patch_count;
       }
@@ -637,6 +513,170 @@
   }
 }
 
+static void CompileMethodDex2Dex(
+    Thread* self,
+    CompilerDriver* driver,
+    const DexFile::CodeItem* code_item,
+    uint32_t access_flags,
+    InvokeType invoke_type,
+    uint16_t class_def_idx,
+    uint32_t method_idx,
+    Handle<mirror::ClassLoader> class_loader,
+    const DexFile& dex_file,
+    optimizer::DexToDexCompiler::CompilationLevel dex_to_dex_compilation_level,
+    bool compilation_enabled,
+    Handle<mirror::DexCache> dex_cache) {
+  auto dex_2_dex_fn = [](Thread* self ATTRIBUTE_UNUSED,
+      CompilerDriver* driver,
+      const DexFile::CodeItem* code_item,
+      uint32_t access_flags,
+      InvokeType invoke_type,
+      uint16_t class_def_idx,
+      uint32_t method_idx,
+      Handle<mirror::ClassLoader> class_loader,
+      const DexFile& dex_file,
+      optimizer::DexToDexCompiler::CompilationLevel dex_to_dex_compilation_level,
+      bool compilation_enabled ATTRIBUTE_UNUSED,
+      Handle<mirror::DexCache> dex_cache ATTRIBUTE_UNUSED) -> CompiledMethod* {
+    DCHECK(driver != nullptr);
+    MethodReference method_ref(&dex_file, method_idx);
+
+    optimizer::DexToDexCompiler* const compiler = &driver->GetDexToDexCompiler();
+
+    if (compiler->ShouldCompileMethod(method_ref)) {
+      VerificationResults* results = driver->GetVerificationResults();
+      DCHECK(results != nullptr);
+      const VerifiedMethod* verified_method = results->GetVerifiedMethod(method_ref);
+      // Do not optimize if a VerifiedMethod is missing. SafeCast elision,
+      // for example, relies on it.
+      return compiler->CompileMethod(
+          code_item,
+          access_flags,
+          invoke_type,
+          class_def_idx,
+          method_idx,
+          class_loader,
+          dex_file,
+          (verified_method != nullptr)
+          ? dex_to_dex_compilation_level
+              : optimizer::DexToDexCompiler::CompilationLevel::kDontDexToDexCompile);
+    }
+    return nullptr;
+  };
+  CompileMethodHarness(self,
+                       driver,
+                       code_item,
+                       access_flags,
+                       invoke_type,
+                       class_def_idx,
+                       method_idx,
+                       class_loader,
+                       dex_file,
+                       dex_to_dex_compilation_level,
+                       compilation_enabled,
+                       dex_cache,
+                       dex_2_dex_fn);
+}
+
+static void CompileMethodQuick(
+    Thread* self,
+    CompilerDriver* driver,
+    const DexFile::CodeItem* code_item,
+    uint32_t access_flags,
+    InvokeType invoke_type,
+    uint16_t class_def_idx,
+    uint32_t method_idx,
+    Handle<mirror::ClassLoader> class_loader,
+    const DexFile& dex_file,
+    optimizer::DexToDexCompiler::CompilationLevel dex_to_dex_compilation_level,
+    bool compilation_enabled,
+    Handle<mirror::DexCache> dex_cache) {
+  auto quick_fn = [](
+      Thread* self,
+      CompilerDriver* driver,
+      const DexFile::CodeItem* code_item,
+      uint32_t access_flags,
+      InvokeType invoke_type,
+      uint16_t class_def_idx,
+      uint32_t method_idx,
+      Handle<mirror::ClassLoader> class_loader,
+      const DexFile& dex_file,
+      optimizer::DexToDexCompiler::CompilationLevel dex_to_dex_compilation_level,
+      bool compilation_enabled,
+      Handle<mirror::DexCache> dex_cache) {
+    DCHECK(driver != nullptr);
+    CompiledMethod* compiled_method = nullptr;
+    MethodReference method_ref(&dex_file, method_idx);
+
+    if ((access_flags & kAccNative) != 0) {
+      // Are we extracting only and have support for generic JNI down calls?
+      if (!driver->GetCompilerOptions().IsJniCompilationEnabled() &&
+          InstructionSetHasGenericJniStub(driver->GetInstructionSet())) {
+        // Leaving this empty will trigger the generic JNI version
+      } else {
+        // Query any JNI optimization annotations such as @FastNative or @CriticalNative.
+        access_flags |= annotations::GetNativeMethodAnnotationAccessFlags(
+            dex_file, dex_file.GetClassDef(class_def_idx), method_idx);
+
+        compiled_method = driver->GetCompiler()->JniCompile(
+            access_flags, method_idx, dex_file, dex_cache);
+        CHECK(compiled_method != nullptr);
+      }
+    } else if ((access_flags & kAccAbstract) != 0) {
+      // Abstract methods don't have code.
+    } else {
+      VerificationResults* results = driver->GetVerificationResults();
+      DCHECK(results != nullptr);
+      const VerifiedMethod* verified_method = results->GetVerifiedMethod(method_ref);
+      bool compile = compilation_enabled &&
+          // Basic checks, e.g., not <clinit>.
+          results->IsCandidateForCompilation(method_ref, access_flags) &&
+          // Did not fail to create VerifiedMethod metadata.
+          verified_method != nullptr &&
+          // Do not have failures that should punt to the interpreter.
+          !verified_method->HasRuntimeThrow() &&
+          (verified_method->GetEncounteredVerificationFailures() &
+              (verifier::VERIFY_ERROR_FORCE_INTERPRETER | verifier::VERIFY_ERROR_LOCKING)) == 0 &&
+              // Is eligable for compilation by methods-to-compile filter.
+              driver->IsMethodToCompile(method_ref) &&
+              driver->ShouldCompileBasedOnProfile(method_ref);
+
+      if (compile) {
+        // NOTE: if compiler declines to compile this method, it will return null.
+        compiled_method = driver->GetCompiler()->Compile(code_item,
+                                                         access_flags,
+                                                         invoke_type,
+                                                         class_def_idx,
+                                                         method_idx,
+                                                         class_loader,
+                                                         dex_file,
+                                                         dex_cache);
+      }
+      if (compiled_method == nullptr &&
+          dex_to_dex_compilation_level !=
+              optimizer::DexToDexCompiler::CompilationLevel::kDontDexToDexCompile) {
+        DCHECK(!Runtime::Current()->UseJitCompilation());
+        // TODO: add a command-line option to disable DEX-to-DEX compilation ?
+        driver->GetDexToDexCompiler().MarkForCompilation(self, method_ref);
+      }
+    }
+    return compiled_method;
+  };
+  CompileMethodHarness(self,
+                       driver,
+                       code_item,
+                       access_flags,
+                       invoke_type,
+                       class_def_idx,
+                       method_idx,
+                       class_loader,
+                       dex_file,
+                       dex_to_dex_compilation_level,
+                       compilation_enabled,
+                       dex_cache,
+                       quick_fn);
+}
+
 void CompilerDriver::CompileOne(Thread* self, ArtMethod* method, TimingLogger* timings) {
   DCHECK(!Runtime::Current()->IsStarted());
   jobject jclass_loader;
@@ -671,53 +711,42 @@
   PreCompile(jclass_loader, dex_files, timings);
 
   // Can we run DEX-to-DEX compiler on this class ?
-  optimizer::DexToDexCompilationLevel dex_to_dex_compilation_level =
+  optimizer::DexToDexCompiler::CompilationLevel dex_to_dex_compilation_level =
       GetDexToDexCompilationLevel(self,
                                   *this,
                                   jclass_loader,
                                   *dex_file,
                                   dex_file->GetClassDef(class_def_idx));
 
-  DCHECK(current_dex_to_dex_methods_ == nullptr);
-  CompileMethod(self,
-                this,
-                code_item,
-                access_flags,
-                invoke_type,
-                class_def_idx,
-                method_idx,
-                class_loader,
-                *dex_file,
-                dex_to_dex_compilation_level,
-                true,
-                dex_cache);
+  CompileMethodQuick(self,
+                     this,
+                     code_item,
+                     access_flags,
+                     invoke_type,
+                     class_def_idx,
+                     method_idx,
+                     class_loader,
+                     *dex_file,
+                     dex_to_dex_compilation_level,
+                     true,
+                     dex_cache);
 
-  ArrayRef<DexFileMethodSet> dex_to_dex_references;
-  {
-    // From this point on, we shall not modify dex_to_dex_references_, so
-    // just grab a reference to it that we use without holding the mutex.
-    MutexLock lock(Thread::Current(), dex_to_dex_references_lock_);
-    dex_to_dex_references = ArrayRef<DexFileMethodSet>(dex_to_dex_references_);
-  }
-  if (!dex_to_dex_references.empty()) {
-    DCHECK_EQ(dex_to_dex_references.size(), 1u);
-    DCHECK(&dex_to_dex_references[0].GetDexFile() == dex_file);
-    current_dex_to_dex_methods_ = &dex_to_dex_references.front().GetMethodIndexes();
-    DCHECK(current_dex_to_dex_methods_->IsBitSet(method_idx));
-    DCHECK_EQ(current_dex_to_dex_methods_->NumSetBits(), 1u);
-    CompileMethod(self,
-                  this,
-                  code_item,
-                  access_flags,
-                  invoke_type,
-                  class_def_idx,
-                  method_idx,
-                  class_loader,
-                  *dex_file,
-                  dex_to_dex_compilation_level,
-                  true,
-                  dex_cache);
-    current_dex_to_dex_methods_ = nullptr;
+  const size_t num_methods = dex_to_dex_compiler_.NumCodeItemsToQuicken(self);
+  if (num_methods != 0) {
+    DCHECK_EQ(num_methods, 1u);
+    CompileMethodDex2Dex(self,
+                         this,
+                         code_item,
+                         access_flags,
+                         invoke_type,
+                         class_def_idx,
+                         method_idx,
+                         class_loader,
+                         *dex_file,
+                         dex_to_dex_compilation_level,
+                         true,
+                         dex_cache);
+    dex_to_dex_compiler_.ClearState();
   }
 
   FreeThreadPools();
@@ -761,19 +790,15 @@
     return;
   }
 
-  const uint16_t* code_ptr = code_item->insns_;
-  const uint16_t* code_end = code_item->insns_ + code_item->insns_size_in_code_units_;
   ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
-
-  while (code_ptr < code_end) {
-    const Instruction* inst = Instruction::At(code_ptr);
+  for (const DexInstructionPcPair& inst : CodeItemInstructionAccessor(dex_file, code_item)) {
     switch (inst->Opcode()) {
       case Instruction::CONST_STRING:
       case Instruction::CONST_STRING_JUMBO: {
         dex::StringIndex string_index((inst->Opcode() == Instruction::CONST_STRING)
             ? inst->VRegB_21c()
             : inst->VRegB_31c());
-        mirror::String* string = class_linker->ResolveString(dex_file, string_index, dex_cache);
+        ObjPtr<mirror::String> string = class_linker->ResolveString(string_index, dex_cache);
         CHECK(string != nullptr) << "Could not allocate a string when forcing determinism";
         break;
       }
@@ -781,8 +806,6 @@
       default:
         break;
     }
-
-    code_ptr += inst->SizeInCodeUnits();
   }
 }
 
@@ -819,31 +842,17 @@
         continue;
       }
 
-      // Direct methods.
-      int64_t previous_direct_method_idx = -1;
-      while (it.HasNextDirectMethod()) {
+      // Direct and virtual methods.
+      int64_t previous_method_idx = -1;
+      while (it.HasNextMethod()) {
         uint32_t method_idx = it.GetMemberIndex();
-        if (method_idx == previous_direct_method_idx) {
+        if (method_idx == previous_method_idx) {
           // smali can create dex files with two encoded_methods sharing the same method_idx
           // http://code.google.com/p/smali/issues/detail?id=119
           it.Next();
           continue;
         }
-        previous_direct_method_idx = method_idx;
-        ResolveConstStrings(dex_cache, *dex_file, it.GetMethodCodeItem());
-        it.Next();
-      }
-      // Virtual methods.
-      int64_t previous_virtual_method_idx = -1;
-      while (it.HasNextVirtualMethod()) {
-        uint32_t method_idx = it.GetMemberIndex();
-        if (method_idx == previous_virtual_method_idx) {
-          // smali can create dex files with two encoded_methods sharing the same method_idx
-          // http://code.google.com/p/smali/issues/detail?id=119
-          it.Next();
-          continue;
-        }
-        previous_virtual_method_idx = method_idx;
+        previous_method_idx = method_idx;
         ResolveConstStrings(dex_cache, *dex_file, it.GetMethodCodeItem());
         it.Next();
       }
@@ -896,7 +905,7 @@
     for (const DexFile* dex_file : dex_files) {
       // Can be already inserted if the caller is CompileOne. This happens for gtests.
       if (!compiled_methods_.HaveDexFile(dex_file)) {
-        compiled_methods_.AddDexFile(dex_file, dex_file->NumMethodIds());
+        compiled_methods_.AddDexFile(dex_file);
       }
     }
     // Resolve eagerly to prepare for compilation.
@@ -923,8 +932,17 @@
   VLOG(compiler) << "Verify: " << GetMemoryUsageString(false);
 
   if (had_hard_verifier_failure_ && GetCompilerOptions().AbortOnHardVerifierFailure()) {
-    LOG(FATAL) << "Had a hard failure verifying all classes, and was asked to abort in such "
-               << "situations. Please check the log.";
+    // Avoid dumping threads. Even if we shut down the thread pools, there will still be three
+    // instances of this thread's stack.
+    LOG(FATAL_WITHOUT_ABORT) << "Had a hard failure verifying all classes, and was asked to abort "
+                             << "in such situations. Please check the log.";
+    _exit(1);
+  } else if (number_of_soft_verifier_failures_ > 0 &&
+             GetCompilerOptions().AbortOnSoftVerifierFailure()) {
+    LOG(FATAL_WITHOUT_ABORT) << "Had " << number_of_soft_verifier_failures_ << " soft failure(s) "
+                             << "verifying all classes, and was asked to abort in such situations. "
+                             << "Please check the log.";
+    _exit(1);
   }
 
   if (compiler_options_->IsAnyCompilationEnabled()) {
@@ -961,7 +979,7 @@
     return true;
   }
 
-  std::string tmp = method_ref.dex_file->PrettyMethod(method_ref.dex_method_index, true);
+  std::string tmp = method_ref.PrettyMethod();
   return methods_to_compile_->find(tmp.c_str()) != methods_to_compile_->end();
 }
 
@@ -982,8 +1000,7 @@
 
   if (kDebugProfileGuidedCompilation) {
     LOG(INFO) << "[ProfileGuidedCompilation] "
-        << (result ? "Compiled" : "Skipped") << " method:"
-        << method_ref.dex_file->PrettyMethod(method_ref.dex_method_index, true);
+        << (result ? "Compiled" : "Skipped") << " method:" << method_ref.PrettyMethod(true);
   }
   return result;
 }
@@ -1013,14 +1030,14 @@
       ArtMethod* method,
       std::set<std::pair<dex::TypeIndex, const DexFile*>>* exceptions_to_resolve)
       REQUIRES_SHARED(Locks::mutator_lock_) {
-    const DexFile::CodeItem* code_item = method->GetCodeItem();
-    if (code_item == nullptr) {
+    if (method->GetCodeItem() == nullptr) {
       return;  // native or abstract method
     }
-    if (code_item->tries_size_ == 0) {
+    CodeItemDataAccessor accessor(method->DexInstructionData());
+    if (accessor.TriesSize() == 0) {
       return;  // nothing to process
     }
-    const uint8_t* encoded_catch_handler_list = DexFile::GetCatchHandlerData(*code_item, 0);
+    const uint8_t* encoded_catch_handler_list = accessor.GetCatchHandlerData();
     size_t num_encoded_catch_handlers = DecodeUnsignedLeb128(&encoded_catch_handler_list);
     for (size_t i = 0; i < num_encoded_catch_handlers; i++) {
       int32_t encoded_catch_handler_size = DecodeSignedLeb128(&encoded_catch_handler_list);
@@ -1112,22 +1129,21 @@
     for (const auto& exception_type : unresolved_exception_types) {
       dex::TypeIndex exception_type_idx = exception_type.first;
       const DexFile* dex_file = exception_type.second;
-      StackHandleScope<2> hs2(self);
+      StackHandleScope<1> hs2(self);
       Handle<mirror::DexCache> dex_cache(hs2.NewHandle(class_linker->RegisterDexFile(*dex_file,
                                                                                      nullptr)));
-      Handle<mirror::Class> klass(hs2.NewHandle(
+      ObjPtr<mirror::Class> klass =
           (dex_cache != nullptr)
-              ? class_linker->ResolveType(*dex_file,
-                                          exception_type_idx,
+              ? class_linker->ResolveType(exception_type_idx,
                                           dex_cache,
                                           ScopedNullHandle<mirror::ClassLoader>())
-              : nullptr));
+              : nullptr;
       if (klass == nullptr) {
         const DexFile::TypeId& type_id = dex_file->GetTypeId(exception_type_idx);
         const char* descriptor = dex_file->GetTypeDescriptor(type_id);
         LOG(FATAL) << "Failed to resolve class " << descriptor;
       }
-      DCHECK(java_lang_Throwable->IsAssignableFrom(klass.Get()));
+      DCHECK(java_lang_Throwable->IsAssignableFrom(klass));
     }
     // Resolving exceptions may load classes that reference more exceptions, iterate until no
     // more are found
@@ -1348,17 +1364,6 @@
   return IsImageClass(descriptor);
 }
 
-void CompilerDriver::MarkForDexToDexCompilation(Thread* self, const MethodReference& method_ref) {
-  MutexLock lock(self, dex_to_dex_references_lock_);
-  // Since we're compiling one dex file at a time, we need to look for the
-  // current dex file entry only at the end of dex_to_dex_references_.
-  if (dex_to_dex_references_.empty() ||
-      &dex_to_dex_references_.back().GetDexFile() != method_ref.dex_file) {
-    dex_to_dex_references_.emplace_back(*method_ref.dex_file);
-  }
-  dex_to_dex_references_.back().GetMethodIndexes().SetBit(method_ref.dex_method_index);
-}
-
 bool CompilerDriver::CanAccessTypeWithoutChecks(ObjPtr<mirror::Class> referrer_class,
                                                 ObjPtr<mirror::Class> resolved_class) {
   if (resolved_class == nullptr) {
@@ -1431,17 +1436,18 @@
 }
 
 ArtField* CompilerDriver::ComputeInstanceFieldInfo(uint32_t field_idx,
-                                                   const DexCompilationUnit* mUnit, bool is_put,
+                                                   const DexCompilationUnit* mUnit,
+                                                   bool is_put,
                                                    const ScopedObjectAccess& soa) {
   // Try to resolve the field and compiling method's class.
   ArtField* resolved_field;
-  mirror::Class* referrer_class;
+  ObjPtr<mirror::Class> referrer_class;
   Handle<mirror::DexCache> dex_cache(mUnit->GetDexCache());
   {
-    Handle<mirror::ClassLoader> class_loader_handle = mUnit->GetClassLoader();
-    resolved_field = ResolveField(soa, dex_cache, class_loader_handle, mUnit, field_idx, false);
+    Handle<mirror::ClassLoader> class_loader = mUnit->GetClassLoader();
+    resolved_field = ResolveField(soa, dex_cache, class_loader, field_idx, /* is_static */ false);
     referrer_class = resolved_field != nullptr
-        ? ResolveCompilingMethodsClass(soa, dex_cache, class_loader_handle, mUnit) : nullptr;
+        ? ResolveCompilingMethodsClass(soa, dex_cache, class_loader, mUnit) : nullptr;
   }
   bool can_link = false;
   if (resolved_field != nullptr && referrer_class != nullptr) {
@@ -1539,13 +1545,19 @@
 
   void ForAll(size_t begin, size_t end, CompilationVisitor* visitor, size_t work_units)
       REQUIRES(!*Locks::mutator_lock_) {
+    ForAllLambda(begin, end, [visitor](size_t index) { visitor->Visit(index); }, work_units);
+  }
+
+  template <typename Fn>
+  void ForAllLambda(size_t begin, size_t end, Fn fn, size_t work_units)
+      REQUIRES(!*Locks::mutator_lock_) {
     Thread* self = Thread::Current();
     self->AssertNoPendingException();
     CHECK_GT(work_units, 0U);
 
     index_.StoreRelaxed(begin);
     for (size_t i = 0; i < work_units; ++i) {
-      thread_pool_->AddTask(self, new ForAllClosure(this, end, visitor));
+      thread_pool_->AddTask(self, new ForAllClosureLambda<Fn>(this, end, fn));
     }
     thread_pool_->StartWorkers(self);
 
@@ -1565,32 +1577,33 @@
   }
 
  private:
-  class ForAllClosure : public Task {
+  template <typename Fn>
+  class ForAllClosureLambda : public Task {
    public:
-    ForAllClosure(ParallelCompilationManager* manager, size_t end, CompilationVisitor* visitor)
+    ForAllClosureLambda(ParallelCompilationManager* manager, size_t end, Fn fn)
         : manager_(manager),
           end_(end),
-          visitor_(visitor) {}
+          fn_(fn) {}
 
-    virtual void Run(Thread* self) {
+    void Run(Thread* self) OVERRIDE {
       while (true) {
         const size_t index = manager_->NextIndex();
         if (UNLIKELY(index >= end_)) {
           break;
         }
-        visitor_->Visit(index);
+        fn_(index);
         self->AssertNoPendingException();
       }
     }
 
-    virtual void Finalize() {
+    void Finalize() OVERRIDE {
       delete this;
     }
 
    private:
     ParallelCompilationManager* const manager_;
     const size_t end_;
-    CompilationVisitor* const visitor_;
+    Fn fn_;
   };
 
   AtomicInteger index_;
@@ -1606,7 +1619,7 @@
 
 // A fast version of SkipClass above if the class pointer is available
 // that avoids the expensive FindInClassPath search.
-static bool SkipClass(jobject class_loader, const DexFile& dex_file, mirror::Class* klass)
+static bool SkipClass(jobject class_loader, const DexFile& dex_file, ObjPtr<mirror::Class> klass)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   DCHECK(klass != nullptr);
   const DexFile& original_dex_file = *klass->GetDexCache()->GetDexFile();
@@ -1674,7 +1687,7 @@
       : manager_(manager) {}
 
   void Visit(size_t class_def_index) OVERRIDE REQUIRES(!Locks::mutator_lock_) {
-    ATRACE_CALL();
+    ScopedTrace trace(__FUNCTION__);
     Thread* const self = Thread::Current();
     jobject jclass_loader = manager_->GetClassLoader();
     const DexFile& dex_file = *manager_->GetDexFile();
@@ -1700,8 +1713,8 @@
     Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->FindDexCache(
         soa.Self(), dex_file)));
     // Resolve the class.
-    mirror::Class* klass = class_linker->ResolveType(dex_file, class_def.class_idx_, dex_cache,
-                                                     class_loader);
+    ObjPtr<mirror::Class> klass =
+        class_linker->ResolveType(class_def.class_idx_, dex_cache, class_loader);
     bool resolve_fields_and_methods;
     if (klass == nullptr) {
       // Class couldn't be resolved, for example, super-class is in a different dex file. Don't
@@ -1727,8 +1740,8 @@
       ClassDataItemIterator it(dex_file, class_data);
       while (it.HasNextStaticField()) {
         if (resolve_fields_and_methods) {
-          ArtField* field = class_linker->ResolveField(dex_file, it.GetMemberIndex(),
-                                                               dex_cache, class_loader, true);
+          ArtField* field = class_linker->ResolveField(
+              it.GetMemberIndex(), dex_cache, class_loader, /* is_static */ true);
           if (field == nullptr) {
             CheckAndClearResolveException(soa.Self());
           }
@@ -1742,8 +1755,8 @@
           requires_constructor_barrier = true;
         }
         if (resolve_fields_and_methods) {
-          ArtField* field = class_linker->ResolveField(dex_file, it.GetMemberIndex(),
-                                                               dex_cache, class_loader, false);
+          ArtField* field = class_linker->ResolveField(
+              it.GetMemberIndex(), dex_cache, class_loader, /* is_static */ false);
           if (field == nullptr) {
             CheckAndClearResolveException(soa.Self());
           }
@@ -1751,18 +1764,12 @@
         it.Next();
       }
       if (resolve_fields_and_methods) {
-        while (it.HasNextDirectMethod()) {
+        while (it.HasNextMethod()) {
           ArtMethod* method = class_linker->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
-              dex_file, it.GetMemberIndex(), dex_cache, class_loader, nullptr,
-              it.GetMethodInvokeType(class_def));
-          if (method == nullptr) {
-            CheckAndClearResolveException(soa.Self());
-          }
-          it.Next();
-        }
-        while (it.HasNextVirtualMethod()) {
-          ArtMethod* method = class_linker->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
-              dex_file, it.GetMemberIndex(), dex_cache, class_loader, nullptr,
+              it.GetMemberIndex(),
+              dex_cache,
+              class_loader,
+              /* referrer */ nullptr,
               it.GetMethodInvokeType(class_def));
           if (method == nullptr) {
             CheckAndClearResolveException(soa.Self());
@@ -1798,7 +1805,7 @@
         dex_file,
         class_loader.Get())));
     ObjPtr<mirror::Class> klass = (dex_cache != nullptr)
-        ? class_linker->ResolveType(dex_file, dex::TypeIndex(type_idx), dex_cache, class_loader)
+        ? class_linker->ResolveType(dex::TypeIndex(type_idx), dex_cache, class_loader)
         : nullptr;
 
     if (klass == nullptr) {
@@ -1869,12 +1876,7 @@
   ClassDataItemIterator it(dex_file, class_data);
   it.SkipAllFields();
 
-  while (it.HasNextDirectMethod()) {
-    verification_results->CreateVerifiedMethodFor(MethodReference(&dex_file, it.GetMemberIndex()));
-    it.Next();
-  }
-
-  while (it.HasNextVirtualMethod()) {
+  while (it.HasNextMethod()) {
     verification_results->CreateVerifiedMethodFor(MethodReference(&dex_file, it.GetMemberIndex()));
     it.Next();
   }
@@ -1883,7 +1885,7 @@
 
 static void LoadAndUpdateStatus(const DexFile& dex_file,
                                 const DexFile::ClassDef& class_def,
-                                mirror::Class::Status status,
+                                ClassStatus status,
                                 Handle<mirror::ClassLoader> class_loader,
                                 Thread* self)
     REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -1941,17 +1943,17 @@
         if (compiler_only_verifies) {
           // Just update the compiled_classes_ map. The compiler doesn't need to resolve
           // the type.
-          DexFileReference ref(dex_file, i);
-          mirror::Class::Status existing = mirror::Class::kStatusNotReady;
+          ClassReference ref(dex_file, i);
+          ClassStatus existing = ClassStatus::kNotReady;
           DCHECK(compiled_classes_.Get(ref, &existing)) << ref.dex_file->GetLocation();
           ClassStateTable::InsertResult result =
-             compiled_classes_.Insert(ref, existing, mirror::Class::kStatusVerified);
+             compiled_classes_.Insert(ref, existing, ClassStatus::kVerified);
           CHECK_EQ(result, ClassStateTable::kInsertResultSuccess);
         } else {
           // Update the class status, so later compilation stages know they don't need to verify
           // the class.
           LoadAndUpdateStatus(
-              *dex_file, class_def, mirror::Class::kStatusVerified, class_loader, soa.Self());
+              *dex_file, class_def, ClassStatus::kVerified, class_loader, soa.Self());
           // Create `VerifiedMethod`s for each methods, the compiler expects one for
           // quickening or compiling.
           // Note that this means:
@@ -1965,7 +1967,7 @@
         // this class again.
         LoadAndUpdateStatus(*dex_file,
                             class_def,
-                            mirror::Class::kStatusRetryVerificationAtRuntime,
+                            ClassStatus::kRetryVerificationAtRuntime,
                             class_loader,
                             soa.Self());
       }
@@ -2033,7 +2035,7 @@
      : manager_(manager), log_level_(log_level) {}
 
   virtual void Visit(size_t class_def_index) REQUIRES(!Locks::mutator_lock_) OVERRIDE {
-    ATRACE_CALL();
+    ScopedTrace trace(__FUNCTION__);
     ScopedObjectAccess soa(Thread::Current());
     const DexFile& dex_file = *manager_->GetDexFile();
     const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
@@ -2072,13 +2074,13 @@
         LOG(ERROR) << "Verification failed on class " << PrettyDescriptor(descriptor)
                    << " because: " << error_msg;
         manager_->GetCompiler()->SetHadHardVerifierFailure();
+      } else if (failure_kind == verifier::FailureKind::kSoftFailure) {
+        manager_->GetCompiler()->AddSoftVerifierFailure();
       } else {
         // Force a soft failure for the VerifierDeps. This is a sanity measure, as
         // the vdex file already records that the class hasn't been resolved. It avoids
         // trying to do future verification optimizations when processing the vdex file.
-        DCHECK(failure_kind == verifier::FailureKind::kSoftFailure ||
-               failure_kind == verifier::FailureKind::kNoFailure)
-            << failure_kind;
+        DCHECK(failure_kind == verifier::FailureKind::kNoFailure) << failure_kind;
         failure_kind = verifier::FailureKind::kSoftFailure;
       }
     } else if (!SkipClass(jclass_loader, dex_file, klass.Get())) {
@@ -2090,6 +2092,8 @@
         CHECK(soa.Self()->IsExceptionPending());
         soa.Self()->ClearException();
         manager_->GetCompiler()->SetHadHardVerifierFailure();
+      } else if (failure_kind == verifier::FailureKind::kSoftFailure) {
+        manager_->GetCompiler()->AddSoftVerifierFailure();
       }
 
       CHECK(klass->ShouldVerifyAtRuntime() || klass->IsVerified() || klass->IsErroneous())
@@ -2099,16 +2103,20 @@
       ClassReference ref(manager_->GetDexFile(), class_def_index);
       manager_->GetCompiler()->RecordClassStatus(ref, klass->GetStatus());
 
-      // 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.
+      // It is *very* problematic if there are resolution errors in the boot classpath.
+      //
+      // It is also bad if classes fail verification. For example, we rely on things working
+      // OK without verification when the decryption dialog is brought up. It is thus highly
+      // recommended to compile the boot classpath with
+      //   --abort-on-hard-verifier-error --abort-on-soft-verifier-error
+      // which is the default build system configuration.
       if (kIsDebugBuild) {
-        // TODO(narayan): Remove this special case for signature polymorphic
-        // invokes once verifier support is fully implemented.
-        if (manager_->GetCompiler()->GetCompilerOptions().IsBootImage() &&
-            !android::base::StartsWith(descriptor, "Ljava/lang/invoke/")) {
-          DCHECK(klass->IsVerified()) << "Boot classpath class " << klass->PrettyClass()
-              << " failed to fully verify: state= " << klass->GetStatus();
+        if (manager_->GetCompiler()->GetCompilerOptions().IsBootImage()) {
+          if (!klass->IsResolved() || klass->IsErroneous()) {
+            LOG(FATAL) << "Boot classpath class " << klass->PrettyClass()
+                       << " failed to resolve/is erroneous: state= " << klass->GetStatus();
+            UNREACHABLE();
+          }
         }
         if (klass->IsVerified()) {
           DCHECK_EQ(failure_kind, verifier::FailureKind::kNoFailure);
@@ -2142,7 +2150,9 @@
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   ParallelCompilationManager context(class_linker, class_loader, this, &dex_file, dex_files,
                                      thread_pool);
-  verifier::HardFailLogMode log_level = GetCompilerOptions().AbortOnHardVerifierFailure()
+  bool abort_on_verifier_failures = GetCompilerOptions().AbortOnHardVerifierFailure()
+                                    || GetCompilerOptions().AbortOnSoftVerifierFailure();
+  verifier::HardFailLogMode log_level = abort_on_verifier_failures
                               ? verifier::HardFailLogMode::kLogInternalFatal
                               : verifier::HardFailLogMode::kLogWarning;
   VerifyClassVisitor visitor(&context, log_level);
@@ -2154,7 +2164,7 @@
   explicit SetVerifiedClassVisitor(const ParallelCompilationManager* manager) : manager_(manager) {}
 
   virtual void Visit(size_t class_def_index) REQUIRES(!Locks::mutator_lock_) OVERRIDE {
-    ATRACE_CALL();
+    ScopedTrace trace(__FUNCTION__);
     ScopedObjectAccess soa(Thread::Current());
     const DexFile& dex_file = *manager_->GetDexFile();
     const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
@@ -2171,10 +2181,10 @@
       // Only do this if the class is resolved. If even resolution fails, quickening will go very,
       // very wrong.
       if (klass->IsResolved() && !klass->IsErroneousResolved()) {
-        if (klass->GetStatus() < mirror::Class::kStatusVerified) {
+        if (klass->GetStatus() < ClassStatus::kVerified) {
           ObjectLock<mirror::Class> lock(soa.Self(), klass);
           // Set class status to verified.
-          mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, soa.Self());
+          mirror::Class::SetStatus(klass, ClassStatus::kVerified, soa.Self());
           // Mark methods as pre-verified. If we don't do this, the interpreter will run with
           // access checks.
           klass->SetSkipAccessChecksFlagOnAllMethods(
@@ -2204,7 +2214,7 @@
                                         TimingLogger* timings) {
   TimingLogger::ScopedTiming t("Verify Dex File", timings);
   if (!compiled_classes_.HaveDexFile(&dex_file)) {
-    compiled_classes_.AddDexFile(&dex_file, dex_file.NumClassDefs());
+    compiled_classes_.AddDexFile(&dex_file);
   }
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   ParallelCompilationManager context(class_linker, class_loader, this, &dex_file, dex_files,
@@ -2218,7 +2228,7 @@
   explicit InitializeClassVisitor(const ParallelCompilationManager* manager) : manager_(manager) {}
 
   void Visit(size_t class_def_index) OVERRIDE {
-    ATRACE_CALL();
+    ScopedTrace trace(__FUNCTION__);
     jobject jclass_loader = manager_->GetClassLoader();
     const DexFile& dex_file = *manager_->GetDexFile();
     const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
@@ -2251,7 +2261,7 @@
     const bool is_boot_image = manager_->GetCompiler()->GetCompilerOptions().IsBootImage();
     const bool is_app_image = manager_->GetCompiler()->GetCompilerOptions().IsAppImage();
 
-    mirror::Class::Status old_status = klass->GetStatus();
+    ClassStatus old_status = klass->GetStatus();
     // Don't initialize classes in boot space when compiling app image
     if (is_app_image && klass->IsBootStrapClassLoaded()) {
       // Also return early and don't store the class status in the recorded class status.
@@ -2307,6 +2317,7 @@
             // The boot image case doesn't need to recursively initialize the dependencies with
             // special logic since the class linker already does this.
             can_init_static_fields =
+                ClassLinker::kAppImageMayContainStrings &&
                 !soa.Self()->IsExceptionPending() &&
                 is_superclass_initialized &&
                 NoClinitInDependency(klass, soa.Self(), &class_loader);
@@ -2323,10 +2334,8 @@
             // a ReaderWriterMutex but we're holding the mutator lock so we fail mutex sanity
             // checks in Thread::AssertThreadSuspensionIsAllowable.
             Runtime* const runtime = Runtime::Current();
-            Transaction transaction;
-
             // Run the class initializer in transaction mode.
-            runtime->EnterTransactionMode(&transaction);
+            runtime->EnterTransactionMode(is_app_image, klass.Get());
             bool success = manager_->GetClassLinker()->EnsureInitialized(soa.Self(), klass, true,
                                                                          true);
             // TODO we detach transaction from runtime to indicate we quit the transactional
@@ -2335,7 +2344,11 @@
 
             {
               ScopedAssertNoThreadSuspension ants("Transaction end");
-              runtime->ExitTransactionMode();
+
+              if (success) {
+                runtime->ExitTransactionMode();
+                DCHECK(!runtime->IsActiveTransaction());
+              }
 
               if (!success) {
                 CHECK(soa.Self()->IsExceptionPending());
@@ -2349,7 +2362,7 @@
                   *file_log << exception->Dump() << "\n";
                 }
                 soa.Self()->ClearException();
-                transaction.Rollback();
+                runtime->RollbackAllTransactions();
                 CHECK_EQ(old_status, klass->GetStatus()) << "Previous class status not restored";
               } else if (is_boot_image) {
                 // For boot image, we want to put the updated status in the oat class since we can't
@@ -2374,7 +2387,7 @@
         // would do so they can be skipped at runtime.
         if (!klass->IsInitialized() &&
             manager_->GetClassLinker()->ValidateSuperClassDescriptors(klass)) {
-          old_status = mirror::Class::kStatusSuperclassValidated;
+          old_status = ClassStatus::kSuperclassValidated;
         } else {
           soa.Self()->ClearException();
         }
@@ -2396,22 +2409,20 @@
     DCHECK(!klass->IsInitialized());
 
     StackHandleScope<1> hs(Thread::Current());
-    Handle<mirror::DexCache> h_dex_cache = hs.NewHandle(klass->GetDexCache());
-    const DexFile* dex_file = manager_->GetDexFile();
+    Handle<mirror::DexCache> dex_cache = hs.NewHandle(klass->GetDexCache());
     const DexFile::ClassDef* class_def = klass->GetClassDef();
     ClassLinker* class_linker = manager_->GetClassLinker();
 
     // Check encoded final field values for strings and intern.
-    annotations::RuntimeEncodedStaticFieldValueIterator value_it(*dex_file,
-                                                                 &h_dex_cache,
-                                                                 &class_loader,
+    annotations::RuntimeEncodedStaticFieldValueIterator value_it(dex_cache,
+                                                                 class_loader,
                                                                  manager_->GetClassLinker(),
                                                                  *class_def);
     for ( ; value_it.HasNext(); value_it.Next()) {
       if (value_it.GetValueType() == annotations::RuntimeEncodedStaticFieldValueIterator::kString) {
         // Resolve the string. This will intern the string.
         art::ObjPtr<mirror::String> resolved = class_linker->ResolveString(
-            *dex_file, dex::StringIndex(value_it.GetJavaValue().i), h_dex_cache);
+            dex::StringIndex(value_it.GetJavaValue().i), dex_cache);
         CHECK(resolved != nullptr);
       }
     }
@@ -2419,30 +2430,24 @@
     // Intern strings seen in <clinit>.
     ArtMethod* clinit = klass->FindClassInitializer(class_linker->GetImagePointerSize());
     if (clinit != nullptr) {
-      const DexFile::CodeItem* code_item = clinit->GetCodeItem();
-      DCHECK(code_item != nullptr);
-      const Instruction* inst = Instruction::At(code_item->insns_);
-
-      const uint32_t insns_size = code_item->insns_size_in_code_units_;
-      for (uint32_t dex_pc = 0; dex_pc < insns_size;) {
+      for (const DexInstructionPcPair& inst : clinit->DexInstructions()) {
         if (inst->Opcode() == Instruction::CONST_STRING) {
           ObjPtr<mirror::String> s = class_linker->ResolveString(
-              *dex_file, dex::StringIndex(inst->VRegB_21c()), h_dex_cache);
+              dex::StringIndex(inst->VRegB_21c()), dex_cache);
           CHECK(s != nullptr);
         } else if (inst->Opcode() == Instruction::CONST_STRING_JUMBO) {
           ObjPtr<mirror::String> s = class_linker->ResolveString(
-              *dex_file, dex::StringIndex(inst->VRegB_31c()), h_dex_cache);
+              dex::StringIndex(inst->VRegB_31c()), dex_cache);
           CHECK(s != nullptr);
         }
-        dex_pc += inst->SizeInCodeUnits();
-        inst = inst->Next();
       }
     }
   }
 
   bool ResolveTypesOfMethods(Thread* self, ArtMethod* m)
       REQUIRES_SHARED(Locks::mutator_lock_) {
-    auto rtn_type = m->GetReturnType(true);  // return value is discarded because resolve will be done internally.
+    // Return value of ResolveReturnType() is discarded because resolve will be done internally.
+    ObjPtr<mirror::Class> rtn_type = m->ResolveReturnType();
     if (rtn_type == nullptr) {
       self->ClearException();
       return false;
@@ -2451,7 +2456,7 @@
     if (types != nullptr) {
       for (uint32_t i = 0; i < types->Size(); ++i) {
         dex::TypeIndex param_type_idx = types->GetTypeItem(i).type_idx_;
-        auto param_type = m->GetClassFromTypeIndex(param_type_idx, true);
+        ObjPtr<mirror::Class> param_type = m->ResolveClassFromTypeIndex(param_type_idx);
         if (param_type == nullptr) {
           self->ClearException();
           return false;
@@ -2674,76 +2679,37 @@
   }
   if (GetCompilerOptions().IsBootImage()) {
     // Prune garbage objects created during aborted transactions.
-    Runtime::Current()->GetHeap()->CollectGarbage(true);
+    Runtime::Current()->GetHeap()->CollectGarbage(/* clear_soft_references */ true);
   }
 }
 
-void CompilerDriver::Compile(jobject class_loader,
-                             const std::vector<const DexFile*>& dex_files,
-                             TimingLogger* timings) {
-  if (kDebugProfileGuidedCompilation) {
-    LOG(INFO) << "[ProfileGuidedCompilation] " <<
-        ((profile_compilation_info_ == nullptr)
-            ? "null"
-            : profile_compilation_info_->DumpInfo(&dex_files));
-  }
+template <typename CompileFn>
+static void CompileDexFile(CompilerDriver* driver,
+                           jobject class_loader,
+                           const DexFile& dex_file,
+                           const std::vector<const DexFile*>& dex_files,
+                           ThreadPool* thread_pool,
+                           size_t thread_count,
+                           TimingLogger* timings,
+                           const char* timing_name,
+                           CompileFn compile_fn) {
+  TimingLogger::ScopedTiming t(timing_name, timings);
+  ParallelCompilationManager context(Runtime::Current()->GetClassLinker(),
+                                     class_loader,
+                                     driver,
+                                     &dex_file,
+                                     dex_files,
+                                     thread_pool);
 
-  current_dex_to_dex_methods_ = nullptr;
-  Thread* const self = Thread::Current();
-  {
-    // Clear in case we aren't the first call to Compile.
-    MutexLock mu(self, dex_to_dex_references_lock_);
-    dex_to_dex_references_.clear();
-  }
-
-  for (const DexFile* dex_file : dex_files) {
-    CHECK(dex_file != nullptr);
-    CompileDexFile(class_loader,
-                   *dex_file,
-                   dex_files,
-                   parallel_thread_pool_.get(),
-                   parallel_thread_count_,
-                   timings);
-    const ArenaPool* const arena_pool = Runtime::Current()->GetArenaPool();
-    const size_t arena_alloc = arena_pool->GetBytesAllocated();
-    max_arena_alloc_ = std::max(arena_alloc, max_arena_alloc_);
-    Runtime::Current()->ReclaimArenaPoolMemory();
-  }
-
-  ArrayRef<DexFileMethodSet> dex_to_dex_references;
-  {
-    // From this point on, we shall not modify dex_to_dex_references_, so
-    // just grab a reference to it that we use without holding the mutex.
-    MutexLock lock(self, dex_to_dex_references_lock_);
-    dex_to_dex_references = ArrayRef<DexFileMethodSet>(dex_to_dex_references_);
-  }
-  for (const auto& method_set : dex_to_dex_references) {
-    current_dex_to_dex_methods_ = &method_set.GetMethodIndexes();
-    CompileDexFile(class_loader,
-                   method_set.GetDexFile(),
-                   dex_files,
-                   parallel_thread_pool_.get(),
-                   parallel_thread_count_,
-                   timings);
-  }
-  current_dex_to_dex_methods_ = nullptr;
-
-  VLOG(compiler) << "Compile: " << GetMemoryUsageString(false);
-}
-
-class CompileClassVisitor : public CompilationVisitor {
- public:
-  explicit CompileClassVisitor(const ParallelCompilationManager* manager) : manager_(manager) {}
-
-  virtual void Visit(size_t class_def_index) REQUIRES(!Locks::mutator_lock_) OVERRIDE {
-    ATRACE_CALL();
-    const DexFile& dex_file = *manager_->GetDexFile();
+  auto compile = [&context, &compile_fn](size_t class_def_index) {
+    ScopedTrace trace(__FUNCTION__);
+    const DexFile& dex_file = *context.GetDexFile();
     const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
-    ClassLinker* class_linker = manager_->GetClassLinker();
-    jobject jclass_loader = manager_->GetClassLoader();
+    ClassLinker* class_linker = context.GetClassLinker();
+    jobject jclass_loader = context.GetClassLoader();
     ClassReference ref(&dex_file, class_def_index);
     // Skip compiling classes with generic verifier failures since they will still fail at runtime
-    if (manager_->GetCompiler()->verification_results_->IsClassRejected(ref)) {
+    if (context.GetCompiler()->GetVerificationResults()->IsClassRejected(ref)) {
       return;
     }
     // Use a scoped object access to perform to the quick SkipClass check.
@@ -2774,10 +2740,10 @@
     // Go to native so that we don't block GC during compilation.
     ScopedThreadSuspension sts(soa.Self(), kNative);
 
-    CompilerDriver* const driver = manager_->GetCompiler();
+    CompilerDriver* const driver = context.GetCompiler();
 
     // Can we run DEX-to-DEX compiler on this class ?
-    optimizer::DexToDexCompilationLevel dex_to_dex_compilation_level =
+    optimizer::DexToDexCompiler::CompilationLevel dex_to_dex_compilation_level =
         GetDexToDexCompilationLevel(soa.Self(), *driver, jclass_loader, dex_file, class_def);
 
     ClassDataItemIterator it(dex_file, class_data);
@@ -2786,132 +2752,159 @@
     bool compilation_enabled = driver->IsClassToCompile(
         dex_file.StringByTypeIdx(class_def.class_idx_));
 
-    // Compile direct methods
-    int64_t previous_direct_method_idx = -1;
-    while (it.HasNextDirectMethod()) {
+    // Compile direct and virtual methods.
+    int64_t previous_method_idx = -1;
+    while (it.HasNextMethod()) {
       uint32_t method_idx = it.GetMemberIndex();
-      if (method_idx == previous_direct_method_idx) {
+      if (method_idx == previous_method_idx) {
         // smali can create dex files with two encoded_methods sharing the same method_idx
         // http://code.google.com/p/smali/issues/detail?id=119
         it.Next();
         continue;
       }
-      previous_direct_method_idx = method_idx;
-      CompileMethod(soa.Self(),
-                    driver,
-                    it.GetMethodCodeItem(),
-                    it.GetMethodAccessFlags(),
-                    it.GetMethodInvokeType(class_def),
-                    class_def_index,
-                    method_idx,
-                    class_loader,
-                    dex_file,
-                    dex_to_dex_compilation_level,
-                    compilation_enabled,
-                    dex_cache);
-      it.Next();
-    }
-    // Compile virtual methods
-    int64_t previous_virtual_method_idx = -1;
-    while (it.HasNextVirtualMethod()) {
-      uint32_t method_idx = it.GetMemberIndex();
-      if (method_idx == previous_virtual_method_idx) {
-        // smali can create dex files with two encoded_methods sharing the same method_idx
-        // http://code.google.com/p/smali/issues/detail?id=119
-        it.Next();
-        continue;
-      }
-      previous_virtual_method_idx = method_idx;
-      CompileMethod(soa.Self(),
-                    driver, it.GetMethodCodeItem(),
-                    it.GetMethodAccessFlags(),
-                    it.GetMethodInvokeType(class_def),
-                    class_def_index,
-                    method_idx,
-                    class_loader,
-                    dex_file,
-                    dex_to_dex_compilation_level,
-                    compilation_enabled,
-                    dex_cache);
+      previous_method_idx = method_idx;
+      compile_fn(soa.Self(),
+                 driver,
+                 it.GetMethodCodeItem(),
+                 it.GetMethodAccessFlags(),
+                 it.GetMethodInvokeType(class_def),
+                 class_def_index,
+                 method_idx,
+                 class_loader,
+                 dex_file,
+                 dex_to_dex_compilation_level,
+                 compilation_enabled,
+                 dex_cache);
       it.Next();
     }
     DCHECK(!it.HasNext());
+  };
+  context.ForAllLambda(0, dex_file.NumClassDefs(), compile, thread_count);
+}
+
+void CompilerDriver::Compile(jobject class_loader,
+                             const std::vector<const DexFile*>& dex_files,
+                             TimingLogger* timings) {
+  if (kDebugProfileGuidedCompilation) {
+    LOG(INFO) << "[ProfileGuidedCompilation] " <<
+        ((profile_compilation_info_ == nullptr)
+            ? "null"
+            : profile_compilation_info_->DumpInfo(&dex_files));
   }
 
- private:
-  const ParallelCompilationManager* const manager_;
-};
+  dex_to_dex_compiler_.ClearState();
+  for (const DexFile* dex_file : dex_files) {
+    CHECK(dex_file != nullptr);
+    CompileDexFile(this,
+                   class_loader,
+                   *dex_file,
+                   dex_files,
+                   parallel_thread_pool_.get(),
+                   parallel_thread_count_,
+                   timings,
+                   "Compile Dex File Quick",
+                   CompileMethodQuick);
+    const ArenaPool* const arena_pool = Runtime::Current()->GetArenaPool();
+    const size_t arena_alloc = arena_pool->GetBytesAllocated();
+    max_arena_alloc_ = std::max(arena_alloc, max_arena_alloc_);
+    Runtime::Current()->ReclaimArenaPoolMemory();
+  }
 
-void CompilerDriver::CompileDexFile(jobject class_loader,
-                                    const DexFile& dex_file,
-                                    const std::vector<const DexFile*>& dex_files,
-                                    ThreadPool* thread_pool,
-                                    size_t thread_count,
-                                    TimingLogger* timings) {
-  TimingLogger::ScopedTiming t("Compile Dex File", timings);
-  ParallelCompilationManager context(Runtime::Current()->GetClassLinker(), class_loader, this,
-                                     &dex_file, dex_files, thread_pool);
-  CompileClassVisitor visitor(&context);
-  context.ForAll(0, dex_file.NumClassDefs(), &visitor, thread_count);
+  if (dex_to_dex_compiler_.NumCodeItemsToQuicken(Thread::Current()) > 0u) {
+    // TODO: Not visit all of the dex files, its probably rare that only one would have quickened
+    // methods though.
+    for (const DexFile* dex_file : dex_files) {
+      CompileDexFile(this,
+                     class_loader,
+                     *dex_file,
+                     dex_files,
+                     parallel_thread_pool_.get(),
+                     parallel_thread_count_,
+                     timings,
+                     "Compile Dex File Dex2Dex",
+                     CompileMethodDex2Dex);
+    }
+    dex_to_dex_compiler_.ClearState();
+  }
+
+  VLOG(compiler) << "Compile: " << GetMemoryUsageString(false);
 }
 
 void CompilerDriver::AddCompiledMethod(const MethodReference& method_ref,
                                        CompiledMethod* const compiled_method,
                                        size_t non_relative_linker_patch_count) {
-  DCHECK(GetCompiledMethod(method_ref) == nullptr)
-      << method_ref.dex_file->PrettyMethod(method_ref.dex_method_index);
-  MethodTable::InsertResult result = compiled_methods_.Insert(
-      DexFileReference(method_ref.dex_file, method_ref.dex_method_index),
-      /*expected*/ nullptr,
-      compiled_method);
+  DCHECK(GetCompiledMethod(method_ref) == nullptr) << method_ref.PrettyMethod();
+  MethodTable::InsertResult result = compiled_methods_.Insert(method_ref,
+                                                              /*expected*/ nullptr,
+                                                              compiled_method);
   CHECK(result == MethodTable::kInsertResultSuccess);
   non_relative_linker_patch_count_.FetchAndAddRelaxed(non_relative_linker_patch_count);
-  DCHECK(GetCompiledMethod(method_ref) != nullptr)
-      << method_ref.dex_file->PrettyMethod(method_ref.dex_method_index);
+  DCHECK(GetCompiledMethod(method_ref) != nullptr) << method_ref.PrettyMethod();
 }
 
-bool CompilerDriver::GetCompiledClass(ClassReference ref, mirror::Class::Status* status) const {
+CompiledMethod* CompilerDriver::RemoveCompiledMethod(const MethodReference& method_ref) {
+  CompiledMethod* ret = nullptr;
+  CHECK(compiled_methods_.Remove(method_ref, &ret));
+  return ret;
+}
+
+bool CompilerDriver::GetCompiledClass(const ClassReference& ref, ClassStatus* status) const {
   DCHECK(status != nullptr);
   // The table doesn't know if something wasn't inserted. For this case it will return
-  // kStatusNotReady. To handle this, just assume anything we didn't try to verify is not compiled.
-  if (!compiled_classes_.Get(DexFileReference(ref.first, ref.second), status) ||
-      *status < mirror::Class::kStatusRetryVerificationAtRuntime) {
+  // ClassStatus::kNotReady. To handle this, just assume anything we didn't try to verify
+  // is not compiled.
+  if (!compiled_classes_.Get(ref, status) ||
+      *status < ClassStatus::kRetryVerificationAtRuntime) {
     return false;
   }
   return true;
 }
 
-void CompilerDriver::RecordClassStatus(ClassReference ref, mirror::Class::Status status) {
+ClassStatus CompilerDriver::GetClassStatus(const ClassReference& ref) const {
+  ClassStatus status = ClassStatus::kNotReady;
+  if (!GetCompiledClass(ref, &status)) {
+    classpath_classes_.Get(ref, &status);
+  }
+  return status;
+}
+
+void CompilerDriver::RecordClassStatus(const ClassReference& ref, ClassStatus status) {
   switch (status) {
-    case mirror::Class::kStatusErrorResolved:
-    case mirror::Class::kStatusErrorUnresolved:
-    case mirror::Class::kStatusNotReady:
-    case mirror::Class::kStatusResolved:
-    case mirror::Class::kStatusRetryVerificationAtRuntime:
-    case mirror::Class::kStatusVerified:
-    case mirror::Class::kStatusSuperclassValidated:
-    case mirror::Class::kStatusInitialized:
+    case ClassStatus::kErrorResolved:
+    case ClassStatus::kErrorUnresolved:
+    case ClassStatus::kNotReady:
+    case ClassStatus::kResolved:
+    case ClassStatus::kRetryVerificationAtRuntime:
+    case ClassStatus::kVerified:
+    case ClassStatus::kSuperclassValidated:
+    case ClassStatus::kInitialized:
       break;  // Expected states.
     default:
       LOG(FATAL) << "Unexpected class status for class "
-          << PrettyDescriptor(ref.first->GetClassDescriptor(ref.first->GetClassDef(ref.second)))
+          << PrettyDescriptor(
+              ref.dex_file->GetClassDescriptor(ref.dex_file->GetClassDef(ref.index)))
           << " of " << status;
   }
 
   ClassStateTable::InsertResult result;
+  ClassStateTable* table = &compiled_classes_;
   do {
-    DexFileReference dex_ref(ref.first, ref.second);
-    mirror::Class::Status existing = mirror::Class::kStatusNotReady;
-    if (!compiled_classes_.Get(dex_ref, &existing)) {
-      // Probably a uses library class, bail.
+    ClassStatus existing = ClassStatus::kNotReady;
+    if (!table->Get(ref, &existing)) {
+      // A classpath class.
       if (kIsDebugBuild) {
         // Check to make sure it's not a dex file for an oat file we are compiling since these
         // should always succeed. These do not include classes in for used libraries.
         for (const DexFile* dex_file : GetDexFilesForOatFile()) {
-          CHECK_NE(dex_ref.dex_file, dex_file) << dex_ref.dex_file->GetLocation();
+          CHECK_NE(ref.dex_file, dex_file) << ref.dex_file->GetLocation();
         }
       }
-      return;
+      if (!classpath_classes_.HaveDexFile(ref.dex_file)) {
+        // Boot classpath dex file.
+        return;
+      }
+      table = &classpath_classes_;
+      table->Get(ref, &existing);
     }
     if (existing >= status) {
       // Existing status is already better than we expect, break.
@@ -2919,14 +2912,14 @@
     }
     // Update the status if we now have a greater one. This happens with vdex,
     // which records a class is verified, but does not resolve it.
-    result = compiled_classes_.Insert(dex_ref, existing, status);
-    CHECK(result != ClassStateTable::kInsertResultInvalidDexFile);
+    result = table->Insert(ref, existing, status);
+    CHECK(result != ClassStateTable::kInsertResultInvalidDexFile) << ref.dex_file->GetLocation();
   } while (result != ClassStateTable::kInsertResultSuccess);
 }
 
 CompiledMethod* CompilerDriver::GetCompiledMethod(MethodReference ref) const {
   CompiledMethod* compiled_method = nullptr;
-  compiled_methods_.Get(DexFileReference(ref.dex_file, ref.dex_method_index), &compiled_method);
+  compiled_methods_.Get(ref, &compiled_method);
   return compiled_method;
 }
 
@@ -3027,17 +3020,12 @@
 
 void CompilerDriver::SetDexFilesForOatFile(const std::vector<const DexFile*>& dex_files) {
   dex_files_for_oat_file_ = dex_files;
-  for (const DexFile* dex_file : dex_files) {
-    if (!compiled_classes_.HaveDexFile(dex_file)) {
-      compiled_classes_.AddDexFile(dex_file, dex_file->NumClassDefs());
-    }
-  }
+  compiled_classes_.AddDexFiles(dex_files);
+  dex_to_dex_compiler_.SetDexFiles(dex_files);
 }
 
-bool CompilerDriver::CanAssumeVerified(ClassReference ref) const {
-  mirror::Class::Status existing = mirror::Class::kStatusNotReady;
-  compiled_classes_.Get(DexFileReference(ref.first, ref.second), &existing);
-  return existing >= mirror::Class::kStatusVerified;
+void CompilerDriver::SetClasspathDexFiles(const std::vector<const DexFile*>& dex_files) {
+  classpath_classes_.AddDexFiles(dex_files);
 }
 
 }  // namespace art
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 5771b19..a5462ee 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -17,27 +17,30 @@
 #ifndef ART_COMPILER_DRIVER_COMPILER_DRIVER_H_
 #define ART_COMPILER_DRIVER_COMPILER_DRIVER_H_
 
+#include <atomic>
 #include <set>
 #include <string>
 #include <unordered_set>
 #include <vector>
 
+#include "android-base/strings.h"
+
 #include "arch/instruction_set.h"
 #include "base/array_ref.h"
 #include "base/bit_utils.h"
 #include "base/mutex.h"
+#include "base/os.h"
+#include "base/quasi_atomic.h"
+#include "base/safe_map.h"
 #include "base/timing_logger.h"
-#include "class_reference.h"
+#include "class_status.h"
 #include "compiler.h"
-#include "dex_file.h"
-#include "dex_file_types.h"
+#include "dex/class_reference.h"
+#include "dex/dex_file.h"
+#include "dex/dex_file_types.h"
+#include "dex/dex_to_dex_compiler.h"
+#include "dex/method_reference.h"
 #include "driver/compiled_method_storage.h"
-#include "jit/profile_compilation_info.h"
-#include "invoke_type.h"
-#include "method_reference.h"
-#include "mirror/class.h"  // For mirror::Class::Status.
-#include "os.h"
-#include "safe_map.h"
 #include "thread_pool.h"
 #include "utils/atomic_dex_ref_map.h"
 #include "utils/dex_cache_arrays_layout.h"
@@ -45,6 +48,7 @@
 namespace art {
 
 namespace mirror {
+class Class;
 class DexCache;
 }  // namespace mirror
 
@@ -53,17 +57,22 @@
 class VerifierDepsTest;
 }  // namespace verifier
 
+class ArtField;
 class BitVector;
 class CompiledMethod;
 class CompilerOptions;
 class DexCompilationUnit;
+template<class T> class Handle;
 struct InlineIGetIPutData;
 class InstructionSetFeatures;
 class InternTable;
+enum InvokeType : uint32_t;
+class MemberOffset;
+template<class MirrorType> class ObjPtr;
 class ParallelCompilationManager;
+class ProfileCompilationInfo;
 class ScopedObjectAccess;
 template <class Allocator> class SrcMap;
-template<class T> class Handle;
 class TimingLogger;
 class VdexFile;
 class VerificationResults;
@@ -94,18 +103,18 @@
                  std::unordered_set<std::string>* compiled_classes,
                  std::unordered_set<std::string>* compiled_methods,
                  size_t thread_count,
-                 bool dump_stats,
-                 bool dump_passes,
-                 CumulativeLogger* timer,
                  int swap_fd,
                  const ProfileCompilationInfo* profile_compilation_info);
 
   ~CompilerDriver();
 
-  // Set dex files that will be stored in the oat file after being compiled.
+  // Set dex files associated with the oat file being compiled.
   void SetDexFilesForOatFile(const std::vector<const DexFile*>& dex_files);
 
-  // Get dex file that will be stored in the oat file after being compiled.
+  // Set dex files classpath.
+  void SetClasspathDexFiles(const std::vector<const DexFile*>& dex_files);
+
+  // Get dex files associated with the the oat file being compiled.
   ArrayRef<const DexFile* const> GetDexFilesForOatFile() const {
     return ArrayRef<const DexFile* const>(dex_files_for_oat_file_);
   }
@@ -113,12 +122,11 @@
   void CompileAll(jobject class_loader,
                   const std::vector<const DexFile*>& dex_files,
                   TimingLogger* timings)
-      REQUIRES(!Locks::mutator_lock_, !dex_to_dex_references_lock_);
+      REQUIRES(!Locks::mutator_lock_);
 
   // Compile a single Method.
   void CompileOne(Thread* self, ArtMethod* method, TimingLogger* timings)
-      REQUIRES_SHARED(Locks::mutator_lock_)
-      REQUIRES(!dex_to_dex_references_lock_);
+      REQUIRES_SHARED(Locks::mutator_lock_);
 
   VerificationResults* GetVerificationResults() const;
 
@@ -149,7 +157,8 @@
   std::unique_ptr<const std::vector<uint8_t>> CreateQuickResolutionTrampoline() const;
   std::unique_ptr<const std::vector<uint8_t>> CreateQuickToInterpreterBridge() const;
 
-  bool GetCompiledClass(ClassReference ref, mirror::Class::Status* status) const;
+  ClassStatus GetClassStatus(const ClassReference& ref) const;
+  bool GetCompiledClass(const ClassReference& ref, ClassStatus* status) const;
 
   CompiledMethod* GetCompiledMethod(MethodReference ref) const;
   size_t GetNonRelativeLinkerPatchCount() const;
@@ -157,6 +166,7 @@
   void AddCompiledMethod(const MethodReference& method_ref,
                          CompiledMethod* const compiled_method,
                          size_t non_relative_linker_patch_count);
+  CompiledMethod* RemoveCompiledMethod(const MethodReference& method_ref);
 
   void SetRequiresConstructorBarrier(Thread* self,
                                      const DexFile* dex_file,
@@ -215,36 +225,33 @@
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Resolve compiling method's class. Returns null on failure.
-  mirror::Class* ResolveCompilingMethodsClass(
-      const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
-      Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit)
+  ObjPtr<mirror::Class> ResolveCompilingMethodsClass(const ScopedObjectAccess& soa,
+                                                     Handle<mirror::DexCache> dex_cache,
+                                                     Handle<mirror::ClassLoader> class_loader,
+                                                     const DexCompilationUnit* mUnit)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
-  mirror::Class* ResolveClass(
-      const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
-      Handle<mirror::ClassLoader> class_loader, dex::TypeIndex type_index,
-      const DexCompilationUnit* mUnit)
+  ObjPtr<mirror::Class> ResolveClass(const ScopedObjectAccess& soa,
+                                     Handle<mirror::DexCache> dex_cache,
+                                     Handle<mirror::ClassLoader> class_loader,
+                                     dex::TypeIndex type_index,
+                                     const DexCompilationUnit* mUnit)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Resolve a field. Returns null on failure, including incompatible class change.
   // NOTE: Unlike ClassLinker's ResolveField(), this method enforces is_static.
-  ArtField* ResolveField(
-      const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
-      Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit,
-      uint32_t field_idx, bool is_static)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
-  // Resolve a field with a given dex file.
-  ArtField* ResolveFieldWithDexFile(
-      const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
-      Handle<mirror::ClassLoader> class_loader, const DexFile* dex_file,
-      uint32_t field_idx, bool is_static)
+  ArtField* ResolveField(const ScopedObjectAccess& soa,
+                         Handle<mirror::DexCache> dex_cache,
+                         Handle<mirror::ClassLoader> class_loader,
+                         uint32_t field_idx,
+                         bool is_static)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Can we fast-path an IGET/IPUT access to an instance field? If yes, compute the field offset.
-  std::pair<bool, bool> IsFastInstanceField(
-      mirror::DexCache* dex_cache, mirror::Class* referrer_class,
-      ArtField* resolved_field, uint16_t field_idx)
+  std::pair<bool, bool> IsFastInstanceField(ObjPtr<mirror::DexCache> dex_cache,
+                                            ObjPtr<mirror::Class> referrer_class,
+                                            ArtField* resolved_field,
+                                            uint16_t field_idx)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Resolve a method. Returns null on failure, including incompatible class change.
@@ -266,9 +273,9 @@
       REQUIRES(!Locks::mutator_lock_);
 
   ArtField* ComputeInstanceFieldInfo(uint32_t field_idx,
-                                             const DexCompilationUnit* mUnit,
-                                             bool is_put,
-                                             const ScopedObjectAccess& soa)
+                                     const DexCompilationUnit* mUnit,
+                                     bool is_put,
+                                     const ScopedObjectAccess& soa)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
 
@@ -295,18 +302,6 @@
     return parallel_thread_count_;
   }
 
-  bool GetDumpStats() const {
-    return dump_stats_;
-  }
-
-  bool GetDumpPasses() const {
-    return dump_passes_;
-  }
-
-  CumulativeLogger* GetTimingsLogger() const {
-    return timings_logger_;
-  }
-
   void SetDedupeEnabled(bool dedupe_enabled) {
     compiled_method_storage_.SetDedupeEnabled(dedupe_enabled);
   }
@@ -332,7 +327,7 @@
   // according to the profile file.
   bool ShouldVerifyClassBasedOnProfile(const DexFile& dex_file, uint16_t class_idx) const;
 
-  void RecordClassStatus(ClassReference ref, mirror::Class::Status status);
+  void RecordClassStatus(const ClassReference& ref, ClassStatus status);
 
   // Checks if the specified method has been verified without failures. Returns
   // false if the method is not in the verification results (GetVerificationResults).
@@ -346,6 +341,9 @@
   void SetHadHardVerifierFailure() {
     had_hard_verifier_failure_ = true;
   }
+  void AddSoftVerifierFailure() {
+    number_of_soft_verifier_failures_++;
+  }
 
   Compiler::Kind GetCompilerKind() {
     return compiler_kind_;
@@ -366,18 +364,30 @@
     return true;
   }
 
-  void MarkForDexToDexCompilation(Thread* self, const MethodReference& method_ref)
-      REQUIRES(!dex_to_dex_references_lock_);
-
-  const BitVector* GetCurrentDexToDexMethods() const {
-    return current_dex_to_dex_methods_;
-  }
-
   const ProfileCompilationInfo* GetProfileCompilationInfo() const {
     return profile_compilation_info_;
   }
 
-  bool CanAssumeVerified(ClassReference ref) const;
+  // Is `boot_image_filename` the name of a core image (small boot
+  // image used for ART testing only)?
+  static bool IsCoreImageFilename(const std::string& boot_image_filename) {
+    // Look for "core.art" or "core-*.art".
+    if (android::base::EndsWith(boot_image_filename, "core.art")) {
+      return true;
+    }
+    if (!android::base::EndsWith(boot_image_filename, ".art")) {
+      return false;
+    }
+    size_t slash_pos = boot_image_filename.rfind('/');
+    if (slash_pos == std::string::npos) {
+      return android::base::StartsWith(boot_image_filename, "core-");
+    }
+    return boot_image_filename.compare(slash_pos + 1, 5u, "core-") == 0;
+  }
+
+  optimizer::DexToDexCompiler& GetDexToDexCompiler() {
+    return dex_to_dex_compiler_;
+  }
 
  private:
   void PreCompile(jobject class_loader,
@@ -445,14 +455,7 @@
 
   void Compile(jobject class_loader,
                const std::vector<const DexFile*>& dex_files,
-               TimingLogger* timings) REQUIRES(!dex_to_dex_references_lock_);
-  void CompileDexFile(jobject class_loader,
-                      const DexFile& dex_file,
-                      const std::vector<const DexFile*>& dex_files,
-                      ThreadPool* thread_pool,
-                      size_t thread_count,
-                      TimingLogger* timings)
-      REQUIRES(!Locks::mutator_lock_);
+               TimingLogger* timings);
 
   bool MayInlineInternal(const DexFile* inlined_from, const DexFile* inlined_into) const;
 
@@ -478,10 +481,12 @@
       GUARDED_BY(requires_constructor_barrier_lock_);
 
   // All class references that this compiler has compiled. Indexed by class defs.
-  using ClassStateTable = AtomicDexRefMap<mirror::Class::Status>;
+  using ClassStateTable = AtomicDexRefMap<ClassReference, ClassStatus>;
   ClassStateTable compiled_classes_;
+  // All class references that are in the classpath. Indexed by class defs.
+  ClassStateTable classpath_classes_;
 
-  typedef AtomicDexRefMap<CompiledMethod*> MethodTable;
+  typedef AtomicDexRefMap<MethodReference, CompiledMethod*> MethodTable;
 
  private:
   // All method references that this compiler has compiled.
@@ -505,6 +510,7 @@
   // This option may be restricted to the boot image, depending on a flag in the implementation.
   std::unique_ptr<std::unordered_set<std::string>> methods_to_compile_;
 
+  std::atomic<uint32_t> number_of_soft_verifier_failures_;
   bool had_hard_verifier_failure_;
 
   // A thread pool that can (potentially) run tasks in parallel.
@@ -517,11 +523,6 @@
   class AOTCompilationStats;
   std::unique_ptr<AOTCompilationStats> stats_;
 
-  bool dump_stats_;
-  const bool dump_passes_;
-
-  CumulativeLogger* const timings_logger_;
-
   typedef void (*CompilerCallbackFn)(CompilerDriver& driver);
   typedef MutexLock* (*CompilerMutexLockFn)(CompilerDriver& driver);
 
@@ -529,7 +530,7 @@
 
   bool support_boot_image_fixup_;
 
-  // List of dex files that will be stored in the oat file.
+  // List of dex files associates with the oat file.
   std::vector<const DexFile*> dex_files_for_oat_file_;
 
   CompiledMethodStorage compiled_method_storage_;
@@ -539,14 +540,8 @@
 
   size_t max_arena_alloc_;
 
-  // Data for delaying dex-to-dex compilation.
-  Mutex dex_to_dex_references_lock_;
-  // In the first phase, dex_to_dex_references_ collects methods for dex-to-dex compilation.
-  class DexFileMethodSet;
-  std::vector<DexFileMethodSet> dex_to_dex_references_ GUARDED_BY(dex_to_dex_references_lock_);
-  // In the second phase, current_dex_to_dex_methods_ points to the BitVector with method
-  // indexes for dex-to-dex compilation in the current dex file.
-  const BitVector* current_dex_to_dex_methods_;
+  // Compiler for dex to dex (quickening).
+  optimizer::DexToDexCompiler dex_to_dex_compiler_;
 
   friend class CompileClassVisitor;
   friend class DexToDexDecompilerTest;
diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc
index 37e17b2..162904c 100644
--- a/compiler/driver/compiler_driver_test.cc
+++ b/compiler/driver/compiler_driver_test.cc
@@ -16,24 +16,26 @@
 
 #include "driver/compiler_driver.h"
 
+#include <limits>
 #include <stdint.h>
 #include <stdio.h>
 #include <memory>
 
 #include "art_method-inl.h"
+#include "base/casts.h"
 #include "class_linker-inl.h"
 #include "common_compiler_test.h"
 #include "compiler_callbacks.h"
-#include "dex_file.h"
-#include "dex_file_types.h"
+#include "dex/dex_file.h"
+#include "dex/dex_file_types.h"
 #include "gc/heap.h"
+#include "handle_scope-inl.h"
+#include "jit/profile_compilation_info.h"
 #include "mirror/class-inl.h"
 #include "mirror/class_loader.h"
 #include "mirror/dex_cache-inl.h"
-#include "mirror/object_array-inl.h"
 #include "mirror/object-inl.h"
-#include "handle_scope-inl.h"
-#include "jit/profile_compilation_info.h"
+#include "mirror/object_array-inl.h"
 #include "scoped_thread_state_change-inl.h"
 
 namespace art {
@@ -344,11 +346,11 @@
     ASSERT_NE(klass, nullptr);
     EXPECT_TRUE(klass->IsVerified());
 
-    mirror::Class::Status status;
+    ClassStatus status;
     bool found = compiler_driver_->GetCompiledClass(
         ClassReference(&klass->GetDexFile(), klass->GetDexTypeIndex().index_), &status);
     ASSERT_TRUE(found);
-    EXPECT_EQ(status, mirror::Class::kStatusVerified);
+    EXPECT_EQ(status, ClassStatus::kVerified);
   }
 };
 
@@ -367,10 +369,8 @@
   CheckVerifiedClass(class_loader, "LSecond;");
 }
 
-// Test that a class of status kStatusRetryVerificationAtRuntime is indeed recorded that way in the
-// driver.
-// Test that checks that classes can be assumed as verified if unloading mode is enabled and
-// the class status is at least verified.
+// Test that a class of status ClassStatus::kRetryVerificationAtRuntime is indeed
+// recorded that way in the driver.
 TEST_F(CompilerDriverVerifyTest, RetryVerifcationStatusCheckVerified) {
   Thread* const self = Thread::Current();
   jobject class_loader;
@@ -388,25 +388,21 @@
   callbacks_->SetDoesClassUnloading(true, compiler_driver_.get());
   ClassReference ref(dex_file, 0u);
   // Test that the status is read from the compiler driver as expected.
-  for (size_t i = mirror::Class::kStatusRetryVerificationAtRuntime;
-      i < mirror::Class::kStatusMax;
-      ++i) {
-    const mirror::Class::Status expected_status = static_cast<mirror::Class::Status>(i);
+  static_assert(enum_cast<size_t>(ClassStatus::kLast) < std::numeric_limits<size_t>::max(),
+                "Make sure incrementing the class status does not overflow.");
+  for (size_t i = enum_cast<size_t>(ClassStatus::kRetryVerificationAtRuntime);
+       i <= enum_cast<size_t>(ClassStatus::kLast);
+       ++i) {
+    const ClassStatus expected_status = enum_cast<ClassStatus>(i);
     // Skip unsupported status that are not supposed to be ever recorded.
-    if (expected_status == mirror::Class::kStatusVerifyingAtRuntime ||
-        expected_status == mirror::Class::kStatusInitializing) {
+    if (expected_status == ClassStatus::kVerifyingAtRuntime ||
+        expected_status == ClassStatus::kInitializing) {
       continue;
     }
     compiler_driver_->RecordClassStatus(ref, expected_status);
-    mirror::Class::Status status = {};
+    ClassStatus status = {};
     ASSERT_TRUE(compiler_driver_->GetCompiledClass(ref, &status));
     EXPECT_EQ(status, expected_status);
-
-    // Check that we can assume verified if we are a status that is at least verified.
-    if (status >= mirror::Class::kStatusVerified) {
-      // Check that the class can be assumed as verified in the compiler driver.
-      EXPECT_TRUE(callbacks_->CanAssumeVerified(ref)) << status;
-    }
   }
 }
 
diff --git a/compiler/driver/compiler_options.cc b/compiler/driver/compiler_options.cc
index 76f0ae9..2d82d79 100644
--- a/compiler/driver/compiler_options.cc
+++ b/compiler/driver/compiler_options.cc
@@ -18,6 +18,15 @@
 
 #include <fstream>
 
+#include "android-base/stringprintf.h"
+
+#include "base/runtime_debug.h"
+#include "base/variant_map.h"
+#include "cmdline_parser.h"
+#include "compiler_options_map-inl.h"
+#include "runtime.h"
+#include "simple_compiler_options_map.h"
+
 namespace art {
 
 CompilerOptions::CompilerOptions()
@@ -30,6 +39,7 @@
       inline_max_code_units_(kUnsetInlineMaxCodeUnits),
       no_inline_from_(nullptr),
       boot_image_(false),
+      core_image_(false),
       app_image_(false),
       top_k_profile_threshold_(kDefaultTopKProfileThreshold),
       debuggable_(false),
@@ -40,12 +50,17 @@
       implicit_so_checks_(true),
       implicit_suspend_checks_(false),
       compile_pic_(false),
+      dump_timings_(false),
+      dump_stats_(false),
       verbose_methods_(),
       abort_on_hard_verifier_failure_(false),
+      abort_on_soft_verifier_failure_(false),
       init_failure_output_(nullptr),
       dump_cfg_file_name_(""),
       dump_cfg_append_(false),
       force_determinism_(false),
+      deduplicate_code_(true),
+      count_hotness_in_compiled_code_(false),
       register_allocation_strategy_(RegisterAllocator::kRegisterAllocatorDefault),
       passes_to_run_(nullptr) {
 }
@@ -55,113 +70,62 @@
   // because we don't want to include the PassManagerOptions definition from the header file.
 }
 
-void CompilerOptions::ParseHugeMethodMax(const StringPiece& option, UsageFn Usage) {
-  ParseUintOption(option, "--huge-method-max", &huge_method_threshold_, Usage);
+namespace {
+
+bool kEmitRuntimeReadBarrierChecks = kIsDebugBuild &&
+    RegisterRuntimeDebugFlag(&kEmitRuntimeReadBarrierChecks);
+
+}  // namespace
+
+bool CompilerOptions::EmitRunTimeChecksInDebugMode() const {
+  // Run-time checks (e.g. Marking Register checks) are only emitted in slow-debug mode.
+  return kEmitRuntimeReadBarrierChecks;
 }
 
-void CompilerOptions::ParseLargeMethodMax(const StringPiece& option, UsageFn Usage) {
-  ParseUintOption(option, "--large-method-max", &large_method_threshold_, Usage);
-}
-
-void CompilerOptions::ParseSmallMethodMax(const StringPiece& option, UsageFn Usage) {
-  ParseUintOption(option, "--small-method-max", &small_method_threshold_, Usage);
-}
-
-void CompilerOptions::ParseTinyMethodMax(const StringPiece& option, UsageFn Usage) {
-  ParseUintOption(option, "--tiny-method-max", &tiny_method_threshold_, Usage);
-}
-
-void CompilerOptions::ParseNumDexMethods(const StringPiece& option, UsageFn Usage) {
-  ParseUintOption(option, "--num-dex-methods", &num_dex_methods_threshold_, Usage);
-}
-
-void CompilerOptions::ParseInlineMaxCodeUnits(const StringPiece& option, UsageFn Usage) {
-  ParseUintOption(option, "--inline-max-code-units", &inline_max_code_units_, Usage);
-}
-
-void CompilerOptions::ParseDumpInitFailures(const StringPiece& option,
-                                            UsageFn Usage ATTRIBUTE_UNUSED) {
-  DCHECK(option.starts_with("--dump-init-failures="));
-  std::string file_name = option.substr(strlen("--dump-init-failures=")).data();
-  init_failure_output_.reset(new std::ofstream(file_name));
+bool CompilerOptions::ParseDumpInitFailures(const std::string& option, std::string* error_msg) {
+  init_failure_output_.reset(new std::ofstream(option));
   if (init_failure_output_.get() == nullptr) {
-    LOG(ERROR) << "Failed to allocate ofstream";
+    *error_msg = "Failed to construct std::ofstream";
+    return false;
   } else if (init_failure_output_->fail()) {
-    LOG(ERROR) << "Failed to open " << file_name << " for writing the initialization "
-               << "failures.";
+    *error_msg = android::base::StringPrintf(
+        "Failed to open %s for writing the initialization failures.", option.c_str());
     init_failure_output_.reset();
-  }
-}
-
-void CompilerOptions::ParseRegisterAllocationStrategy(const StringPiece& option,
-                                                      UsageFn Usage) {
-  DCHECK(option.starts_with("--register-allocation-strategy="));
-  StringPiece choice = option.substr(strlen("--register-allocation-strategy=")).data();
-  if (choice == "linear-scan") {
-    register_allocation_strategy_ = RegisterAllocator::Strategy::kRegisterAllocatorLinearScan;
-  } else if (choice == "graph-color") {
-    register_allocation_strategy_ = RegisterAllocator::Strategy::kRegisterAllocatorGraphColor;
-  } else {
-    Usage("Unrecognized register allocation strategy. Try linear-scan, or graph-color.");
-  }
-}
-
-bool CompilerOptions::ParseCompilerOption(const StringPiece& option, UsageFn Usage) {
-  if (option.starts_with("--compiler-filter=")) {
-    const char* compiler_filter_string = option.substr(strlen("--compiler-filter=")).data();
-    if (!CompilerFilter::ParseCompilerFilter(compiler_filter_string, &compiler_filter_)) {
-      Usage("Unknown --compiler-filter value %s", compiler_filter_string);
-    }
-  } else if (option == "--compile-pic") {
-    compile_pic_ = true;
-  } else if (option.starts_with("--huge-method-max=")) {
-    ParseHugeMethodMax(option, Usage);
-  } else if (option.starts_with("--large-method-max=")) {
-    ParseLargeMethodMax(option, Usage);
-  } else if (option.starts_with("--small-method-max=")) {
-    ParseSmallMethodMax(option, Usage);
-  } else if (option.starts_with("--tiny-method-max=")) {
-    ParseTinyMethodMax(option, Usage);
-  } else if (option.starts_with("--num-dex-methods=")) {
-    ParseNumDexMethods(option, Usage);
-  } else if (option.starts_with("--inline-max-code-units=")) {
-    ParseInlineMaxCodeUnits(option, Usage);
-  } else if (option == "--generate-debug-info" || option == "-g") {
-    generate_debug_info_ = true;
-  } else if (option == "--no-generate-debug-info") {
-    generate_debug_info_ = false;
-  } else if (option == "--generate-mini-debug-info") {
-    generate_mini_debug_info_ = true;
-  } else if (option == "--no-generate-mini-debug-info") {
-    generate_mini_debug_info_ = false;
-  } else if (option == "--generate-build-id") {
-    generate_build_id_ = true;
-  } else if (option == "--no-generate-build-id") {
-    generate_build_id_ = false;
-  } else if (option == "--debuggable") {
-    debuggable_ = true;
-  } else if (option.starts_with("--top-k-profile-threshold=")) {
-    ParseDouble(option.data(), '=', 0.0, 100.0, &top_k_profile_threshold_, Usage);
-  } else if (option == "--abort-on-hard-verifier-error") {
-    abort_on_hard_verifier_failure_ = true;
-  } else if (option.starts_with("--dump-init-failures=")) {
-    ParseDumpInitFailures(option, Usage);
-  } else if (option.starts_with("--dump-cfg=")) {
-    dump_cfg_file_name_ = option.substr(strlen("--dump-cfg=")).data();
-  } else if (option == "--dump-cfg-append") {
-    dump_cfg_append_ = true;
-  } else if (option.starts_with("--register-allocation-strategy=")) {
-    ParseRegisterAllocationStrategy(option, Usage);
-  } else if (option.starts_with("--verbose-methods=")) {
-    // TODO: rather than switch off compiler logging, make all VLOG(compiler) messages
-    //       conditional on having verbose methods.
-    gLogVerbosity.compiler = false;
-    Split(option.substr(strlen("--verbose-methods=")).ToString(), ',', &verbose_methods_);
-  } else {
-    // Option not recognized.
     return false;
   }
   return true;
 }
 
+bool CompilerOptions::ParseRegisterAllocationStrategy(const std::string& option,
+                                                      std::string* error_msg) {
+  if (option == "linear-scan") {
+    register_allocation_strategy_ = RegisterAllocator::Strategy::kRegisterAllocatorLinearScan;
+  } else if (option == "graph-color") {
+    register_allocation_strategy_ = RegisterAllocator::Strategy::kRegisterAllocatorGraphColor;
+  } else {
+    *error_msg = "Unrecognized register allocation strategy. Try linear-scan, or graph-color.";
+    return false;
+  }
+  return true;
+}
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wframe-larger-than="
+
+bool CompilerOptions::ParseCompilerOptions(const std::vector<std::string>& options,
+                                           bool ignore_unrecognized,
+                                           std::string* error_msg) {
+  auto parser = CreateSimpleParser(ignore_unrecognized);
+  CmdlineResult parse_result = parser.Parse(options);
+  if (!parse_result.IsSuccess()) {
+    *error_msg = parse_result.GetMessage();
+    return false;
+  }
+
+  SimpleParseArgumentMap args = parser.ReleaseArgumentsMap();
+  return ReadCompilerOptions(args, this, error_msg);
+}
+
+#pragma GCC diagnostic pop
+
 }  // namespace art
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index 0a2d542..05d8805 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -22,15 +22,15 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "base/utils.h"
 #include "compiler_filter.h"
 #include "globals.h"
 #include "optimizing/register_allocator.h"
-#include "utils.h"
 
 namespace art {
 
 namespace verifier {
-  class VerifierDepsTest;
+class VerifierDepsTest;
 }  // namespace verifier
 
 class DexFile;
@@ -161,6 +161,9 @@
     return generate_mini_debug_info_;
   }
 
+  // Should run-time checks be emitted in debug mode?
+  bool EmitRunTimeChecksInDebugMode() const;
+
   bool GetGenerateBuildId() const {
     return generate_build_id_;
   }
@@ -177,10 +180,19 @@
     return implicit_suspend_checks_;
   }
 
+  // Are we compiling a boot image?
   bool IsBootImage() const {
     return boot_image_;
   }
 
+  // Are we compiling a core image (small boot image only used for ART testing)?
+  bool IsCoreImage() const {
+    // Ensure that `core_image_` => `boot_image_`.
+    DCHECK(!core_image_ || boot_image_);
+    return core_image_;
+  }
+
+  // Are we compiling an app image?
   bool IsAppImage() const {
     return app_image_;
   }
@@ -214,12 +226,17 @@
   bool AbortOnHardVerifierFailure() const {
     return abort_on_hard_verifier_failure_;
   }
+  bool AbortOnSoftVerifierFailure() const {
+    return abort_on_soft_verifier_failure_;
+  }
 
   const std::vector<const DexFile*>* GetNoInlineFromDexFile() const {
     return no_inline_from_;
   }
 
-  bool ParseCompilerOption(const StringPiece& option, UsageFn Usage);
+  bool ParseCompilerOptions(const std::vector<std::string>& options,
+                            bool ignore_unrecognized,
+                            std::string* error_msg);
 
   void SetNonPic() {
     compile_pic_ = false;
@@ -237,6 +254,10 @@
     return force_determinism_;
   }
 
+  bool DeduplicateCode() const {
+    return deduplicate_code_;
+  }
+
   RegisterAllocator::Strategy GetRegisterAllocationStrategy() const {
     return register_allocation_strategy_;
   }
@@ -245,8 +266,20 @@
     return passes_to_run_;
   }
 
+  bool GetDumpTimings() const {
+    return dump_timings_;
+  }
+
+  bool GetDumpStats() const {
+    return dump_stats_;
+  }
+
+  bool CountHotnessInCompiledCode() const {
+    return count_hotness_in_compiled_code_;
+  }
+
  private:
-  void ParseDumpInitFailures(const StringPiece& option, UsageFn Usage);
+  bool ParseDumpInitFailures(const std::string& option, std::string* error_msg);
   void ParseDumpCfgPasses(const StringPiece& option, UsageFn Usage);
   void ParseInlineMaxCodeUnits(const StringPiece& option, UsageFn Usage);
   void ParseNumDexMethods(const StringPiece& option, UsageFn Usage);
@@ -254,7 +287,7 @@
   void ParseSmallMethodMax(const StringPiece& option, UsageFn Usage);
   void ParseLargeMethodMax(const StringPiece& option, UsageFn Usage);
   void ParseHugeMethodMax(const StringPiece& option, UsageFn Usage);
-  void ParseRegisterAllocationStrategy(const StringPiece& option, UsageFn Usage);
+  bool ParseRegisterAllocationStrategy(const std::string& option, std::string* error_msg);
 
   CompilerFilter::Filter compiler_filter_;
   size_t huge_method_threshold_;
@@ -270,6 +303,7 @@
   const std::vector<const DexFile*>* no_inline_from_;
 
   bool boot_image_;
+  bool core_image_;
   bool app_image_;
   // When using a profile file only the top K% of the profiled samples will be compiled.
   double top_k_profile_threshold_;
@@ -281,6 +315,8 @@
   bool implicit_so_checks_;
   bool implicit_suspend_checks_;
   bool compile_pic_;
+  bool dump_timings_;
+  bool dump_stats_;
 
   // Vector of methods to have verbose output enabled for.
   std::vector<std::string> verbose_methods_;
@@ -288,6 +324,8 @@
   // Abort compilation with an error if we find a class that fails verification with a hard
   // failure.
   bool abort_on_hard_verifier_failure_;
+  // Same for soft failures.
+  bool abort_on_soft_verifier_failure_;
 
   // Log initialization of initialization failures to this stream if not null.
   std::unique_ptr<std::ostream> init_failure_output_;
@@ -299,6 +337,13 @@
   // outcomes.
   bool force_determinism_;
 
+  // Whether code should be deduplicated.
+  bool deduplicate_code_;
+
+  // Whether compiled code should increment the hotness count of ArtMethod. Note that the increments
+  // won't be atomic for performance reasons, so we accept races, just like in interpreter.
+  bool count_hotness_in_compiled_code_;
+
   RegisterAllocator::Strategy register_allocation_strategy_;
 
   // If not null, specifies optimization passes which will be run instead of defaults.
@@ -314,6 +359,9 @@
   friend class CommonCompilerTest;
   friend class verifier::VerifierDepsTest;
 
+  template <class Base>
+  friend bool ReadCompilerOptions(Base& map, CompilerOptions* options, std::string* error_msg);
+
   DISALLOW_COPY_AND_ASSIGN(CompilerOptions);
 };
 
diff --git a/compiler/driver/compiler_options_map-inl.h b/compiler/driver/compiler_options_map-inl.h
new file mode 100644
index 0000000..3b18db0
--- /dev/null
+++ b/compiler/driver/compiler_options_map-inl.h
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef ART_COMPILER_DRIVER_COMPILER_OPTIONS_MAP_INL_H_
+#define ART_COMPILER_DRIVER_COMPILER_OPTIONS_MAP_INL_H_
+
+#include "compiler_options_map.h"
+
+#include <memory>
+
+#include "android-base/logging.h"
+#include "android-base/macros.h"
+#include "android-base/stringprintf.h"
+
+#include "base/macros.h"
+#include "cmdline_parser.h"
+#include "compiler_options.h"
+
+namespace art {
+
+template <class Base>
+inline bool ReadCompilerOptions(Base& map, CompilerOptions* options, std::string* error_msg) {
+  if (map.Exists(Base::CompilerFilter)) {
+    CompilerFilter::Filter compiler_filter;
+    if (!CompilerFilter::ParseCompilerFilter(map.Get(Base::CompilerFilter)->c_str(),
+                                             &compiler_filter)) {
+      *error_msg = android::base::StringPrintf("Unknown --compiler-filter value %s",
+                                               map.Get(Base::CompilerFilter)->c_str());
+      return false;
+    }
+    options->SetCompilerFilter(compiler_filter);
+  }
+  if (map.Exists(Base::PIC)) {
+    options->compile_pic_ = true;
+  }
+  map.AssignIfExists(Base::HugeMethodMaxThreshold, &options->huge_method_threshold_);
+  map.AssignIfExists(Base::LargeMethodMaxThreshold, &options->large_method_threshold_);
+  map.AssignIfExists(Base::SmallMethodMaxThreshold, &options->small_method_threshold_);
+  map.AssignIfExists(Base::TinyMethodMaxThreshold, &options->tiny_method_threshold_);
+  map.AssignIfExists(Base::NumDexMethodsThreshold, &options->num_dex_methods_threshold_);
+  map.AssignIfExists(Base::InlineMaxCodeUnitsThreshold, &options->inline_max_code_units_);
+  map.AssignIfExists(Base::GenerateDebugInfo, &options->generate_debug_info_);
+  map.AssignIfExists(Base::GenerateMiniDebugInfo, &options->generate_mini_debug_info_);
+  map.AssignIfExists(Base::GenerateBuildID, &options->generate_build_id_);
+  if (map.Exists(Base::Debuggable)) {
+    options->debuggable_ = true;
+  }
+  map.AssignIfExists(Base::TopKProfileThreshold, &options->top_k_profile_threshold_);
+  map.AssignIfExists(Base::AbortOnHardVerifierFailure, &options->abort_on_hard_verifier_failure_);
+  map.AssignIfExists(Base::AbortOnSoftVerifierFailure, &options->abort_on_soft_verifier_failure_);
+  if (map.Exists(Base::DumpInitFailures)) {
+    if (!options->ParseDumpInitFailures(*map.Get(Base::DumpInitFailures), error_msg)) {
+      return false;
+    }
+  }
+  map.AssignIfExists(Base::DumpCFG, &options->dump_cfg_file_name_);
+  if (map.Exists(Base::DumpCFGAppend)) {
+    options->dump_cfg_append_ = true;
+  }
+  if (map.Exists(Base::RegisterAllocationStrategy)) {
+    if (!options->ParseRegisterAllocationStrategy(*map.Get(Base::DumpInitFailures), error_msg)) {
+      return false;
+    }
+  }
+  map.AssignIfExists(Base::VerboseMethods, &options->verbose_methods_);
+  options->deduplicate_code_ = map.GetOrDefault(Base::DeduplicateCode);
+  if (map.Exists(Base::CountHotnessInCompiledCode)) {
+    options->count_hotness_in_compiled_code_ = true;
+  }
+
+  if (map.Exists(Base::DumpTimings)) {
+    options->dump_timings_ = true;
+  }
+
+  if (map.Exists(Base::DumpStats)) {
+    options->dump_stats_ = true;
+  }
+
+  return true;
+}
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wframe-larger-than="
+
+template <typename Map, typename Builder>
+inline void AddCompilerOptionsArgumentParserOptions(Builder& b) {
+  b.
+      Define("--compiler-filter=_")
+          .template WithType<std::string>()
+          .IntoKey(Map::CompilerFilter)
+
+      .Define("--compile-pic")
+          .IntoKey(Map::PIC)
+
+      .Define("--huge-method-max=_")
+          .template WithType<unsigned int>()
+          .IntoKey(Map::HugeMethodMaxThreshold)
+      .Define("--large-method-max=_")
+          .template WithType<unsigned int>()
+          .IntoKey(Map::LargeMethodMaxThreshold)
+      .Define("--small-method-max=_")
+          .template WithType<unsigned int>()
+          .IntoKey(Map::SmallMethodMaxThreshold)
+      .Define("--tiny-method-max=_")
+          .template WithType<unsigned int>()
+          .IntoKey(Map::TinyMethodMaxThreshold)
+      .Define("--num-dex-methods=_")
+          .template WithType<unsigned int>()
+          .IntoKey(Map::NumDexMethodsThreshold)
+      .Define("--inline-max-code-units=_")
+          .template WithType<unsigned int>()
+          .IntoKey(Map::InlineMaxCodeUnitsThreshold)
+
+      .Define({"--generate-debug-info", "-g", "--no-generate-debug-info"})
+          .WithValues({true, true, false})
+          .IntoKey(Map::GenerateDebugInfo)
+      .Define({"--generate-mini-debug-info", "--no-generate-mini-debug-info"})
+          .WithValues({true, false})
+          .IntoKey(Map::GenerateMiniDebugInfo)
+
+      .Define({"--generate-build-id", "--no-generate-build-id"})
+          .WithValues({true, false})
+          .IntoKey(Map::GenerateBuildID)
+
+      .Define({"--deduplicate-code=_"})
+          .template WithType<bool>()
+          .WithValueMap({{"false", false}, {"true", true}})
+          .IntoKey(Map::DeduplicateCode)
+
+      .Define({"--count-hotness-in-compiled-code"})
+          .IntoKey(Map::CountHotnessInCompiledCode)
+
+      .Define({"--dump-timings"})
+          .IntoKey(Map::DumpTimings)
+
+      .Define({"--dump-stats"})
+          .IntoKey(Map::DumpStats)
+
+      .Define("--debuggable")
+          .IntoKey(Map::Debuggable)
+
+      .Define("--top-k-profile-threshold=_")
+          .template WithType<double>().WithRange(0.0, 100.0)
+          .IntoKey(Map::TopKProfileThreshold)
+
+      .Define({"--abort-on-hard-verifier-error", "--no-abort-on-hard-verifier-error"})
+          .WithValues({true, false})
+          .IntoKey(Map::AbortOnHardVerifierFailure)
+      .Define({"--abort-on-soft-verifier-error", "--no-abort-on-soft-verifier-error"})
+          .WithValues({true, false})
+          .IntoKey(Map::AbortOnSoftVerifierFailure)
+
+      .Define("--dump-init-failures=_")
+          .template WithType<std::string>()
+          .IntoKey(Map::DumpInitFailures)
+
+      .Define("--dump-cfg=_")
+          .template WithType<std::string>()
+          .IntoKey(Map::DumpCFG)
+      .Define("--dump-cfg-append")
+          .IntoKey(Map::DumpCFGAppend)
+
+      .Define("--register-allocation-strategy=_")
+          .template WithType<std::string>()
+          .IntoKey(Map::RegisterAllocationStrategy)
+
+      .Define("--verbose-methods=_")
+          .template WithType<ParseStringList<','>>()
+          .IntoKey(Map::VerboseMethods);
+}
+
+#pragma GCC diagnostic pop
+
+}  // namespace art
+
+#endif  // ART_COMPILER_DRIVER_COMPILER_OPTIONS_MAP_INL_H_
diff --git a/compiler/driver/compiler_options_map-storage.h b/compiler/driver/compiler_options_map-storage.h
new file mode 100644
index 0000000..01f32e0
--- /dev/null
+++ b/compiler/driver/compiler_options_map-storage.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef ART_COMPILER_DRIVER_COMPILER_OPTIONS_MAP_STORAGE_H_
+#define ART_COMPILER_DRIVER_COMPILER_OPTIONS_MAP_STORAGE_H_
+
+// Assumes:
+// * #include "compiler_options_map.h"
+// * namespace art
+//
+// Usage:
+// #define COMPILER_OPTIONS_MAP_TYPE TheTypeOfTheMap
+// #define COMPILER_OPTIONS_MAP_KEY_TYPE TheTypeOfTheMapsKey
+// #include "driver/compiler_options_map-storage.h
+
+#ifndef COMPILER_OPTIONS_MAP_TYPE
+#error "Expected COMPILER_OPTIONS_MAP_TYPE"
+#endif
+
+#ifndef COMPILER_OPTIONS_MAP_KEY_TYPE
+#error "Expected COMPILER_OPTIONS_MAP_KEY_TYPE"
+#endif
+
+#define COMPILER_OPTIONS_KEY(Type, Name, ...) \
+  template <typename Base, template <typename TV> class KeyType> \
+  const KeyType<Type> CompilerOptionsMap<Base, KeyType>::Name {__VA_ARGS__};
+#include <driver/compiler_options_map.def>
+
+template struct CompilerOptionsMap<COMPILER_OPTIONS_MAP_TYPE, COMPILER_OPTIONS_MAP_KEY_TYPE>;
+
+#undef COMPILER_OPTIONS_MAP_TYPE
+#undef COMPILER_OPTIONS_MAP_KEY_TYPE
+
+#endif  // ART_COMPILER_DRIVER_COMPILER_OPTIONS_MAP_STORAGE_H_
+#undef ART_COMPILER_DRIVER_COMPILER_OPTIONS_MAP_STORAGE_H_  // Guard is only for cpplint
diff --git a/compiler/driver/compiler_options_map.def b/compiler/driver/compiler_options_map.def
new file mode 100644
index 0000000..acddae7
--- /dev/null
+++ b/compiler/driver/compiler_options_map.def
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef COMPILER_OPTIONS_KEY
+#error "Please #define COMPILER_OPTIONS_KEY before #including this file"
+#define COMPILER_OPTIONS_KEY(...)  // Don't display errors in this file in IDEs.
+#endif
+
+// This file defines the list of keys for CompilerOptionsMap.
+// These can be used with CompilerOptionsMap.Get/Set/etc, once that template class has been
+// instantiated.
+//
+// Column Descriptions:
+//                    <<Type>>                     <<Key Name>>                  (<<Default Value>>)
+//
+// Default values are only used by Map::GetOrDefault(K<T>).
+// If a default value is omitted here, T{} is used as the default value, which is
+// almost-always the value of the type as if it was memset to all 0.
+//
+// Please keep the columns aligned if possible when adding new rows.
+//
+
+// Parse-able keys from the command line.
+
+// TODO: Add type parser.
+COMPILER_OPTIONS_KEY (std::string,                 CompilerFilter)
+COMPILER_OPTIONS_KEY (Unit,                        PIC)
+COMPILER_OPTIONS_KEY (unsigned int,                HugeMethodMaxThreshold)
+COMPILER_OPTIONS_KEY (unsigned int,                LargeMethodMaxThreshold)
+COMPILER_OPTIONS_KEY (unsigned int,                SmallMethodMaxThreshold)
+COMPILER_OPTIONS_KEY (unsigned int,                TinyMethodMaxThreshold)
+COMPILER_OPTIONS_KEY (unsigned int,                NumDexMethodsThreshold)
+COMPILER_OPTIONS_KEY (unsigned int,                InlineMaxCodeUnitsThreshold)
+COMPILER_OPTIONS_KEY (bool,                        GenerateDebugInfo)
+COMPILER_OPTIONS_KEY (bool,                        GenerateMiniDebugInfo)
+COMPILER_OPTIONS_KEY (bool,                        GenerateBuildID)
+COMPILER_OPTIONS_KEY (Unit,                        Debuggable)
+COMPILER_OPTIONS_KEY (double,                      TopKProfileThreshold)
+COMPILER_OPTIONS_KEY (bool,                        AbortOnHardVerifierFailure)
+COMPILER_OPTIONS_KEY (bool,                        AbortOnSoftVerifierFailure)
+COMPILER_OPTIONS_KEY (std::string,                 DumpInitFailures)
+COMPILER_OPTIONS_KEY (std::string,                 DumpCFG)
+COMPILER_OPTIONS_KEY (Unit,                        DumpCFGAppend)
+// TODO: Add type parser.
+COMPILER_OPTIONS_KEY (std::string,                 RegisterAllocationStrategy)
+COMPILER_OPTIONS_KEY (ParseStringList<','>,        VerboseMethods)
+COMPILER_OPTIONS_KEY (bool,                        DeduplicateCode,        true)
+COMPILER_OPTIONS_KEY (Unit,                        CountHotnessInCompiledCode)
+COMPILER_OPTIONS_KEY (Unit,                        DumpTimings)
+COMPILER_OPTIONS_KEY (Unit,                        DumpStats)
+
+#undef COMPILER_OPTIONS_KEY
diff --git a/compiler/driver/compiler_options_map.h b/compiler/driver/compiler_options_map.h
new file mode 100644
index 0000000..b9bc8b6
--- /dev/null
+++ b/compiler/driver/compiler_options_map.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef ART_COMPILER_DRIVER_COMPILER_OPTIONS_MAP_H_
+#define ART_COMPILER_DRIVER_COMPILER_OPTIONS_MAP_H_
+
+#include <string>
+#include <vector>
+
+#include "base/variant_map.h"
+#include "cmdline_types.h"
+
+namespace art {
+
+// Defines a type-safe heterogeneous key->value map. This is to be used as the base for
+// an extended map.
+template <typename Base, template <typename TV> class KeyType>
+struct CompilerOptionsMap : VariantMap<Base, KeyType> {
+  // Make the next many usages of Key slightly shorter to type.
+  template <typename TValue>
+  using Key = KeyType<TValue>;
+
+  // List of key declarations, shorthand for 'static const Key<T> Name'
+#define COMPILER_OPTIONS_KEY(Type, Name, ...) static const Key<Type> (Name);
+#include "compiler_options_map.def"
+};
+
+#undef DECLARE_KEY
+
+}  // namespace art
+
+#endif  // ART_COMPILER_DRIVER_COMPILER_OPTIONS_MAP_H_
diff --git a/compiler/driver/dex_compilation_unit.cc b/compiler/driver/dex_compilation_unit.cc
index 7e8e812..c90c37d 100644
--- a/compiler/driver/dex_compilation_unit.cc
+++ b/compiler/driver/dex_compilation_unit.cc
@@ -16,8 +16,10 @@
 
 #include "dex_compilation_unit.h"
 
+#include "base/utils.h"
+#include "dex/code_item_accessors-inl.h"
+#include "dex/descriptors_names.h"
 #include "mirror/dex_cache.h"
-#include "utils.h"
 
 namespace art {
 
@@ -38,8 +40,8 @@
       dex_method_idx_(method_idx),
       access_flags_(access_flags),
       verified_method_(verified_method),
-      dex_cache_(dex_cache) {
-}
+      dex_cache_(dex_cache),
+      code_item_accessor_(dex_file, code_item) {}
 
 const std::string& DexCompilationUnit::GetSymbol() {
   if (symbol_.empty()) {
diff --git a/compiler/driver/dex_compilation_unit.h b/compiler/driver/dex_compilation_unit.h
index 24a9a5b..c1ae3c9 100644
--- a/compiler/driver/dex_compilation_unit.h
+++ b/compiler/driver/dex_compilation_unit.h
@@ -20,7 +20,8 @@
 #include <stdint.h>
 
 #include "base/arena_object.h"
-#include "dex_file.h"
+#include "dex/code_item_accessors.h"
+#include "dex/dex_file.h"
 #include "handle.h"
 #include "jni.h"
 
@@ -112,6 +113,10 @@
     return dex_cache_;
   }
 
+  const CodeItemDataAccessor& GetCodeItemAccessor() const {
+    return code_item_accessor_;
+  }
+
  private:
   const Handle<mirror::ClassLoader> class_loader_;
 
@@ -127,6 +132,8 @@
 
   const Handle<mirror::DexCache> dex_cache_;
 
+  const CodeItemDataAccessor code_item_accessor_;
+
   std::string symbol_;
 };
 
diff --git a/compiler/driver/simple_compiler_options_map.h b/compiler/driver/simple_compiler_options_map.h
new file mode 100644
index 0000000..3860da9
--- /dev/null
+++ b/compiler/driver/simple_compiler_options_map.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+// This file declares a completion of the CompilerOptionsMap and should be included into a
+// .cc file, only.
+
+#ifndef ART_COMPILER_DRIVER_SIMPLE_COMPILER_OPTIONS_MAP_H_
+#define ART_COMPILER_DRIVER_SIMPLE_COMPILER_OPTIONS_MAP_H_
+
+#include <memory>
+
+#include "compiler_options_map-inl.h"
+#include "base/variant_map.h"
+
+namespace art {
+
+template <typename TValue>
+struct SimpleParseArgumentMapKey : VariantMapKey<TValue> {
+  SimpleParseArgumentMapKey() {}
+  explicit SimpleParseArgumentMapKey(TValue default_value)
+      : VariantMapKey<TValue>(std::move(default_value)) {}
+  // Don't ODR-use constexpr default values, which means that Struct::Fields
+  // that are declared 'static constexpr T Name = Value' don't need to have a matching definition.
+};
+
+struct SimpleParseArgumentMap : CompilerOptionsMap<SimpleParseArgumentMap,
+                                                   SimpleParseArgumentMapKey> {
+  // This 'using' line is necessary to inherit the variadic constructor.
+  using CompilerOptionsMap<SimpleParseArgumentMap, SimpleParseArgumentMapKey>::CompilerOptionsMap;
+};
+
+#define COMPILER_OPTIONS_MAP_TYPE SimpleParseArgumentMap
+#define COMPILER_OPTIONS_MAP_KEY_TYPE SimpleParseArgumentMapKey
+#include "compiler_options_map-storage.h"
+
+using Parser = CmdlineParser<SimpleParseArgumentMap, SimpleParseArgumentMapKey>;
+
+static inline Parser CreateSimpleParser(bool ignore_unrecognized) {
+  std::unique_ptr<Parser::Builder> parser_builder =
+      std::unique_ptr<Parser::Builder>(new Parser::Builder());
+
+  AddCompilerOptionsArgumentParserOptions<SimpleParseArgumentMap>(*parser_builder);
+
+  parser_builder->IgnoreUnrecognized(ignore_unrecognized);
+
+  return parser_builder->Build();
+}
+
+}  // namespace art
+
+#endif  // ART_COMPILER_DRIVER_SIMPLE_COMPILER_OPTIONS_MAP_H_
diff --git a/compiler/elf_builder.h b/compiler/elf_builder.h
deleted file mode 100644
index 2ef9fa1..0000000
--- a/compiler/elf_builder.h
+++ /dev/null
@@ -1,1026 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-#ifndef ART_COMPILER_ELF_BUILDER_H_
-#define ART_COMPILER_ELF_BUILDER_H_
-
-#include <vector>
-
-#include "arch/instruction_set.h"
-#include "arch/mips/instruction_set_features_mips.h"
-#include "base/array_ref.h"
-#include "base/bit_utils.h"
-#include "base/casts.h"
-#include "base/unix_file/fd_file.h"
-#include "elf_utils.h"
-#include "leb128.h"
-#include "linker/error_delaying_output_stream.h"
-
-namespace art {
-
-// Writes ELF file.
-//
-// The basic layout of the elf file:
-//   Elf_Ehdr                    - The ELF header.
-//   Elf_Phdr[]                  - Program headers for the linker.
-//   .note.gnu.build-id          - Optional build ID section (SHA-1 digest).
-//   .rodata                     - DEX files and oat metadata.
-//   .text                       - Compiled code.
-//   .bss                        - Zero-initialized writeable section.
-//   .MIPS.abiflags              - MIPS specific section.
-//   .dynstr                     - Names for .dynsym.
-//   .dynsym                     - A few oat-specific dynamic symbols.
-//   .hash                       - Hash-table for .dynsym.
-//   .dynamic                    - Tags which let the linker locate .dynsym.
-//   .strtab                     - Names for .symtab.
-//   .symtab                     - Debug symbols.
-//   .eh_frame                   - Unwind information (CFI).
-//   .eh_frame_hdr               - Index of .eh_frame.
-//   .debug_frame                - Unwind information (CFI).
-//   .debug_frame.oat_patches    - Addresses for relocation.
-//   .debug_info                 - Debug information.
-//   .debug_info.oat_patches     - Addresses for relocation.
-//   .debug_abbrev               - Decoding information for .debug_info.
-//   .debug_str                  - Strings for .debug_info.
-//   .debug_line                 - Line number tables.
-//   .debug_line.oat_patches     - Addresses for relocation.
-//   .text.oat_patches           - Addresses for relocation.
-//   .shstrtab                   - Names of ELF sections.
-//   Elf_Shdr[]                  - Section headers.
-//
-// Some section are optional (the debug sections in particular).
-//
-// We try write the section data directly into the file without much
-// in-memory buffering.  This means we generally write sections based on the
-// dependency order (e.g. .dynamic points to .dynsym which points to .text).
-//
-// In the cases where we need to buffer, we write the larger section first
-// and buffer the smaller one (e.g. .strtab is bigger than .symtab).
-//
-// The debug sections are written last for easier stripping.
-//
-template <typename ElfTypes>
-class ElfBuilder FINAL {
- public:
-  static constexpr size_t kMaxProgramHeaders = 16;
-  // SHA-1 digest.  Not using SHA_DIGEST_LENGTH from openssl/sha.h to avoid
-  // spreading this header dependency for just this single constant.
-  static constexpr size_t kBuildIdLen = 20;
-
-  using Elf_Addr = typename ElfTypes::Addr;
-  using Elf_Off = typename ElfTypes::Off;
-  using Elf_Word = typename ElfTypes::Word;
-  using Elf_Sword = typename ElfTypes::Sword;
-  using Elf_Ehdr = typename ElfTypes::Ehdr;
-  using Elf_Shdr = typename ElfTypes::Shdr;
-  using Elf_Sym = typename ElfTypes::Sym;
-  using Elf_Phdr = typename ElfTypes::Phdr;
-  using Elf_Dyn = typename ElfTypes::Dyn;
-
-  // Base class of all sections.
-  class Section : public OutputStream {
-   public:
-    Section(ElfBuilder<ElfTypes>* owner,
-            const std::string& name,
-            Elf_Word type,
-            Elf_Word flags,
-            const Section* link,
-            Elf_Word info,
-            Elf_Word align,
-            Elf_Word entsize)
-        : OutputStream(name),
-          owner_(owner),
-          header_(),
-          section_index_(0),
-          name_(name),
-          link_(link),
-          started_(false),
-          finished_(false),
-          phdr_flags_(PF_R),
-          phdr_type_(0) {
-      DCHECK_GE(align, 1u);
-      header_.sh_type = type;
-      header_.sh_flags = flags;
-      header_.sh_info = info;
-      header_.sh_addralign = align;
-      header_.sh_entsize = entsize;
-    }
-
-    // Start writing of this section.
-    void Start() {
-      CHECK(!started_);
-      CHECK(!finished_);
-      started_ = true;
-      auto& sections = owner_->sections_;
-      // Check that the previous section is complete.
-      CHECK(sections.empty() || sections.back()->finished_);
-      // The first ELF section index is 1. Index 0 is reserved for NULL.
-      section_index_ = sections.size() + 1;
-      // Page-align if we switch between allocated and non-allocated sections,
-      // or if we change the type of allocation (e.g. executable vs non-executable).
-      if (!sections.empty()) {
-        if (header_.sh_flags != sections.back()->header_.sh_flags) {
-          header_.sh_addralign = kPageSize;
-        }
-      }
-      // Align file position.
-      if (header_.sh_type != SHT_NOBITS) {
-        header_.sh_offset = owner_->AlignFileOffset(header_.sh_addralign);
-      } else {
-        header_.sh_offset = 0;
-      }
-      // Align virtual memory address.
-      if ((header_.sh_flags & SHF_ALLOC) != 0) {
-        header_.sh_addr = owner_->AlignVirtualAddress(header_.sh_addralign);
-      } else {
-        header_.sh_addr = 0;
-      }
-      // Push this section on the list of written sections.
-      sections.push_back(this);
-    }
-
-    // Finish writing of this section.
-    void End() {
-      CHECK(started_);
-      CHECK(!finished_);
-      finished_ = true;
-      if (header_.sh_type == SHT_NOBITS) {
-        CHECK_GT(header_.sh_size, 0u);
-      } else {
-        // Use the current file position to determine section size.
-        off_t file_offset = owner_->stream_.Seek(0, kSeekCurrent);
-        CHECK_GE(file_offset, (off_t)header_.sh_offset);
-        header_.sh_size = file_offset - header_.sh_offset;
-      }
-      if ((header_.sh_flags & SHF_ALLOC) != 0) {
-        owner_->virtual_address_ += header_.sh_size;
-      }
-    }
-
-    // Get the location of this section in virtual memory.
-    Elf_Addr GetAddress() const {
-      CHECK(started_);
-      return header_.sh_addr;
-    }
-
-    // Returns the size of the content of this section.
-    Elf_Word GetSize() const {
-      if (finished_) {
-        return header_.sh_size;
-      } else {
-        CHECK(started_);
-        CHECK_NE(header_.sh_type, (Elf_Word)SHT_NOBITS);
-        return owner_->stream_.Seek(0, kSeekCurrent) - header_.sh_offset;
-      }
-    }
-
-    // Write this section as "NOBITS" section. (used for the .bss section)
-    // This means that the ELF file does not contain the initial data for this section
-    // and it will be zero-initialized when the ELF file is loaded in the running program.
-    void WriteNoBitsSection(Elf_Word size) {
-      DCHECK_NE(header_.sh_flags & SHF_ALLOC, 0u);
-      header_.sh_type = SHT_NOBITS;
-      Start();
-      header_.sh_size = size;
-      End();
-    }
-
-    // This function always succeeds to simplify code.
-    // Use builder's Good() to check the actual status.
-    bool WriteFully(const void* buffer, size_t byte_count) OVERRIDE {
-      CHECK(started_);
-      CHECK(!finished_);
-      return owner_->stream_.WriteFully(buffer, byte_count);
-    }
-
-    // This function always succeeds to simplify code.
-    // Use builder's Good() to check the actual status.
-    off_t Seek(off_t offset, Whence whence) OVERRIDE {
-      // Forward the seek as-is and trust the caller to use it reasonably.
-      return owner_->stream_.Seek(offset, whence);
-    }
-
-    // This function flushes the output and returns whether it succeeded.
-    // If there was a previous failure, this does nothing and returns false, i.e. failed.
-    bool Flush() OVERRIDE {
-      return owner_->stream_.Flush();
-    }
-
-    Elf_Word GetSectionIndex() const {
-      DCHECK(started_);
-      DCHECK_NE(section_index_, 0u);
-      return section_index_;
-    }
-
-   private:
-    ElfBuilder<ElfTypes>* owner_;
-    Elf_Shdr header_;
-    Elf_Word section_index_;
-    const std::string name_;
-    const Section* const link_;
-    bool started_;
-    bool finished_;
-    Elf_Word phdr_flags_;
-    Elf_Word phdr_type_;
-
-    friend class ElfBuilder;
-
-    DISALLOW_COPY_AND_ASSIGN(Section);
-  };
-
-  class CachedSection : public Section {
-   public:
-    CachedSection(ElfBuilder<ElfTypes>* owner,
-                  const std::string& name,
-                  Elf_Word type,
-                  Elf_Word flags,
-                  const Section* link,
-                  Elf_Word info,
-                  Elf_Word align,
-                  Elf_Word entsize)
-        : Section(owner, name, type, flags, link, info, align, entsize), cache_() { }
-
-    Elf_Word Add(const void* data, size_t length) {
-      Elf_Word offset = cache_.size();
-      const uint8_t* d = reinterpret_cast<const uint8_t*>(data);
-      cache_.insert(cache_.end(), d, d + length);
-      return offset;
-    }
-
-    Elf_Word GetCacheSize() {
-      return cache_.size();
-    }
-
-    void Write() {
-      this->WriteFully(cache_.data(), cache_.size());
-      cache_.clear();
-      cache_.shrink_to_fit();
-    }
-
-    void WriteCachedSection() {
-      this->Start();
-      Write();
-      this->End();
-    }
-
-   private:
-    std::vector<uint8_t> cache_;
-  };
-
-  // Writer of .dynstr section.
-  class CachedStringSection FINAL : public CachedSection {
-   public:
-    CachedStringSection(ElfBuilder<ElfTypes>* owner,
-                        const std::string& name,
-                        Elf_Word flags,
-                        Elf_Word align)
-        : CachedSection(owner,
-                        name,
-                        SHT_STRTAB,
-                        flags,
-                        /* link */ nullptr,
-                        /* info */ 0,
-                        align,
-                        /* entsize */ 0) { }
-
-    Elf_Word Add(const std::string& name) {
-      if (CachedSection::GetCacheSize() == 0u) {
-        DCHECK(name.empty());
-      }
-      return CachedSection::Add(name.c_str(), name.length() + 1);
-    }
-  };
-
-  // Writer of .strtab and .shstrtab sections.
-  class StringSection FINAL : public Section {
-   public:
-    StringSection(ElfBuilder<ElfTypes>* owner,
-                  const std::string& name,
-                  Elf_Word flags,
-                  Elf_Word align)
-        : Section(owner,
-                  name,
-                  SHT_STRTAB,
-                  flags,
-                  /* link */ nullptr,
-                  /* info */ 0,
-                  align,
-                  /* entsize */ 0),
-          current_offset_(0) {
-    }
-
-    Elf_Word Write(const std::string& name) {
-      if (current_offset_ == 0) {
-        DCHECK(name.empty());
-      }
-      Elf_Word offset = current_offset_;
-      this->WriteFully(name.c_str(), name.length() + 1);
-      current_offset_ += name.length() + 1;
-      return offset;
-    }
-
-   private:
-    Elf_Word current_offset_;
-  };
-
-  // Writer of .dynsym and .symtab sections.
-  class SymbolSection FINAL : public CachedSection {
-   public:
-    SymbolSection(ElfBuilder<ElfTypes>* owner,
-                  const std::string& name,
-                  Elf_Word type,
-                  Elf_Word flags,
-                  Section* strtab)
-        : CachedSection(owner,
-                        name,
-                        type,
-                        flags,
-                        strtab,
-                        /* info */ 0,
-                        sizeof(Elf_Off),
-                        sizeof(Elf_Sym)) {
-      // The symbol table always has to start with NULL symbol.
-      Elf_Sym null_symbol = Elf_Sym();
-      CachedSection::Add(&null_symbol, sizeof(null_symbol));
-    }
-
-    // Buffer symbol for this section.  It will be written later.
-    // If the symbol's section is null, it will be considered absolute (SHN_ABS).
-    // (we use this in JIT to reference code which is stored outside the debug ELF file)
-    void Add(Elf_Word name,
-             const Section* section,
-             Elf_Addr addr,
-             Elf_Word size,
-             uint8_t binding,
-             uint8_t type) {
-      Elf_Word section_index;
-      if (section != nullptr) {
-        DCHECK_LE(section->GetAddress(), addr);
-        DCHECK_LE(addr, section->GetAddress() + section->GetSize());
-        section_index = section->GetSectionIndex();
-      } else {
-        section_index = static_cast<Elf_Word>(SHN_ABS);
-      }
-      Add(name, section_index, addr, size, binding, type);
-    }
-
-    void Add(Elf_Word name,
-             Elf_Word section_index,
-             Elf_Addr addr,
-             Elf_Word size,
-             uint8_t binding,
-             uint8_t type) {
-      Elf_Sym sym = Elf_Sym();
-      sym.st_name = name;
-      sym.st_value = addr;
-      sym.st_size = size;
-      sym.st_other = 0;
-      sym.st_shndx = section_index;
-      sym.st_info = (binding << 4) + (type & 0xf);
-      CachedSection::Add(&sym, sizeof(sym));
-    }
-  };
-
-  class AbiflagsSection FINAL : public Section {
-   public:
-    // Section with Mips abiflag info.
-    static constexpr uint8_t MIPS_AFL_REG_NONE =         0;  // no registers
-    static constexpr uint8_t MIPS_AFL_REG_32 =           1;  // 32-bit registers
-    static constexpr uint8_t MIPS_AFL_REG_64 =           2;  // 64-bit registers
-    static constexpr uint32_t MIPS_AFL_FLAGS1_ODDSPREG = 1;  // Uses odd single-prec fp regs
-    static constexpr uint8_t MIPS_ABI_FP_DOUBLE =        1;  // -mdouble-float
-    static constexpr uint8_t MIPS_ABI_FP_XX =            5;  // -mfpxx
-    static constexpr uint8_t MIPS_ABI_FP_64A =           7;  // -mips32r* -mfp64 -mno-odd-spreg
-
-    AbiflagsSection(ElfBuilder<ElfTypes>* owner,
-                    const std::string& name,
-                    Elf_Word type,
-                    Elf_Word flags,
-                    const Section* link,
-                    Elf_Word info,
-                    Elf_Word align,
-                    Elf_Word entsize,
-                    InstructionSet isa,
-                    const InstructionSetFeatures* features)
-        : Section(owner, name, type, flags, link, info, align, entsize) {
-      if (isa == kMips || isa == kMips64) {
-        bool fpu32 = false;    // assume mips64 values
-        uint8_t isa_rev = 6;   // assume mips64 values
-        if (isa == kMips) {
-          // adjust for mips32 values
-          fpu32 = features->AsMipsInstructionSetFeatures()->Is32BitFloatingPoint();
-          isa_rev = features->AsMipsInstructionSetFeatures()->IsR6()
-              ? 6
-              : features->AsMipsInstructionSetFeatures()->IsMipsIsaRevGreaterThanEqual2()
-                  ? (fpu32 ? 2 : 5)
-                  : 1;
-        }
-        abiflags_.version = 0;  // version of flags structure
-        abiflags_.isa_level = (isa == kMips) ? 32 : 64;
-        abiflags_.isa_rev = isa_rev;
-        abiflags_.gpr_size = (isa == kMips) ? MIPS_AFL_REG_32 : MIPS_AFL_REG_64;
-        abiflags_.cpr1_size = fpu32 ? MIPS_AFL_REG_32 : MIPS_AFL_REG_64;
-        abiflags_.cpr2_size = MIPS_AFL_REG_NONE;
-        // Set the fp_abi to MIPS_ABI_FP_64A for mips32 with 64-bit FPUs (ie: mips32 R5 and R6).
-        // Otherwise set to MIPS_ABI_FP_DOUBLE.
-        abiflags_.fp_abi = (isa == kMips && !fpu32) ? MIPS_ABI_FP_64A : MIPS_ABI_FP_DOUBLE;
-        abiflags_.isa_ext = 0;
-        abiflags_.ases = 0;
-        // To keep the code simple, we are not using odd FP reg for single floats for both
-        // mips32 and mips64 ART. Therefore we are not setting the MIPS_AFL_FLAGS1_ODDSPREG bit.
-        abiflags_.flags1 = 0;
-        abiflags_.flags2 = 0;
-      }
-    }
-
-    Elf_Word GetSize() const {
-      return sizeof(abiflags_);
-    }
-
-    void Write() {
-      this->WriteFully(&abiflags_, sizeof(abiflags_));
-    }
-
-   private:
-    struct {
-      uint16_t version;  // version of this structure
-      uint8_t  isa_level, isa_rev, gpr_size, cpr1_size, cpr2_size;
-      uint8_t  fp_abi;
-      uint32_t isa_ext, ases, flags1, flags2;
-    } abiflags_;
-  };
-
-  class BuildIdSection FINAL : public Section {
-   public:
-    BuildIdSection(ElfBuilder<ElfTypes>* owner,
-                   const std::string& name,
-                   Elf_Word type,
-                   Elf_Word flags,
-                   const Section* link,
-                   Elf_Word info,
-                   Elf_Word align,
-                   Elf_Word entsize)
-        : Section(owner, name, type, flags, link, info, align, entsize),
-          digest_start_(-1) {
-    }
-
-    void Write() {
-      // The size fields are 32-bit on both 32-bit and 64-bit systems, confirmed
-      // with the 64-bit linker and libbfd code. The size of name and desc must
-      // be a multiple of 4 and it currently is.
-      this->WriteUint32(4);  // namesz.
-      this->WriteUint32(kBuildIdLen);  // descsz.
-      this->WriteUint32(3);  // type = NT_GNU_BUILD_ID.
-      this->WriteFully("GNU", 4);  // name.
-      digest_start_ = this->Seek(0, kSeekCurrent);
-      static_assert(kBuildIdLen % 4 == 0, "expecting a mutliple of 4 for build ID length");
-      this->WriteFully(std::string(kBuildIdLen, '\0').c_str(), kBuildIdLen);  // desc.
-    }
-
-    off_t GetDigestStart() {
-      CHECK_GT(digest_start_, 0);
-      return digest_start_;
-    }
-
-   private:
-    bool WriteUint32(uint32_t v) {
-      return this->WriteFully(&v, sizeof(v));
-    }
-
-    // File offset where the build ID digest starts.
-    // Populated with zeros first, then updated with the actual value as the
-    // very last thing in the output file creation.
-    off_t digest_start_;
-  };
-
-  ElfBuilder(InstructionSet isa, const InstructionSetFeatures* features, OutputStream* output)
-      : isa_(isa),
-        features_(features),
-        stream_(output),
-        rodata_(this, ".rodata", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0),
-        text_(this, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, nullptr, 0, kPageSize, 0),
-        bss_(this, ".bss", SHT_NOBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0),
-        dynstr_(this, ".dynstr", SHF_ALLOC, kPageSize),
-        dynsym_(this, ".dynsym", SHT_DYNSYM, SHF_ALLOC, &dynstr_),
-        hash_(this, ".hash", SHT_HASH, SHF_ALLOC, &dynsym_, 0, sizeof(Elf_Word), sizeof(Elf_Word)),
-        dynamic_(this, ".dynamic", SHT_DYNAMIC, SHF_ALLOC, &dynstr_, 0, kPageSize, sizeof(Elf_Dyn)),
-        eh_frame_(this, ".eh_frame", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0),
-        eh_frame_hdr_(this, ".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, 4, 0),
-        strtab_(this, ".strtab", 0, 1),
-        symtab_(this, ".symtab", SHT_SYMTAB, 0, &strtab_),
-        debug_frame_(this, ".debug_frame", SHT_PROGBITS, 0, nullptr, 0, sizeof(Elf_Addr), 0),
-        debug_info_(this, ".debug_info", SHT_PROGBITS, 0, nullptr, 0, 1, 0),
-        debug_line_(this, ".debug_line", SHT_PROGBITS, 0, nullptr, 0, 1, 0),
-        shstrtab_(this, ".shstrtab", 0, 1),
-        abiflags_(this, ".MIPS.abiflags", SHT_MIPS_ABIFLAGS, SHF_ALLOC, nullptr, 0, kPageSize, 0,
-                  isa, features),
-        build_id_(this, ".note.gnu.build-id", SHT_NOTE, SHF_ALLOC, nullptr, 0, 4, 0),
-        started_(false),
-        write_program_headers_(false),
-        loaded_size_(0u),
-        virtual_address_(0) {
-    text_.phdr_flags_ = PF_R | PF_X;
-    bss_.phdr_flags_ = PF_R | PF_W;
-    dynamic_.phdr_flags_ = PF_R | PF_W;
-    dynamic_.phdr_type_ = PT_DYNAMIC;
-    eh_frame_hdr_.phdr_type_ = PT_GNU_EH_FRAME;
-    abiflags_.phdr_type_ = PT_MIPS_ABIFLAGS;
-    build_id_.phdr_type_ = PT_NOTE;
-  }
-  ~ElfBuilder() {}
-
-  InstructionSet GetIsa() { return isa_; }
-  Section* GetRoData() { return &rodata_; }
-  Section* GetText() { return &text_; }
-  Section* GetBss() { return &bss_; }
-  StringSection* GetStrTab() { return &strtab_; }
-  SymbolSection* GetSymTab() { return &symtab_; }
-  Section* GetEhFrame() { return &eh_frame_; }
-  Section* GetEhFrameHdr() { return &eh_frame_hdr_; }
-  Section* GetDebugFrame() { return &debug_frame_; }
-  Section* GetDebugInfo() { return &debug_info_; }
-  Section* GetDebugLine() { return &debug_line_; }
-
-  // Encode patch locations as LEB128 list of deltas between consecutive addresses.
-  // (exposed publicly for tests)
-  static void EncodeOatPatches(const ArrayRef<const uintptr_t>& locations,
-                               std::vector<uint8_t>* buffer) {
-    buffer->reserve(buffer->size() + locations.size() * 2);  // guess 2 bytes per ULEB128.
-    uintptr_t address = 0;  // relative to start of section.
-    for (uintptr_t location : locations) {
-      DCHECK_GE(location, address) << "Patch locations are not in sorted order";
-      EncodeUnsignedLeb128(buffer, dchecked_integral_cast<uint32_t>(location - address));
-      address = location;
-    }
-  }
-
-  void WritePatches(const char* name, const ArrayRef<const uintptr_t>& patch_locations) {
-    std::vector<uint8_t> buffer;
-    EncodeOatPatches(patch_locations, &buffer);
-    std::unique_ptr<Section> s(new Section(this, name, SHT_OAT_PATCH, 0, nullptr, 0, 1, 0));
-    s->Start();
-    s->WriteFully(buffer.data(), buffer.size());
-    s->End();
-    other_sections_.push_back(std::move(s));
-  }
-
-  void WriteSection(const char* name, const std::vector<uint8_t>* buffer) {
-    std::unique_ptr<Section> s(new Section(this, name, SHT_PROGBITS, 0, nullptr, 0, 1, 0));
-    s->Start();
-    s->WriteFully(buffer->data(), buffer->size());
-    s->End();
-    other_sections_.push_back(std::move(s));
-  }
-
-  // Reserve space for ELF header and program headers.
-  // We do not know the number of headers until later, so
-  // it is easiest to just reserve a fixed amount of space.
-  // Program headers are required for loading by the linker.
-  // It is possible to omit them for ELF files used for debugging.
-  void Start(bool write_program_headers = true) {
-    int size = sizeof(Elf_Ehdr);
-    if (write_program_headers) {
-      size += sizeof(Elf_Phdr) * kMaxProgramHeaders;
-    }
-    stream_.Seek(size, kSeekSet);
-    started_ = true;
-    virtual_address_ += size;
-    write_program_headers_ = write_program_headers;
-  }
-
-  void End() {
-    DCHECK(started_);
-
-    // Note: loaded_size_ == 0 for tests that don't write .rodata, .text, .bss,
-    // .dynstr, dynsym, .hash and .dynamic. These tests should not read loaded_size_.
-    // TODO: Either refactor the .eh_frame creation so that it counts towards loaded_size_,
-    // or remove all support for .eh_frame. (The currently unused .eh_frame counts towards
-    // the virtual_address_ but we don't consider it for loaded_size_.)
-    CHECK(loaded_size_ == 0 || loaded_size_ == RoundUp(virtual_address_, kPageSize))
-        << loaded_size_ << " " << virtual_address_;
-
-    // Write section names and finish the section headers.
-    shstrtab_.Start();
-    shstrtab_.Write("");
-    for (auto* section : sections_) {
-      section->header_.sh_name = shstrtab_.Write(section->name_);
-      if (section->link_ != nullptr) {
-        section->header_.sh_link = section->link_->GetSectionIndex();
-      }
-    }
-    shstrtab_.End();
-
-    // Write section headers at the end of the ELF file.
-    std::vector<Elf_Shdr> shdrs;
-    shdrs.reserve(1u + sections_.size());
-    shdrs.push_back(Elf_Shdr());  // NULL at index 0.
-    for (auto* section : sections_) {
-      shdrs.push_back(section->header_);
-    }
-    Elf_Off section_headers_offset;
-    section_headers_offset = AlignFileOffset(sizeof(Elf_Off));
-    stream_.WriteFully(shdrs.data(), shdrs.size() * sizeof(shdrs[0]));
-
-    // Flush everything else before writing the program headers. This should prevent
-    // the OS from reordering writes, so that we don't end up with valid headers
-    // and partially written data if we suddenly lose power, for example.
-    stream_.Flush();
-
-    // The main ELF header.
-    Elf_Ehdr elf_header = MakeElfHeader(isa_, features_);
-    elf_header.e_shoff = section_headers_offset;
-    elf_header.e_shnum = shdrs.size();
-    elf_header.e_shstrndx = shstrtab_.GetSectionIndex();
-
-    // Program headers (i.e. mmap instructions).
-    std::vector<Elf_Phdr> phdrs;
-    if (write_program_headers_) {
-      phdrs = MakeProgramHeaders();
-      CHECK_LE(phdrs.size(), kMaxProgramHeaders);
-      elf_header.e_phoff = sizeof(Elf_Ehdr);
-      elf_header.e_phnum = phdrs.size();
-    }
-
-    stream_.Seek(0, kSeekSet);
-    stream_.WriteFully(&elf_header, sizeof(elf_header));
-    stream_.WriteFully(phdrs.data(), phdrs.size() * sizeof(phdrs[0]));
-    stream_.Flush();
-  }
-
-  // The running program does not have access to section headers
-  // and the loader is not supposed to use them either.
-  // The dynamic sections therefore replicates some of the layout
-  // information like the address and size of .rodata and .text.
-  // It also contains other metadata like the SONAME.
-  // The .dynamic section is found using the PT_DYNAMIC program header.
-  void PrepareDynamicSection(const std::string& elf_file_path,
-                             Elf_Word rodata_size,
-                             Elf_Word text_size,
-                             Elf_Word bss_size,
-                             Elf_Word bss_methods_offset,
-                             Elf_Word bss_roots_offset) {
-    std::string soname(elf_file_path);
-    size_t directory_separator_pos = soname.rfind('/');
-    if (directory_separator_pos != std::string::npos) {
-      soname = soname.substr(directory_separator_pos + 1);
-    }
-
-    // Calculate addresses of .text, .bss and .dynstr.
-    DCHECK_EQ(rodata_.header_.sh_addralign, static_cast<Elf_Word>(kPageSize));
-    DCHECK_EQ(text_.header_.sh_addralign, static_cast<Elf_Word>(kPageSize));
-    DCHECK_EQ(bss_.header_.sh_addralign, static_cast<Elf_Word>(kPageSize));
-    DCHECK_EQ(dynstr_.header_.sh_addralign, static_cast<Elf_Word>(kPageSize));
-    Elf_Word rodata_address = rodata_.GetAddress();
-    Elf_Word text_address = RoundUp(rodata_address + rodata_size, kPageSize);
-    Elf_Word bss_address = RoundUp(text_address + text_size, kPageSize);
-    Elf_Word abiflags_address = RoundUp(bss_address + bss_size, kPageSize);
-    Elf_Word abiflags_size = 0;
-    if (isa_ == kMips || isa_ == kMips64) {
-      abiflags_size = abiflags_.GetSize();
-    }
-    Elf_Word dynstr_address = RoundUp(abiflags_address + abiflags_size, kPageSize);
-
-    // Cache .dynstr, .dynsym and .hash data.
-    dynstr_.Add("");  // dynstr should start with empty string.
-    Elf_Word rodata_index = rodata_.GetSectionIndex();
-    Elf_Word oatdata = dynstr_.Add("oatdata");
-    dynsym_.Add(oatdata, rodata_index, rodata_address, rodata_size, STB_GLOBAL, STT_OBJECT);
-    if (text_size != 0u) {
-      Elf_Word text_index = rodata_index + 1u;
-      Elf_Word oatexec = dynstr_.Add("oatexec");
-      dynsym_.Add(oatexec, text_index, text_address, text_size, STB_GLOBAL, STT_OBJECT);
-      Elf_Word oatlastword = dynstr_.Add("oatlastword");
-      Elf_Word oatlastword_address = text_address + text_size - 4;
-      dynsym_.Add(oatlastword, text_index, oatlastword_address, 4, STB_GLOBAL, STT_OBJECT);
-    } else if (rodata_size != 0) {
-      // rodata_ can be size 0 for dwarf_test.
-      Elf_Word oatlastword = dynstr_.Add("oatlastword");
-      Elf_Word oatlastword_address = rodata_address + rodata_size - 4;
-      dynsym_.Add(oatlastword, rodata_index, oatlastword_address, 4, STB_GLOBAL, STT_OBJECT);
-    }
-    DCHECK_LE(bss_roots_offset, bss_size);
-    if (bss_size != 0u) {
-      Elf_Word bss_index = rodata_index + 1u + (text_size != 0 ? 1u : 0u);
-      Elf_Word oatbss = dynstr_.Add("oatbss");
-      dynsym_.Add(oatbss, bss_index, bss_address, bss_roots_offset, STB_GLOBAL, STT_OBJECT);
-      DCHECK_LE(bss_methods_offset, bss_roots_offset);
-      DCHECK_LE(bss_roots_offset, bss_size);
-      // Add a symbol marking the start of the methods part of the .bss, if not empty.
-      if (bss_methods_offset != bss_roots_offset) {
-        Elf_Word bss_methods_address = bss_address + bss_methods_offset;
-        Elf_Word bss_methods_size = bss_roots_offset - bss_methods_offset;
-        Elf_Word oatbssroots = dynstr_.Add("oatbssmethods");
-        dynsym_.Add(
-            oatbssroots, bss_index, bss_methods_address, bss_methods_size, STB_GLOBAL, STT_OBJECT);
-      }
-      // Add a symbol marking the start of the GC roots part of the .bss, if not empty.
-      if (bss_roots_offset != bss_size) {
-        Elf_Word bss_roots_address = bss_address + bss_roots_offset;
-        Elf_Word bss_roots_size = bss_size - bss_roots_offset;
-        Elf_Word oatbssroots = dynstr_.Add("oatbssroots");
-        dynsym_.Add(
-            oatbssroots, bss_index, bss_roots_address, bss_roots_size, STB_GLOBAL, STT_OBJECT);
-      }
-      Elf_Word oatbsslastword = dynstr_.Add("oatbsslastword");
-      Elf_Word bsslastword_address = bss_address + bss_size - 4;
-      dynsym_.Add(oatbsslastword, bss_index, bsslastword_address, 4, STB_GLOBAL, STT_OBJECT);
-    }
-    Elf_Word soname_offset = dynstr_.Add(soname);
-
-    // We do not really need a hash-table since there is so few entries.
-    // However, the hash-table is the only way the linker can actually
-    // determine the number of symbols in .dynsym so it is required.
-    int count = dynsym_.GetCacheSize() / sizeof(Elf_Sym);  // Includes NULL.
-    std::vector<Elf_Word> hash;
-    hash.push_back(1);  // Number of buckets.
-    hash.push_back(count);  // Number of chains.
-    // Buckets.  Having just one makes it linear search.
-    hash.push_back(1);  // Point to first non-NULL symbol.
-    // Chains.  This creates linked list of symbols.
-    hash.push_back(0);  // Dummy entry for the NULL symbol.
-    for (int i = 1; i < count - 1; i++) {
-      hash.push_back(i + 1);  // Each symbol points to the next one.
-    }
-    hash.push_back(0);  // Last symbol terminates the chain.
-    hash_.Add(hash.data(), hash.size() * sizeof(hash[0]));
-
-    // Calculate addresses of .dynsym, .hash and .dynamic.
-    DCHECK_EQ(dynstr_.header_.sh_flags, dynsym_.header_.sh_flags);
-    DCHECK_EQ(dynsym_.header_.sh_flags, hash_.header_.sh_flags);
-    Elf_Word dynsym_address =
-        RoundUp(dynstr_address + dynstr_.GetCacheSize(), dynsym_.header_.sh_addralign);
-    Elf_Word hash_address =
-        RoundUp(dynsym_address + dynsym_.GetCacheSize(), hash_.header_.sh_addralign);
-    DCHECK_EQ(dynamic_.header_.sh_addralign, static_cast<Elf_Word>(kPageSize));
-    Elf_Word dynamic_address = RoundUp(hash_address + dynsym_.GetCacheSize(), kPageSize);
-
-    Elf_Dyn dyns[] = {
-      { DT_HASH, { hash_address } },
-      { DT_STRTAB, { dynstr_address } },
-      { DT_SYMTAB, { dynsym_address } },
-      { DT_SYMENT, { sizeof(Elf_Sym) } },
-      { DT_STRSZ, { dynstr_.GetCacheSize() } },
-      { DT_SONAME, { soname_offset } },
-      { DT_NULL, { 0 } },
-    };
-    dynamic_.Add(&dyns, sizeof(dyns));
-
-    loaded_size_ = RoundUp(dynamic_address + dynamic_.GetCacheSize(), kPageSize);
-  }
-
-  void WriteDynamicSection() {
-    dynstr_.WriteCachedSection();
-    dynsym_.WriteCachedSection();
-    hash_.WriteCachedSection();
-    dynamic_.WriteCachedSection();
-
-    CHECK_EQ(loaded_size_, RoundUp(dynamic_.GetAddress() + dynamic_.GetSize(), kPageSize));
-  }
-
-  Elf_Word GetLoadedSize() {
-    CHECK_NE(loaded_size_, 0u);
-    return loaded_size_;
-  }
-
-  void WriteMIPSabiflagsSection() {
-    abiflags_.Start();
-    abiflags_.Write();
-    abiflags_.End();
-  }
-
-  void WriteBuildIdSection() {
-    build_id_.Start();
-    build_id_.Write();
-    build_id_.End();
-  }
-
-  void WriteBuildId(uint8_t build_id[kBuildIdLen]) {
-    stream_.Seek(build_id_.GetDigestStart(), kSeekSet);
-    stream_.WriteFully(build_id, kBuildIdLen);
-  }
-
-  // Returns true if all writes and seeks on the output stream succeeded.
-  bool Good() {
-    return stream_.Good();
-  }
-
-  // Returns the builder's internal stream.
-  OutputStream* GetStream() {
-    return &stream_;
-  }
-
-  off_t AlignFileOffset(size_t alignment) {
-     return stream_.Seek(RoundUp(stream_.Seek(0, kSeekCurrent), alignment), kSeekSet);
-  }
-
-  Elf_Addr AlignVirtualAddress(size_t alignment) {
-     return virtual_address_ = RoundUp(virtual_address_, alignment);
-  }
-
- private:
-  static Elf_Ehdr MakeElfHeader(InstructionSet isa, const InstructionSetFeatures* features) {
-    Elf_Ehdr elf_header = Elf_Ehdr();
-    switch (isa) {
-      case kArm:
-        // Fall through.
-      case kThumb2: {
-        elf_header.e_machine = EM_ARM;
-        elf_header.e_flags = EF_ARM_EABI_VER5;
-        break;
-      }
-      case kArm64: {
-        elf_header.e_machine = EM_AARCH64;
-        elf_header.e_flags = 0;
-        break;
-      }
-      case kX86: {
-        elf_header.e_machine = EM_386;
-        elf_header.e_flags = 0;
-        break;
-      }
-      case kX86_64: {
-        elf_header.e_machine = EM_X86_64;
-        elf_header.e_flags = 0;
-        break;
-      }
-      case kMips: {
-        elf_header.e_machine = EM_MIPS;
-        elf_header.e_flags = (EF_MIPS_NOREORDER |
-                              EF_MIPS_PIC       |
-                              EF_MIPS_CPIC      |
-                              EF_MIPS_ABI_O32   |
-                              (features->AsMipsInstructionSetFeatures()->IsR6()
-                                   ? EF_MIPS_ARCH_32R6
-                                   : EF_MIPS_ARCH_32R2));
-        break;
-      }
-      case kMips64: {
-        elf_header.e_machine = EM_MIPS;
-        elf_header.e_flags = (EF_MIPS_NOREORDER |
-                              EF_MIPS_PIC       |
-                              EF_MIPS_CPIC      |
-                              EF_MIPS_ARCH_64R6);
-        break;
-      }
-      case kNone: {
-        LOG(FATAL) << "No instruction set";
-        break;
-      }
-      default: {
-        LOG(FATAL) << "Unknown instruction set " << isa;
-      }
-    }
-
-    elf_header.e_ident[EI_MAG0]       = ELFMAG0;
-    elf_header.e_ident[EI_MAG1]       = ELFMAG1;
-    elf_header.e_ident[EI_MAG2]       = ELFMAG2;
-    elf_header.e_ident[EI_MAG3]       = ELFMAG3;
-    elf_header.e_ident[EI_CLASS]      = (sizeof(Elf_Addr) == sizeof(Elf32_Addr))
-                                         ? ELFCLASS32 : ELFCLASS64;
-    elf_header.e_ident[EI_DATA]       = ELFDATA2LSB;
-    elf_header.e_ident[EI_VERSION]    = EV_CURRENT;
-    elf_header.e_ident[EI_OSABI]      = ELFOSABI_LINUX;
-    elf_header.e_ident[EI_ABIVERSION] = 0;
-    elf_header.e_type = ET_DYN;
-    elf_header.e_version = 1;
-    elf_header.e_entry = 0;
-    elf_header.e_ehsize = sizeof(Elf_Ehdr);
-    elf_header.e_phentsize = sizeof(Elf_Phdr);
-    elf_header.e_shentsize = sizeof(Elf_Shdr);
-    elf_header.e_phoff = sizeof(Elf_Ehdr);
-    return elf_header;
-  }
-
-  // Create program headers based on written sections.
-  std::vector<Elf_Phdr> MakeProgramHeaders() {
-    CHECK(!sections_.empty());
-    std::vector<Elf_Phdr> phdrs;
-    {
-      // The program headers must start with PT_PHDR which is used in
-      // loaded process to determine the number of program headers.
-      Elf_Phdr phdr = Elf_Phdr();
-      phdr.p_type    = PT_PHDR;
-      phdr.p_flags   = PF_R;
-      phdr.p_offset  = phdr.p_vaddr = phdr.p_paddr = sizeof(Elf_Ehdr);
-      phdr.p_filesz  = phdr.p_memsz = 0;  // We need to fill this later.
-      phdr.p_align   = sizeof(Elf_Off);
-      phdrs.push_back(phdr);
-      // Tell the linker to mmap the start of file to memory.
-      Elf_Phdr load = Elf_Phdr();
-      load.p_type    = PT_LOAD;
-      load.p_flags   = PF_R;
-      load.p_offset  = load.p_vaddr = load.p_paddr = 0;
-      load.p_filesz  = load.p_memsz = sizeof(Elf_Ehdr) + sizeof(Elf_Phdr) * kMaxProgramHeaders;
-      load.p_align   = kPageSize;
-      phdrs.push_back(load);
-    }
-    // Create program headers for sections.
-    for (auto* section : sections_) {
-      const Elf_Shdr& shdr = section->header_;
-      if ((shdr.sh_flags & SHF_ALLOC) != 0 && shdr.sh_size != 0) {
-        // PT_LOAD tells the linker to mmap part of the file.
-        // The linker can only mmap page-aligned sections.
-        // Single PT_LOAD may contain several ELF sections.
-        Elf_Phdr& prev = phdrs.back();
-        Elf_Phdr load = Elf_Phdr();
-        load.p_type   = PT_LOAD;
-        load.p_flags  = section->phdr_flags_;
-        load.p_offset = shdr.sh_offset;
-        load.p_vaddr  = load.p_paddr = shdr.sh_addr;
-        load.p_filesz = (shdr.sh_type != SHT_NOBITS ? shdr.sh_size : 0u);
-        load.p_memsz  = shdr.sh_size;
-        load.p_align  = shdr.sh_addralign;
-        if (prev.p_type == load.p_type &&
-            prev.p_flags == load.p_flags &&
-            prev.p_filesz == prev.p_memsz &&  // Do not merge .bss
-            load.p_filesz == load.p_memsz) {  // Do not merge .bss
-          // Merge this PT_LOAD with the previous one.
-          Elf_Word size = shdr.sh_offset + shdr.sh_size - prev.p_offset;
-          prev.p_filesz = size;
-          prev.p_memsz  = size;
-        } else {
-          // If we are adding new load, it must be aligned.
-          CHECK_EQ(shdr.sh_addralign, (Elf_Word)kPageSize);
-          phdrs.push_back(load);
-        }
-      }
-    }
-    for (auto* section : sections_) {
-      const Elf_Shdr& shdr = section->header_;
-      if ((shdr.sh_flags & SHF_ALLOC) != 0 && shdr.sh_size != 0) {
-        // Other PT_* types allow the program to locate interesting
-        // parts of memory at runtime. They must overlap with PT_LOAD.
-        if (section->phdr_type_ != 0) {
-          Elf_Phdr phdr = Elf_Phdr();
-          phdr.p_type   = section->phdr_type_;
-          phdr.p_flags  = section->phdr_flags_;
-          phdr.p_offset = shdr.sh_offset;
-          phdr.p_vaddr  = phdr.p_paddr = shdr.sh_addr;
-          phdr.p_filesz = phdr.p_memsz = shdr.sh_size;
-          phdr.p_align  = shdr.sh_addralign;
-          phdrs.push_back(phdr);
-        }
-      }
-    }
-    // Set the size of the initial PT_PHDR.
-    CHECK_EQ(phdrs[0].p_type, (Elf_Word)PT_PHDR);
-    phdrs[0].p_filesz = phdrs[0].p_memsz = phdrs.size() * sizeof(Elf_Phdr);
-
-    return phdrs;
-  }
-
-  InstructionSet isa_;
-  const InstructionSetFeatures* features_;
-
-  ErrorDelayingOutputStream stream_;
-
-  Section rodata_;
-  Section text_;
-  Section bss_;
-  CachedStringSection dynstr_;
-  SymbolSection dynsym_;
-  CachedSection hash_;
-  CachedSection dynamic_;
-  Section eh_frame_;
-  Section eh_frame_hdr_;
-  StringSection strtab_;
-  SymbolSection symtab_;
-  Section debug_frame_;
-  Section debug_info_;
-  Section debug_line_;
-  StringSection shstrtab_;
-  AbiflagsSection abiflags_;
-  BuildIdSection build_id_;
-  std::vector<std::unique_ptr<Section>> other_sections_;
-
-  // List of used section in the order in which they were written.
-  std::vector<Section*> sections_;
-
-  bool started_;
-  bool write_program_headers_;
-
-  // The size of the memory taken by the ELF file when loaded.
-  size_t loaded_size_;
-
-  // Used for allocation of virtual address space.
-  Elf_Addr virtual_address_;
-
-  DISALLOW_COPY_AND_ASSIGN(ElfBuilder);
-};
-
-}  // namespace art
-
-#endif  // ART_COMPILER_ELF_BUILDER_H_
diff --git a/compiler/elf_writer.cc b/compiler/elf_writer.cc
deleted file mode 100644
index 37e4f11..0000000
--- a/compiler/elf_writer.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2012 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 "elf_writer.h"
-
-#include "base/unix_file/fd_file.h"
-#include "elf_file.h"
-
-namespace art {
-
-uintptr_t ElfWriter::GetOatDataAddress(ElfFile* elf_file) {
-  uintptr_t oatdata_address = elf_file->FindSymbolAddress(SHT_DYNSYM,
-                                                           "oatdata",
-                                                           false);
-  CHECK_NE(0U, oatdata_address);
-  return oatdata_address;
-}
-
-void ElfWriter::GetOatElfInformation(File* file,
-                                     size_t* oat_loaded_size,
-                                     size_t* oat_data_offset) {
-  std::string error_msg;
-  std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file,
-                                                  false,
-                                                  false,
-                                                  /*low_4gb*/false,
-                                                  &error_msg));
-  CHECK(elf_file.get() != nullptr) << error_msg;
-
-  bool success = elf_file->GetLoadedSize(oat_loaded_size, &error_msg);
-  CHECK(success) << error_msg;
-  CHECK_NE(0U, *oat_loaded_size);
-  *oat_data_offset = GetOatDataAddress(elf_file.get());
-  CHECK_NE(0U, *oat_data_offset);
-}
-
-bool ElfWriter::Fixup(File* file, uintptr_t oat_data_begin) {
-  std::string error_msg;
-  std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file, true, false, /*low_4gb*/false, &error_msg));
-  CHECK(elf_file.get() != nullptr) << error_msg;
-
-  // Lookup "oatdata" symbol address.
-  uintptr_t oatdata_address = ElfWriter::GetOatDataAddress(elf_file.get());
-  uintptr_t base_address = oat_data_begin - oatdata_address;
-
-  return elf_file->Fixup(base_address);
-}
-
-}  // namespace art
diff --git a/compiler/elf_writer.h b/compiler/elf_writer.h
deleted file mode 100644
index a8a5bc3..0000000
--- a/compiler/elf_writer.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-#ifndef ART_COMPILER_ELF_WRITER_H_
-#define ART_COMPILER_ELF_WRITER_H_
-
-#include <stdint.h>
-#include <cstddef>
-#include <string>
-#include <vector>
-
-#include "base/array_ref.h"
-#include "base/macros.h"
-#include "base/mutex.h"
-#include "os.h"
-
-namespace art {
-
-class ElfFile;
-class OutputStream;
-
-namespace debug {
-struct MethodDebugInfo;
-}  // namespace debug
-
-class ElfWriter {
- public:
-  // Looks up information about location of oat file in elf file container.
-  // Used for ImageWriter to perform memory layout.
-  static void GetOatElfInformation(File* file,
-                                   size_t* oat_loaded_size,
-                                   size_t* oat_data_offset);
-
-  // Returns runtime oat_data runtime address for an opened ElfFile.
-  static uintptr_t GetOatDataAddress(ElfFile* elf_file);
-
-  static bool Fixup(File* file, uintptr_t oat_data_begin);
-
-  virtual ~ElfWriter() {}
-
-  virtual void Start() = 0;
-  virtual void PrepareDynamicSection(size_t rodata_size,
-                                     size_t text_size,
-                                     size_t bss_size,
-                                     size_t bss_methods_offset,
-                                     size_t bss_roots_offset) = 0;
-  virtual void PrepareDebugInfo(const ArrayRef<const debug::MethodDebugInfo>& method_infos) = 0;
-  virtual OutputStream* StartRoData() = 0;
-  virtual void EndRoData(OutputStream* rodata) = 0;
-  virtual OutputStream* StartText() = 0;
-  virtual void EndText(OutputStream* text) = 0;
-  virtual void WriteDynamicSection() = 0;
-  virtual void WriteDebugInfo(const ArrayRef<const debug::MethodDebugInfo>& method_infos) = 0;
-  virtual bool End() = 0;
-
-  // Get the ELF writer's stream. This stream can be used for writing data directly
-  // to a section after the section has been finished. When that's done, the user
-  // should Seek() back to the position where the stream was before this operation.
-  virtual OutputStream* GetStream() = 0;
-
-  // Get the size that the loaded ELF file will occupy in memory.
-  virtual size_t GetLoadedSize() = 0;
-
- protected:
-  ElfWriter() = default;
-};
-
-}  // namespace art
-
-#endif  // ART_COMPILER_ELF_WRITER_H_
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
deleted file mode 100644
index 5d6dd2e..0000000
--- a/compiler/elf_writer_quick.cc
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * Copyright (C) 2012 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 "elf_writer_quick.h"
-
-#include <openssl/sha.h>
-#include <unordered_map>
-#include <unordered_set>
-
-#include "base/casts.h"
-#include "base/logging.h"
-#include "compiled_method.h"
-#include "debug/elf_debug_writer.h"
-#include "debug/method_debug_info.h"
-#include "driver/compiler_options.h"
-#include "elf.h"
-#include "elf_builder.h"
-#include "elf_utils.h"
-#include "globals.h"
-#include "leb128.h"
-#include "linker/buffered_output_stream.h"
-#include "linker/file_output_stream.h"
-#include "thread-current-inl.h"
-#include "thread_pool.h"
-#include "utils.h"
-
-namespace art {
-
-// .eh_frame and .debug_frame are almost identical.
-// Except for some minor formatting differences, the main difference
-// is that .eh_frame is allocated within the running program because
-// it is used by C++ exception handling (which we do not use so we
-// can choose either).  C++ compilers generally tend to use .eh_frame
-// because if they need it sometimes, they might as well always use it.
-// Let's use .debug_frame because it is easier to strip or compress.
-constexpr dwarf::CFIFormat kCFIFormat = dwarf::DW_DEBUG_FRAME_FORMAT;
-
-class DebugInfoTask : public Task {
- public:
-  DebugInfoTask(InstructionSet isa,
-                const InstructionSetFeatures* features,
-                size_t rodata_section_size,
-                size_t text_section_size,
-                const ArrayRef<const debug::MethodDebugInfo>& method_infos)
-      : isa_(isa),
-        instruction_set_features_(features),
-        rodata_section_size_(rodata_section_size),
-        text_section_size_(text_section_size),
-        method_infos_(method_infos) {
-  }
-
-  void Run(Thread*) {
-    result_ = debug::MakeMiniDebugInfo(isa_,
-                                       instruction_set_features_,
-                                       rodata_section_size_,
-                                       text_section_size_,
-                                       method_infos_);
-  }
-
-  std::vector<uint8_t>* GetResult() {
-    return &result_;
-  }
-
- private:
-  InstructionSet isa_;
-  const InstructionSetFeatures* instruction_set_features_;
-  size_t rodata_section_size_;
-  size_t text_section_size_;
-  const ArrayRef<const debug::MethodDebugInfo> method_infos_;
-  std::vector<uint8_t> result_;
-};
-
-template <typename ElfTypes>
-class ElfWriterQuick FINAL : public ElfWriter {
- public:
-  ElfWriterQuick(InstructionSet instruction_set,
-                 const InstructionSetFeatures* features,
-                 const CompilerOptions* compiler_options,
-                 File* elf_file);
-  ~ElfWriterQuick();
-
-  void Start() OVERRIDE;
-  void PrepareDynamicSection(size_t rodata_size,
-                             size_t text_size,
-                             size_t bss_size,
-                             size_t bss_methods_offset,
-                             size_t bss_roots_offset) OVERRIDE;
-  void PrepareDebugInfo(const ArrayRef<const debug::MethodDebugInfo>& method_infos) OVERRIDE;
-  OutputStream* StartRoData() OVERRIDE;
-  void EndRoData(OutputStream* rodata) OVERRIDE;
-  OutputStream* StartText() OVERRIDE;
-  void EndText(OutputStream* text) OVERRIDE;
-  void WriteDynamicSection() OVERRIDE;
-  void WriteDebugInfo(const ArrayRef<const debug::MethodDebugInfo>& method_infos) OVERRIDE;
-  bool End() OVERRIDE;
-
-  virtual OutputStream* GetStream() OVERRIDE;
-
-  size_t GetLoadedSize() OVERRIDE;
-
-  static void EncodeOatPatches(const std::vector<uintptr_t>& locations,
-                               std::vector<uint8_t>* buffer);
-
- private:
-  const InstructionSetFeatures* instruction_set_features_;
-  const CompilerOptions* const compiler_options_;
-  File* const elf_file_;
-  size_t rodata_size_;
-  size_t text_size_;
-  size_t bss_size_;
-  std::unique_ptr<BufferedOutputStream> output_stream_;
-  std::unique_ptr<ElfBuilder<ElfTypes>> builder_;
-  std::unique_ptr<DebugInfoTask> debug_info_task_;
-  std::unique_ptr<ThreadPool> debug_info_thread_pool_;
-
-  void ComputeFileBuildId(uint8_t (*build_id)[ElfBuilder<ElfTypes>::kBuildIdLen]);
-
-  DISALLOW_IMPLICIT_CONSTRUCTORS(ElfWriterQuick);
-};
-
-std::unique_ptr<ElfWriter> CreateElfWriterQuick(InstructionSet instruction_set,
-                                                const InstructionSetFeatures* features,
-                                                const CompilerOptions* compiler_options,
-                                                File* elf_file) {
-  if (Is64BitInstructionSet(instruction_set)) {
-    return std::make_unique<ElfWriterQuick<ElfTypes64>>(instruction_set,
-                                                        features,
-                                                        compiler_options,
-                                                        elf_file);
-  } else {
-    return std::make_unique<ElfWriterQuick<ElfTypes32>>(instruction_set,
-                                                        features,
-                                                        compiler_options,
-                                                        elf_file);
-  }
-}
-
-template <typename ElfTypes>
-ElfWriterQuick<ElfTypes>::ElfWriterQuick(InstructionSet instruction_set,
-                                         const InstructionSetFeatures* features,
-                                         const CompilerOptions* compiler_options,
-                                         File* elf_file)
-    : ElfWriter(),
-      instruction_set_features_(features),
-      compiler_options_(compiler_options),
-      elf_file_(elf_file),
-      rodata_size_(0u),
-      text_size_(0u),
-      bss_size_(0u),
-      output_stream_(
-          std::make_unique<BufferedOutputStream>(std::make_unique<FileOutputStream>(elf_file))),
-      builder_(new ElfBuilder<ElfTypes>(instruction_set, features, output_stream_.get())) {}
-
-template <typename ElfTypes>
-ElfWriterQuick<ElfTypes>::~ElfWriterQuick() {}
-
-template <typename ElfTypes>
-void ElfWriterQuick<ElfTypes>::Start() {
-  builder_->Start();
-  if (compiler_options_->GetGenerateBuildId()) {
-    builder_->WriteBuildIdSection();
-  }
-}
-
-template <typename ElfTypes>
-void ElfWriterQuick<ElfTypes>::PrepareDynamicSection(size_t rodata_size,
-                                                     size_t text_size,
-                                                     size_t bss_size,
-                                                     size_t bss_methods_offset,
-                                                     size_t bss_roots_offset) {
-  DCHECK_EQ(rodata_size_, 0u);
-  rodata_size_ = rodata_size;
-  DCHECK_EQ(text_size_, 0u);
-  text_size_ = text_size;
-  DCHECK_EQ(bss_size_, 0u);
-  bss_size_ = bss_size;
-  builder_->PrepareDynamicSection(elf_file_->GetPath(),
-                                  rodata_size_,
-                                  text_size_,
-                                  bss_size_,
-                                  bss_methods_offset,
-                                  bss_roots_offset);
-}
-
-template <typename ElfTypes>
-OutputStream* ElfWriterQuick<ElfTypes>::StartRoData() {
-  auto* rodata = builder_->GetRoData();
-  rodata->Start();
-  return rodata;
-}
-
-template <typename ElfTypes>
-void ElfWriterQuick<ElfTypes>::EndRoData(OutputStream* rodata) {
-  CHECK_EQ(builder_->GetRoData(), rodata);
-  builder_->GetRoData()->End();
-}
-
-template <typename ElfTypes>
-OutputStream* ElfWriterQuick<ElfTypes>::StartText() {
-  auto* text = builder_->GetText();
-  text->Start();
-  return text;
-}
-
-template <typename ElfTypes>
-void ElfWriterQuick<ElfTypes>::EndText(OutputStream* text) {
-  CHECK_EQ(builder_->GetText(), text);
-  builder_->GetText()->End();
-}
-
-template <typename ElfTypes>
-void ElfWriterQuick<ElfTypes>::WriteDynamicSection() {
-  if (bss_size_ != 0u) {
-    builder_->GetBss()->WriteNoBitsSection(bss_size_);
-  }
-  if (builder_->GetIsa() == kMips || builder_->GetIsa() == kMips64) {
-    builder_->WriteMIPSabiflagsSection();
-  }
-  builder_->WriteDynamicSection();
-}
-
-template <typename ElfTypes>
-void ElfWriterQuick<ElfTypes>::PrepareDebugInfo(
-    const ArrayRef<const debug::MethodDebugInfo>& method_infos) {
-  if (!method_infos.empty() && compiler_options_->GetGenerateMiniDebugInfo()) {
-    // Prepare the mini-debug-info in background while we do other I/O.
-    Thread* self = Thread::Current();
-    debug_info_task_ = std::unique_ptr<DebugInfoTask>(
-        new DebugInfoTask(builder_->GetIsa(),
-                          instruction_set_features_,
-                          rodata_size_,
-                          text_size_,
-                          method_infos));
-    debug_info_thread_pool_ = std::unique_ptr<ThreadPool>(
-        new ThreadPool("Mini-debug-info writer", 1));
-    debug_info_thread_pool_->AddTask(self, debug_info_task_.get());
-    debug_info_thread_pool_->StartWorkers(self);
-  }
-}
-
-template <typename ElfTypes>
-void ElfWriterQuick<ElfTypes>::WriteDebugInfo(
-    const ArrayRef<const debug::MethodDebugInfo>& method_infos) {
-  if (!method_infos.empty()) {
-    if (compiler_options_->GetGenerateDebugInfo()) {
-      // Generate all the debug information we can.
-      debug::WriteDebugInfo(builder_.get(), method_infos, kCFIFormat, true /* write_oat_patches */);
-    }
-    if (compiler_options_->GetGenerateMiniDebugInfo()) {
-      // Wait for the mini-debug-info generation to finish and write it to disk.
-      Thread* self = Thread::Current();
-      DCHECK(debug_info_thread_pool_ != nullptr);
-      debug_info_thread_pool_->Wait(self, true, false);
-      builder_->WriteSection(".gnu_debugdata", debug_info_task_->GetResult());
-    }
-  }
-}
-
-template <typename ElfTypes>
-bool ElfWriterQuick<ElfTypes>::End() {
-  builder_->End();
-  if (compiler_options_->GetGenerateBuildId()) {
-    uint8_t build_id[ElfBuilder<ElfTypes>::kBuildIdLen];
-    ComputeFileBuildId(&build_id);
-    builder_->WriteBuildId(build_id);
-  }
-  return builder_->Good();
-}
-
-template <typename ElfTypes>
-void ElfWriterQuick<ElfTypes>::ComputeFileBuildId(
-    uint8_t (*build_id)[ElfBuilder<ElfTypes>::kBuildIdLen]) {
-  constexpr int kBufSize = 8192;
-  std::vector<char> buffer(kBufSize);
-  int64_t offset = 0;
-  SHA_CTX ctx;
-  SHA1_Init(&ctx);
-  while (true) {
-    int64_t bytes_read = elf_file_->Read(buffer.data(), kBufSize, offset);
-    CHECK_GE(bytes_read, 0);
-    if (bytes_read == 0) {
-      // End of file.
-      break;
-    }
-    SHA1_Update(&ctx, buffer.data(), bytes_read);
-    offset += bytes_read;
-  }
-  SHA1_Final(*build_id, &ctx);
-}
-
-template <typename ElfTypes>
-OutputStream* ElfWriterQuick<ElfTypes>::GetStream() {
-  return builder_->GetStream();
-}
-
-template <typename ElfTypes>
-size_t ElfWriterQuick<ElfTypes>::GetLoadedSize() {
-  return builder_->GetLoadedSize();
-}
-
-// Explicit instantiations
-template class ElfWriterQuick<ElfTypes32>;
-template class ElfWriterQuick<ElfTypes64>;
-
-}  // namespace art
diff --git a/compiler/elf_writer_quick.h b/compiler/elf_writer_quick.h
deleted file mode 100644
index 3d5dd39..0000000
--- a/compiler/elf_writer_quick.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-#ifndef ART_COMPILER_ELF_WRITER_QUICK_H_
-#define ART_COMPILER_ELF_WRITER_QUICK_H_
-
-#include <memory>
-
-#include "arch/instruction_set.h"
-#include "elf_writer.h"
-#include "os.h"
-
-namespace art {
-
-class CompilerOptions;
-class InstructionSetFeatures;
-
-std::unique_ptr<ElfWriter> CreateElfWriterQuick(InstructionSet instruction_set,
-                                                const InstructionSetFeatures* features,
-                                                const CompilerOptions* compiler_options,
-                                                File* elf_file);
-
-}  // namespace art
-
-#endif  // ART_COMPILER_ELF_WRITER_QUICK_H_
diff --git a/compiler/elf_writer_test.cc b/compiler/elf_writer_test.cc
deleted file mode 100644
index fa2d78d..0000000
--- a/compiler/elf_writer_test.cc
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * 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