libart-compiler cleanup

- Move compile-time code to src/compiler and libart-compiler
  OatWriter, ImageWriter, ElfWriter, ElfFixup, ElfStripper, stub generation
- Move ClassReference and MethodReference to remove MethodVerifier dependency on CompilerDriver
- Move runtime_support_llvm.cc out of src/compiler and next to runtime_support.cc
- Change dex2oat and gtests to directly depend on libart-compiler
- Move non-common definitions from Android.common.mk to more specific makefiles
- Add LOCAL_ADDITIONAL_DEPENDENCIES on appropriate makefiles

Change-Id: I897027e69945914128f21f317a92caf9255bc600
diff --git a/src/compiler/dex/dex_to_dex_compiler.cc b/src/compiler/dex/dex_to_dex_compiler.cc
index afb29f4..ce512ec 100644
--- a/src/compiler/dex/dex_to_dex_compiler.cc
+++ b/src/compiler/dex/dex_to_dex_compiler.cc
@@ -206,7 +206,7 @@
     return;
   }
   uint32_t method_idx = is_range ? inst->VRegB_3rc() : inst->VRegB_35c();
-  CompilerDriver::MethodReference target_method(&GetDexFile(), method_idx);
+  MethodReference target_method(&GetDexFile(), method_idx);
   InvokeType invoke_type = kVirtual;
   InvokeType original_invoke_type = invoke_type;
   int vtable_idx;
diff --git a/src/compiler/dex/mir_dataflow.cc b/src/compiler/dex/mir_dataflow.cc
index 3b2c1a6..381afb1 100644
--- a/src/compiler/dex/mir_dataflow.cc
+++ b/src/compiler/dex/mir_dataflow.cc
@@ -1225,7 +1225,7 @@
       return false;
   }
   DexCompilationUnit m_unit(cu_);
-  CompilerDriver::MethodReference target_method(cu_->dex_file, mir->dalvikInsn.vB);
+  MethodReference target_method(cu_->dex_file, mir->dalvikInsn.vB);
   int vtable_idx;
   uintptr_t direct_code;
   uintptr_t direct_method;
diff --git a/src/compiler/dex/quick/codegen_util.cc b/src/compiler/dex/quick/codegen_util.cc
index ac2828c..766cdce 100644
--- a/src/compiler/dex/quick/codegen_util.cc
+++ b/src/compiler/dex/quick/codegen_util.cc
@@ -632,7 +632,7 @@
       max_native_offset = native_offset;
     }
   }
-  CompilerDriver::MethodReference method_ref(cu_->dex_file, cu_->method_idx);
+  MethodReference method_ref(cu_->dex_file, cu_->method_idx);
   const std::vector<uint8_t>* gc_map_raw = verifier::MethodVerifier::GetDexGcMap(method_ref);
   verifier::DexPcToReferenceMap dex_gc_map(&(*gc_map_raw)[4], gc_map_raw->size() - 4);
   // Compute native offset to references size.
diff --git a/src/compiler/dex/quick/gen_common.cc b/src/compiler/dex/quick/gen_common.cc
index 7aa71cf..2980acb 100644
--- a/src/compiler/dex/quick/gen_common.cc
+++ b/src/compiler/dex/quick/gen_common.cc
@@ -1077,7 +1077,7 @@
   // Note: currently type_known_final is unused, as optimizing will only improve the performance
   // of the exception throw path.
   DexCompilationUnit* cu = mir_graph_->GetCurrentDexCompilationUnit();
-  const CompilerDriver::MethodReference mr(cu->GetDexFile(), cu->GetDexMethodIndex());
+  const MethodReference mr(cu->GetDexFile(), cu->GetDexMethodIndex());
   if (!needs_access_check && cu_->compiler_driver->IsSafeCast(mr, insn_idx)) {
     // Verifier type analysis proved this check cast would never cause an exception.
     return;
diff --git a/src/compiler/dex/quick/gen_invoke.cc b/src/compiler/dex/quick/gen_invoke.cc
index 4b12bb4..3bc7340 100644
--- a/src/compiler/dex/quick/gen_invoke.cc
+++ b/src/compiler/dex/quick/gen_invoke.cc
@@ -313,7 +313,7 @@
  * emit the next instruction in static & direct invoke sequences.
  */
 static int NextSDCallInsn(CompilationUnit* cu, CallInfo* info,
-                          int state, const CompilerDriver::MethodReference& target_method,
+                          int state, const MethodReference& target_method,
                           uint32_t unused,
                           uintptr_t direct_code, uintptr_t direct_method,
                           InvokeType type)
@@ -418,7 +418,7 @@
  * kArg1 here rather than the standard LoadArgRegs.
  */
 static int NextVCallInsn(CompilationUnit* cu, CallInfo* info,
-                         int state, const CompilerDriver::MethodReference& target_method,
+                         int state, const MethodReference& target_method,
                          uint32_t method_idx, uintptr_t unused, uintptr_t unused2,
                          InvokeType unused3)
 {
@@ -467,7 +467,7 @@
  * which will locate the target and continue on via a tail call.
  */
 static int NextInterfaceCallInsn(CompilationUnit* cu, CallInfo* info, int state,
-                                 const CompilerDriver::MethodReference& target_method,
+                                 const MethodReference& target_method,
                                  uint32_t unused, uintptr_t unused2,
                                  uintptr_t direct_method, InvokeType unused4)
 {
@@ -535,7 +535,7 @@
 }
 
 static int NextInvokeInsnSP(CompilationUnit* cu, CallInfo* info, int trampoline,
-                            int state, const CompilerDriver::MethodReference& target_method,
+                            int state, const MethodReference& target_method,
                             uint32_t method_idx)
 {
   Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
@@ -558,7 +558,7 @@
 
 static int NextStaticCallInsnSP(CompilationUnit* cu, CallInfo* info,
                                 int state,
-                                const CompilerDriver::MethodReference& target_method,
+                                const MethodReference& target_method,
                                 uint32_t method_idx,
                                 uintptr_t unused, uintptr_t unused2,
                                 InvokeType unused3)
@@ -568,7 +568,7 @@
 }
 
 static int NextDirectCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
-                                const CompilerDriver::MethodReference& target_method,
+                                const MethodReference& target_method,
                                 uint32_t method_idx, uintptr_t unused,
                                 uintptr_t unused2, InvokeType unused3)
 {
@@ -577,7 +577,7 @@
 }
 
 static int NextSuperCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
-                               const CompilerDriver::MethodReference& target_method,
+                               const MethodReference& target_method,
                                uint32_t method_idx, uintptr_t unused,
                                uintptr_t unused2, InvokeType unused3)
 {
@@ -586,7 +586,7 @@
 }
 
 static int NextVCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
-                           const CompilerDriver::MethodReference& target_method,
+                           const MethodReference& target_method,
                            uint32_t method_idx, uintptr_t unused,
                            uintptr_t unused2, InvokeType unused3)
 {
@@ -596,7 +596,7 @@
 
 static int NextInterfaceCallInsnWithAccessCheck(CompilationUnit* cu,
                                                 CallInfo* info, int state,
-                                                const CompilerDriver::MethodReference& target_method,
+                                                const MethodReference& target_method,
                                                 uint32_t unused,
                                                 uintptr_t unused2, uintptr_t unused3,
                                                 InvokeType unused4)
@@ -607,7 +607,7 @@
 
 int Mir2Lir::LoadArgRegs(CallInfo* info, int call_state,
                          NextCallInsn next_call_insn,
-                         const CompilerDriver::MethodReference& target_method,
+                         const MethodReference& target_method,
                          uint32_t vtable_idx, uintptr_t direct_code,
                          uintptr_t direct_method, InvokeType type, bool skip_this)
 {
@@ -647,7 +647,7 @@
  */
 int Mir2Lir::GenDalvikArgsNoRange(CallInfo* info,
                                   int call_state, LIR** pcrLabel, NextCallInsn next_call_insn,
-                                  const CompilerDriver::MethodReference& target_method,
+                                  const MethodReference& target_method,
                                   uint32_t vtable_idx, uintptr_t direct_code,
                                   uintptr_t direct_method, InvokeType type, bool skip_this)
 {
@@ -747,7 +747,7 @@
  */
 int Mir2Lir::GenDalvikArgsRange(CallInfo* info, int call_state,
                                 LIR** pcrLabel, NextCallInsn next_call_insn,
-                                const CompilerDriver::MethodReference& target_method,
+                                const MethodReference& target_method,
                                 uint32_t vtable_idx, uintptr_t direct_code, uintptr_t direct_method,
                                 InvokeType type, bool skip_this)
 {
@@ -1373,7 +1373,7 @@
   LockCallTemps();
 
   DexCompilationUnit* cUnit = mir_graph_->GetCurrentDexCompilationUnit();
-  CompilerDriver::MethodReference target_method(cUnit->GetDexFile(), info->index);
+  MethodReference target_method(cUnit->GetDexFile(), info->index);
   int vtable_idx;
   uintptr_t direct_code;
   uintptr_t direct_method;
diff --git a/src/compiler/dex/quick/mir_to_lir.h b/src/compiler/dex/quick/mir_to_lir.h
index 9eb4524..93098db 100644
--- a/src/compiler/dex/quick/mir_to_lir.h
+++ b/src/compiler/dex/quick/mir_to_lir.h
@@ -100,7 +100,7 @@
 class Mir2Lir;
 
 typedef int (*NextCallInsn)(CompilationUnit*, CallInfo*, int,
-                            const CompilerDriver::MethodReference& target_method,
+                            const MethodReference& target_method,
                             uint32_t method_idx, uintptr_t direct_code,
                             uintptr_t direct_method, InvokeType type);
 
@@ -467,13 +467,13 @@
     void FlushIns(RegLocation* ArgLocs, RegLocation rl_method);
     int GenDalvikArgsNoRange(CallInfo* info, int call_state, LIR** pcrLabel,
                              NextCallInsn next_call_insn,
-                             const CompilerDriver::MethodReference& target_method,
+                             const MethodReference& target_method,
                              uint32_t vtable_idx,
                              uintptr_t direct_code, uintptr_t direct_method, InvokeType type,
                              bool skip_this);
     int GenDalvikArgsRange(CallInfo* info, int call_state, LIR** pcrLabel,
                            NextCallInsn next_call_insn,
-                           const CompilerDriver::MethodReference& target_method,
+                           const MethodReference& target_method,
                            uint32_t vtable_idx,
                            uintptr_t direct_code, uintptr_t direct_method, InvokeType type,
                            bool skip_this);
@@ -495,7 +495,7 @@
     bool GenIntrinsic(CallInfo* info);
     int LoadArgRegs(CallInfo* info, int call_state,
                     NextCallInsn next_call_insn,
-                    const CompilerDriver::MethodReference& target_method,
+                    const MethodReference& target_method,
                     uint32_t vtable_idx,
                     uintptr_t direct_code, uintptr_t direct_method, InvokeType type,
                     bool skip_this);
diff --git a/src/compiler/dex/write_elf.cc b/src/compiler/dex/write_elf.cc
deleted file mode 100644
index d9e45a9..0000000
--- a/src/compiler/dex/write_elf.cc
+++ /dev/null
@@ -1,55 +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_fixup.h"
-#include "elf_stripper.h"
-#include "os.h"
-
-#if defined(ART_USE_PORTABLE_COMPILER)
-#include "elf_writer_mclinker.h"
-#else
-#include "elf_writer_quick.h"
-#endif
-
-namespace art {
-class CompilerDriver;
-class DexFile;
-}  // namespace art
-
-extern "C" bool WriteElf(art::CompilerDriver& driver,
-                         const std::string& android_root,
-                         bool is_host,
-                         const std::vector<const art::DexFile*>& dex_files,
-                         std::vector<uint8_t>& oat_contents,
-                         art::File* file)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-#if defined(ART_USE_PORTABLE_COMPILER)
-  return art::ElfWriterMclinker::Create(file, oat_contents, dex_files, android_root, is_host, driver);
-#else
-  return art::ElfWriterQuick::Create(file, oat_contents, dex_files, android_root, is_host, driver);
-#endif
-}
-extern "C" bool FixupElf(art::File* file, uintptr_t oat_data_begin) {
-  return art::ElfFixup::Fixup(file, oat_data_begin);
-}
-extern "C" void GetOatElfInformation(art::File* file,
-                                     size_t& oat_loaded_size,
-                                     size_t& oat_data_offset) {
-  art::ElfWriter::GetOatElfInformation(file, oat_loaded_size, oat_data_offset);
-}
-extern "C" bool StripElf(art::File* file) {
-  return art::ElfStripper::Strip(file);
-}
diff --git a/src/compiler/driver/compiler_driver.cc b/src/compiler/driver/compiler_driver.cc
index c8ccbe9..c876252 100644
--- a/src/compiler/driver/compiler_driver.cc
+++ b/src/compiler/driver/compiler_driver.cc
@@ -18,7 +18,6 @@
 
 #include <vector>
 
-#include <dlfcn.h>
 #include <unistd.h>
 
 #include "base/stl_util.h"
@@ -48,8 +47,10 @@
 #include "thread_pool.h"
 #include "verifier/method_verifier.h"
 
-#if defined(__APPLE__)
-#include <mach-o/dyld.h>
+#if defined(ART_USE_PORTABLE_COMPILER)
+#include "compiler/elf_writer_mclinker.h"
+#else
+#include "compiler/elf_writer_quick.h"
 #endif
 
 namespace art {
@@ -281,48 +282,57 @@
   DISALLOW_COPY_AND_ASSIGN(AOTCompilationStats);
 };
 
-static std::string MakeCompilerSoName(CompilerBackend compiler_backend) {
+extern "C" void ArtInitCompilerContext(art::CompilerDriver& driver);
+extern "C" void ArtInitQuickCompilerContext(art::CompilerDriver& compiler);
 
-  // Bad things happen if we pull in the libartd-compiler to a libart dex2oat or vice versa,
-  // because we end up with both libart and libartd in the same address space!
-  const char* suffix = (kIsDebugBuild ? "d" : "");
+extern "C" void ArtUnInitCompilerContext(art::CompilerDriver& driver);
+extern "C" void ArtUnInitQuickCompilerContext(art::CompilerDriver& compiler);
 
-  // Work out the filename for the compiler library.
-  std::string library_name(StringPrintf("art%s-compiler", suffix));
-  std::string filename(StringPrintf(OS_SHARED_LIB_FORMAT_STR, library_name.c_str()));
+extern "C" art::CompiledMethod* ArtCompileMethod(art::CompilerDriver& driver,
+                                                 const art::DexFile::CodeItem* code_item,
+                                                 uint32_t access_flags,
+                                                 art::InvokeType invoke_type,
+                                                 uint32_t class_def_idx,
+                                                 uint32_t method_idx,
+                                                 jobject class_loader,
+                                                 const art::DexFile& dex_file);
+extern "C" art::CompiledMethod* ArtQuickCompileMethod(art::CompilerDriver& compiler,
+                                                      const art::DexFile::CodeItem* code_item,
+                                                      uint32_t access_flags,
+                                                      art::InvokeType invoke_type,
+                                                      uint32_t class_def_idx,
+                                                      uint32_t method_idx,
+                                                      jobject class_loader,
+                                                      const art::DexFile& dex_file);
 
-#if defined(__APPLE__)
-  // On Linux, dex2oat will have been built with an RPATH of $ORIGIN/../lib, so dlopen(3) will find
-  // the .so by itself. On Mac OS, there isn't really an equivalent, so we have to manually do the
-  // same work.
-  uint32_t executable_path_length = 0;
-  _NSGetExecutablePath(NULL, &executable_path_length);
-  std::string path(executable_path_length, static_cast<char>(0));
-  CHECK_EQ(_NSGetExecutablePath(&path[0], &executable_path_length), 0);
+extern "C" art::CompiledMethod* ArtCompileDEX(art::CompilerDriver& compiler,
+                                              const art::DexFile::CodeItem* code_item,
+                                              uint32_t access_flags,
+                                              art::InvokeType invoke_type,
+                                              uint32_t class_def_idx,
+                                              uint32_t method_idx,
+                                              jobject class_loader,
+                                              const art::DexFile& dex_file);
 
-  // Strip the "/dex2oat".
-  size_t last_slash = path.find_last_of('/');
-  CHECK_NE(last_slash, std::string::npos) << path;
-  path.resize(last_slash);
+extern "C" art::CompiledMethod* SeaIrCompileMethod(art::CompilerDriver& compiler,
+                                                   const art::DexFile::CodeItem* code_item,
+                                                   uint32_t access_flags,
+                                                   art::InvokeType invoke_type,
+                                                   uint32_t class_def_idx,
+                                                   uint32_t method_idx,
+                                                   jobject class_loader,
+                                                   const art::DexFile& dex_file);
 
-  // Strip the "/bin".
-  last_slash = path.find_last_of('/');
-  path.resize(last_slash);
+extern "C" art::CompiledMethod* ArtLLVMJniCompileMethod(art::CompilerDriver& driver,
+                                                        uint32_t access_flags, uint32_t method_idx,
+                                                        const art::DexFile& dex_file);
 
-  filename = path + "/lib/" + filename;
-#endif
-  return filename;
-}
+extern "C" art::CompiledMethod* ArtQuickJniCompileMethod(art::CompilerDriver& compiler,
+                                                         uint32_t access_flags, uint32_t method_idx,
+                                                         const art::DexFile& dex_file);
 
-template<typename Fn>
-static Fn FindFunction(const std::string& compiler_so_name, void* library, const char* name) {
-  Fn fn = reinterpret_cast<Fn>(dlsym(library, name));
-  if (fn == NULL) {
-    LOG(FATAL) << "Couldn't find \"" << name << "\" in compiler library " << compiler_so_name << ": " << dlerror();
-  }
-  VLOG(compiler) << "Found \"" << name << "\" at " << reinterpret_cast<void*>(fn);
-  return fn;
-}
+extern "C" void compilerLLVMSetBitcodeFileName(art::CompilerDriver& driver,
+                                               std::string const& filename);
 
 CompilerDriver::CompilerDriver(CompilerBackend compiler_backend, InstructionSet instruction_set,
                                bool image, DescriptorSet* image_classes,
@@ -349,13 +359,6 @@
       compiler_get_method_code_addr_(NULL),
       support_boot_image_fixup_(true)
 {
-  std::string compiler_so_name(MakeCompilerSoName(compiler_backend_));
-  compiler_library_ = dlopen(compiler_so_name.c_str(), RTLD_LAZY);
-  if (compiler_library_ == NULL) {
-    LOG(FATAL) << "Couldn't find compiler library " << compiler_so_name << ": " << dlerror();
-  }
-  VLOG(compiler) << "dlopen(\"" << compiler_so_name << "\", RTLD_LAZY) returned " << compiler_library_;
-
   CHECK_PTHREAD_CALL(pthread_key_create, (&tls_key_, NULL), "compiler tls key");
 
   // TODO: more work needed to combine initializations and allow per-method backend selection
@@ -363,28 +366,28 @@
   InitCompilerContextFn init_compiler_context;
   if (compiler_backend_ == kPortable){
     // Initialize compiler_context_
-    init_compiler_context = FindFunction<void (*)(CompilerDriver&)>(compiler_so_name,
-                                                  compiler_library_, "ArtInitCompilerContext");
-    compiler_ = FindFunction<CompilerFn>(compiler_so_name, compiler_library_, "ArtCompileMethod");
+    init_compiler_context = reinterpret_cast<void (*)(CompilerDriver&)>(ArtInitCompilerContext);
+    compiler_ = reinterpret_cast<CompilerFn>(ArtCompileMethod);
   } else {
-    init_compiler_context = FindFunction<void (*)(CompilerDriver&)>(compiler_so_name,
-                                                  compiler_library_, "ArtInitQuickCompilerContext");
-    compiler_ = FindFunction<CompilerFn>(compiler_so_name, compiler_library_, "ArtQuickCompileMethod");
+    init_compiler_context = reinterpret_cast<void (*)(CompilerDriver&)>(ArtInitQuickCompilerContext);
+    compiler_ = reinterpret_cast<CompilerFn>(ArtQuickCompileMethod);
   }
 
-  dex_to_dex_compiler_ = FindFunction<CompilerFn>(compiler_so_name, compiler_library_, "ArtCompileDEX");
+  dex_to_dex_compiler_ = reinterpret_cast<CompilerFn>(ArtCompileDEX);
 
+#ifdef ART_SEA_IR_MODE
   sea_ir_compiler_ = NULL;
   if (Runtime::Current()->IsSeaIRMode()) {
-    sea_ir_compiler_ = FindFunction<CompilerFn>(compiler_so_name, compiler_library_, "SeaIrCompileMethod");
+    sea_ir_compiler_ = reinterpret_cast<CompilerFn>(SeaIrCompileMethod);
   }
+#endif
 
   init_compiler_context(*this);
 
   if (compiler_backend_ == kPortable) {
-    jni_compiler_ = FindFunction<JniCompilerFn>(compiler_so_name, compiler_library_, "ArtLLVMJniCompileMethod");
+    jni_compiler_ = reinterpret_cast<JniCompilerFn>(ArtLLVMJniCompileMethod);
   } else {
-    jni_compiler_ = FindFunction<JniCompilerFn>(compiler_so_name, compiler_library_, "ArtQuickJniCompileMethod");
+    jni_compiler_ = reinterpret_cast<JniCompilerFn>(ArtQuickJniCompileMethod);
   }
 
   CHECK(!Runtime::Current()->IsStarted());
@@ -413,39 +416,15 @@
   }
   CHECK_PTHREAD_CALL(pthread_key_delete, (tls_key_), "delete tls key");
   typedef void (*UninitCompilerContextFn)(CompilerDriver&);
-  std::string compiler_so_name(MakeCompilerSoName(compiler_backend_));
   UninitCompilerContextFn uninit_compiler_context;
   // Uninitialize compiler_context_
   // TODO: rework to combine initialization/uninitialization
   if (compiler_backend_ == kPortable) {
-    uninit_compiler_context = FindFunction<void (*)(CompilerDriver&)>(compiler_so_name,
-                                                    compiler_library_, "ArtUnInitCompilerContext");
+    uninit_compiler_context = reinterpret_cast<void (*)(CompilerDriver&)>(ArtUnInitCompilerContext);
   } else {
-    uninit_compiler_context = FindFunction<void (*)(CompilerDriver&)>(compiler_so_name,
-                                                    compiler_library_, "ArtUnInitQuickCompilerContext");
+    uninit_compiler_context = reinterpret_cast<void (*)(CompilerDriver&)>(ArtUnInitQuickCompilerContext);
   }
   uninit_compiler_context(*this);
-#if 0
-  if (compiler_library_ != NULL) {
-    VLOG(compiler) << "dlclose(" << compiler_library_ << ")";
-    /*
-     * FIXME: Temporary workaround
-     * Apparently, llvm is adding dctors to atexit, but if we unload
-     * the library here the code will no longer be around at exit time
-     * and we die a flaming death in __cxa_finalize().  Apparently, some
-     * dlclose() implementations will scan the atexit list on unload and
-     * handle any associated with the soon-to-be-unloaded library.
-     * However, this is not required by POSIX and we don't do it.
-     * See: http://b/issue?id=4998315
-     * What's the right thing to do here?
-     *
-     * This has now been completely disabled because mclinker was
-     * closing stdout on exit, which was affecting both quick and
-     * portable.
-     */
-    dlclose(compiler_library_);
-  }
-#endif
 }
 
 CompilerTls* CompilerDriver::GetTls() {
@@ -1217,9 +1196,8 @@
         if (kEnableVerifierBasedSharpening && (invoke_type == kVirtual ||
                                                invoke_type == kInterface)) {
           // Did the verifier record a more precise invoke target based on its type information?
-          const CompilerDriver::MethodReference caller_method(mUnit->GetDexFile(),
-                                                              mUnit->GetDexMethodIndex());
-          const CompilerDriver::MethodReference* devirt_map_target =
+          const MethodReference caller_method(mUnit->GetDexFile(), mUnit->GetDexMethodIndex());
+          const MethodReference* devirt_map_target =
               verifier::MethodVerifier::GetDevirtMap(caller_method, dex_pc);
           if (devirt_map_target != NULL) {
             mirror::DexCache* target_dex_cache =
@@ -2138,7 +2116,7 @@
     }
     // Record the final class status if necessary.
     mirror::Class::Status status = klass->GetStatus();
-    CompilerDriver::ClassReference ref(manager->GetDexFile(), class_def_index);
+    ClassReference ref(manager->GetDexFile(), class_def_index);
     CompiledClass* compiled_class = manager->GetCompiler()->GetCompiledClass(ref);
     if (compiled_class == NULL) {
       compiled_class = new CompiledClass(status);
@@ -2287,21 +2265,16 @@
       dont_compile = false;
     }
     if (!dont_compile) {
-      bool use_sea = false;
-
-      if (Runtime::Current()->IsSeaIRMode()) {
-        use_sea = true;
-      }
+      CompilerFn compiler = compiler_;
+#ifdef ART_SEA_IR_MODE
+      bool use_sea = Runtime::Current()->IsSeaIRMode();
+      use_sea &&= (std::string::npos != PrettyMethod(method_idx, dex_file).find("fibonacci"));
       if (use_sea) {
-        use_sea = (std::string::npos != PrettyMethod(method_idx, dex_file).find("fibonacci"));
+        compiler = sea_ir_compiler_;
       }
-      if (!use_sea) {
-        compiled_method = (*compiler_)(*this, code_item, access_flags, invoke_type, class_def_idx,
-                                     method_idx, class_loader, dex_file);
-      } else {
-        compiled_method = (*sea_ir_compiler_)(*this, code_item, access_flags, invoke_type, class_def_idx,
-                                             method_idx, class_loader, dex_file);
-      }
+#endif
+      compiled_method = (*compiler)(*this, code_item, access_flags, invoke_type, class_def_idx,
+                                    method_idx, class_loader, dex_file);
       CHECK(compiled_method != NULL) << PrettyMethod(method_idx, dex_file);
     } else if (allow_dex_to_dex_compilation) {
       // TODO: add a mode to disable DEX-to-DEX compilation ?
@@ -2365,8 +2338,7 @@
   typedef void (*SetBitcodeFileNameFn)(CompilerDriver&, std::string const&);
 
   SetBitcodeFileNameFn set_bitcode_file_name =
-    FindFunction<SetBitcodeFileNameFn>(MakeCompilerSoName(compiler_backend_), compiler_library_,
-                                       "compilerLLVMSetBitcodeFileName");
+    reinterpret_cast<SetBitcodeFileNameFn>(compilerLLVMSetBitcodeFileName);
 
   set_bitcode_file_name(*this, filename);
 }
@@ -2386,45 +2358,16 @@
 
 bool CompilerDriver::WriteElf(const std::string& android_root,
                               bool is_host,
-                              const std::vector<const DexFile*>& dex_files,
+                              const std::vector<const art::DexFile*>& dex_files,
                               std::vector<uint8_t>& oat_contents,
-                              File* file) {
-  typedef bool (*WriteElfFn)(CompilerDriver&,
-                             const std::string& android_root,
-                             bool is_host,
-                             const std::vector<const DexFile*>& dex_files,
-                             std::vector<uint8_t>&,
-                             File*);
-  WriteElfFn WriteElf =
-    FindFunction<WriteElfFn>(MakeCompilerSoName(compiler_backend_), compiler_library_, "WriteElf");
-  Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
-  return WriteElf(*this, android_root, is_host, dex_files, oat_contents, file);
+                              art::File* file)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+#if defined(ART_USE_PORTABLE_COMPILER)
+  return art::ElfWriterMclinker::Create(file, oat_contents, dex_files, android_root, is_host, *this);
+#else
+  return art::ElfWriterQuick::Create(file, oat_contents, dex_files, android_root, is_host, *this);
+#endif
 }
-
-bool CompilerDriver::FixupElf(File* file, uintptr_t oat_data_begin) const {
-  typedef bool (*FixupElfFn)(File*, uintptr_t oat_data_begin);
-  FixupElfFn FixupElf =
-    FindFunction<FixupElfFn>(MakeCompilerSoName(compiler_backend_), compiler_library_, "FixupElf");
-  return FixupElf(file, oat_data_begin);
-}
-
-void CompilerDriver::GetOatElfInformation(File* file,
-                                          size_t& oat_loaded_size,
-                                          size_t& oat_data_offset) const {
-  typedef bool (*GetOatElfInformationFn)(File*, size_t& oat_loaded_size, size_t& oat_data_offset);
-  GetOatElfInformationFn GetOatElfInformation =
-    FindFunction<GetOatElfInformationFn>(MakeCompilerSoName(compiler_backend_), compiler_library_,
-                                         "GetOatElfInformation");
-  GetOatElfInformation(file, oat_loaded_size, oat_data_offset);
-}
-
-bool CompilerDriver::StripElf(File* file) const {
-  typedef bool (*StripElfFn)(File*);
-  StripElfFn StripElf =
-    FindFunction<StripElfFn>(MakeCompilerSoName(compiler_backend_), compiler_library_, "StripElf");
-  return StripElf(file);
-}
-
 void CompilerDriver::InstructionSetToLLVMTarget(InstructionSet instruction_set,
                                                 std::string& target_triple,
                                                 std::string& target_cpu,
diff --git a/src/compiler/driver/compiler_driver.h b/src/compiler/driver/compiler_driver.h
index b37b74b..d37f494 100644
--- a/src/compiler/driver/compiler_driver.h
+++ b/src/compiler/driver/compiler_driver.h
@@ -22,11 +22,13 @@
 #include <vector>
 
 #include "base/mutex.h"
+#include "class_reference.h"
 #include "compiled_class.h"
 #include "compiled_method.h"
 #include "dex_file.h"
 #include "instruction_set.h"
 #include "invoke_type.h"
+#include "method_reference.h"
 #include "oat_file.h"
 #include "runtime.h"
 #include "safe_map.h"
@@ -114,30 +116,9 @@
   const std::vector<uint8_t>* CreateInterpreterToQuickEntry() const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  // A class is uniquely located by its DexFile and the class_defs_ table index into that DexFile
-  typedef std::pair<const DexFile*, uint32_t> ClassReference;
-
   CompiledClass* GetCompiledClass(ClassReference ref) const
       LOCKS_EXCLUDED(compiled_classes_lock_);
 
-  // A method is uniquely located by its DexFile and the method_ids_ table index into that DexFile
-  struct MethodReference {
-    MethodReference(const DexFile* file, uint32_t index) : dex_file(file), dex_method_index(index) {
-    }
-    const DexFile* dex_file;
-    uint32_t dex_method_index;
-  };
-
-  struct MethodReferenceComparator {
-    bool operator()(MethodReference mr1, MethodReference mr2) const {
-      if (mr1.dex_file == mr2.dex_file) {
-        return mr1.dex_method_index < mr2.dex_method_index;
-      } else {
-        return mr1.dex_file < mr2.dex_file;
-      }
-    }
-  };
-
   CompiledMethod* GetCompiledMethod(MethodReference ref) const
       LOCKS_EXCLUDED(compiled_methods_lock_);
 
@@ -212,15 +193,11 @@
   }
 
 
-  // TODO: remove these Elf wrappers when libart links against LLVM (when separate compiler library is gone)
   bool WriteElf(const std::string& android_root,
                 bool is_host,
                 const std::vector<const DexFile*>& dex_files,
                 std::vector<uint8_t>& oat_contents,
                 File* file);
-  bool FixupElf(File* file, uintptr_t oat_data_begin) const;
-  void GetOatElfInformation(File* file, size_t& oat_loaded_size, size_t& oat_data_offset) const;
-  bool StripElf(File* file) const;
 
   // TODO: move to a common home for llvm helpers once quick/portable are merged
   static void InstructionSetToLLVMTarget(InstructionSet instruction_set,
@@ -404,7 +381,9 @@
                                         uint32_t class_dex_idx, uint32_t method_idx,
                                         jobject class_loader, const DexFile& dex_file);
   CompilerFn compiler_;
+#ifdef ART_SEA_IR_MODE
   CompilerFn sea_ir_compiler_;
+#endif
 
   CompilerFn dex_to_dex_compiler_;
 
@@ -429,16 +408,6 @@
   DISALLOW_COPY_AND_ASSIGN(CompilerDriver);
 };
 
-inline bool operator<(const CompilerDriver::ClassReference& lhs, const CompilerDriver::ClassReference& rhs) {
-  if (lhs.second < rhs.second) {
-    return true;
-  } else if (lhs.second > rhs.second) {
-    return false;
-  } else {
-    return (lhs.first < rhs.first);
-  }
-}
-
 }  // namespace art
 
 #endif  // ART_SRC_COMPILER_DRIVER_COMPILER_DRIVER_H_
diff --git a/src/compiler/elf_fixup.cc b/src/compiler/elf_fixup.cc
new file mode 100644
index 0000000..127bc85
--- /dev/null
+++ b/src/compiler/elf_fixup.cc
@@ -0,0 +1,279 @@
+/*
+ * 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_fixup.h"
+
+#include "base/logging.h"
+#include "base/stringprintf.h"
+#include "elf_file.h"
+#include "elf_writer.h"
+#include "UniquePtr.h"
+
+namespace art {
+
+static const bool DEBUG_FIXUP = false;
+
+bool ElfFixup::Fixup(File* file, uintptr_t oat_data_begin) {
+  UniquePtr<ElfFile> elf_file(ElfFile::Open(file, true, false));
+  CHECK(elf_file.get() != NULL);
+
+  // Lookup "oatdata" symbol address.
+  ::llvm::ELF::Elf32_Addr oatdata_address = ElfWriter::GetOatDataAddress(elf_file.get());
+  ::llvm::ELF::Elf32_Off base_address = oat_data_begin - oatdata_address;
+
+  if (!FixupDynamic(*elf_file.get(), base_address)) {
+      LOG(WARNING) << "Failed fo fixup .dynamic in " << file->GetPath();
+      return false;
+  }
+  if (!FixupSectionHeaders(*elf_file.get(), base_address)) {
+      LOG(WARNING) << "Failed fo fixup section headers in " << file->GetPath();
+      return false;
+  }
+  if (!FixupProgramHeaders(*elf_file.get(), base_address)) {
+      LOG(WARNING) << "Failed fo fixup program headers in " << file->GetPath();
+      return false;
+  }
+  if (!FixupSymbols(*elf_file.get(), base_address, true)) {
+      LOG(WARNING) << "Failed fo fixup .dynsym in " << file->GetPath();
+      return false;
+  }
+  if (!FixupSymbols(*elf_file.get(), base_address, false)) {
+      LOG(WARNING) << "Failed fo fixup .symtab in " << file->GetPath();
+      return false;
+  }
+  if (!FixupRelocations(*elf_file.get(), base_address)) {
+      LOG(WARNING) << "Failed fo fixup .rel.dyn in " << file->GetPath();
+      return false;
+  }
+  return true;
+}
+
+// MIPS seems to break the rules d_val vs d_ptr even though their values are between DT_LOPROC and DT_HIPROC
+#define DT_MIPS_RLD_VERSION  0x70000001 // d_val
+#define DT_MIPS_TIME_STAMP   0x70000002 // d_val
+#define DT_MIPS_ICHECKSUM    0x70000003 // d_val
+#define DT_MIPS_IVERSION     0x70000004 // d_val
+#define DT_MIPS_FLAGS        0x70000005 // d_val
+#define DT_MIPS_BASE_ADDRESS 0x70000006 // d_ptr
+#define DT_MIPS_CONFLICT     0x70000008 // d_ptr
+#define DT_MIPS_LIBLIST      0x70000009 // d_ptr
+#define DT_MIPS_LOCAL_GOTNO  0x7000000A // d_val
+#define DT_MIPS_CONFLICTNO   0x7000000B // d_val
+#define DT_MIPS_LIBLISTNO    0x70000010 // d_val
+#define DT_MIPS_SYMTABNO     0x70000011 // d_val
+#define DT_MIPS_UNREFEXTNO   0x70000012 // d_val
+#define DT_MIPS_GOTSYM       0x70000013 // d_val
+#define DT_MIPS_HIPAGENO     0x70000014 // d_val
+#define DT_MIPS_RLD_MAP      0x70000016 // d_ptr
+
+bool ElfFixup::FixupDynamic(ElfFile& elf_file, uintptr_t base_address) {
+  // TODO: C++0x auto.
+  for (::llvm::ELF::Elf32_Word i = 0; i < elf_file.GetDynamicNum(); i++) {
+    ::llvm::ELF::Elf32_Dyn& elf_dyn = elf_file.GetDynamic(i);
+    ::llvm::ELF::Elf32_Word d_tag = elf_dyn.d_tag;
+    bool elf_dyn_needs_fixup = false;
+    switch (d_tag) {
+      // case 1: well known d_tag values that imply Elf32_Dyn.d_un contains an address in d_ptr
+      case ::llvm::ELF::DT_PLTGOT:
+      case ::llvm::ELF::DT_HASH:
+      case ::llvm::ELF::DT_STRTAB:
+      case ::llvm::ELF::DT_SYMTAB:
+      case ::llvm::ELF::DT_RELA:
+      case ::llvm::ELF::DT_INIT:
+      case ::llvm::ELF::DT_FINI:
+      case ::llvm::ELF::DT_REL:
+      case ::llvm::ELF::DT_DEBUG:
+      case ::llvm::ELF::DT_JMPREL: {
+        elf_dyn_needs_fixup = true;
+        break;
+      }
+      // d_val or ignored values
+      case ::llvm::ELF::DT_NULL:
+      case ::llvm::ELF::DT_NEEDED:
+      case ::llvm::ELF::DT_PLTRELSZ:
+      case ::llvm::ELF::DT_RELASZ:
+      case ::llvm::ELF::DT_RELAENT:
+      case ::llvm::ELF::DT_STRSZ:
+      case ::llvm::ELF::DT_SYMENT:
+      case ::llvm::ELF::DT_SONAME:
+      case ::llvm::ELF::DT_RPATH:
+      case ::llvm::ELF::DT_SYMBOLIC:
+      case ::llvm::ELF::DT_RELSZ:
+      case ::llvm::ELF::DT_RELENT:
+      case ::llvm::ELF::DT_PLTREL:
+      case ::llvm::ELF::DT_TEXTREL:
+      case ::llvm::ELF::DT_BIND_NOW:
+      case ::llvm::ELF::DT_INIT_ARRAYSZ:
+      case ::llvm::ELF::DT_FINI_ARRAYSZ:
+      case ::llvm::ELF::DT_RUNPATH:
+      case ::llvm::ELF::DT_FLAGS: {
+        break;
+      }
+      // boundary values that should not be used
+      case ::llvm::ELF::DT_ENCODING:
+      case ::llvm::ELF::DT_LOOS:
+      case ::llvm::ELF::DT_HIOS:
+      case ::llvm::ELF::DT_LOPROC:
+      case ::llvm::ELF::DT_HIPROC: {
+        LOG(FATAL) << "Illegal d_tag value 0x" << std::hex << d_tag;
+        break;
+      }
+      default: {
+        // case 2: "regular" DT_* ranges where even d_tag values imply an address in d_ptr
+        if ((::llvm::ELF::DT_ENCODING  < d_tag && d_tag < ::llvm::ELF::DT_LOOS)
+            || (::llvm::ELF::DT_LOOS   < d_tag && d_tag < ::llvm::ELF::DT_HIOS)
+            || (::llvm::ELF::DT_LOPROC < d_tag && d_tag < ::llvm::ELF::DT_HIPROC)) {
+          // Special case for MIPS which breaks the regular rules between DT_LOPROC and DT_HIPROC
+          if (elf_file.GetHeader().e_machine == ::llvm::ELF::EM_MIPS) {
+            switch (d_tag) {
+              case DT_MIPS_RLD_VERSION:
+              case DT_MIPS_TIME_STAMP:
+              case DT_MIPS_ICHECKSUM:
+              case DT_MIPS_IVERSION:
+              case DT_MIPS_FLAGS:
+              case DT_MIPS_LOCAL_GOTNO:
+              case DT_MIPS_CONFLICTNO:
+              case DT_MIPS_LIBLISTNO:
+              case DT_MIPS_SYMTABNO:
+              case DT_MIPS_UNREFEXTNO:
+              case DT_MIPS_GOTSYM:
+              case DT_MIPS_HIPAGENO: {
+                break;
+              }
+              case DT_MIPS_BASE_ADDRESS:
+              case DT_MIPS_CONFLICT:
+              case DT_MIPS_LIBLIST:
+              case DT_MIPS_RLD_MAP: {
+                elf_dyn_needs_fixup = true;
+                break;
+              }
+              default: {
+                LOG(FATAL) << "Unknown MIPS d_tag value 0x" << std::hex << d_tag;
+                break;
+              }
+            }
+          } else if ((elf_dyn.d_tag % 2) == 0) {
+            elf_dyn_needs_fixup = true;
+          }
+        } else {
+          LOG(FATAL) << "Unknown d_tag value 0x" << std::hex << d_tag;
+        }
+        break;
+      }
+    }
+    if (elf_dyn_needs_fixup) {
+      uint32_t d_ptr = elf_dyn.d_un.d_ptr;
+      if (DEBUG_FIXUP) {
+        LOG(INFO) << StringPrintf("In %s moving Elf32_Dyn[%d] from 0x%08x to 0x%08x",
+                                  elf_file.GetFile().GetPath().c_str(), i,
+                                  d_ptr, d_ptr + base_address);
+      }
+      d_ptr += base_address;
+      elf_dyn.d_un.d_ptr = d_ptr;
+    }
+  }
+  return true;
+}
+
+bool ElfFixup::FixupSectionHeaders(ElfFile& elf_file, uintptr_t base_address) {
+  for (::llvm::ELF::Elf32_Word i = 0; i < elf_file.GetSectionHeaderNum(); i++) {
+    ::llvm::ELF::Elf32_Shdr& sh = elf_file.GetSectionHeader(i);
+    // 0 implies that the section will not exist in the memory of the process
+    if (sh.sh_addr == 0) {
+      continue;
+    }
+    if (DEBUG_FIXUP) {
+      LOG(INFO) << StringPrintf("In %s moving Elf32_Shdr[%d] from 0x%08x to 0x%08x",
+                                elf_file.GetFile().GetPath().c_str(), i,
+                                sh.sh_addr, sh.sh_addr + base_address);
+    }
+    sh.sh_addr += base_address;
+  }
+  return true;
+}
+
+bool ElfFixup::FixupProgramHeaders(ElfFile& elf_file, uintptr_t base_address) {
+  // TODO: ELFObjectFile doesn't have give to Elf32_Phdr, so we do that ourselves for now.
+  for (::llvm::ELF::Elf32_Word i = 0; i < elf_file.GetProgramHeaderNum(); i++) {
+    ::llvm::ELF::Elf32_Phdr& ph = elf_file.GetProgramHeader(i);
+    CHECK_EQ(ph.p_vaddr, ph.p_paddr) << elf_file.GetFile().GetPath() << " i=" << i;
+    CHECK((ph.p_align == 0) || (0 == ((ph.p_vaddr - ph.p_offset) & (ph.p_align - 1))))
+            << elf_file.GetFile().GetPath() << " i=" << i;
+    if (DEBUG_FIXUP) {
+      LOG(INFO) << StringPrintf("In %s moving Elf32_Phdr[%d] from 0x%08x to 0x%08x",
+                                elf_file.GetFile().GetPath().c_str(), i,
+                                ph.p_vaddr, ph.p_vaddr + base_address);
+    }
+    ph.p_vaddr += base_address;
+    ph.p_paddr += base_address;
+    CHECK((ph.p_align == 0) || (0 == ((ph.p_vaddr - ph.p_offset) & (ph.p_align - 1))))
+            << elf_file.GetFile().GetPath() << " i=" << i;
+  }
+  return true;
+}
+
+bool ElfFixup::FixupSymbols(ElfFile& elf_file, uintptr_t base_address, bool dynamic) {
+  ::llvm::ELF::Elf32_Word section_type = dynamic ? ::llvm::ELF::SHT_DYNSYM : ::llvm::ELF::SHT_SYMTAB;
+  // TODO: Unfortunate ELFObjectFile has protected symbol access, so use ElfFile
+  ::llvm::ELF::Elf32_Shdr* symbol_section = elf_file.FindSectionByType(section_type);
+  if (symbol_section == NULL) {
+    // file is missing optional .symtab
+    CHECK(!dynamic) << elf_file.GetFile().GetPath();
+    return true;
+  }
+  for (uint32_t i = 0; i < elf_file.GetSymbolNum(*symbol_section); i++) {
+    ::llvm::ELF::Elf32_Sym& symbol = elf_file.GetSymbol(section_type, i);
+    if (symbol.st_value != 0) {
+      if (DEBUG_FIXUP) {
+        LOG(INFO) << StringPrintf("In %s moving Elf32_Sym[%d] from 0x%08x to 0x%08x",
+                                  elf_file.GetFile().GetPath().c_str(), i,
+                                  symbol.st_value, symbol.st_value + base_address);
+      }
+      symbol.st_value += base_address;
+    }
+  }
+  return true;
+}
+
+bool ElfFixup::FixupRelocations(ElfFile& elf_file, uintptr_t base_address) {
+  for (llvm::ELF::Elf32_Word i = 0; i < elf_file.GetSectionHeaderNum(); i++) {
+    llvm::ELF::Elf32_Shdr& sh = elf_file.GetSectionHeader(i);
+    if (sh.sh_type == llvm::ELF::SHT_REL) {
+      for (uint32_t i = 0; i < elf_file.GetRelNum(sh); i++) {
+        llvm::ELF::Elf32_Rel& rel = elf_file.GetRel(sh, i);
+        if (DEBUG_FIXUP) {
+          LOG(INFO) << StringPrintf("In %s moving Elf32_Rel[%d] from 0x%08x to 0x%08x",
+                                    elf_file.GetFile().GetPath().c_str(), i,
+                                    rel.r_offset, rel.r_offset + base_address);
+        }
+        rel.r_offset += base_address;
+      }
+    } else if (sh.sh_type == llvm::ELF::SHT_RELA) {
+      for (uint32_t i = 0; i < elf_file.GetRelaNum(sh); i++) {
+        llvm::ELF::Elf32_Rela& rela = elf_file.GetRela(sh, i);
+        if (DEBUG_FIXUP) {
+          LOG(INFO) << StringPrintf("In %s moving Elf32_Rela[%d] from 0x%08x to 0x%08x",
+                                    elf_file.GetFile().GetPath().c_str(), i,
+                                    rela.r_offset, rela.r_offset + base_address);
+        }
+        rela.r_offset += base_address;
+      }
+    }
+  }
+  return true;
+}
+
+}  // namespace art
diff --git a/src/compiler/elf_fixup.h b/src/compiler/elf_fixup.h
new file mode 100644
index 0000000..79c45c1
--- /dev/null
+++ b/src/compiler/elf_fixup.h
@@ -0,0 +1,56 @@
+/*
+ * 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_SRC_ELF_FIXUP_H_
+#define ART_SRC_ELF_FIXUP_H_
+
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "os.h"
+
+namespace art {
+
+class ElfFile;
+
+class ElfFixup {
+ public:
+  // Fixup an ELF file so that that oat header will be loaded at oat_begin.
+  // Returns true on success, false on failure.
+  static bool Fixup(File* file, uintptr_t oat_data_begin);
+
+ private:
+  // Fixup .dynamic d_ptr values for the expected base_address.
+  static bool FixupDynamic(ElfFile& elf_file, uintptr_t base_address);
+
+  // Fixup Elf32_Shdr p_vaddr to load at the desired address.
+  static bool FixupSectionHeaders(ElfFile& elf_file, uintptr_t base_address);
+
+  // Fixup Elf32_Phdr p_vaddr to load at the desired address.
+  static bool FixupProgramHeaders(ElfFile& elf_file, uintptr_t base_address);
+
+  // Fixup symbol table
+  static bool FixupSymbols(ElfFile& elf_file, uintptr_t base_address, bool dynamic);
+
+  // Fixup dynamic relocations
+  static bool FixupRelocations(ElfFile& elf_file, uintptr_t base_address);
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ElfFixup);
+};
+
+}  // namespace art
+
+#endif  // ART_SRC_ELF_FIXUP_H_
diff --git a/src/compiler/elf_stripper.cc b/src/compiler/elf_stripper.cc
new file mode 100644
index 0000000..7fc662c
--- /dev/null
+++ b/src/compiler/elf_stripper.cc
@@ -0,0 +1,129 @@
+/*
+ * 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_stripper.h"
+
+#include <vector>
+
+#include <llvm/Support/ELF.h>
+
+#include "UniquePtr.h"
+#include "base/logging.h"
+#include "elf_file.h"
+#include "utils.h"
+
+namespace art {
+
+bool ElfStripper::Strip(File* file) {
+  UniquePtr<ElfFile> elf_file(ElfFile::Open(file, true, false));
+  CHECK(elf_file.get() != NULL);
+
+  // ELF files produced by MCLinker look roughly like this
+  //
+  // +------------+
+  // | Elf32_Ehdr | contains number of Elf32_Shdr and offset to first
+  // +------------+
+  // | Elf32_Phdr | program headers
+  // | Elf32_Phdr |
+  // | ...        |
+  // | Elf32_Phdr |
+  // +------------+
+  // | section    | mixture of needed and unneeded sections
+  // +------------+
+  // | section    |
+  // +------------+
+  // | ...        |
+  // +------------+
+  // | section    |
+  // +------------+
+  // | Elf32_Shdr | section headers
+  // | Elf32_Shdr |
+  // | ...        | contains offset to section start
+  // | Elf32_Shdr |
+  // +------------+
+  //
+  // To strip:
+  // - leave the Elf32_Ehdr and Elf32_Phdr values in place.
+  // - walk the sections making a new set of Elf32_Shdr section headers for what we want to keep
+  // - move the sections are keeping up to fill in gaps of sections we want to strip
+  // - write new Elf32_Shdr section headers to end of file, updating Elf32_Ehdr
+  // - truncate rest of file
+  //
+
+  std::vector<llvm::ELF::Elf32_Shdr> section_headers;
+  std::vector<llvm::ELF::Elf32_Word> section_headers_original_indexes;
+  section_headers.reserve(elf_file->GetSectionHeaderNum());
+
+
+  llvm::ELF::Elf32_Shdr& string_section = elf_file->GetSectionNameStringSection();
+  for (llvm::ELF::Elf32_Word i = 0; i < elf_file->GetSectionHeaderNum(); i++) {
+    llvm::ELF::Elf32_Shdr& sh = elf_file->GetSectionHeader(i);
+    const char* name = elf_file->GetString(string_section, sh.sh_name);
+    if (name == NULL) {
+      CHECK_EQ(0U, i);
+      section_headers.push_back(sh);
+      section_headers_original_indexes.push_back(0);
+      continue;
+    }
+    if (StartsWith(name, ".debug")
+        || (strcmp(name, ".strtab") == 0)
+        || (strcmp(name, ".symtab") == 0)) {
+      continue;
+    }
+    section_headers.push_back(sh);
+    section_headers_original_indexes.push_back(i);
+  }
+  CHECK_NE(0U, section_headers.size());
+  CHECK_EQ(section_headers.size(), section_headers_original_indexes.size());
+
+  // section 0 is the NULL section, sections start at offset of first section
+  llvm::ELF::Elf32_Off offset = elf_file->GetSectionHeader(1).sh_offset;
+  for (size_t i = 1; i < section_headers.size(); i++) {
+    llvm::ELF::Elf32_Shdr& new_sh = section_headers[i];
+    llvm::ELF::Elf32_Shdr& old_sh = elf_file->GetSectionHeader(section_headers_original_indexes[i]);
+    CHECK_EQ(new_sh.sh_name, old_sh.sh_name);
+    if (old_sh.sh_addralign > 1) {
+      offset = RoundUp(offset, old_sh.sh_addralign);
+    }
+    if (old_sh.sh_offset == offset) {
+      // already in place
+      offset += old_sh.sh_size;
+      continue;
+    }
+    // shift section earlier
+    memmove(elf_file->Begin() + offset,
+            elf_file->Begin() + old_sh.sh_offset,
+            old_sh.sh_size);
+    new_sh.sh_offset = offset;
+    offset += old_sh.sh_size;
+  }
+
+  llvm::ELF::Elf32_Off shoff = offset;
+  size_t section_headers_size_in_bytes = section_headers.size() * sizeof(llvm::ELF::Elf32_Shdr);
+  memcpy(elf_file->Begin() + offset, &section_headers[0], section_headers_size_in_bytes);
+  offset += section_headers_size_in_bytes;
+
+  elf_file->GetHeader().e_shnum = section_headers.size();
+  elf_file->GetHeader().e_shoff = shoff;
+  int result = ftruncate(file->Fd(), offset);
+  if (result != 0) {
+    PLOG(ERROR) << "Failed to truncate while stripping ELF file: " << file->GetPath();
+    return false;
+  }
+  return true;
+}
+
+}  // namespace art
diff --git a/src/compiler/elf_stripper.h b/src/compiler/elf_stripper.h
new file mode 100644
index 0000000..b202e6e
--- /dev/null
+++ b/src/compiler/elf_stripper.h
@@ -0,0 +1,37 @@
+/*
+ * 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_SRC_ELF_STRIPPER_H_
+#define ART_SRC_ELF_STRIPPER_H_
+
+#include "base/macros.h"
+#include "os.h"
+
+namespace art {
+
+class ElfStripper {
+ public:
+  // Strip an ELF file of unneeded debugging information.
+  // Returns true on success, false on failure.
+  static bool Strip(File* file);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ElfStripper);
+};
+
+}  // namespace art
+
+#endif  // ART_SRC_ELF_STRIPPER_H_
diff --git a/src/compiler/elf_writer.cc b/src/compiler/elf_writer.cc
new file mode 100644
index 0000000..7592eb5
--- /dev/null
+++ b/src/compiler/elf_writer.cc
@@ -0,0 +1,60 @@
+/*
+ * 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 "class_linker.h"
+#include "compiler/driver/compiler_driver.h"
+#include "compiler/llvm/utils_llvm.h"
+#include "dex_file-inl.h"
+#include "dex_method_iterator.h"
+#include "elf_file.h"
+#include "invoke_type.h"
+#include "mirror/abstract_method-inl.h"
+#include "mirror/object-inl.h"
+#include "oat.h"
+#include "oat_file.h"
+#include "scoped_thread_state_change.h"
+
+namespace art {
+
+ElfWriter::ElfWriter(const CompilerDriver& driver, File* elf_file)
+  : compiler_driver_(&driver), elf_file_(elf_file) {}
+
+ElfWriter::~ElfWriter() {}
+
+llvm::ELF::Elf32_Addr ElfWriter::GetOatDataAddress(ElfFile* elf_file) {
+  llvm::ELF::Elf32_Addr oatdata_address = elf_file->FindSymbolAddress(llvm::ELF::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) {
+  UniquePtr<ElfFile> elf_file(ElfFile::Open(file, false, false));
+  CHECK(elf_file.get() != NULL);
+
+  oat_loaded_size = elf_file->GetLoadedSize();
+  CHECK_NE(0U, oat_loaded_size);
+  oat_data_offset = GetOatDataAddress(elf_file.get());
+  CHECK_NE(0U, oat_data_offset);
+}
+
+}  // namespace art
diff --git a/src/compiler/elf_writer.h b/src/compiler/elf_writer.h
new file mode 100644
index 0000000..7392e67
--- /dev/null
+++ b/src/compiler/elf_writer.h
@@ -0,0 +1,65 @@
+/*
+ * 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_SRC_ELF_WRITER_H_
+#define ART_SRC_ELF_WRITER_H_
+
+#include <stdint.h>
+
+#include <cstddef>
+#include <string>
+#include <vector>
+
+#include <llvm/Support/ELF.h>
+
+#include "base/macros.h"
+#include "os.h"
+
+namespace art {
+
+class CompilerDriver;
+class DexFile;
+class ElfFile;
+
+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 llvm::ELF::Elf32_Addr GetOatDataAddress(ElfFile* elf_file);
+
+ protected:
+  ElfWriter(const CompilerDriver& driver, File* elf_file);
+  ~ElfWriter();
+
+  virtual bool Write(std::vector<uint8_t>& oat_contents,
+                     const std::vector<const DexFile*>& dex_files,
+                     const std::string& android_root,
+                     bool is_host)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0;
+
+  // Setup by constructor
+  const CompilerDriver* compiler_driver_;
+  File* elf_file_;
+};
+
+}  // namespace art
+
+#endif  // ART_SRC_ELF_WRITER_H_
diff --git a/src/compiler/elf_writer_mclinker.cc b/src/compiler/elf_writer_mclinker.cc
new file mode 100644
index 0000000..e1d98f6
--- /dev/null
+++ b/src/compiler/elf_writer_mclinker.cc
@@ -0,0 +1,401 @@
+/*
+ * 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_mclinker.h"
+
+#include <llvm/Support/TargetSelect.h>
+
+#include <mcld/Environment.h>
+#include <mcld/IRBuilder.h>
+#include <mcld/Linker.h>
+#include <mcld/LinkerConfig.h>
+#include <mcld/MC/ZOption.h>
+#include <mcld/Module.h>
+#include <mcld/Support/Path.h>
+#include <mcld/Support/TargetSelect.h>
+
+#include "base/unix_file/fd_file.h"
+#include "class_linker.h"
+#include "compiler/driver/compiler_driver.h"
+#include "dex_method_iterator.h"
+#include "elf_file.h"
+#include "globals.h"
+#include "mirror/abstract_method.h"
+#include "mirror/abstract_method-inl.h"
+#include "mirror/object-inl.h"
+#include "scoped_thread_state_change.h"
+
+namespace art {
+
+ElfWriterMclinker::ElfWriterMclinker(const CompilerDriver& driver, File* elf_file)
+  : ElfWriter(driver, elf_file), oat_input_(NULL) {}
+
+ElfWriterMclinker::~ElfWriterMclinker() {}
+
+bool ElfWriterMclinker::Create(File* elf_file,
+                               std::vector<uint8_t>& oat_contents,
+                               const std::vector<const DexFile*>& dex_files,
+                               const std::string& android_root,
+                               bool is_host,
+                               const CompilerDriver& driver) {
+  ElfWriterMclinker elf_writer(driver, elf_file);
+  return elf_writer.Write(oat_contents, dex_files, android_root, is_host);
+}
+
+bool ElfWriterMclinker::Write(std::vector<uint8_t>& oat_contents,
+                              const std::vector<const DexFile*>& dex_files,
+                              const std::string& android_root,
+                              bool is_host) {
+  Init();
+  AddOatInput(oat_contents);
+#if defined(ART_USE_PORTABLE_COMPILER)
+  AddMethodInputs(dex_files);
+  AddRuntimeInputs(android_root, is_host);
+#endif
+  if (!Link()) {
+    return false;
+  }
+#if defined(ART_USE_PORTABLE_COMPILER)
+  FixupOatMethodOffsets(dex_files);
+#endif
+  return true;
+}
+
+static void InitializeLLVM() {
+  // TODO: this is lifted from art's compiler_llvm.cc, should be factored out
+  if (kIsTargetBuild) {
+    llvm::InitializeNativeTarget();
+    // TODO: odd that there is no InitializeNativeTargetMC?
+  } else {
+    llvm::InitializeAllTargets();
+    llvm::InitializeAllTargetMCs();
+  }
+}
+
+void ElfWriterMclinker::Init() {
+  std::string target_triple;
+  std::string target_cpu;
+  std::string target_attr;
+  CompilerDriver::InstructionSetToLLVMTarget(compiler_driver_->GetInstructionSet(),
+                                             target_triple,
+                                             target_cpu,
+                                             target_attr);
+
+  // Based on mclinker's llvm-mcld.cpp main() and LinkerTest
+  //
+  // TODO: LinkerTest uses mcld::Initialize(), but it does an
+  // llvm::InitializeAllTargets, which we don't want. Basically we
+  // want mcld::InitializeNative, but it doesn't exist yet, so we
+  // inline the minimal we need here.
+  InitializeLLVM();
+  mcld::InitializeAllTargets();
+  mcld::InitializeAllLinkers();
+  mcld::InitializeAllEmulations();
+  mcld::InitializeAllDiagnostics();
+
+  linker_config_.reset(new mcld::LinkerConfig(target_triple));
+  CHECK(linker_config_.get() != NULL);
+  linker_config_->setCodeGenType(mcld::LinkerConfig::DynObj);
+  linker_config_->options().setSOName(elf_file_->GetPath());
+
+  // error on undefined symbols.
+  // TODO: should this just be set if kIsDebugBuild?
+  linker_config_->options().setNoUndefined(true);
+
+  if (compiler_driver_->GetInstructionSet() == kMips) {
+     // MCLinker defaults MIPS section alignment to 0x10000, not
+     // 0x1000.  The ABI says this is because the max page size is
+     // general is 64k but that isn't true on Android.
+     mcld::ZOption z_option;
+     z_option.setKind(mcld::ZOption::MaxPageSize);
+     z_option.setPageSize(kPageSize);
+     linker_config_->options().addZOption(z_option);
+  }
+
+  // TODO: Wire up mcld DiagnosticEngine to LOG?
+  linker_config_->options().setColor(false);
+  if (false) {
+    // enables some tracing of input file processing
+    linker_config_->options().setTrace(true);
+  }
+
+  // Based on alone::Linker::config
+  module_.reset(new mcld::Module(linker_config_->options().soname()));
+  CHECK(module_.get() != NULL);
+  ir_builder_.reset(new mcld::IRBuilder(*module_.get(), *linker_config_.get()));
+  CHECK(ir_builder_.get() != NULL);
+  linker_.reset(new mcld::Linker());
+  CHECK(linker_.get() != NULL);
+  linker_->config(*linker_config_.get());
+}
+
+void ElfWriterMclinker::AddOatInput(std::vector<uint8_t>& oat_contents) {
+  // Add an artificial memory input. Based on LinkerTest.
+  UniquePtr<OatFile> oat_file(OatFile::OpenMemory(oat_contents, elf_file_->GetPath()));
+  CHECK(oat_file.get() != NULL) << elf_file_->GetPath();
+
+  const char* oat_data_start = reinterpret_cast<const char*>(&oat_file->GetOatHeader());
+  const size_t oat_data_length = oat_file->GetOatHeader().GetExecutableOffset();
+  const char* oat_code_start = oat_data_start + oat_data_length;
+  const size_t oat_code_length = oat_file->Size() - oat_data_length;
+
+  // TODO: ownership of oat_input?
+  oat_input_ = ir_builder_->CreateInput("oat contents",
+                                        mcld::sys::fs::Path("oat contents path"),
+                                        mcld::Input::Object);
+  CHECK(oat_input_ != NULL);
+
+  // TODO: ownership of null_section?
+  mcld::LDSection* null_section = ir_builder_->CreateELFHeader(*oat_input_,
+                                                               "",
+                                                               mcld::LDFileFormat::Null,
+                                                               llvm::ELF::SHT_NULL,
+                                                               0);
+  CHECK(null_section != NULL);
+
+  // TODO: we should split readonly data from readonly executable
+  // code like .oat does.  We need to control section layout with
+  // linker script like functionality to guarantee references
+  // between sections maintain relative position which isn't
+  // possible right now with the mclinker APIs.
+  CHECK(oat_code_start != NULL);
+
+  // we need to ensure that oatdata is page aligned so when we
+  // fixup the segment load addresses, they remain page aligned.
+  uint32_t alignment = kPageSize;
+
+  // TODO: ownership of text_section?
+  mcld::LDSection* text_section = ir_builder_->CreateELFHeader(*oat_input_,
+                                                               ".text",
+                                                               llvm::ELF::SHT_PROGBITS,
+                                                               llvm::ELF::SHF_EXECINSTR
+                                                               | llvm::ELF::SHF_ALLOC,
+                                                               alignment);
+  CHECK(text_section != NULL);
+
+  mcld::SectionData* text_sectiondata = ir_builder_->CreateSectionData(*text_section);
+  CHECK(text_sectiondata != NULL);
+
+  // TODO: why does IRBuilder::CreateRegion take a non-const pointer?
+  mcld::Fragment* text_fragment = ir_builder_->CreateRegion(const_cast<char*>(oat_data_start),
+                                                            oat_file->Size());
+  CHECK(text_fragment != NULL);
+  ir_builder_->AppendFragment(*text_fragment, *text_sectiondata);
+
+  ir_builder_->AddSymbol(*oat_input_,
+                         "oatdata",
+                         mcld::ResolveInfo::Object,
+                         mcld::ResolveInfo::Define,
+                         mcld::ResolveInfo::Global,
+                         oat_data_length,  // size
+                         0,                // offset
+                         text_section);
+
+  ir_builder_->AddSymbol(*oat_input_,
+                         "oatexec",
+                         mcld::ResolveInfo::Function,
+                         mcld::ResolveInfo::Define,
+                         mcld::ResolveInfo::Global,
+                         oat_code_length,  // size
+                         oat_data_length,  // offset
+                         text_section);
+
+  ir_builder_->AddSymbol(*oat_input_,
+                         "oatlastword",
+                         mcld::ResolveInfo::Object,
+                         mcld::ResolveInfo::Define,
+                         mcld::ResolveInfo::Global,
+                         0,                // size
+                         // subtract a word so symbol is within section
+                         (oat_data_length + oat_code_length) - sizeof(uint32_t),  // offset
+                         text_section);
+}
+
+#if defined(ART_USE_PORTABLE_COMPILER)
+void ElfWriterMclinker::AddMethodInputs(const std::vector<const DexFile*>& dex_files) {
+  DCHECK(oat_input_ != NULL);
+
+  DexMethodIterator it(dex_files);
+  while (it.HasNext()) {
+    const DexFile& dex_file = it.GetDexFile();
+    uint32_t method_idx = it.GetMemberIndex();
+    const CompiledMethod* compiled_method =
+      compiler_driver_->GetCompiledMethod(CompilerDriver::MethodReference(&dex_file, method_idx));
+    if (compiled_method != NULL) {
+      AddCompiledCodeInput(*compiled_method);
+    }
+    it.Next();
+  }
+  added_symbols_.clear();
+}
+
+void ElfWriterMclinker::AddCompiledCodeInput(const CompiledCode& compiled_code) {
+  // Check if we've seen this compiled code before. If so skip
+  // it. This can happen for reused code such as invoke stubs.
+  const std::string& symbol = compiled_code.GetSymbol();
+  SafeMap<const std::string*, const std::string*>::iterator it = added_symbols_.find(&symbol);
+  if (it != added_symbols_.end()) {
+    return;
+  }
+  added_symbols_.Put(&symbol, &symbol);
+
+  // Add input to supply code for symbol
+  const std::vector<uint8_t>& code = compiled_code.GetCode();
+  // TODO: ownership of code_input?
+  // TODO: why does IRBuilder::ReadInput take a non-const pointer?
+  mcld::Input* code_input = ir_builder_->ReadInput(symbol,
+                                                   const_cast<uint8_t*>(&code[0]),
+                                                   code.size());
+  CHECK(code_input != NULL);
+}
+
+void ElfWriterMclinker::AddRuntimeInputs(const std::string& android_root, bool is_host) {
+  std::string libart_so(android_root);
+  libart_so += kIsDebugBuild ? "/lib/libartd.so" : "/lib/libart.so";
+  // TODO: ownership of libart_so_input?
+  mcld::Input* libart_so_input = ir_builder_->ReadInput(libart_so, libart_so);
+  CHECK(libart_so_input != NULL);
+
+  std::string host_prebuilt_dir("prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6");
+
+  std::string compiler_runtime_lib;
+  if (is_host) {
+    compiler_runtime_lib += host_prebuilt_dir;
+    compiler_runtime_lib += "/lib/gcc/i686-linux/4.6.x-google/libgcc.a";
+  } else {
+    compiler_runtime_lib += android_root;
+    compiler_runtime_lib += "/lib/libcompiler_rt.a";
+  }
+  // TODO: ownership of compiler_runtime_lib_input?
+  mcld::Input* compiler_runtime_lib_input = ir_builder_->ReadInput(compiler_runtime_lib,
+                                                                   compiler_runtime_lib);
+  CHECK(compiler_runtime_lib_input != NULL);
+
+  std::string libc_lib;
+  if (is_host) {
+    libc_lib += host_prebuilt_dir;
+    libc_lib += "/sysroot/usr/lib/libc.so.6";
+  } else {
+    libc_lib += android_root;
+    libc_lib += "/lib/libc.so";
+  }
+  // TODO: ownership of libc_lib_input?
+  mcld::Input* libc_lib_input_input = ir_builder_->ReadInput(libc_lib, libc_lib);
+  CHECK(libc_lib_input_input != NULL);
+
+  std::string libm_lib;
+  if (is_host) {
+    libm_lib += host_prebuilt_dir;
+    libm_lib += "/sysroot/usr/lib/libm.so";
+  } else {
+    libm_lib += android_root;
+    libm_lib += "/lib/libm.so";
+  }
+  // TODO: ownership of libm_lib_input?
+  mcld::Input* libm_lib_input_input = ir_builder_->ReadInput(libm_lib, libm_lib);
+  CHECK(libm_lib_input_input != NULL);
+
+}
+#endif
+
+bool ElfWriterMclinker::Link() {
+  // link inputs
+  if (!linker_->link(*module_.get(), *ir_builder_.get())) {
+    LOG(ERROR) << "Failed to link " << elf_file_->GetPath();
+    return false;
+  }
+
+  // emit linked output
+  // TODO: avoid dup of fd by fixing Linker::emit to not close the argument fd.
+  int fd = dup(elf_file_->Fd());
+  if (fd == -1) {
+    PLOG(ERROR) << "Failed to dup file descriptor for " << elf_file_->GetPath();
+    return false;
+  }
+  if (!linker_->emit(fd)) {
+    LOG(ERROR) << "Failed to emit " << elf_file_->GetPath();
+    return false;
+  }
+  mcld::Finalize();
+  LOG(INFO) << "ELF file written successfully: " << elf_file_->GetPath();
+  return true;
+}
+
+#if defined(ART_USE_PORTABLE_COMPILER)
+void ElfWriterMclinker::FixupOatMethodOffsets(const std::vector<const DexFile*>& dex_files) {
+  UniquePtr<ElfFile> elf_file(ElfFile::Open(elf_file_, true, false));
+  CHECK(elf_file.get() != NULL) << elf_file_->GetPath();
+
+  llvm::ELF::Elf32_Addr oatdata_address = GetOatDataAddress(elf_file.get());
+  DexMethodIterator it(dex_files);
+  while (it.HasNext()) {
+    const DexFile& dex_file = it.GetDexFile();
+    uint32_t method_idx = it.GetMemberIndex();
+    InvokeType invoke_type = it.GetInvokeType();
+    mirror::AbstractMethod* method = NULL;
+    if (compiler_driver_->IsImage()) {
+      ClassLinker* linker = Runtime::Current()->GetClassLinker();
+      mirror::DexCache* dex_cache = linker->FindDexCache(dex_file);
+      // Unchecked as we hold mutator_lock_ on entry.
+      ScopedObjectAccessUnchecked soa(Thread::Current());
+      method = linker->ResolveMethod(dex_file, method_idx, dex_cache, NULL, NULL, invoke_type);
+      CHECK(method != NULL);
+    }
+    const CompiledMethod* compiled_method =
+      compiler_driver_->GetCompiledMethod(CompilerDriver::MethodReference(&dex_file, method_idx));
+    if (compiled_method != NULL) {
+      uint32_t offset = FixupCompiledCodeOffset(*elf_file.get(), oatdata_address, *compiled_method);
+      // Don't overwrite static method trampoline
+      if (method != NULL &&
+          (!method->IsStatic() ||
+           method->IsConstructor() ||
+           method->GetDeclaringClass()->IsInitialized())) {
+        method->SetOatCodeOffset(offset);
+      }
+    }
+    it.Next();
+  }
+  symbol_to_compiled_code_offset_.clear();
+}
+
+uint32_t ElfWriterMclinker::FixupCompiledCodeOffset(ElfFile& elf_file,
+                                                    llvm::ELF::Elf32_Addr oatdata_address,
+                                                    const CompiledCode& compiled_code) {
+  const std::string& symbol = compiled_code.GetSymbol();
+  SafeMap<const std::string*, uint32_t>::iterator it = symbol_to_compiled_code_offset_.find(&symbol);
+  if (it != symbol_to_compiled_code_offset_.end()) {
+    return it->second;
+  }
+
+  llvm::ELF::Elf32_Addr compiled_code_address = elf_file.FindSymbolAddress(llvm::ELF::SHT_SYMTAB,
+                                                                           symbol,
+                                                                           true);
+  CHECK_NE(0U, compiled_code_address) << symbol;
+  CHECK_LT(oatdata_address, compiled_code_address) << symbol;
+  uint32_t compiled_code_offset = compiled_code_address - oatdata_address;
+  symbol_to_compiled_code_offset_.Put(&symbol, compiled_code_offset);
+
+  const std::vector<uint32_t>& offsets = compiled_code.GetOatdataOffsetsToCompliledCodeOffset();
+  for (uint32_t i = 0; i < offsets.size(); i++) {
+    uint32_t oatdata_offset = oatdata_address + offsets[i];
+    uint32_t* addr = reinterpret_cast<uint32_t*>(elf_file.Begin() + oatdata_offset);
+    *addr = compiled_code_offset;
+  }
+  return compiled_code_offset;
+}
+#endif
+
+}  // namespace art
diff --git a/src/compiler/elf_writer_mclinker.h b/src/compiler/elf_writer_mclinker.h
new file mode 100644
index 0000000..21f23e1
--- /dev/null
+++ b/src/compiler/elf_writer_mclinker.h
@@ -0,0 +1,99 @@
+/*
+ * 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_SRC_ELF_WRITER_MCLINKER_H_
+#define ART_SRC_ELF_WRITER_MCLINKER_H_
+
+#include "elf_writer.h"
+
+#include "UniquePtr.h"
+#include "safe_map.h"
+
+namespace mcld {
+class IRBuilder;
+class Input;
+class LDSection;
+class LDSymbol;
+class Linker;
+class LinkerConfig;
+class Module;
+} // namespace mcld
+
+namespace art {
+
+class CompiledCode;
+
+class ElfWriterMclinker : public ElfWriter {
+ public:
+
+  // Write an ELF file. Returns true on success, false on failure.
+  static bool Create(File* file,
+                     std::vector<uint8_t>& oat_contents,
+                     const std::vector<const DexFile*>& dex_files,
+                     const std::string& android_root,
+                     bool is_host,
+                     const CompilerDriver& driver)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ protected:
+  virtual bool Write(std::vector<uint8_t>& oat_contents,
+                     const std::vector<const DexFile*>& dex_files,
+                     const std::string& android_root,
+                     bool is_host)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ private:
+  ElfWriterMclinker(const CompilerDriver& driver, File* elf_file);
+  ~ElfWriterMclinker();
+
+  void Init();
+  void AddOatInput(std::vector<uint8_t>& oat_contents);
+  void AddMethodInputs(const std::vector<const DexFile*>& dex_files);
+  void AddCompiledCodeInput(const CompiledCode& compiled_code);
+  void AddRuntimeInputs(const std::string& android_root, bool is_host);
+  bool Link();
+#if defined(ART_USE_PORTABLE_COMPILER)
+  void FixupOatMethodOffsets(const std::vector<const DexFile*>& dex_files)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  uint32_t FixupCompiledCodeOffset(ElfFile& elf_file,
+                                   llvm::ELF::Elf32_Addr oatdata_address,
+                                   const CompiledCode& compiled_code);
+#endif
+
+  // Setup by Init()
+  UniquePtr<mcld::LinkerConfig> linker_config_;
+  UniquePtr<mcld::Module> module_;
+  UniquePtr<mcld::IRBuilder> ir_builder_;
+  UniquePtr<mcld::Linker> linker_;
+
+  // Setup by AddOatInput()
+  // TODO: ownership of oat_input_?
+  mcld::Input* oat_input_;
+
+  // Setup by AddCompiledCodeInput
+  // set of symbols for already added mcld::Inputs
+  SafeMap<const std::string*, const std::string*> added_symbols_;
+
+  // Setup by FixupCompiledCodeOffset
+  // map of symbol names to oatdata offset
+  SafeMap<const std::string*, uint32_t> symbol_to_compiled_code_offset_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ElfWriterMclinker);
+};
+
+}  // namespace art
+
+#endif  // ART_SRC_ELF_WRITER_MCLINKER_H_
diff --git a/src/compiler/elf_writer_quick.cc b/src/compiler/elf_writer_quick.cc
new file mode 100644
index 0000000..c3c5415
--- /dev/null
+++ b/src/compiler/elf_writer_quick.cc
@@ -0,0 +1,665 @@
+/*
+ * 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 "base/logging.h"
+#include "base/unix_file/fd_file.h"
+#include "compiler/driver/compiler_driver.h"
+#include "globals.h"
+#include "oat.h"
+#include "utils.h"
+
+namespace art {
+
+ElfWriterQuick::ElfWriterQuick(const CompilerDriver& driver, File* elf_file)
+  : ElfWriter(driver, elf_file) {}
+
+ElfWriterQuick::~ElfWriterQuick() {}
+
+bool ElfWriterQuick::Create(File* elf_file,
+                            std::vector<uint8_t>& oat_contents,
+                            const std::vector<const DexFile*>& dex_files,
+                            const std::string& android_root,
+                            bool is_host,
+                            const CompilerDriver& driver) {
+  ElfWriterQuick elf_writer(driver, elf_file);
+  return elf_writer.Write(oat_contents, dex_files, android_root, is_host);
+}
+
+bool ElfWriterQuick::Write(std::vector<uint8_t>& oat_contents,
+                           const std::vector<const DexFile*>& dex_files_unused,
+                           const std::string& android_root_unused,
+                           bool is_host_unused) {
+  const bool debug = false;
+  // +-------------------------+
+  // | Elf32_Ehdr              |
+  // +-------------------------+
+  // | Elf32_Phdr PHDR         |
+  // | Elf32_Phdr LOAD R       | .dynsym .dynstr .hash .rodata
+  // | Elf32_Phdr LOAD R X     | .text
+  // | Elf32_Phdr LOAD RW      | .dynamic
+  // | Elf32_Phdr DYNAMIC      | .dynamic
+  // +-------------------------+
+  // | .dynsym                 |
+  // | Elf32_Sym  STN_UNDEF    |
+  // | Elf32_Sym  oatdata      |
+  // | Elf32_Sym  oatexec      |
+  // | Elf32_Sym  oatlastword  |
+  // +-------------------------+
+  // | .dynstr                 |
+  // | \0                      |
+  // | oatdata\0               |
+  // | oatexec\0               |
+  // | oatlastword\0           |
+  // | boot.oat\0              |
+  // +-------------------------+
+  // | .hash                   |
+  // | Elf32_Word nbucket = 1  |
+  // | Elf32_Word nchain  = 3  |
+  // | Elf32_Word bucket[0] = 0|
+  // | Elf32_Word chain[0]  = 1|
+  // | Elf32_Word chain[1]  = 2|
+  // | Elf32_Word chain[2]  = 3|
+  // +-------------------------+
+  // | .rodata                 |
+  // | oatdata..oatexec-4      |
+  // +-------------------------+
+  // | .text                   |
+  // | oatexec..oatlastword    |
+  // +-------------------------+
+  // | .dynamic                |
+  // | Elf32_Dyn DT_SONAME     |
+  // | Elf32_Dyn DT_HASH       |
+  // | Elf32_Dyn DT_SYMTAB     |
+  // | Elf32_Dyn DT_SYMENT     |
+  // | Elf32_Dyn DT_STRTAB     |
+  // | Elf32_Dyn DT_STRSZ      |
+  // | Elf32_Dyn DT_NULL       |
+  // +-------------------------+
+  // | .shstrtab               |
+  // | \0                      |
+  // | .dynamic\0              |
+  // | .dynsym\0               |
+  // | .dynstr\0               |
+  // | .hash\0                 |
+  // | .rodata\0               |
+  // | .text\0                 |
+  // | .shstrtab\0             |
+  // +-------------------------+
+  // | Elf32_Shdr NULL         |
+  // | Elf32_Shdr .dynsym      |
+  // | Elf32_Shdr .dynstr      |
+  // | Elf32_Shdr .hash        |
+  // | Elf32_Shdr .text        |
+  // | Elf32_Shdr .rodata      |
+  // | Elf32_Shdr .dynamic     |
+  // | Elf32_Shdr .shstrtab    |
+  // +-------------------------+
+
+  // phase 1: computing offsets
+  uint32_t expected_offset = 0;
+
+  // Elf32_Ehdr
+  expected_offset += sizeof(llvm::ELF::Elf32_Ehdr);
+
+  // PHDR
+  uint32_t phdr_alignment = sizeof(llvm::ELF::Elf32_Word);
+  uint32_t phdr_offset = expected_offset;
+  const uint8_t PH_PHDR     = 0;
+  const uint8_t PH_LOAD_R__ = 1;
+  const uint8_t PH_LOAD_R_X = 2;
+  const uint8_t PH_LOAD_RW_ = 3;
+  const uint8_t PH_DYNAMIC  = 4;
+  const uint8_t PH_NUM      = 5;
+  uint32_t phdr_size = sizeof(llvm::ELF::Elf32_Phdr) * PH_NUM;
+  expected_offset += phdr_size;
+  if (debug) {
+    LOG(INFO) << "phdr_offset=" << phdr_offset << std::hex << " " << phdr_offset;
+    LOG(INFO) << "phdr_size=" << phdr_size << std::hex << " " << phdr_size;
+  }
+
+  // .dynsym
+  uint32_t dynsym_alignment = sizeof(llvm::ELF::Elf32_Word);
+  uint32_t dynsym_offset = expected_offset = RoundUp(expected_offset, dynsym_alignment);
+  const uint8_t SYM_UNDEF       = 0; // aka STN_UNDEF
+  const uint8_t SYM_OATDATA     = 1;
+  const uint8_t SYM_OATEXEC     = 2;
+  const uint8_t SYM_OATLASTWORD = 3;
+  const uint8_t SYM_NUM         = 4;
+  uint32_t dynsym_size = sizeof(llvm::ELF::Elf32_Sym) * SYM_NUM;
+  expected_offset += dynsym_size;
+  if (debug) {
+    LOG(INFO) << "dynsym_offset=" << dynsym_offset << std::hex << " " << dynsym_offset;
+    LOG(INFO) << "dynsym_size=" << dynsym_size << std::hex << " " << dynsym_size;
+  }
+
+  // .dynstr
+  uint32_t dynstr_alignment = 1;
+  uint32_t dynstr_offset = expected_offset = RoundUp(expected_offset, dynstr_alignment);
+  std::string dynstr;
+  dynstr += '\0';
+  uint32_t dynstr_oatdata_offset = dynstr.size();
+  dynstr += "oatdata";
+  dynstr += '\0';
+  uint32_t dynstr_oatexec_offset = dynstr.size();
+  dynstr += "oatexec";
+  dynstr += '\0';
+  uint32_t dynstr_oatlastword_offset = dynstr.size();
+  dynstr += "oatlastword";
+  dynstr += '\0';
+  uint32_t dynstr_soname_offset = dynstr.size();
+  std::string file_name(elf_file_->GetPath());
+  size_t directory_separator_pos = file_name.rfind('/');
+  if (directory_separator_pos != std::string::npos) {
+    file_name = file_name.substr(directory_separator_pos + 1);
+  }
+  dynstr += file_name;
+  dynstr += '\0';
+  uint32_t dynstr_size = dynstr.size();
+  expected_offset += dynstr_size;
+  if (debug) {
+    LOG(INFO) << "dynstr_offset=" << dynstr_offset << std::hex << " " << dynstr_offset;
+    LOG(INFO) << "dynstr_size=" << dynstr_size << std::hex << " " << dynstr_size;
+  }
+
+  // .hash
+  uint32_t hash_alignment = sizeof(llvm::ELF::Elf32_Word);  // Even for 64-bit
+  uint32_t hash_offset = expected_offset = RoundUp(expected_offset, hash_alignment);
+  const uint8_t HASH_NBUCKET = 0;
+  const uint8_t HASH_NCHAIN  = 1;
+  const uint8_t HASH_BUCKET0 = 2;
+  const uint8_t HASH_NUM     = HASH_BUCKET0 + 1 + SYM_NUM;
+  uint32_t hash_size = sizeof(llvm::ELF::Elf32_Word) * HASH_NUM;
+  expected_offset += hash_size;
+  if (debug) {
+    LOG(INFO) << "hash_offset=" << hash_offset << std::hex << " " << hash_offset;
+    LOG(INFO) << "hash_size=" << hash_size << std::hex << " " << hash_size;
+  }
+
+  // .rodata
+  uint32_t oat_data_alignment = kPageSize;
+  uint32_t oat_data_offset = expected_offset = RoundUp(expected_offset, oat_data_alignment);
+  const OatHeader* oat_header = reinterpret_cast<OatHeader*>(&oat_contents[0]);
+  CHECK(oat_header->IsValid());
+  uint32_t oat_data_size = oat_header->GetExecutableOffset();
+  expected_offset += oat_data_size;
+  if (debug) {
+    LOG(INFO) << "oat_data_offset=" << oat_data_offset << std::hex << " " << oat_data_offset;
+    LOG(INFO) << "oat_data_size=" << oat_data_size << std::hex << " " << oat_data_size;
+  }
+
+  // .text
+  uint32_t oat_exec_alignment = kPageSize;
+  CHECK_ALIGNED(expected_offset, kPageSize);
+  uint32_t oat_exec_offset = expected_offset = RoundUp(expected_offset, oat_exec_alignment);
+  uint32_t oat_exec_size = oat_contents.size() - oat_data_size;
+  expected_offset += oat_exec_size;
+  CHECK_EQ(oat_data_offset + oat_contents.size(), expected_offset);
+  if (debug) {
+    LOG(INFO) << "oat_exec_offset=" << oat_exec_offset << std::hex << " " << oat_exec_offset;
+    LOG(INFO) << "oat_exec_size=" << oat_exec_size << std::hex << " " << oat_exec_size;
+  }
+
+  // .dynamic
+  // alignment would naturally be sizeof(llvm::ELF::Elf32_Word), but we want this in a new segment
+  uint32_t dynamic_alignment = kPageSize;
+  uint32_t dynamic_offset = expected_offset = RoundUp(expected_offset, dynamic_alignment);
+  const uint8_t DH_SONAME = 0;
+  const uint8_t DH_HASH   = 1;
+  const uint8_t DH_SYMTAB = 2;
+  const uint8_t DH_SYMENT = 3;
+  const uint8_t DH_STRTAB = 4;
+  const uint8_t DH_STRSZ  = 5;
+  const uint8_t DH_NULL   = 6;
+  const uint8_t DH_NUM    = 7;
+  uint32_t dynamic_size = sizeof(llvm::ELF::Elf32_Dyn) * DH_NUM;
+  expected_offset += dynamic_size;
+  if (debug) {
+    LOG(INFO) << "dynamic_offset=" << dynamic_offset << std::hex << " " << dynamic_offset;
+    LOG(INFO) << "dynamic_size=" << dynamic_size << std::hex << " " << dynamic_size;
+  }
+
+  // .shstrtab
+  uint32_t shstrtab_alignment = 1;
+  uint32_t shstrtab_offset = expected_offset = RoundUp(expected_offset, shstrtab_alignment);
+  std::string shstrtab;
+  shstrtab += '\0';
+  uint32_t shstrtab_dynamic_offset = shstrtab.size();
+  CHECK_EQ(1U, shstrtab_dynamic_offset);
+  shstrtab += ".dynamic";
+  shstrtab += '\0';
+  uint32_t shstrtab_dynsym_offset = shstrtab.size();
+  shstrtab += ".dynsym";
+  shstrtab += '\0';
+  uint32_t shstrtab_dynstr_offset = shstrtab.size();
+  shstrtab += ".dynstr";
+  shstrtab += '\0';
+  uint32_t shstrtab_hash_offset = shstrtab.size();
+  shstrtab += ".hash";
+  shstrtab += '\0';
+  uint32_t shstrtab_rodata_offset = shstrtab.size();
+  shstrtab += ".rodata";
+  shstrtab += '\0';
+  uint32_t shstrtab_text_offset = shstrtab.size();
+  shstrtab += ".text";
+  shstrtab += '\0';
+  uint32_t shstrtab_shstrtab_offset = shstrtab.size();
+  shstrtab += ".shstrtab";
+  shstrtab += '\0';
+  uint32_t shstrtab_size = shstrtab.size();
+  expected_offset += shstrtab_size;
+  if (debug) {
+    LOG(INFO) << "shstrtab_offset=" << shstrtab_offset << std::hex << " " << shstrtab_offset;
+    LOG(INFO) << "shstrtab_size=" << shstrtab_size << std::hex << " " << shstrtab_size;
+  }
+
+  // section headers (after all sections)
+  uint32_t shdr_alignment = sizeof(llvm::ELF::Elf32_Word);
+  uint32_t shdr_offset = expected_offset = RoundUp(expected_offset, shdr_alignment);
+  const uint8_t SH_NULL     = 0;
+  const uint8_t SH_DYNSYM   = 1;
+  const uint8_t SH_DYNSTR   = 2;
+  const uint8_t SH_HASH     = 3;
+  const uint8_t SH_RODATA   = 4;
+  const uint8_t SH_TEXT     = 5;
+  const uint8_t SH_DYNAMIC  = 6;
+  const uint8_t SH_SHSTRTAB = 7;
+  const uint8_t SH_NUM      = 8;
+  uint32_t shdr_size = sizeof(llvm::ELF::Elf32_Shdr) * SH_NUM;
+  expected_offset += shdr_size;
+  if (debug) {
+    LOG(INFO) << "shdr_offset=" << shdr_offset << std::hex << " " << shdr_offset;
+    LOG(INFO) << "shdr_size=" << shdr_size << std::hex << " " << shdr_size;
+  }
+
+  // phase 2: initializing data
+
+  // Elf32_Ehdr
+  llvm::ELF::Elf32_Ehdr elf_header;
+  memset(&elf_header, 0, sizeof(elf_header));
+  elf_header.e_ident[llvm::ELF::EI_MAG0]       = llvm::ELF::ElfMagic[0];
+  elf_header.e_ident[llvm::ELF::EI_MAG1]       = llvm::ELF::ElfMagic[1];
+  elf_header.e_ident[llvm::ELF::EI_MAG2]       = llvm::ELF::ElfMagic[2];
+  elf_header.e_ident[llvm::ELF::EI_MAG3]       = llvm::ELF::ElfMagic[3];
+  elf_header.e_ident[llvm::ELF::EI_CLASS]      = llvm::ELF::ELFCLASS32;
+  elf_header.e_ident[llvm::ELF::EI_DATA]       = llvm::ELF::ELFDATA2LSB;
+  elf_header.e_ident[llvm::ELF::EI_VERSION]    = llvm::ELF::EV_CURRENT;
+  elf_header.e_ident[llvm::ELF::EI_OSABI]      = llvm::ELF::ELFOSABI_LINUX;
+  elf_header.e_ident[llvm::ELF::EI_ABIVERSION] = 0;
+  elf_header.e_type = llvm::ELF::ET_DYN;
+  switch (compiler_driver_->GetInstructionSet()) {
+    case kThumb2: {
+      elf_header.e_machine = llvm::ELF::EM_ARM;
+      elf_header.e_flags = llvm::ELF::EF_ARM_EABI_VER5;
+      break;
+    }
+    case kX86: {
+      elf_header.e_machine = llvm::ELF::EM_386;
+      elf_header.e_flags = 0;
+      break;
+    }
+    case kMips: {
+      elf_header.e_machine = llvm::ELF::EM_MIPS;
+      elf_header.e_flags = (llvm::ELF::EF_MIPS_NOREORDER |
+                            llvm::ELF::EF_MIPS_PIC       |
+                            llvm::ELF::EF_MIPS_CPIC      |
+                            llvm::ELF::EF_MIPS_ABI_O32   |
+                            llvm::ELF::EF_MIPS_ARCH_32R2);
+      break;
+    }
+    case kArm:
+    default: {
+      LOG(FATAL) << "Unknown instruction set: " << compiler_driver_->GetInstructionSet();
+      break;
+    }
+  }
+  elf_header.e_version = 1;
+  elf_header.e_entry = 0;
+  elf_header.e_phoff = phdr_offset;
+  elf_header.e_shoff = shdr_offset;
+  elf_header.e_ehsize = sizeof(llvm::ELF::Elf32_Ehdr);
+  elf_header.e_phentsize = sizeof(llvm::ELF::Elf32_Phdr);
+  elf_header.e_phnum = PH_NUM;
+  elf_header.e_shentsize = sizeof(llvm::ELF::Elf32_Shdr);
+  elf_header.e_shnum = SH_NUM;
+  elf_header.e_shstrndx = SH_SHSTRTAB;
+
+  // PHDR
+  llvm::ELF::Elf32_Phdr program_headers[PH_NUM];
+  memset(&program_headers, 0, sizeof(program_headers));
+
+  program_headers[PH_PHDR].p_type    = llvm::ELF::PT_PHDR;
+  program_headers[PH_PHDR].p_offset  = phdr_offset;
+  program_headers[PH_PHDR].p_vaddr   = phdr_offset;
+  program_headers[PH_PHDR].p_paddr   = phdr_offset;
+  program_headers[PH_PHDR].p_filesz  = sizeof(program_headers);
+  program_headers[PH_PHDR].p_memsz   = sizeof(program_headers);
+  program_headers[PH_PHDR].p_flags   = llvm::ELF::PF_R;
+  program_headers[PH_PHDR].p_align   = phdr_alignment;
+
+  program_headers[PH_LOAD_R__].p_type    = llvm::ELF::PT_LOAD;
+  program_headers[PH_LOAD_R__].p_offset  = 0;
+  program_headers[PH_LOAD_R__].p_vaddr   = 0;
+  program_headers[PH_LOAD_R__].p_paddr   = 0;
+  program_headers[PH_LOAD_R__].p_filesz  = oat_data_offset + oat_data_size;
+  program_headers[PH_LOAD_R__].p_memsz   = oat_data_offset + oat_data_size;
+  program_headers[PH_LOAD_R__].p_flags   = llvm::ELF::PF_R;
+  program_headers[PH_LOAD_R__].p_align   = oat_data_alignment;
+
+  program_headers[PH_LOAD_R_X].p_type    = llvm::ELF::PT_LOAD;
+  program_headers[PH_LOAD_R_X].p_offset  = oat_exec_offset;
+  program_headers[PH_LOAD_R_X].p_vaddr   = oat_exec_offset;
+  program_headers[PH_LOAD_R_X].p_paddr   = oat_exec_offset;
+  program_headers[PH_LOAD_R_X].p_filesz  = oat_exec_size;
+  program_headers[PH_LOAD_R_X].p_memsz   = oat_exec_size;
+  program_headers[PH_LOAD_R_X].p_flags   = llvm::ELF::PF_R | llvm::ELF::PF_X;
+  program_headers[PH_LOAD_R_X].p_align   = oat_exec_alignment;
+
+  // TODO: PF_W for DYNAMIC is considered processor specific, do we need it?
+  program_headers[PH_LOAD_RW_].p_type    = llvm::ELF::PT_LOAD;
+  program_headers[PH_LOAD_RW_].p_offset  = dynamic_offset;
+  program_headers[PH_LOAD_RW_].p_vaddr   = dynamic_offset;
+  program_headers[PH_LOAD_RW_].p_paddr   = dynamic_offset;
+  program_headers[PH_LOAD_RW_].p_filesz  = dynamic_size;
+  program_headers[PH_LOAD_RW_].p_memsz   = dynamic_size;
+  program_headers[PH_LOAD_RW_].p_flags   = llvm::ELF::PF_R | llvm::ELF::PF_W;
+  program_headers[PH_LOAD_RW_].p_align   = dynamic_alignment;
+
+  // TODO: PF_W for DYNAMIC is considered processor specific, do we need it?
+  program_headers[PH_DYNAMIC].p_type    = llvm::ELF::PT_DYNAMIC;
+  program_headers[PH_DYNAMIC].p_offset  = dynamic_offset;
+  program_headers[PH_DYNAMIC].p_vaddr   = dynamic_offset;
+  program_headers[PH_DYNAMIC].p_paddr   = dynamic_offset;
+  program_headers[PH_DYNAMIC].p_filesz  = dynamic_size;
+  program_headers[PH_DYNAMIC].p_memsz   = dynamic_size;
+  program_headers[PH_DYNAMIC].p_flags   = llvm::ELF::PF_R | llvm::ELF::PF_W;
+  program_headers[PH_DYNAMIC].p_align   = dynamic_alignment;
+
+  // .dynsym
+  llvm::ELF::Elf32_Sym dynsym[SYM_NUM];
+  memset(&dynsym, 0, sizeof(dynsym));
+
+  dynsym[SYM_UNDEF].st_name  = 0;
+  dynsym[SYM_UNDEF].st_value = 0;
+  dynsym[SYM_UNDEF].st_size  = 0;
+  dynsym[SYM_UNDEF].st_info  = 0;
+  dynsym[SYM_UNDEF].st_other = 0;
+  dynsym[SYM_UNDEF].st_shndx = 0;
+
+  dynsym[SYM_OATDATA].st_name  = dynstr_oatdata_offset;
+  dynsym[SYM_OATDATA].st_value = oat_data_offset;
+  dynsym[SYM_OATDATA].st_size  = oat_data_size;
+  dynsym[SYM_OATDATA].setBindingAndType(llvm::ELF::STB_GLOBAL, llvm::ELF::STT_OBJECT);
+  dynsym[SYM_OATDATA].st_other = llvm::ELF::STV_DEFAULT;
+  dynsym[SYM_OATDATA].st_shndx = SH_RODATA;
+
+  dynsym[SYM_OATEXEC].st_name  = dynstr_oatexec_offset;
+  dynsym[SYM_OATEXEC].st_value = oat_exec_offset;
+  dynsym[SYM_OATEXEC].st_size  = oat_exec_size;
+  dynsym[SYM_OATEXEC].setBindingAndType(llvm::ELF::STB_GLOBAL, llvm::ELF::STT_OBJECT);
+  dynsym[SYM_OATEXEC].st_other = llvm::ELF::STV_DEFAULT;
+  dynsym[SYM_OATEXEC].st_shndx = SH_TEXT;
+
+  dynsym[SYM_OATLASTWORD].st_name  = dynstr_oatlastword_offset;
+  dynsym[SYM_OATLASTWORD].st_value = oat_exec_offset + oat_exec_size - 4;
+  dynsym[SYM_OATLASTWORD].st_size  = 4;
+  dynsym[SYM_OATLASTWORD].setBindingAndType(llvm::ELF::STB_GLOBAL, llvm::ELF::STT_OBJECT);
+  dynsym[SYM_OATLASTWORD].st_other = llvm::ELF::STV_DEFAULT;
+  dynsym[SYM_OATLASTWORD].st_shndx = SH_TEXT;
+
+  // .dynstr initialized above as dynstr
+
+  // .hash
+  llvm::ELF::Elf32_Word hash[HASH_NUM];  // Note this is Elf32_Word even on 64-bit
+  hash[HASH_NBUCKET] = 1;
+  hash[HASH_NCHAIN]  = SYM_NUM;
+  hash[HASH_BUCKET0] = SYM_OATDATA;
+  hash[HASH_BUCKET0 + 1 + SYM_UNDEF]       = SYM_UNDEF;
+  hash[HASH_BUCKET0 + 1 + SYM_OATDATA]     = SYM_OATEXEC;
+  hash[HASH_BUCKET0 + 1 + SYM_OATEXEC]     = SYM_OATLASTWORD;
+  hash[HASH_BUCKET0 + 1 + SYM_OATLASTWORD] = SYM_UNDEF;
+
+  // .rodata and .text content come from oat_contents
+
+  // .dynamic
+  llvm::ELF::Elf32_Dyn dynamic_headers[DH_NUM];
+  memset(&dynamic_headers, 0, sizeof(dynamic_headers));
+
+  dynamic_headers[DH_SONAME].d_tag = llvm::ELF::DT_SONAME;
+  dynamic_headers[DH_SONAME].d_un.d_val = dynstr_soname_offset;
+
+  dynamic_headers[DH_HASH].d_tag = llvm::ELF::DT_HASH;
+  dynamic_headers[DH_HASH].d_un.d_ptr = hash_offset;
+
+  dynamic_headers[DH_SYMTAB].d_tag = llvm::ELF::DT_SYMTAB;
+  dynamic_headers[DH_SYMTAB].d_un.d_ptr = dynsym_offset;
+
+  dynamic_headers[DH_SYMENT].d_tag = llvm::ELF::DT_SYMENT;
+  dynamic_headers[DH_SYMENT].d_un.d_val = sizeof(llvm::ELF::Elf32_Sym);
+
+  dynamic_headers[DH_STRTAB].d_tag = llvm::ELF::DT_STRTAB;
+  dynamic_headers[DH_STRTAB].d_un.d_ptr = dynstr_offset;
+
+  dynamic_headers[DH_STRSZ].d_tag = llvm::ELF::DT_STRSZ;
+  dynamic_headers[DH_STRSZ].d_un.d_val = dynstr_size;
+
+  dynamic_headers[DH_NULL].d_tag = llvm::ELF::DT_NULL;
+  dynamic_headers[DH_NULL].d_un.d_val = 0;
+
+  // .shstrtab initialized above as shstrtab
+
+  // section headers (after all sections)
+  llvm::ELF::Elf32_Shdr section_headers[SH_NUM];
+  memset(&section_headers, 0, sizeof(section_headers));
+
+  section_headers[SH_NULL].sh_name      = 0;
+  section_headers[SH_NULL].sh_type      = llvm::ELF::SHT_NULL;
+  section_headers[SH_NULL].sh_flags     = 0;
+  section_headers[SH_NULL].sh_addr      = 0;
+  section_headers[SH_NULL].sh_offset    = 0;
+  section_headers[SH_NULL].sh_size      = 0;
+  section_headers[SH_NULL].sh_link      = 0;
+  section_headers[SH_NULL].sh_info      = 0;
+  section_headers[SH_NULL].sh_addralign = 0;
+  section_headers[SH_NULL].sh_entsize   = 0;
+
+  section_headers[SH_DYNSYM].sh_name      = shstrtab_dynsym_offset;
+  section_headers[SH_DYNSYM].sh_type      = llvm::ELF::SHT_DYNSYM;
+  section_headers[SH_DYNSYM].sh_flags     = llvm::ELF::SHF_ALLOC;
+  section_headers[SH_DYNSYM].sh_addr      = dynsym_offset;
+  section_headers[SH_DYNSYM].sh_offset    = dynsym_offset;
+  section_headers[SH_DYNSYM].sh_size      = dynsym_size;
+  section_headers[SH_DYNSYM].sh_link      = SH_DYNSTR;
+  section_headers[SH_DYNSYM].sh_info      = 1;  // 1 because we have not STB_LOCAL symbols
+  section_headers[SH_DYNSYM].sh_addralign = dynsym_alignment;
+  section_headers[SH_DYNSYM].sh_entsize   = sizeof(llvm::ELF::Elf32_Sym);
+
+  section_headers[SH_DYNSTR].sh_name      = shstrtab_dynstr_offset;
+  section_headers[SH_DYNSTR].sh_type      = llvm::ELF::SHT_STRTAB;
+  section_headers[SH_DYNSTR].sh_flags     = llvm::ELF::SHF_ALLOC;
+  section_headers[SH_DYNSTR].sh_addr      = dynstr_offset;
+  section_headers[SH_DYNSTR].sh_offset    = dynstr_offset;
+  section_headers[SH_DYNSTR].sh_size      = dynstr_size;
+  section_headers[SH_DYNSTR].sh_link      = 0;
+  section_headers[SH_DYNSTR].sh_info      = 0;
+  section_headers[SH_DYNSTR].sh_addralign = dynstr_alignment;
+  section_headers[SH_DYNSTR].sh_entsize   = 0;
+
+  section_headers[SH_HASH].sh_name      = shstrtab_hash_offset;
+  section_headers[SH_HASH].sh_type      = llvm::ELF::SHT_HASH;
+  section_headers[SH_HASH].sh_flags     = llvm::ELF::SHF_ALLOC;
+  section_headers[SH_HASH].sh_addr      = hash_offset;
+  section_headers[SH_HASH].sh_offset    = hash_offset;
+  section_headers[SH_HASH].sh_size      = hash_size;
+  section_headers[SH_HASH].sh_link      = SH_DYNSYM;
+  section_headers[SH_HASH].sh_info      = 0;
+  section_headers[SH_HASH].sh_addralign = hash_alignment;
+  section_headers[SH_HASH].sh_entsize   = sizeof(llvm::ELF::Elf32_Word); // This is Elf32_Word even on 64-bit
+
+  section_headers[SH_RODATA].sh_name      = shstrtab_rodata_offset;
+  section_headers[SH_RODATA].sh_type      = llvm::ELF::SHT_PROGBITS;
+  section_headers[SH_RODATA].sh_flags     = llvm::ELF::SHF_ALLOC;
+  section_headers[SH_RODATA].sh_addr      = oat_data_offset;
+  section_headers[SH_RODATA].sh_offset    = oat_data_offset;
+  section_headers[SH_RODATA].sh_size      = oat_data_size;
+  section_headers[SH_RODATA].sh_link      = 0;
+  section_headers[SH_RODATA].sh_info      = 0;
+  section_headers[SH_RODATA].sh_addralign = oat_data_alignment;
+  section_headers[SH_RODATA].sh_entsize   = 0;
+
+  section_headers[SH_TEXT].sh_name      = shstrtab_text_offset;
+  section_headers[SH_TEXT].sh_type      = llvm::ELF::SHT_PROGBITS;
+  section_headers[SH_TEXT].sh_flags     = llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR;
+  section_headers[SH_TEXT].sh_addr      = oat_exec_offset;
+  section_headers[SH_TEXT].sh_offset    = oat_exec_offset;
+  section_headers[SH_TEXT].sh_size      = oat_exec_size;
+  section_headers[SH_TEXT].sh_link      = 0;
+  section_headers[SH_TEXT].sh_info      = 0;
+  section_headers[SH_TEXT].sh_addralign = oat_exec_alignment;
+  section_headers[SH_TEXT].sh_entsize   = 0;
+
+  // TODO: SHF_WRITE for .dynamic is considered processor specific, do we need it?
+  section_headers[SH_DYNAMIC].sh_name      = shstrtab_dynamic_offset;
+  section_headers[SH_DYNAMIC].sh_type      = llvm::ELF::SHT_DYNAMIC;
+  section_headers[SH_DYNAMIC].sh_flags     = llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC;
+  section_headers[SH_DYNAMIC].sh_addr      = dynamic_offset;
+  section_headers[SH_DYNAMIC].sh_offset    = dynamic_offset;
+  section_headers[SH_DYNAMIC].sh_size      = dynamic_size;
+  section_headers[SH_DYNAMIC].sh_link      = SH_DYNSTR;
+  section_headers[SH_DYNAMIC].sh_info      = 0;
+  section_headers[SH_DYNAMIC].sh_addralign = dynamic_alignment;
+  section_headers[SH_DYNAMIC].sh_entsize   = sizeof(llvm::ELF::Elf32_Dyn);
+
+  section_headers[SH_SHSTRTAB].sh_name      = shstrtab_shstrtab_offset;
+  section_headers[SH_SHSTRTAB].sh_type      = llvm::ELF::SHT_STRTAB;
+  section_headers[SH_SHSTRTAB].sh_flags     = 0;
+  section_headers[SH_SHSTRTAB].sh_addr      = shstrtab_offset;
+  section_headers[SH_SHSTRTAB].sh_offset    = shstrtab_offset;
+  section_headers[SH_SHSTRTAB].sh_size      = shstrtab_size;
+  section_headers[SH_SHSTRTAB].sh_link      = 0;
+  section_headers[SH_SHSTRTAB].sh_info      = 0;
+  section_headers[SH_SHSTRTAB].sh_addralign = shstrtab_alignment;
+  section_headers[SH_SHSTRTAB].sh_entsize   = 0;
+
+  // phase 3: writing file
+
+  // Elf32_Ehdr
+  if (!elf_file_->WriteFully(&elf_header, sizeof(elf_header))) {
+    PLOG(ERROR) << "Failed to write ELF header for " << elf_file_->GetPath();
+    return false;
+  }
+
+  // PHDR
+  if (static_cast<off_t>(phdr_offset) != lseek(elf_file_->Fd(), 0, SEEK_CUR)) {
+    PLOG(ERROR) << "Failed to be at expected ELF program header offset phdr_offset "
+                << " for " << elf_file_->GetPath();
+    return false;
+  }
+  if (!elf_file_->WriteFully(program_headers, sizeof(program_headers))) {
+    PLOG(ERROR) << "Failed to write ELF program headers for " << elf_file_->GetPath();
+    return false;
+  }
+
+  // .dynsym
+  DCHECK_LE(phdr_offset + phdr_size, dynsym_offset);
+  if (static_cast<off_t>(dynsym_offset) != lseek(elf_file_->Fd(), dynsym_offset, SEEK_SET)) {
+    PLOG(ERROR) << "Failed to seek to .dynsym offset location " << dynsym_offset
+                << " for " << elf_file_->GetPath();
+    return false;
+  }
+  if (!elf_file_->WriteFully(dynsym, sizeof(dynsym))) {
+    PLOG(ERROR) << "Failed to write .dynsym for " << elf_file_->GetPath();
+    return false;
+  }
+
+  // .dynstr
+  DCHECK_LE(dynsym_offset + dynsym_size, dynstr_offset);
+  if (static_cast<off_t>(dynstr_offset) != lseek(elf_file_->Fd(), dynstr_offset, SEEK_SET)) {
+    PLOG(ERROR) << "Failed to seek to .dynstr offset " << dynstr_offset
+                << " for " << elf_file_->GetPath();
+    return false;
+  }
+  if (!elf_file_->WriteFully(&dynstr[0], dynsym_size)) {
+    PLOG(ERROR) << "Failed to write .dynsym for " << elf_file_->GetPath();
+    return false;
+  }
+
+  // .hash
+  DCHECK_LE(dynstr_offset + dynstr_size, hash_offset);
+  if (static_cast<off_t>(hash_offset) != lseek(elf_file_->Fd(), hash_offset, SEEK_SET)) {
+    PLOG(ERROR) << "Failed to seek to .hash offset " << hash_offset
+                << " for " << elf_file_->GetPath();
+    return false;
+  }
+  if (!elf_file_->WriteFully(hash, sizeof(hash))) {
+    PLOG(ERROR) << "Failed to write .dynsym for " << elf_file_->GetPath();
+    return false;
+  }
+
+  // .rodata .text
+  DCHECK_LE(hash_offset + hash_size, oat_data_offset);
+  if (static_cast<off_t>(oat_data_offset) != lseek(elf_file_->Fd(), oat_data_offset, SEEK_SET)) {
+    PLOG(ERROR) << "Failed to seek to .rodata offset " << oat_data_offset
+                << " for " << elf_file_->GetPath();
+    return false;
+  }
+  if (!elf_file_->WriteFully(&oat_contents[0], oat_contents.size())) {
+    PLOG(ERROR) << "Failed to write .rodata and .text for " << elf_file_->GetPath();
+    return false;
+  }
+
+  // .dynamic
+  DCHECK_LE(oat_data_offset + oat_contents.size(), dynamic_offset);
+  if (static_cast<off_t>(dynamic_offset) != lseek(elf_file_->Fd(), dynamic_offset, SEEK_SET)) {
+    PLOG(ERROR) << "Failed to seek to .dynamic offset " << dynamic_offset
+                << " for " << elf_file_->GetPath();
+    return false;
+  }
+  if (!elf_file_->WriteFully(&dynamic_headers[0], dynamic_size)) {
+    PLOG(ERROR) << "Failed to write .dynamic for " << elf_file_->GetPath();
+    return false;
+  }
+
+  // .shstrtab
+  DCHECK_LE(dynamic_offset + dynamic_size, shstrtab_offset);
+  if (static_cast<off_t>(shstrtab_offset) != lseek(elf_file_->Fd(), shstrtab_offset, SEEK_SET)) {
+    PLOG(ERROR) << "Failed to seek to .shstrtab offset " << shstrtab_offset
+                << " for " << elf_file_->GetPath();
+    return false;
+  }
+  if (!elf_file_->WriteFully(&shstrtab[0], shstrtab_size)) {
+    PLOG(ERROR) << "Failed to write .shstrtab for " << elf_file_->GetPath();
+    return false;
+  }
+
+  // section headers (after all sections)
+  DCHECK_LE(shstrtab_offset + shstrtab_size, shdr_offset);
+  if (static_cast<off_t>(shdr_offset) != lseek(elf_file_->Fd(), shdr_offset, SEEK_SET)) {
+    PLOG(ERROR) << "Failed to seek to ELF section headers offset " << shdr_offset
+                << " for " << elf_file_->GetPath();
+    return false;
+  }
+  if (!elf_file_->WriteFully(section_headers, sizeof(section_headers))) {
+    PLOG(ERROR) << "Failed to write ELF section headers for " << elf_file_->GetPath();
+    return false;
+  }
+
+  LOG(INFO) << "ELF file written successfully: " << elf_file_->GetPath();
+  return true;
+}
+
+}  // namespace art
diff --git a/src/compiler/elf_writer_quick.h b/src/compiler/elf_writer_quick.h
new file mode 100644
index 0000000..a1a386b
--- /dev/null
+++ b/src/compiler/elf_writer_quick.h
@@ -0,0 +1,51 @@
+/*
+ * 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_SRC_ELF_WRITER_MCLINKER_H_
+#define ART_SRC_ELF_WRITER_MCLINKER_H_
+
+#include "elf_writer.h"
+
+namespace art {
+
+class ElfWriterQuick : public ElfWriter {
+ public:
+  // Write an ELF file. Returns true on success, false on failure.
+  static bool Create(File* file,
+                     std::vector<uint8_t>& oat_contents,
+                     const std::vector<const DexFile*>& dex_files,
+                     const std::string& android_root,
+                     bool is_host,
+                     const CompilerDriver& driver)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ protected:
+  virtual bool Write(std::vector<uint8_t>& oat_contents,
+                     const std::vector<const DexFile*>& dex_files,
+                     const std::string& android_root,
+                     bool is_host)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ private:
+  ElfWriterQuick(const CompilerDriver& driver, File* elf_file);
+  ~ElfWriterQuick();
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ElfWriterQuick);
+};
+
+}  // namespace art
+
+#endif  // ART_SRC_ELF_WRITER_MCLINKER_H_
diff --git a/src/compiler/elf_writer_test.cc b/src/compiler/elf_writer_test.cc
new file mode 100644
index 0000000..d4486d2
--- /dev/null
+++ b/src/compiler/elf_writer_test.cc
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common_test.h"
+
+#include "oat.h"
+#include "elf_file.h"
+
+namespace art {
+
+class ElfWriterTest : public CommonTest {
+
+ protected:
+  virtual void SetUp() {
+    ReserveImageSpace();
+    CommonTest::SetUp();
+  }
+};
+
+#define EXPECT_ELF_FILE_ADDRESS(ef, value, name, build_map) \
+  EXPECT_EQ(value, reinterpret_cast<void*>(ef->FindSymbolAddress(::llvm::ELF::SHT_DYNSYM, name, build_map))); \
+  EXPECT_EQ(value, ef->FindDynamicSymbolAddress(name)); \
+
+TEST_F(ElfWriterTest, dlsym) {
+  std::string elf_filename;
+  if (IsHost()) {
+    const char* host_dir = getenv("ANDROID_HOST_OUT");
+    CHECK(host_dir != NULL);
+    elf_filename = StringPrintf("%s/framework/core.oat", host_dir);
+  } else {
+    elf_filename = "/data/art-test/core.oat";
+  }
+  LOG(INFO) << "elf_filename=" << elf_filename;
+
+  UnreserveImageSpace();
+  void* dl_oat_so = dlopen(elf_filename.c_str(), RTLD_NOW);
+  ASSERT_TRUE(dl_oat_so != NULL) << dlerror();
+  void* dl_oatdata = dlsym(dl_oat_so, "oatdata");
+  ASSERT_TRUE(dl_oatdata != NULL);
+
+  OatHeader* dl_oat_header = reinterpret_cast<OatHeader*>(dl_oatdata);
+  ASSERT_TRUE(dl_oat_header->IsValid());
+  void* dl_oatexec = dlsym(dl_oat_so, "oatexec");
+  ASSERT_TRUE(dl_oatexec != NULL);
+  ASSERT_LT(dl_oatdata, dl_oatexec);
+
+  void* dl_oatlastword = dlsym(dl_oat_so, "oatlastword");
+  ASSERT_TRUE(dl_oatlastword != NULL);
+  ASSERT_LT(dl_oatexec, dl_oatlastword);
+
+  ASSERT_EQ(0, dlclose(dl_oat_so));
+
+  UniquePtr<File> file(OS::OpenFile(elf_filename.c_str(), false));
+  ASSERT_TRUE(file.get() != NULL);
+  {
+    UniquePtr<ElfFile> ef(ElfFile::Open(file.get(), false, false));
+    CHECK(ef.get() != NULL);
+    EXPECT_ELF_FILE_ADDRESS(ef, dl_oatdata, "oatdata", false);
+    EXPECT_ELF_FILE_ADDRESS(ef, dl_oatexec, "oatexec", false);
+    EXPECT_ELF_FILE_ADDRESS(ef, dl_oatlastword, "oatlastword", false);
+  }
+  {
+    UniquePtr<ElfFile> ef(ElfFile::Open(file.get(), false, false));
+    CHECK(ef.get() != NULL);
+    EXPECT_ELF_FILE_ADDRESS(ef, dl_oatdata, "oatdata", true);
+    EXPECT_ELF_FILE_ADDRESS(ef, dl_oatexec, "oatexec", true);
+    EXPECT_ELF_FILE_ADDRESS(ef, dl_oatlastword, "oatlastword", true);
+  }
+  {
+    UniquePtr<ElfFile> ef(ElfFile::Open(file.get(), false, true));
+    CHECK(ef.get() != NULL);
+    ef->Load();
+    EXPECT_EQ(dl_oatdata, ef->FindDynamicSymbolAddress("oatdata"));
+    EXPECT_EQ(dl_oatexec, ef->FindDynamicSymbolAddress("oatexec"));
+    EXPECT_EQ(dl_oatlastword, ef->FindDynamicSymbolAddress("oatlastword"));
+  }
+}
+
+}  // namespace art
diff --git a/src/compiler/image_writer.cc b/src/compiler/image_writer.cc
new file mode 100644
index 0000000..8b84e12
--- /dev/null
+++ b/src/compiler/image_writer.cc
@@ -0,0 +1,680 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "image_writer.h"
+
+#include <sys/stat.h>
+
+#include <vector>
+
+#include "base/logging.h"
+#include "base/unix_file/fd_file.h"
+#include "class_linker.h"
+#include "compiled_method.h"
+#include "compiler/driver/compiler_driver.h"
+#include "compiler/elf_writer.h"
+#include "dex_file-inl.h"
+#include "gc/accounting/card_table-inl.h"
+#include "gc/accounting/heap_bitmap.h"
+#include "gc/heap.h"
+#include "gc/space/large_object_space.h"
+#include "gc/space/space-inl.h"
+#include "globals.h"
+#include "image.h"
+#include "intern_table.h"
+#include "mirror/array-inl.h"
+#include "mirror/class-inl.h"
+#include "mirror/class_loader.h"
+#include "mirror/dex_cache-inl.h"
+#include "mirror/field-inl.h"
+#include "mirror/abstract_method-inl.h"
+#include "mirror/object-inl.h"
+#include "mirror/object_array-inl.h"
+#include "oat.h"
+#include "oat_file.h"
+#include "object_utils.h"
+#include "runtime.h"
+#include "scoped_thread_state_change.h"
+#include "sirt_ref.h"
+#include "UniquePtr.h"
+#include "utils.h"
+
+using namespace art::mirror;
+
+namespace art {
+
+bool ImageWriter::Write(const std::string& image_filename,
+                        uintptr_t image_begin,
+                        const std::string& oat_filename,
+                        const std::string& oat_location) {
+  CHECK(!image_filename.empty());
+
+  CHECK_NE(image_begin, 0U);
+  image_begin_ = reinterpret_cast<byte*>(image_begin);
+
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  const std::vector<DexCache*>& all_dex_caches = class_linker->GetDexCaches();
+  for (size_t i = 0; i < all_dex_caches.size(); i++) {
+    DexCache* dex_cache = all_dex_caches[i];
+    dex_caches_.insert(dex_cache);
+  }
+
+  UniquePtr<File> oat_file(OS::OpenFile(oat_filename.c_str(), true, false));
+  if (oat_file.get() == NULL) {
+    LOG(ERROR) << "Failed to open oat file " << oat_filename << " for " << oat_location;
+    return false;
+  }
+  oat_file_ = OatFile::OpenWritable(oat_file.get(), oat_location);
+  class_linker->RegisterOatFile(*oat_file_);
+  interpreter_to_interpreter_entry_offset_ = oat_file_->GetOatHeader().GetInterpreterToInterpreterEntryOffset();
+  interpreter_to_quick_entry_offset_ = oat_file_->GetOatHeader().GetInterpreterToQuickEntryOffset();
+  portable_resolution_trampoline_offset_ = oat_file_->GetOatHeader().GetPortableResolutionTrampolineOffset();
+  quick_resolution_trampoline_offset_ = oat_file_->GetOatHeader().GetQuickResolutionTrampolineOffset();
+
+  {
+    Thread::Current()->TransitionFromSuspendedToRunnable();
+    PruneNonImageClasses();  // Remove junk
+    ComputeLazyFieldsForImageClasses();  // Add useful information
+    ComputeEagerResolvedStrings();
+    Thread::Current()->TransitionFromRunnableToSuspended(kNative);
+  }
+  gc::Heap* heap = Runtime::Current()->GetHeap();
+  heap->CollectGarbage(false);  // Remove garbage.
+  // Trim size of alloc spaces.
+  const std::vector<gc::space::ContinuousSpace*>& spaces = heap->GetContinuousSpaces();
+  // TODO: C++0x auto
+  typedef std::vector<gc::space::ContinuousSpace*>::const_iterator It;
+  for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
+    gc::space::ContinuousSpace* space = *it;
+    if (space->IsDlMallocSpace()) {
+      space->AsDlMallocSpace()->Trim();
+    }
+  }
+
+  if (!AllocMemory()) {
+    return false;
+  }
+#ifndef NDEBUG
+  {
+    ScopedObjectAccess soa(Thread::Current());
+    CheckNonImageClassesRemoved();
+  }
+#endif
+  Thread::Current()->TransitionFromSuspendedToRunnable();
+  size_t oat_loaded_size = 0;
+  size_t oat_data_offset = 0;
+  ElfWriter::GetOatElfInformation(oat_file.get(), oat_loaded_size, oat_data_offset);
+  CalculateNewObjectOffsets(oat_loaded_size, oat_data_offset);
+  CopyAndFixupObjects();
+  PatchOatCodeAndMethods();
+  Thread::Current()->TransitionFromRunnableToSuspended(kNative);
+
+  UniquePtr<File> image_file(OS::OpenFile(image_filename.c_str(), true));
+  if (image_file.get() == NULL) {
+    LOG(ERROR) << "Failed to open image file " << image_filename;
+    return false;
+  }
+  if (fchmod(image_file->Fd(), 0644) != 0) {
+    PLOG(ERROR) << "Failed to make image file world readable: " << image_filename;
+    return EXIT_FAILURE;
+  }
+  bool success = image_file->WriteFully(image_->Begin(), image_end_);
+  if (!success) {
+    PLOG(ERROR) << "Failed to write image file " << image_filename;
+    return false;
+  }
+  return true;
+}
+
+bool ImageWriter::AllocMemory() {
+  gc::Heap* heap = Runtime::Current()->GetHeap();
+  const std::vector<gc::space::ContinuousSpace*>& spaces = heap->GetContinuousSpaces();
+  size_t size = 0;
+  // TODO: C++0x auto
+  typedef std::vector<gc::space::ContinuousSpace*>::const_iterator It;
+  for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
+    gc::space::ContinuousSpace* space = *it;
+    if (space->IsDlMallocSpace()) {
+      size += space->Size();
+    }
+  }
+
+  int prot = PROT_READ | PROT_WRITE;
+  size_t length = RoundUp(size, kPageSize);
+  image_.reset(MemMap::MapAnonymous("image writer image", NULL, length, prot));
+  if (image_.get() == NULL) {
+    LOG(ERROR) << "Failed to allocate memory for image file generation";
+    return false;
+  }
+  return true;
+}
+
+void ImageWriter::ComputeLazyFieldsForImageClasses() {
+  Runtime* runtime = Runtime::Current();
+  ClassLinker* class_linker = runtime->GetClassLinker();
+  class_linker->VisitClassesWithoutClassesLock(ComputeLazyFieldsForClassesVisitor, NULL);
+}
+
+bool ImageWriter::ComputeLazyFieldsForClassesVisitor(Class* c, void* /*arg*/) {
+  c->ComputeName();
+  return true;
+}
+
+void ImageWriter::ComputeEagerResolvedStringsCallback(Object* obj, void* arg) {
+  if (!obj->GetClass()->IsStringClass()) {
+    return;
+  }
+  String* string = obj->AsString();
+  const uint16_t* utf16_string = string->GetCharArray()->GetData() + string->GetOffset();
+  ImageWriter* writer = reinterpret_cast<ImageWriter*>(arg);
+  typedef Set::const_iterator CacheIt;  // TODO: C++0x auto
+  for (CacheIt it = writer->dex_caches_.begin(), end = writer->dex_caches_.end(); it != end; ++it) {
+    DexCache* dex_cache = *it;
+    const DexFile& dex_file = *dex_cache->GetDexFile();
+    const DexFile::StringId* string_id = dex_file.FindStringId(utf16_string);
+    if (string_id != NULL) {
+      // This string occurs in this dex file, assign the dex cache entry.
+      uint32_t string_idx = dex_file.GetIndexForStringId(*string_id);
+      if (dex_cache->GetResolvedString(string_idx) == NULL) {
+        dex_cache->SetResolvedString(string_idx, string);
+      }
+    }
+  }
+}
+
+void ImageWriter::ComputeEagerResolvedStrings()
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  // TODO: Check image spaces only?
+  gc::Heap* heap = Runtime::Current()->GetHeap();
+  WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
+  heap->FlushAllocStack();
+  heap->GetLiveBitmap()->Walk(ComputeEagerResolvedStringsCallback, this);
+}
+
+bool ImageWriter::IsImageClass(const Class* klass) {
+  return compiler_driver_.IsImageClass(ClassHelper(klass).GetDescriptor());
+}
+
+struct NonImageClasses {
+  ImageWriter* image_writer;
+  std::set<std::string>* non_image_classes;
+};
+
+void ImageWriter::PruneNonImageClasses() {
+  if (compiler_driver_.GetImageClasses() == NULL) {
+    return;
+  }
+  Runtime* runtime = Runtime::Current();
+  ClassLinker* class_linker = runtime->GetClassLinker();
+
+  // Make a list of classes we would like to prune.
+  std::set<std::string> non_image_classes;
+  NonImageClasses context;
+  context.image_writer = this;
+  context.non_image_classes = &non_image_classes;
+  class_linker->VisitClasses(NonImageClassesVisitor, &context);
+
+  // Remove the undesired classes from the class roots.
+  typedef std::set<std::string>::const_iterator ClassIt;  // TODO: C++0x auto
+  for (ClassIt it = non_image_classes.begin(), end = non_image_classes.end(); it != end; ++it) {
+    class_linker->RemoveClass((*it).c_str(), NULL);
+  }
+
+  // Clear references to removed classes from the DexCaches.
+  AbstractMethod* resolution_method = runtime->GetResolutionMethod();
+  typedef Set::const_iterator CacheIt;  // TODO: C++0x auto
+  for (CacheIt it = dex_caches_.begin(), end = dex_caches_.end(); it != end; ++it) {
+    DexCache* dex_cache = *it;
+    for (size_t i = 0; i < dex_cache->NumResolvedTypes(); i++) {
+      Class* klass = dex_cache->GetResolvedType(i);
+      if (klass != NULL && !IsImageClass(klass)) {
+        dex_cache->SetResolvedType(i, NULL);
+        dex_cache->GetInitializedStaticStorage()->Set(i, NULL);
+      }
+    }
+    for (size_t i = 0; i < dex_cache->NumResolvedMethods(); i++) {
+      AbstractMethod* method = dex_cache->GetResolvedMethod(i);
+      if (method != NULL && !IsImageClass(method->GetDeclaringClass())) {
+        dex_cache->SetResolvedMethod(i, resolution_method);
+      }
+    }
+    for (size_t i = 0; i < dex_cache->NumResolvedFields(); i++) {
+      Field* field = dex_cache->GetResolvedField(i);
+      if (field != NULL && !IsImageClass(field->GetDeclaringClass())) {
+        dex_cache->SetResolvedField(i, NULL);
+      }
+    }
+  }
+}
+
+bool ImageWriter::NonImageClassesVisitor(Class* klass, void* arg) {
+  NonImageClasses* context = reinterpret_cast<NonImageClasses*>(arg);
+  if (!context->image_writer->IsImageClass(klass)) {
+    context->non_image_classes->insert(ClassHelper(klass).GetDescriptor());
+  }
+  return true;
+}
+
+void ImageWriter::CheckNonImageClassesRemoved()
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  if (compiler_driver_.GetImageClasses() == NULL) {
+    return;
+  }
+
+  gc::Heap* heap = Runtime::Current()->GetHeap();
+  Thread* self = Thread::Current();
+  {
+    WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
+    heap->FlushAllocStack();
+  }
+
+  ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
+  heap->GetLiveBitmap()->Walk(CheckNonImageClassesRemovedCallback, this);
+}
+
+void ImageWriter::CheckNonImageClassesRemovedCallback(Object* obj, void* arg) {
+  ImageWriter* image_writer = reinterpret_cast<ImageWriter*>(arg);
+  if (!obj->IsClass()) {
+    return;
+  }
+  Class* klass = obj->AsClass();
+  if (!image_writer->IsImageClass(klass)) {
+    image_writer->DumpImageClasses();
+    CHECK(image_writer->IsImageClass(klass)) << ClassHelper(klass).GetDescriptor()
+                                             << " " << PrettyDescriptor(klass);
+  }
+}
+
+void ImageWriter::DumpImageClasses() {
+  CompilerDriver::DescriptorSet* image_classes = compiler_driver_.GetImageClasses();
+  CHECK(image_classes != NULL);
+  typedef std::set<std::string>::const_iterator It;  // TODO: C++0x auto
+  for (It it = image_classes->begin(), end = image_classes->end(); it != end; ++it) {
+    LOG(INFO) << " " << *it;
+  }
+}
+
+void ImageWriter::CalculateNewObjectOffsetsCallback(Object* obj, void* arg) {
+  DCHECK(obj != NULL);
+  DCHECK(arg != NULL);
+  ImageWriter* image_writer = reinterpret_cast<ImageWriter*>(arg);
+
+  // if it is a string, we want to intern it if its not interned.
+  if (obj->GetClass()->IsStringClass()) {
+    // we must be an interned string that was forward referenced and already assigned
+    if (image_writer->IsImageOffsetAssigned(obj)) {
+      DCHECK_EQ(obj, obj->AsString()->Intern());
+      return;
+    }
+    SirtRef<String> interned(Thread::Current(), obj->AsString()->Intern());
+    if (obj != interned.get()) {
+      if (!image_writer->IsImageOffsetAssigned(interned.get())) {
+        // interned obj is after us, allocate its location early
+        image_writer->AssignImageOffset(interned.get());
+      }
+      // point those looking for this object to the interned version.
+      image_writer->SetImageOffset(obj, image_writer->GetImageOffset(interned.get()));
+      return;
+    }
+    // else (obj == interned), nothing to do but fall through to the normal case
+  }
+
+  image_writer->AssignImageOffset(obj);
+}
+
+ObjectArray<Object>* ImageWriter::CreateImageRoots() const {
+  Runtime* runtime = Runtime::Current();
+  ClassLinker* class_linker = runtime->GetClassLinker();
+  Class* object_array_class = class_linker->FindSystemClass("[Ljava/lang/Object;");
+  Thread* self = Thread::Current();
+
+  // build an Object[] of all the DexCaches used in the source_space_
+  ObjectArray<Object>* dex_caches = ObjectArray<Object>::Alloc(self, object_array_class,
+                                                               dex_caches_.size());
+  int i = 0;
+  typedef Set::const_iterator It;  // TODO: C++0x auto
+  for (It it = dex_caches_.begin(), end = dex_caches_.end(); it != end; ++it, ++i) {
+    dex_caches->Set(i, *it);
+  }
+
+  // build an Object[] of the roots needed to restore the runtime
+  SirtRef<ObjectArray<Object> >
+      image_roots(self,
+                  ObjectArray<Object>::Alloc(self, object_array_class,
+                                             ImageHeader::kImageRootsMax));
+  image_roots->Set(ImageHeader::kResolutionMethod, runtime->GetResolutionMethod());
+  image_roots->Set(ImageHeader::kCalleeSaveMethod,
+                   runtime->GetCalleeSaveMethod(Runtime::kSaveAll));
+  image_roots->Set(ImageHeader::kRefsOnlySaveMethod,
+                   runtime->GetCalleeSaveMethod(Runtime::kRefsOnly));
+  image_roots->Set(ImageHeader::kRefsAndArgsSaveMethod,
+                   runtime->GetCalleeSaveMethod(Runtime::kRefsAndArgs));
+  image_roots->Set(ImageHeader::kOatLocation,
+                   String::AllocFromModifiedUtf8(self, oat_file_->GetLocation().c_str()));
+  image_roots->Set(ImageHeader::kDexCaches,
+                   dex_caches);
+  image_roots->Set(ImageHeader::kClassRoots,
+                   class_linker->GetClassRoots());
+  for (int i = 0; i < ImageHeader::kImageRootsMax; i++) {
+    CHECK(image_roots->Get(i) != NULL);
+  }
+  return image_roots.get();
+}
+
+void ImageWriter::CalculateNewObjectOffsets(size_t oat_loaded_size, size_t oat_data_offset) {
+  CHECK_NE(0U, oat_loaded_size);
+  Thread* self = Thread::Current();
+  SirtRef<ObjectArray<Object> > image_roots(self, CreateImageRoots());
+
+  gc::Heap* heap = Runtime::Current()->GetHeap();
+  const std::vector<gc::space::ContinuousSpace*>& spaces = heap->GetContinuousSpaces();
+  DCHECK(!spaces.empty());
+  DCHECK_EQ(0U, image_end_);
+
+  // leave space for the header, but do not write it yet, we need to
+  // know where image_roots is going to end up
+  image_end_ += RoundUp(sizeof(ImageHeader), 8); // 64-bit-alignment
+
+  {
+    WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
+    heap->FlushAllocStack();
+    // TODO: Image spaces only?
+    // TODO: Add InOrderWalk to heap bitmap.
+    const char* old = self->StartAssertNoThreadSuspension("ImageWriter");
+    DCHECK(heap->GetLargeObjectsSpace()->GetLiveObjects()->IsEmpty());
+    // TODO: C++0x auto
+    typedef std::vector<gc::space::ContinuousSpace*>::const_iterator It;
+    for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
+      gc::space::ContinuousSpace* space = *it;
+      space->GetLiveBitmap()->InOrderWalk(CalculateNewObjectOffsetsCallback, this);
+      DCHECK_LT(image_end_, image_->Size());
+    }
+    self->EndAssertNoThreadSuspension(old);
+  }
+
+  const byte* oat_file_begin = image_begin_ + RoundUp(image_end_, kPageSize);
+  const byte* oat_file_end = oat_file_begin + oat_loaded_size;
+  oat_data_begin_ = oat_file_begin + oat_data_offset;
+  const byte* oat_data_end = oat_data_begin_ + oat_file_->Size();
+
+  // return to write header at start of image with future location of image_roots
+  ImageHeader image_header(reinterpret_cast<uint32_t>(image_begin_),
+                           reinterpret_cast<uint32_t>(GetImageAddress(image_roots.get())),
+                           oat_file_->GetOatHeader().GetChecksum(),
+                           reinterpret_cast<uint32_t>(oat_file_begin),
+                           reinterpret_cast<uint32_t>(oat_data_begin_),
+                           reinterpret_cast<uint32_t>(oat_data_end),
+                           reinterpret_cast<uint32_t>(oat_file_end));
+  memcpy(image_->Begin(), &image_header, sizeof(image_header));
+
+  // Note that image_end_ is left at end of used space
+}
+
+void ImageWriter::CopyAndFixupObjects()
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  Thread* self = Thread::Current();
+  const char* old_cause = self->StartAssertNoThreadSuspension("ImageWriter");
+  gc::Heap* heap = Runtime::Current()->GetHeap();
+  // TODO: heap validation can't handle this fix up pass
+  heap->DisableObjectValidation();
+  // TODO: Image spaces only?
+  WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
+  heap->FlushAllocStack();
+  heap->GetLiveBitmap()->Walk(CopyAndFixupObjectsCallback, this);
+  self->EndAssertNoThreadSuspension(old_cause);
+}
+
+void ImageWriter::CopyAndFixupObjectsCallback(Object* object, void* arg) {
+  DCHECK(object != NULL);
+  DCHECK(arg != NULL);
+  const Object* obj = object;
+  ImageWriter* image_writer = reinterpret_cast<ImageWriter*>(arg);
+
+  // see GetLocalAddress for similar computation
+  size_t offset = image_writer->GetImageOffset(obj);
+  byte* dst = image_writer->image_->Begin() + offset;
+  const byte* src = reinterpret_cast<const byte*>(obj);
+  size_t n = obj->SizeOf();
+  DCHECK_LT(offset + n, image_writer->image_->Size());
+  memcpy(dst, src, n);
+  Object* copy = reinterpret_cast<Object*>(dst);
+  copy->SetField32(Object::MonitorOffset(), 0, false); // We may have inflated the lock during compilation.
+  image_writer->FixupObject(obj, copy);
+}
+
+void ImageWriter::FixupObject(const Object* orig, Object* copy) {
+  DCHECK(orig != NULL);
+  DCHECK(copy != NULL);
+  copy->SetClass(down_cast<Class*>(GetImageAddress(orig->GetClass())));
+  // TODO: special case init of pointers to malloc data (or removal of these pointers)
+  if (orig->IsClass()) {
+    FixupClass(orig->AsClass(), down_cast<Class*>(copy));
+  } else if (orig->IsObjectArray()) {
+    FixupObjectArray(orig->AsObjectArray<Object>(), down_cast<ObjectArray<Object>*>(copy));
+  } else if (orig->IsMethod()) {
+    FixupMethod(orig->AsMethod(), down_cast<AbstractMethod*>(copy));
+  } else {
+    FixupInstanceFields(orig, copy);
+  }
+}
+
+void ImageWriter::FixupClass(const Class* orig, Class* copy) {
+  FixupInstanceFields(orig, copy);
+  FixupStaticFields(orig, copy);
+}
+
+void ImageWriter::FixupMethod(const AbstractMethod* orig, AbstractMethod* copy) {
+  FixupInstanceFields(orig, copy);
+
+  // OatWriter replaces the code_ with an offset value.
+  // Here we readjust to a pointer relative to oat_begin_
+  if (orig->IsAbstract()) {
+    // Code for abstract methods is set to the abstract method error stub when we load the image.
+    copy->SetEntryPointFromCompiledCode(NULL);
+    copy->SetEntryPointFromInterpreter(reinterpret_cast<EntryPointFromInterpreter*>
+                                       (GetOatAddress(interpreter_to_interpreter_entry_offset_)));
+    return;
+  } else {
+    copy->SetEntryPointFromInterpreter(reinterpret_cast<EntryPointFromInterpreter*>
+                                       (GetOatAddress(interpreter_to_quick_entry_offset_)));
+  }
+
+  if (orig == Runtime::Current()->GetResolutionMethod()) {
+#if defined(ART_USE_PORTABLE_COMPILER)
+    copy->SetEntryPointFromCompiledCode(GetOatAddress(portable_resolution_trampoline_offset_));
+#else
+    copy->SetEntryPointFromCompiledCode(GetOatAddress(quick_resolution_trampoline_offset_));
+#endif
+    return;
+  }
+
+  // Use original code if it exists. Otherwise, set the code pointer to the resolution trampoline.
+  const byte* code = GetOatAddress(orig->GetOatCodeOffset());
+  if (code != NULL) {
+    copy->SetEntryPointFromCompiledCode(code);
+  } else {
+#if defined(ART_USE_PORTABLE_COMPILER)
+    copy->SetEntryPointFromCompiledCode(GetOatAddress(portable_resolution_trampoline_offset_));
+#else
+    copy->SetEntryPointFromCompiledCode(GetOatAddress(quick_resolution_trampoline_offset_));
+#endif
+  }
+
+  if (orig->IsNative()) {
+    // The native method's pointer is set to a stub to lookup via dlsym when we load the image.
+    // Note this is not the code_ pointer, that is handled above.
+    copy->SetNativeMethod(NULL);
+  } else {
+    // normal (non-abstract non-native) methods have mapping tables to relocate
+    uint32_t mapping_table_off = orig->GetOatMappingTableOffset();
+    const byte* mapping_table = GetOatAddress(mapping_table_off);
+    copy->SetMappingTable(reinterpret_cast<const uint32_t*>(mapping_table));
+
+    uint32_t vmap_table_offset = orig->GetOatVmapTableOffset();
+    const byte* vmap_table = GetOatAddress(vmap_table_offset);
+    copy->SetVmapTable(reinterpret_cast<const uint16_t*>(vmap_table));
+
+    uint32_t native_gc_map_offset = orig->GetOatNativeGcMapOffset();
+    const byte* native_gc_map = GetOatAddress(native_gc_map_offset);
+    copy->SetNativeGcMap(reinterpret_cast<const uint8_t*>(native_gc_map));
+  }
+}
+
+void ImageWriter::FixupObjectArray(const ObjectArray<Object>* orig, ObjectArray<Object>* copy) {
+  for (int32_t i = 0; i < orig->GetLength(); ++i) {
+    const Object* element = orig->Get(i);
+    copy->SetPtrWithoutChecks(i, GetImageAddress(element));
+  }
+}
+
+void ImageWriter::FixupInstanceFields(const Object* orig, Object* copy) {
+  DCHECK(orig != NULL);
+  DCHECK(copy != NULL);
+  Class* klass = orig->GetClass();
+  DCHECK(klass != NULL);
+  FixupFields(orig,
+              copy,
+              klass->GetReferenceInstanceOffsets(),
+              false);
+}
+
+void ImageWriter::FixupStaticFields(const Class* orig, Class* copy) {
+  DCHECK(orig != NULL);
+  DCHECK(copy != NULL);
+  FixupFields(orig,
+              copy,
+              orig->GetReferenceStaticOffsets(),
+              true);
+}
+
+void ImageWriter::FixupFields(const Object* orig,
+                              Object* copy,
+                              uint32_t ref_offsets,
+                              bool is_static) {
+  if (ref_offsets != CLASS_WALK_SUPER) {
+    // Found a reference offset bitmap.  Fixup the specified offsets.
+    while (ref_offsets != 0) {
+      size_t right_shift = CLZ(ref_offsets);
+      MemberOffset byte_offset = CLASS_OFFSET_FROM_CLZ(right_shift);
+      const Object* ref = orig->GetFieldObject<const Object*>(byte_offset, false);
+      // Use SetFieldPtr to avoid card marking since we are writing to the image.
+      copy->SetFieldPtr(byte_offset, GetImageAddress(ref), false);
+      ref_offsets &= ~(CLASS_HIGH_BIT >> right_shift);
+    }
+  } else {
+    // There is no reference offset bitmap.  In the non-static case,
+    // walk up the class inheritance hierarchy and find reference
+    // offsets the hard way. In the static case, just consider this
+    // class.
+    for (const Class *klass = is_static ? orig->AsClass() : orig->GetClass();
+         klass != NULL;
+         klass = is_static ? NULL : klass->GetSuperClass()) {
+      size_t num_reference_fields = (is_static
+                                     ? klass->NumReferenceStaticFields()
+                                     : klass->NumReferenceInstanceFields());
+      for (size_t i = 0; i < num_reference_fields; ++i) {
+        Field* field = (is_static
+                        ? klass->GetStaticField(i)
+                        : klass->GetInstanceField(i));
+        MemberOffset field_offset = field->GetOffset();
+        const Object* ref = orig->GetFieldObject<const Object*>(field_offset, false);
+        // Use SetFieldPtr to avoid card marking since we are writing to the image.
+        copy->SetFieldPtr(field_offset, GetImageAddress(ref), false);
+      }
+    }
+  }
+  if (!is_static && orig->IsReferenceInstance()) {
+    // Fix-up referent, that isn't marked as an object field, for References.
+    Field* field = orig->GetClass()->FindInstanceField("referent", "Ljava/lang/Object;");
+    MemberOffset field_offset = field->GetOffset();
+    const Object* ref = orig->GetFieldObject<const Object*>(field_offset, false);
+    // Use SetFieldPtr to avoid card marking since we are writing to the image.
+    copy->SetFieldPtr(field_offset, GetImageAddress(ref), false);
+  }
+}
+
+static AbstractMethod* GetTargetMethod(const CompilerDriver::PatchInformation* patch)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  DexCache* dex_cache = class_linker->FindDexCache(patch->GetDexFile());
+  AbstractMethod* method = class_linker->ResolveMethod(patch->GetDexFile(),
+                                               patch->GetTargetMethodIdx(),
+                                               dex_cache,
+                                               NULL,
+                                               NULL,
+                                               patch->GetTargetInvokeType());
+  CHECK(method != NULL)
+    << patch->GetDexFile().GetLocation() << " " << patch->GetTargetMethodIdx();
+  CHECK(!method->IsRuntimeMethod())
+    << patch->GetDexFile().GetLocation() << " " << patch->GetTargetMethodIdx();
+  CHECK(dex_cache->GetResolvedMethods()->Get(patch->GetTargetMethodIdx()) == method)
+    << patch->GetDexFile().GetLocation() << " " << patch->GetReferrerMethodIdx() << " "
+    << PrettyMethod(dex_cache->GetResolvedMethods()->Get(patch->GetTargetMethodIdx())) << " "
+    << PrettyMethod(method);
+  return method;
+}
+
+void ImageWriter::PatchOatCodeAndMethods() {
+  Thread* self = Thread::Current();
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  const char* old_cause = self->StartAssertNoThreadSuspension("ImageWriter");
+
+  typedef std::vector<const CompilerDriver::PatchInformation*> Patches;
+  const Patches& code_to_patch = compiler_driver_.GetCodeToPatch();
+  for (size_t i = 0; i < code_to_patch.size(); i++) {
+    const CompilerDriver::PatchInformation* patch = code_to_patch[i];
+    AbstractMethod* target = GetTargetMethod(patch);
+    uint32_t code = reinterpret_cast<uint32_t>(class_linker->GetOatCodeFor(target));
+    uint32_t code_base = reinterpret_cast<uint32_t>(&oat_file_->GetOatHeader());
+    uint32_t code_offset = code - code_base;
+    SetPatchLocation(patch, reinterpret_cast<uint32_t>(GetOatAddress(code_offset)));
+  }
+
+  const Patches& methods_to_patch = compiler_driver_.GetMethodsToPatch();
+  for (size_t i = 0; i < methods_to_patch.size(); i++) {
+    const CompilerDriver::PatchInformation* patch = methods_to_patch[i];
+    AbstractMethod* target = GetTargetMethod(patch);
+    SetPatchLocation(patch, reinterpret_cast<uint32_t>(GetImageAddress(target)));
+  }
+
+  // Update the image header with the new checksum after patching
+  ImageHeader* image_header = reinterpret_cast<ImageHeader*>(image_->Begin());
+  image_header->SetOatChecksum(oat_file_->GetOatHeader().GetChecksum());
+  self->EndAssertNoThreadSuspension(old_cause);
+}
+
+void ImageWriter::SetPatchLocation(const CompilerDriver::PatchInformation* patch, uint32_t value) {
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  const void* oat_code = class_linker->GetOatCodeFor(patch->GetDexFile(),
+                                                     patch->GetReferrerMethodIdx());
+  OatHeader& oat_header = const_cast<OatHeader&>(oat_file_->GetOatHeader());
+  // TODO: make this Thumb2 specific
+  uint8_t* base = reinterpret_cast<uint8_t*>(reinterpret_cast<uint32_t>(oat_code) & ~0x1);
+  uint32_t* patch_location = reinterpret_cast<uint32_t*>(base + patch->GetLiteralOffset());
+#ifndef NDEBUG
+  const DexFile::MethodId& id = patch->GetDexFile().GetMethodId(patch->GetTargetMethodIdx());
+  uint32_t expected = reinterpret_cast<uint32_t>(&id);
+  uint32_t actual = *patch_location;
+  CHECK(actual == expected || actual == value) << std::hex
+    << "actual=" << actual
+    << "expected=" << expected
+    << "value=" << value;
+#endif
+  *patch_location = value;
+  oat_header.UpdateChecksum(patch_location, sizeof(value));
+}
+
+}  // namespace art
diff --git a/src/compiler/image_writer.h b/src/compiler/image_writer.h
new file mode 100644
index 0000000..b79cb2f
--- /dev/null
+++ b/src/compiler/image_writer.h
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_IMAGE_WRITER_H_
+#define ART_SRC_IMAGE_WRITER_H_
+
+#include <stdint.h>
+
+#include <cstddef>
+#include <set>
+#include <string>
+
+#include "compiler/driver/compiler_driver.h"
+#include "mem_map.h"
+#include "oat_file.h"
+#include "mirror/dex_cache.h"
+#include "os.h"
+#include "safe_map.h"
+#include "gc/space/space.h"
+#include "UniquePtr.h"
+
+namespace art {
+
+// Write a Space built during compilation for use during execution.
+class ImageWriter {
+ public:
+  explicit ImageWriter(const CompilerDriver& compiler_driver)
+      : compiler_driver_(compiler_driver), oat_file_(NULL), image_end_(0), image_begin_(NULL),
+        oat_data_begin_(NULL), interpreter_to_interpreter_entry_offset_(0),
+        interpreter_to_quick_entry_offset_(0), portable_resolution_trampoline_offset_(0),
+        quick_resolution_trampoline_offset_(0) {}
+
+  ~ImageWriter() {}
+
+  bool Write(const std::string& image_filename,
+             uintptr_t image_begin,
+             const std::string& oat_filename,
+             const std::string& oat_location)
+      LOCKS_EXCLUDED(Locks::mutator_lock_);
+
+  uintptr_t GetOatDataBegin() {
+    return reinterpret_cast<uintptr_t>(oat_data_begin_);
+  }
+
+ private:
+  bool AllocMemory();
+
+  // we use the lock word to store the offset of the object in the image
+  void AssignImageOffset(mirror::Object* object)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    DCHECK(object != NULL);
+    SetImageOffset(object, image_end_);
+    image_end_ += RoundUp(object->SizeOf(), 8);  // 64-bit alignment
+    DCHECK_LT(image_end_, image_->Size());
+  }
+
+  void SetImageOffset(mirror::Object* object, size_t offset) {
+    DCHECK(object != NULL);
+    DCHECK_NE(offset, 0U);
+    DCHECK(!IsImageOffsetAssigned(object));
+    offsets_.Put(object, offset);
+  }
+
+  size_t IsImageOffsetAssigned(const mirror::Object* object) const {
+    DCHECK(object != NULL);
+    return offsets_.find(object) != offsets_.end();
+  }
+
+  size_t GetImageOffset(const mirror::Object* object) const {
+    DCHECK(object != NULL);
+    DCHECK(IsImageOffsetAssigned(object));
+    return offsets_.find(object)->second;
+  }
+
+  mirror::Object* GetImageAddress(const mirror::Object* object) const {
+    if (object == NULL) {
+      return NULL;
+    }
+    return reinterpret_cast<mirror::Object*>(image_begin_ + GetImageOffset(object));
+  }
+
+  mirror::Object* GetLocalAddress(const mirror::Object* object) const {
+    size_t offset = GetImageOffset(object);
+    byte* dst = image_->Begin() + offset;
+    return reinterpret_cast<mirror::Object*>(dst);
+  }
+
+  const byte* GetOatAddress(uint32_t offset) const {
+#if !defined(ART_USE_PORTABLE_COMPILER)
+    // With Quick, code is within the OatFile, as there are all in one
+    // .o ELF object. However with Portable, the code is always in
+    // different .o ELF objects.
+    DCHECK_LT(offset, oat_file_->Size());
+#endif
+    if (offset == 0) {
+      return NULL;
+    }
+    return oat_data_begin_ + offset;
+  }
+
+  // Returns true if the class was in the original requested image classes list.
+  bool IsImageClass(const mirror::Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Debug aid that list of requested image classes.
+  void DumpImageClasses();
+
+  // Preinitializes some otherwise lazy fields (such as Class name) to avoid runtime image dirtying.
+  void ComputeLazyFieldsForImageClasses()
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static bool ComputeLazyFieldsForClassesVisitor(mirror::Class* klass, void* arg)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Wire dex cache resolved strings to strings in the image to avoid runtime resolution.
+  void ComputeEagerResolvedStrings();
+  static void ComputeEagerResolvedStringsCallback(mirror::Object* obj, void* arg)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Remove unwanted classes from various roots.
+  void PruneNonImageClasses() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static bool NonImageClassesVisitor(mirror::Class* c, void* arg)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Verify unwanted classes removed.
+  void CheckNonImageClassesRemoved();
+  static void CheckNonImageClassesRemovedCallback(mirror::Object* obj, void* arg)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Lays out where the image objects will be at runtime.
+  void CalculateNewObjectOffsets(size_t oat_loaded_size, size_t oat_data_offset)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  mirror::ObjectArray<mirror::Object>* CreateImageRoots() const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static void CalculateNewObjectOffsetsCallback(mirror::Object* obj, void* arg)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Creates the contiguous image in memory and adjusts pointers.
+  void CopyAndFixupObjects();
+  static void CopyAndFixupObjectsCallback(mirror::Object* obj, void* arg)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void FixupClass(const mirror::Class* orig, mirror::Class* copy)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void FixupMethod(const mirror::AbstractMethod* orig, mirror::AbstractMethod* copy)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void FixupObject(const mirror::Object* orig, mirror::Object* copy)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void FixupObjectArray(const mirror::ObjectArray<mirror::Object>* orig,
+                        mirror::ObjectArray<mirror::Object>* copy)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void FixupInstanceFields(const mirror::Object* orig, mirror::Object* copy)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void FixupStaticFields(const mirror::Class* orig, mirror::Class* copy)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void FixupFields(const mirror::Object* orig, mirror::Object* copy, uint32_t ref_offsets,
+                   bool is_static)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Patches references in OatFile to expect runtime addresses.
+  void PatchOatCodeAndMethods()
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void SetPatchLocation(const CompilerDriver::PatchInformation* patch, uint32_t value)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+
+  const CompilerDriver& compiler_driver_;
+
+  // Map of Object to where it will be at runtime.
+  SafeMap<const mirror::Object*, size_t> offsets_;
+
+  // oat file with code for this image
+  OatFile* oat_file_;
+
+  // Memory mapped for generating the image.
+  UniquePtr<MemMap> image_;
+
+  // Offset to the free space in image_.
+  size_t image_end_;
+
+  // Beginning target image address for the output image.
+  byte* image_begin_;
+
+  // Beginning target oat address for the pointers from the output image to its oat file.
+  const byte* oat_data_begin_;
+
+  // Offset from oat_data_begin_ to the stubs.
+  uint32_t interpreter_to_interpreter_entry_offset_;
+  uint32_t interpreter_to_quick_entry_offset_;
+  uint32_t portable_resolution_trampoline_offset_;
+  uint32_t quick_resolution_trampoline_offset_;
+
+  // DexCaches seen while scanning for fixing up CodeAndDirectMethods
+  typedef std::set<mirror::DexCache*> Set;
+  Set dex_caches_;
+};
+
+}  // namespace art
+
+#endif  // ART_SRC_IMAGE_WRITER_H_
diff --git a/src/compiler/jni/portable/jni_compiler.cc b/src/compiler/jni/portable/jni_compiler.cc
index 2795d05..cd8158d 100644
--- a/src/compiler/jni/portable/jni_compiler.cc
+++ b/src/compiler/jni/portable/jni_compiler.cc
@@ -24,7 +24,7 @@
 #include "compiler/llvm/compiler_llvm.h"
 #include "compiler/llvm/ir_builder.h"
 #include "compiler/llvm/llvm_compilation_unit.h"
-#include "compiler/llvm/runtime_support_func.h"
+#include "compiler/llvm/runtime_support_llvm_func.h"
 #include "compiler/llvm/utils_llvm.h"
 #include "dex_file-inl.h"
 #include "mirror/abstract_method.h"
diff --git a/src/compiler/llvm/compiler_llvm.cc b/src/compiler/llvm/compiler_llvm.cc
index dfd0e32..3af6687 100644
--- a/src/compiler/llvm/compiler_llvm.cc
+++ b/src/compiler/llvm/compiler_llvm.cc
@@ -152,8 +152,8 @@
 
   cunit->Materialize();
 
-  CompilerDriver::MethodReference mref(dex_compilation_unit->GetDexFile(),
-                                       dex_compilation_unit->GetDexMethodIndex());
+  MethodReference mref(dex_compilation_unit->GetDexFile(),
+                       dex_compilation_unit->GetDexMethodIndex());
   return new CompiledMethod(compiler_driver_->GetInstructionSet(),
                             cunit->GetElfObject(),
                             *verifier::MethodVerifier::GetDexGcMap(mref),
diff --git a/src/compiler/llvm/gbc_expander.cc b/src/compiler/llvm/gbc_expander.cc
index bdf9aca..4702b37 100644
--- a/src/compiler/llvm/gbc_expander.cc
+++ b/src/compiler/llvm/gbc_expander.cc
@@ -19,6 +19,7 @@
 #include "dex_file-inl.h"
 #include "intrinsic_helper.h"
 #include "ir_builder.h"
+#include "method_reference.h"
 #include "mirror/abstract_method.h"
 #include "mirror/array.h"
 #include "mirror/string.h"
@@ -776,8 +777,8 @@
   art::InvokeType invoke_type =
       static_cast<art::InvokeType>(LV2UInt(call_inst.getArgOperand(0)));
   bool is_static = (invoke_type == art::kStatic);
-  art::CompilerDriver::MethodReference target_method(dex_compilation_unit_->GetDexFile(),
-                                                     LV2UInt(call_inst.getArgOperand(1)));
+  art::MethodReference target_method(dex_compilation_unit_->GetDexFile(),
+                                     LV2UInt(call_inst.getArgOperand(1)));
 
   // Load *this* actual parameter
   llvm::Value* this_addr = (!is_static) ? call_inst.getArgOperand(3) : NULL;
diff --git a/src/compiler/llvm/ir_builder.h b/src/compiler/llvm/ir_builder.h
index 9d78fe6..eb88fca 100644
--- a/src/compiler/llvm/ir_builder.h
+++ b/src/compiler/llvm/ir_builder.h
@@ -22,7 +22,7 @@
 #include "intrinsic_helper.h"
 #include "md_builder.h"
 #include "runtime_support_builder.h"
-#include "runtime_support_func.h"
+#include "runtime_support_llvm_func.h"
 
 #include <llvm/IR/Constants.h>
 #include <llvm/IR/DerivedTypes.h>
diff --git a/src/compiler/llvm/llvm_compilation_unit.h b/src/compiler/llvm/llvm_compilation_unit.h
index 857d924..a5d4e11 100644
--- a/src/compiler/llvm/llvm_compilation_unit.h
+++ b/src/compiler/llvm/llvm_compilation_unit.h
@@ -25,7 +25,7 @@
 #include "instruction_set.h"
 #include "compiler/driver/dex_compilation_unit.h"
 #include "runtime_support_builder.h"
-#include "runtime_support_func.h"
+#include "runtime_support_llvm_func.h"
 #include "safe_map.h"
 
 #include <UniquePtr.h>
diff --git a/src/compiler/llvm/runtime_support_builder.cc b/src/compiler/llvm/runtime_support_builder.cc
index 2be2ddf..28405f6 100644
--- a/src/compiler/llvm/runtime_support_builder.cc
+++ b/src/compiler/llvm/runtime_support_builder.cc
@@ -48,7 +48,7 @@
     runtime_support_func_decls_[runtime_support::ID] = fn; \
   } while (0);
 
-#include "runtime_support_func_list.h"
+#include "runtime_support_llvm_func_list.h"
   RUNTIME_SUPPORT_FUNC_LIST(GET_RUNTIME_SUPPORT_FUNC_DECL)
 #undef RUNTIME_SUPPORT_FUNC_LIST
 #undef GET_RUNTIME_SUPPORT_FUNC_DECL
diff --git a/src/compiler/llvm/runtime_support_builder.h b/src/compiler/llvm/runtime_support_builder.h
index 04d72b8..267b406 100644
--- a/src/compiler/llvm/runtime_support_builder.h
+++ b/src/compiler/llvm/runtime_support_builder.h
@@ -19,7 +19,7 @@
 
 #include "backend_types.h"
 #include "base/logging.h"
-#include "runtime_support_func.h"
+#include "runtime_support_llvm_func.h"
 
 #include <stdint.h>
 
diff --git a/src/compiler/llvm/runtime_support_func_list.h b/src/compiler/llvm/runtime_support_func_list.h
deleted file mode 100644
index a58b061..0000000
--- a/src/compiler/llvm/runtime_support_func_list.h
+++ /dev/null
@@ -1,76 +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.
- */
-
-#define RUNTIME_SUPPORT_FUNC_LIST(V) \
-  V(LockObject, art_portable_lock_object_from_code) \
-  V(UnlockObject, art_portable_unlock_object_from_code) \
-  V(GetCurrentThread, art_portable_get_current_thread_from_code) \
-  V(SetCurrentThread, art_portable_set_current_thread_from_code) \
-  V(PushShadowFrame, art_portable_push_shadow_frame_from_code) \
-  V(PopShadowFrame, art_portable_pop_shadow_frame_from_code) \
-  V(TestSuspend, art_portable_test_suspend_from_code) \
-  V(ThrowException, art_portable_throw_exception_from_code) \
-  V(ThrowStackOverflowException, art_portable_throw_stack_overflow_from_code) \
-  V(ThrowNullPointerException, art_portable_throw_null_pointer_exception_from_code) \
-  V(ThrowDivZeroException, art_portable_throw_div_zero_from_code) \
-  V(ThrowIndexOutOfBounds, art_portable_throw_array_bounds_from_code) \
-  V(InitializeTypeAndVerifyAccess, art_portable_initialize_type_and_verify_access_from_code) \
-  V(InitializeType, art_portable_initialize_type_from_code) \
-  V(IsAssignable, art_portable_is_assignable_from_code) \
-  V(CheckCast, art_portable_check_cast_from_code) \
-  V(CheckPutArrayElement, art_portable_check_put_array_element_from_code) \
-  V(AllocObject, art_portable_alloc_object_from_code) \
-  V(AllocObjectWithAccessCheck, art_portable_alloc_object_from_code_with_access_check) \
-  V(AllocArray, art_portable_alloc_array_from_code) \
-  V(AllocArrayWithAccessCheck, art_portable_alloc_array_from_code_with_access_check) \
-  V(CheckAndAllocArray, art_portable_check_and_alloc_array_from_code) \
-  V(CheckAndAllocArrayWithAccessCheck, art_portable_check_and_alloc_array_from_code_with_access_check) \
-  V(FindStaticMethodWithAccessCheck, art_portable_find_static_method_from_code_with_access_check) \
-  V(FindDirectMethodWithAccessCheck, art_portable_find_direct_method_from_code_with_access_check) \
-  V(FindVirtualMethodWithAccessCheck, art_portable_find_virtual_method_from_code_with_access_check) \
-  V(FindSuperMethodWithAccessCheck, art_portable_find_super_method_from_code_with_access_check) \
-  V(FindInterfaceMethodWithAccessCheck, art_portable_find_interface_method_from_code_with_access_check) \
-  V(FindInterfaceMethod, art_portable_find_interface_method_from_code) \
-  V(ResolveString, art_portable_resolve_string_from_code) \
-  V(Set32Static, art_portable_set32_static_from_code) \
-  V(Set64Static, art_portable_set64_static_from_code) \
-  V(SetObjectStatic, art_portable_set_obj_static_from_code) \
-  V(Get32Static, art_portable_get32_static_from_code) \
-  V(Get64Static, art_portable_get64_static_from_code) \
-  V(GetObjectStatic, art_portable_get_obj_static_from_code) \
-  V(Set32Instance, art_portable_set32_instance_from_code) \
-  V(Set64Instance, art_portable_set64_instance_from_code) \
-  V(SetObjectInstance, art_portable_set_obj_instance_from_code) \
-  V(Get32Instance, art_portable_get32_instance_from_code) \
-  V(Get64Instance, art_portable_get64_instance_from_code) \
-  V(GetObjectInstance, art_portable_get_obj_instance_from_code) \
-  V(InitializeStaticStorage, art_portable_initialize_static_storage_from_code) \
-  V(FillArrayData, art_portable_fill_array_data_from_code) \
-  V(GetAndClearException, art_portable_get_and_clear_exception) \
-  V(IsExceptionPending, art_portable_is_exception_pending_from_code) \
-  V(FindCatchBlock, art_portable_find_catch_block_from_code) \
-  V(MarkGCCard, art_portable_mark_gc_card_from_code) \
-  V(ProxyInvokeHandler, art_portable_proxy_invoke_handler_from_code) \
-  V(art_d2l, art_d2l) \
-  V(art_d2i, art_d2i) \
-  V(art_f2l, art_f2l) \
-  V(art_f2i, art_f2i) \
-  V(JniMethodStart,                        art_portable_jni_method_start) \
-  V(JniMethodStartSynchronized,            art_portable_jni_method_start_synchronized) \
-  V(JniMethodEnd,                          art_portable_jni_method_end) \
-  V(JniMethodEndSynchronized,              art_portable_jni_method_end_synchronized) \
-  V(JniMethodEndWithReference,             art_portable_jni_method_end_with_reference) \
-  V(JniMethodEndWithReferenceSynchronized, art_portable_jni_method_end_with_reference_synchronized)
diff --git a/src/compiler/llvm/runtime_support_llvm.cc b/src/compiler/llvm/runtime_support_llvm.cc
deleted file mode 100644
index bff13f9..0000000
--- a/src/compiler/llvm/runtime_support_llvm.cc
+++ /dev/null
@@ -1,849 +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 "runtime_support_llvm.h"
-
-#include "ScopedLocalRef.h"
-#include "asm_support.h"
-#include "class_linker.h"
-#include "class_linker-inl.h"
-#include "dex_file-inl.h"
-#include "dex_instruction.h"
-#include "mirror/abstract_method-inl.h"
-#include "mirror/class-inl.h"
-#include "mirror/dex_cache-inl.h"
-#include "mirror/field-inl.h"
-#include "mirror/object.h"
-#include "mirror/object-inl.h"
-#include "mirror/object_array-inl.h"
-#include "nth_caller_visitor.h"
-#include "object_utils.h"
-#include "reflection.h"
-#include "runtime_support.h"
-#include "runtime_support_func_list.h"
-#include "scoped_thread_state_change.h"
-#include "thread.h"
-#include "thread_list.h"
-#include "utils_llvm.h"
-#include "verifier/dex_gc_map.h"
-#include "verifier/method_verifier.h"
-#include "well_known_classes.h"
-
-#include <algorithm>
-#include <math.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-using namespace art;
-
-extern "C" {
-
-class ShadowFrameCopyVisitor : public StackVisitor {
- public:
-  explicit ShadowFrameCopyVisitor(Thread* self) : StackVisitor(self, NULL), prev_frame_(NULL),
-      top_frame_(NULL) {}
-
-  bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    if (IsShadowFrame()) {
-      ShadowFrame* cur_frame = GetCurrentShadowFrame();
-      size_t num_regs = cur_frame->NumberOfVRegs();
-      mirror::AbstractMethod* method = cur_frame->GetMethod();
-      uint32_t dex_pc = cur_frame->GetDexPC();
-      ShadowFrame* new_frame = ShadowFrame::Create(num_regs, NULL, method, dex_pc);
-
-      const uint8_t* gc_map = method->GetNativeGcMap();
-      uint32_t gc_map_length = static_cast<uint32_t>((gc_map[0] << 24) |
-                                                     (gc_map[1] << 16) |
-                                                     (gc_map[2] << 8) |
-                                                     (gc_map[3] << 0));
-      verifier::DexPcToReferenceMap dex_gc_map(gc_map + 4, gc_map_length);
-      const uint8_t* reg_bitmap = dex_gc_map.FindBitMap(dex_pc);
-      for (size_t reg = 0; reg < num_regs; ++reg) {
-        if (TestBitmap(reg, reg_bitmap)) {
-          new_frame->SetVRegReference(reg, cur_frame->GetVRegReference(reg));
-        } else {
-          new_frame->SetVReg(reg, cur_frame->GetVReg(reg));
-        }
-      }
-
-      if (prev_frame_ != NULL) {
-        prev_frame_->SetLink(new_frame);
-      } else {
-        top_frame_ = new_frame;
-      }
-      prev_frame_ = new_frame;
-    }
-    return true;
-  }
-
-  ShadowFrame* GetShadowFrameCopy() {
-    return top_frame_;
-  }
-
- private:
-  static bool TestBitmap(int reg, const uint8_t* reg_vector) {
-    return ((reg_vector[reg / 8] >> (reg % 8)) & 0x01) != 0;
-  }
-
-  ShadowFrame* prev_frame_;
-  ShadowFrame* top_frame_;
-};
-
-//----------------------------------------------------------------------------
-// Thread
-//----------------------------------------------------------------------------
-
-Thread* art_portable_get_current_thread_from_code() {
-#if defined(__arm__) || defined(__i386__)
-  LOG(FATAL) << "UNREACHABLE";
-#endif
-  return Thread::Current();
-}
-
-void* art_portable_set_current_thread_from_code(void* thread_object_addr) {
-  // Hijacked to set r9 on ARM.
-  LOG(FATAL) << "UNREACHABLE";
-  return NULL;
-}
-
-void art_portable_lock_object_from_code(mirror::Object* obj, Thread* thread)
-    EXCLUSIVE_LOCK_FUNCTION(monitor_lock_) {
-  DCHECK(obj != NULL);        // Assumed to have been checked before entry
-  obj->MonitorEnter(thread);  // May block
-  DCHECK(thread->HoldsLock(obj));
-  // Only possible exception is NPE and is handled before entry
-  DCHECK(!thread->IsExceptionPending());
-}
-
-void art_portable_unlock_object_from_code(mirror::Object* obj, Thread* thread)
-    UNLOCK_FUNCTION(monitor_lock_) {
-  DCHECK(obj != NULL);  // Assumed to have been checked before entry
-  // MonitorExit may throw exception
-  obj->MonitorExit(thread);
-}
-
-void art_portable_test_suspend_from_code(Thread* self)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  CheckSuspend(self);
-  if (Runtime::Current()->GetInstrumentation()->ShouldPortableCodeDeoptimize()) {
-    // Save out the shadow frame to the heap
-    ShadowFrameCopyVisitor visitor(self);
-    visitor.WalkStack(true);
-    self->SetDeoptimizationShadowFrame(visitor.GetShadowFrameCopy());
-    self->SetDeoptimizationReturnValue(JValue());
-    self->SetException(ThrowLocation(), reinterpret_cast<mirror::Throwable*>(-1));
-  }
-}
-
-ShadowFrame* art_portable_push_shadow_frame_from_code(Thread* thread,
-                                              ShadowFrame* new_shadow_frame,
-                                              mirror::AbstractMethod* method,
-                                              uint32_t num_vregs) {
-  ShadowFrame* old_frame = thread->PushShadowFrame(new_shadow_frame);
-  new_shadow_frame->SetMethod(method);
-  new_shadow_frame->SetNumberOfVRegs(num_vregs);
-  return old_frame;
-}
-
-void art_portable_pop_shadow_frame_from_code(void*) {
-  LOG(FATAL) << "Implemented by IRBuilder.";
-}
-
-void art_portable_mark_gc_card_from_code(void *, void*) {
-  LOG(FATAL) << "Implemented by IRBuilder.";
-}
-
-//----------------------------------------------------------------------------
-// Exception
-//----------------------------------------------------------------------------
-
-bool art_portable_is_exception_pending_from_code() {
-  LOG(FATAL) << "Implemented by IRBuilder.";
-  return false;
-}
-
-void art_portable_throw_div_zero_from_code() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ThrowArithmeticExceptionDivideByZero();
-}
-
-void art_portable_throw_array_bounds_from_code(int32_t index, int32_t length)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ThrowArrayIndexOutOfBoundsException(index, length);
-}
-
-void art_portable_throw_no_such_method_from_code(int32_t method_idx)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ThrowNoSuchMethodError(method_idx);
-}
-
-void art_portable_throw_null_pointer_exception_from_code(uint32_t dex_pc)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  // TODO: remove dex_pc argument from caller.
-  UNUSED(dex_pc);
-  Thread* self = Thread::Current();
-  ThrowLocation throw_location = self->GetCurrentLocationForThrow();
-  ThrowNullPointerExceptionFromDexPC(throw_location);
-}
-
-void art_portable_throw_stack_overflow_from_code() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ThrowStackOverflowError(Thread::Current());
-}
-
-void art_portable_throw_exception_from_code(mirror::Throwable* exception)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  Thread* self = Thread::Current();
-  ThrowLocation throw_location = self->GetCurrentLocationForThrow();
-  if (exception == NULL) {
-    ThrowNullPointerException(NULL, "throw with null exception");
-  } else {
-    self->SetException(throw_location, exception);
-  }
-}
-
-void* art_portable_get_and_clear_exception(Thread* self)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  DCHECK(self->IsExceptionPending());
-  // TODO: make this inline.
-  mirror::Throwable* exception = self->GetException(NULL);
-  self->ClearException();
-  return exception;
-}
-
-int32_t art_portable_find_catch_block_from_code(mirror::AbstractMethod* current_method, uint32_t ti_offset)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  Thread* self = Thread::Current();  // TODO: make an argument.
-  ThrowLocation throw_location;
-  mirror::Throwable* exception = self->GetException(&throw_location);
-  // Check for special deoptimization exception.
-  if (UNLIKELY(reinterpret_cast<int32_t>(exception) == -1)) {
-    return -1;
-  }
-  mirror::Class* exception_type = exception->GetClass();
-  MethodHelper mh(current_method);
-  const DexFile::CodeItem* code_item = mh.GetCodeItem();
-  DCHECK_LT(ti_offset, code_item->tries_size_);
-  const DexFile::TryItem* try_item = DexFile::GetTryItems(*code_item, ti_offset);
-
-  int iter_index = 0;
-  int result = -1;
-  uint32_t catch_dex_pc = -1;
-  // Iterate over the catch handlers associated with dex_pc
-  for (CatchHandlerIterator it(*code_item, *try_item); it.HasNext(); it.Next()) {
-    uint16_t iter_type_idx = it.GetHandlerTypeIndex();
-    // Catch all case
-    if (iter_type_idx == DexFile::kDexNoIndex16) {
-      catch_dex_pc = it.GetHandlerAddress();
-      result = iter_index;
-      break;
-    }
-    // Does this catch exception type apply?
-    mirror::Class* iter_exception_type = mh.GetDexCacheResolvedType(iter_type_idx);
-    if (UNLIKELY(iter_exception_type == NULL)) {
-      // TODO: check, the verifier (class linker?) should take care of resolving all exception
-      //       classes early.
-      LOG(WARNING) << "Unresolved exception class when finding catch block: "
-          << mh.GetTypeDescriptorFromTypeIdx(iter_type_idx);
-    } else if (iter_exception_type->IsAssignableFrom(exception_type)) {
-      catch_dex_pc = it.GetHandlerAddress();
-      result = iter_index;
-      break;
-    }
-    ++iter_index;
-  }
-  if (result != -1) {
-    // Handler found.
-    Runtime::Current()->GetInstrumentation()->ExceptionCaughtEvent(self,
-                                                                   throw_location,
-                                                                   current_method,
-                                                                   catch_dex_pc,
-                                                                   exception);
-  }
-  return result;
-}
-
-
-//----------------------------------------------------------------------------
-// Object Space
-//----------------------------------------------------------------------------
-
-mirror::Object* art_portable_alloc_object_from_code(uint32_t type_idx,
-                                            mirror::AbstractMethod* referrer,
-                                            Thread* thread)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return AllocObjectFromCode(type_idx, referrer, thread, false);
-}
-
-mirror::Object* art_portable_alloc_object_from_code_with_access_check(uint32_t type_idx,
-                                                              mirror::AbstractMethod* referrer,
-                                                              Thread* thread)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return AllocObjectFromCode(type_idx, referrer, thread, true);
-}
-
-mirror::Object* art_portable_alloc_array_from_code(uint32_t type_idx,
-                                           mirror::AbstractMethod* referrer,
-                                           uint32_t length,
-                                           Thread* self)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return AllocArrayFromCode(type_idx, referrer, length, self, false);
-}
-
-mirror::Object* art_portable_alloc_array_from_code_with_access_check(uint32_t type_idx,
-                                                             mirror::AbstractMethod* referrer,
-                                                             uint32_t length,
-                                                             Thread* self)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return AllocArrayFromCode(type_idx, referrer, length, self, true);
-}
-
-mirror::Object* art_portable_check_and_alloc_array_from_code(uint32_t type_idx,
-                                                     mirror::AbstractMethod* referrer,
-                                                     uint32_t length,
-                                                     Thread* thread)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return CheckAndAllocArrayFromCode(type_idx, referrer, length, thread, false);
-}
-
-mirror::Object* art_portable_check_and_alloc_array_from_code_with_access_check(uint32_t type_idx,
-                                                                       mirror::AbstractMethod* referrer,
-                                                                       uint32_t length,
-                                                                       Thread* thread)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return CheckAndAllocArrayFromCode(type_idx, referrer, length, thread, true);
-}
-
-static mirror::AbstractMethod* FindMethodHelper(uint32_t method_idx, mirror::Object* this_object,
-                                        mirror::AbstractMethod* caller_method, bool access_check,
-                                        InvokeType type, Thread* thread)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::AbstractMethod* method = FindMethodFast(method_idx, this_object, caller_method, access_check, type);
-  if (UNLIKELY(method == NULL)) {
-    method = FindMethodFromCode(method_idx, this_object, caller_method,
-                                thread, access_check, type);
-    if (UNLIKELY(method == NULL)) {
-      CHECK(thread->IsExceptionPending());
-      return 0;  // failure
-    }
-  }
-  DCHECK(!thread->IsExceptionPending());
-  const void* code = method->GetEntryPointFromCompiledCode();
-
-  // When we return, the caller will branch to this address, so it had better not be 0!
-  if (UNLIKELY(code == NULL)) {
-      MethodHelper mh(method);
-      LOG(FATAL) << "Code was NULL in method: " << PrettyMethod(method)
-                 << " location: " << mh.GetDexFile().GetLocation();
-  }
-  return method;
-}
-
-mirror::Object* art_portable_find_static_method_from_code_with_access_check(uint32_t method_idx,
-                                                                    mirror::Object* this_object,
-                                                                    mirror::AbstractMethod* referrer,
-                                                                    Thread* thread)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return FindMethodHelper(method_idx, this_object, referrer, true, kStatic, thread);
-}
-
-mirror::Object* art_portable_find_direct_method_from_code_with_access_check(uint32_t method_idx,
-                                                                    mirror::Object* this_object,
-                                                                    mirror::AbstractMethod* referrer,
-                                                                    Thread* thread)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return FindMethodHelper(method_idx, this_object, referrer, true, kDirect, thread);
-}
-
-mirror::Object* art_portable_find_virtual_method_from_code_with_access_check(uint32_t method_idx,
-                                                                     mirror::Object* this_object,
-                                                                     mirror::AbstractMethod* referrer,
-                                                                     Thread* thread)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return FindMethodHelper(method_idx, this_object, referrer, true, kVirtual, thread);
-}
-
-mirror::Object* art_portable_find_super_method_from_code_with_access_check(uint32_t method_idx,
-                                                                   mirror::Object* this_object,
-                                                                   mirror::AbstractMethod* referrer,
-                                                                   Thread* thread)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return FindMethodHelper(method_idx, this_object, referrer, true, kSuper, thread);
-}
-
-mirror::Object*
-art_portable_find_interface_method_from_code_with_access_check(uint32_t method_idx,
-                                                       mirror::Object* this_object,
-                                                       mirror::AbstractMethod* referrer,
-                                                       Thread* thread)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return FindMethodHelper(method_idx, this_object, referrer, true, kInterface, thread);
-}
-
-mirror::Object* art_portable_find_interface_method_from_code(uint32_t method_idx,
-                                                     mirror::Object* this_object,
-                                                     mirror::AbstractMethod* referrer,
-                                                     Thread* thread)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return FindMethodHelper(method_idx, this_object, referrer, false, kInterface, thread);
-}
-
-mirror::Object* art_portable_initialize_static_storage_from_code(uint32_t type_idx,
-                                                         mirror::AbstractMethod* referrer,
-                                                         Thread* thread)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return ResolveVerifyAndClinit(type_idx, referrer, thread, true, false);
-}
-
-mirror::Object* art_portable_initialize_type_from_code(uint32_t type_idx,
-                                               mirror::AbstractMethod* referrer,
-                                               Thread* thread)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return ResolveVerifyAndClinit(type_idx, referrer, thread, false, false);
-}
-
-mirror::Object* art_portable_initialize_type_and_verify_access_from_code(uint32_t type_idx,
-                                                                 mirror::AbstractMethod* referrer,
-                                                                 Thread* thread)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  // Called when caller isn't guaranteed to have access to a type and the dex cache may be
-  // unpopulated
-  return ResolveVerifyAndClinit(type_idx, referrer, thread, false, true);
-}
-
-mirror::Object* art_portable_resolve_string_from_code(mirror::AbstractMethod* referrer, uint32_t string_idx)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return ResolveStringFromCode(referrer, string_idx);
-}
-
-int32_t art_portable_set32_static_from_code(uint32_t field_idx, mirror::AbstractMethod* referrer, int32_t new_value)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::Field* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite, sizeof(uint32_t));
-  if (LIKELY(field != NULL)) {
-    field->Set32(field->GetDeclaringClass(), new_value);
-    return 0;
-  }
-  field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            StaticPrimitiveWrite, sizeof(uint32_t), true);
-  if (LIKELY(field != NULL)) {
-    field->Set32(field->GetDeclaringClass(), new_value);
-    return 0;
-  }
-  return -1;
-}
-
-int32_t art_portable_set64_static_from_code(uint32_t field_idx, mirror::AbstractMethod* referrer, int64_t new_value)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::Field* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite, sizeof(uint64_t));
-  if (LIKELY(field != NULL)) {
-    field->Set64(field->GetDeclaringClass(), new_value);
-    return 0;
-  }
-  field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            StaticPrimitiveWrite, sizeof(uint64_t), true);
-  if (LIKELY(field != NULL)) {
-    field->Set64(field->GetDeclaringClass(), new_value);
-    return 0;
-  }
-  return -1;
-}
-
-int32_t art_portable_set_obj_static_from_code(uint32_t field_idx, mirror::AbstractMethod* referrer, mirror::Object* new_value)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::Field* field = FindFieldFast(field_idx, referrer, StaticObjectWrite, sizeof(mirror::Object*));
-  if (LIKELY(field != NULL)) {
-    field->SetObj(field->GetDeclaringClass(), new_value);
-    return 0;
-  }
-  field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            StaticObjectWrite, sizeof(mirror::Object*), true);
-  if (LIKELY(field != NULL)) {
-    field->SetObj(field->GetDeclaringClass(), new_value);
-    return 0;
-  }
-  return -1;
-}
-
-int32_t art_portable_get32_static_from_code(uint32_t field_idx, mirror::AbstractMethod* referrer)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::Field* field = FindFieldFast(field_idx, referrer, StaticPrimitiveRead, sizeof(uint32_t));
-  if (LIKELY(field != NULL)) {
-    return field->Get32(field->GetDeclaringClass());
-  }
-  field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            StaticPrimitiveRead, sizeof(uint32_t), true);
-  if (LIKELY(field != NULL)) {
-    return field->Get32(field->GetDeclaringClass());
-  }
-  return 0;
-}
-
-int64_t art_portable_get64_static_from_code(uint32_t field_idx, mirror::AbstractMethod* referrer)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::Field* field = FindFieldFast(field_idx, referrer, StaticPrimitiveRead, sizeof(uint64_t));
-  if (LIKELY(field != NULL)) {
-    return field->Get64(field->GetDeclaringClass());
-  }
-  field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            StaticPrimitiveRead, sizeof(uint64_t), true);
-  if (LIKELY(field != NULL)) {
-    return field->Get64(field->GetDeclaringClass());
-  }
-  return 0;
-}
-
-mirror::Object* art_portable_get_obj_static_from_code(uint32_t field_idx, mirror::AbstractMethod* referrer)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::Field* field = FindFieldFast(field_idx, referrer, StaticObjectRead, sizeof(mirror::Object*));
-  if (LIKELY(field != NULL)) {
-    return field->GetObj(field->GetDeclaringClass());
-  }
-  field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            StaticObjectRead, sizeof(mirror::Object*), true);
-  if (LIKELY(field != NULL)) {
-    return field->GetObj(field->GetDeclaringClass());
-  }
-  return 0;
-}
-
-int32_t art_portable_set32_instance_from_code(uint32_t field_idx, mirror::AbstractMethod* referrer,
-                                     mirror::Object* obj, uint32_t new_value)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::Field* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite, sizeof(uint32_t));
-  if (LIKELY(field != NULL)) {
-    field->Set32(obj, new_value);
-    return 0;
-  }
-  field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            InstancePrimitiveWrite, sizeof(uint32_t), true);
-  if (LIKELY(field != NULL)) {
-    field->Set32(obj, new_value);
-    return 0;
-  }
-  return -1;
-}
-
-int32_t art_portable_set64_instance_from_code(uint32_t field_idx, mirror::AbstractMethod* referrer,
-                                      mirror::Object* obj, int64_t new_value)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::Field* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite, sizeof(uint64_t));
-  if (LIKELY(field != NULL)) {
-    field->Set64(obj, new_value);
-    return 0;
-  }
-  field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            InstancePrimitiveWrite, sizeof(uint64_t), true);
-  if (LIKELY(field != NULL)) {
-    field->Set64(obj, new_value);
-    return 0;
-  }
-  return -1;
-}
-
-int32_t art_portable_set_obj_instance_from_code(uint32_t field_idx, mirror::AbstractMethod* referrer,
-                                        mirror::Object* obj, mirror::Object* new_value)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::Field* field = FindFieldFast(field_idx, referrer, InstanceObjectWrite, sizeof(mirror::Object*));
-  if (LIKELY(field != NULL)) {
-    field->SetObj(obj, new_value);
-    return 0;
-  }
-  field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            InstanceObjectWrite, sizeof(mirror::Object*), true);
-  if (LIKELY(field != NULL)) {
-    field->SetObj(obj, new_value);
-    return 0;
-  }
-  return -1;
-}
-
-int32_t art_portable_get32_instance_from_code(uint32_t field_idx, mirror::AbstractMethod* referrer, mirror::Object* obj)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::Field* field = FindFieldFast(field_idx, referrer, InstancePrimitiveRead, sizeof(uint32_t));
-  if (LIKELY(field != NULL)) {
-    return field->Get32(obj);
-  }
-  field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            InstancePrimitiveRead, sizeof(uint32_t), true);
-  if (LIKELY(field != NULL)) {
-    return field->Get32(obj);
-  }
-  return 0;
-}
-
-int64_t art_portable_get64_instance_from_code(uint32_t field_idx, mirror::AbstractMethod* referrer, mirror::Object* obj)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::Field* field = FindFieldFast(field_idx, referrer, InstancePrimitiveRead, sizeof(uint64_t));
-  if (LIKELY(field != NULL)) {
-    return field->Get64(obj);
-  }
-  field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            InstancePrimitiveRead, sizeof(uint64_t), true);
-  if (LIKELY(field != NULL)) {
-    return field->Get64(obj);
-  }
-  return 0;
-}
-
-mirror::Object* art_portable_get_obj_instance_from_code(uint32_t field_idx, mirror::AbstractMethod* referrer, mirror::Object* obj)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::Field* field = FindFieldFast(field_idx, referrer, InstanceObjectRead, sizeof(mirror::Object*));
-  if (LIKELY(field != NULL)) {
-    return field->GetObj(obj);
-  }
-  field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            InstanceObjectRead, sizeof(mirror::Object*), true);
-  if (LIKELY(field != NULL)) {
-    return field->GetObj(obj);
-  }
-  return 0;
-}
-
-void art_portable_fill_array_data_from_code(mirror::AbstractMethod* method, uint32_t dex_pc,
-                                    mirror::Array* array, uint32_t payload_offset)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  // Test: Is array equal to null? (Guard NullPointerException)
-  if (UNLIKELY(array == NULL)) {
-    art_portable_throw_null_pointer_exception_from_code(dex_pc);
-    return;
-  }
-
-  // Find the payload from the CodeItem
-  MethodHelper mh(method);
-  const DexFile::CodeItem* code_item = mh.GetCodeItem();
-
-  DCHECK_GT(code_item->insns_size_in_code_units_, payload_offset);
-
-  const Instruction::ArrayDataPayload* payload =
-    reinterpret_cast<const Instruction::ArrayDataPayload*>(
-        code_item->insns_ + payload_offset);
-
-  DCHECK_EQ(payload->ident,
-            static_cast<uint16_t>(Instruction::kArrayDataSignature));
-
-  // Test: Is array big enough?
-  uint32_t array_len = static_cast<uint32_t>(array->GetLength());
-  if (UNLIKELY(array_len < payload->element_count)) {
-    int32_t last_index = payload->element_count - 1;
-    art_portable_throw_array_bounds_from_code(array_len, last_index);
-    return;
-  }
-
-  // Copy the data
-  size_t size = payload->element_width * payload->element_count;
-  memcpy(array->GetRawData(payload->element_width), payload->data, size);
-}
-
-
-
-//----------------------------------------------------------------------------
-// Type checking, in the nature of casting
-//----------------------------------------------------------------------------
-
-int32_t art_portable_is_assignable_from_code(const mirror::Class* dest_type, const mirror::Class* src_type)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  DCHECK(dest_type != NULL);
-  DCHECK(src_type != NULL);
-  return dest_type->IsAssignableFrom(src_type) ? 1 : 0;
-}
-
-void art_portable_check_cast_from_code(const mirror::Class* dest_type, const mirror::Class* src_type)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  DCHECK(dest_type->IsClass()) << PrettyClass(dest_type);
-  DCHECK(src_type->IsClass()) << PrettyClass(src_type);
-  if (UNLIKELY(!dest_type->IsAssignableFrom(src_type))) {
-    ThrowClassCastException(dest_type, src_type);
-  }
-}
-
-void art_portable_check_put_array_element_from_code(const mirror::Object* element,
-                                                    const mirror::Object* array)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  if (element == NULL) {
-    return;
-  }
-  DCHECK(array != NULL);
-  mirror::Class* array_class = array->GetClass();
-  DCHECK(array_class != NULL);
-  mirror::Class* component_type = array_class->GetComponentType();
-  mirror::Class* element_class = element->GetClass();
-  if (UNLIKELY(!component_type->IsAssignableFrom(element_class))) {
-    ThrowArrayStoreException(element_class, array_class);
-  }
-  return;
-}
-
-//----------------------------------------------------------------------------
-// JNI
-//----------------------------------------------------------------------------
-
-// Called on entry to JNI, transition out of Runnable and release share of mutator_lock_.
-uint32_t art_portable_jni_method_start(Thread* self)
-    UNLOCK_FUNCTION(GlobalSynchronizatio::mutator_lock_) {
-  JNIEnvExt* env = self->GetJniEnv();
-  uint32_t saved_local_ref_cookie = env->local_ref_cookie;
-  env->local_ref_cookie = env->locals.GetSegmentState();
-  self->TransitionFromRunnableToSuspended(kNative);
-  return saved_local_ref_cookie;
-}
-
-uint32_t art_portable_jni_method_start_synchronized(jobject to_lock, Thread* self)
-    UNLOCK_FUNCTION(Locks::mutator_lock_) {
-  self->DecodeJObject(to_lock)->MonitorEnter(self);
-  return art_portable_jni_method_start(self);
-}
-
-static inline void PopLocalReferences(uint32_t saved_local_ref_cookie, Thread* self) {
-  JNIEnvExt* env = self->GetJniEnv();
-  env->locals.SetSegmentState(env->local_ref_cookie);
-  env->local_ref_cookie = saved_local_ref_cookie;
-}
-
-void art_portable_jni_method_end(uint32_t saved_local_ref_cookie, Thread* self)
-    SHARED_LOCK_FUNCTION(Locks::mutator_lock_) {
-  self->TransitionFromSuspendedToRunnable();
-  PopLocalReferences(saved_local_ref_cookie, self);
-}
-
-
-void art_portable_jni_method_end_synchronized(uint32_t saved_local_ref_cookie,
-                                      jobject locked,
-                                      Thread* self)
-    SHARED_LOCK_FUNCTION(Locks::mutator_lock_) {
-  self->TransitionFromSuspendedToRunnable();
-  UnlockJniSynchronizedMethod(locked, self);  // Must decode before pop.
-  PopLocalReferences(saved_local_ref_cookie, self);
-}
-
-mirror::Object* art_portable_jni_method_end_with_reference(jobject result, uint32_t saved_local_ref_cookie,
-                                                   Thread* self)
-    SHARED_LOCK_FUNCTION(Locks::mutator_lock_) {
-  self->TransitionFromSuspendedToRunnable();
-  mirror::Object* o = self->DecodeJObject(result);  // Must decode before pop.
-  PopLocalReferences(saved_local_ref_cookie, self);
-  // Process result.
-  if (UNLIKELY(self->GetJniEnv()->check_jni)) {
-    if (self->IsExceptionPending()) {
-      return NULL;
-    }
-    CheckReferenceResult(o, self);
-  }
-  return o;
-}
-
-mirror::Object* art_portable_jni_method_end_with_reference_synchronized(jobject result,
-                                                                uint32_t saved_local_ref_cookie,
-                                                                jobject locked, Thread* self)
-    SHARED_LOCK_FUNCTION(Locks::mutator_lock_) {
-  self->TransitionFromSuspendedToRunnable();
-  UnlockJniSynchronizedMethod(locked, self);  // Must decode before pop.
-  mirror::Object* o = self->DecodeJObject(result);
-  PopLocalReferences(saved_local_ref_cookie, self);
-  // Process result.
-  if (UNLIKELY(self->GetJniEnv()->check_jni)) {
-    if (self->IsExceptionPending()) {
-      return NULL;
-    }
-    CheckReferenceResult(o, self);
-  }
-  return o;
-}
-
-// Handler for invocation on proxy methods. Create a boxed argument array and invoke the invocation
-// handler which is a field within the proxy object receiver. The var args encode the arguments
-// with the last argument being a pointer to a JValue to store the result in.
-void art_portable_proxy_invoke_handler_from_code(mirror::AbstractMethod* proxy_method, ...)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  va_list ap;
-  va_start(ap, proxy_method);
-
-  mirror::Object* receiver = va_arg(ap, mirror::Object*);
-  Thread* self = va_arg(ap, Thread*);
-  MethodHelper proxy_mh(proxy_method);
-
-  // Ensure we don't get thread suspension until the object arguments are safely in jobjects.
-  const char* old_cause =
-      self->StartAssertNoThreadSuspension("Adding to IRT proxy object arguments");
-  self->VerifyStack();
-
-  // Start new JNI local reference state.
-  JNIEnvExt* env = self->GetJniEnv();
-  ScopedObjectAccessUnchecked soa(env);
-  ScopedJniEnvLocalRefState env_state(env);
-
-  // Create local ref. copies of the receiver.
-  jobject rcvr_jobj = soa.AddLocalReference<jobject>(receiver);
-
-  // Convert proxy method into expected interface method.
-  mirror::AbstractMethod* interface_method = proxy_method->FindOverriddenMethod();
-  DCHECK(interface_method != NULL);
-  DCHECK(!interface_method->IsProxyMethod()) << PrettyMethod(interface_method);
-  jobject interface_method_jobj = soa.AddLocalReference<jobject>(interface_method);
-
-  // Record arguments and turn mirror::Object* arguments into jobject to survive GC.
-  std::vector<jvalue> args;
-  const size_t num_params = proxy_mh.NumArgs();
-  for (size_t i = 1; i < num_params; ++i) {
-    jvalue val;
-    switch (proxy_mh.GetParamPrimitiveType(i)) {
-      case Primitive::kPrimNot:
-        val.l = soa.AddLocalReference<jobject>(va_arg(ap, mirror::Object*));
-        break;
-      case Primitive::kPrimBoolean:  // Fall-through.
-      case Primitive::kPrimByte:     // Fall-through.
-      case Primitive::kPrimChar:     // Fall-through.
-      case Primitive::kPrimShort:    // Fall-through.
-      case Primitive::kPrimInt:      // Fall-through.
-        val.i = va_arg(ap, jint);
-        break;
-      case Primitive::kPrimFloat:
-        // TODO: should this be jdouble? Floats aren't passed to var arg routines.
-        val.i = va_arg(ap, jint);
-        break;
-      case Primitive::kPrimDouble:
-        val.d = (va_arg(ap, jdouble));
-        break;
-      case Primitive::kPrimLong:
-        val.j = (va_arg(ap, jlong));
-        break;
-      case Primitive::kPrimVoid:
-        LOG(FATAL) << "UNREACHABLE";
-        val.j = 0;
-        break;
-    }
-    args.push_back(val);
-  }
-  self->EndAssertNoThreadSuspension(old_cause);
-  JValue* result_location = NULL;
-  const char* shorty = proxy_mh.GetShorty();
-  if (shorty[0] != 'V') {
-    result_location = va_arg(ap, JValue*);
-  }
-  va_end(ap);
-  JValue result = InvokeProxyInvocationHandler(soa, shorty, rcvr_jobj, interface_method_jobj, args);
-  if (result_location != NULL) {
-    *result_location = result;
-  }
-}
-
-//----------------------------------------------------------------------------
-// Memory barrier
-//----------------------------------------------------------------------------
-
-void art_portable_constructor_barrier() {
-  LOG(FATAL) << "Implemented by IRBuilder.";
-}
-
-}  // extern "C"
diff --git a/src/compiler/llvm/runtime_support_llvm.h b/src/compiler/llvm/runtime_support_llvm.h
deleted file mode 100644
index af99842..0000000
--- a/src/compiler/llvm/runtime_support_llvm.h
+++ /dev/null
@@ -1,30 +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_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_LLVM_H_
-#define ART_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_LLVM_H_
-
-extern "C" {
-
-//----------------------------------------------------------------------------
-// Runtime Support Function Lookup Callback
-//----------------------------------------------------------------------------
-
-void* art_portable_find_runtime_support_func(void* context, const char* name);
-
-}  // extern "C"
-
-#endif  // ART_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_LLVM_H_
diff --git a/src/compiler/llvm/runtime_support_func.h b/src/compiler/llvm/runtime_support_llvm_func.h
similarity index 95%
rename from src/compiler/llvm/runtime_support_func.h
rename to src/compiler/llvm/runtime_support_llvm_func.h
index 6dfa961..ac6f3b8 100644
--- a/src/compiler/llvm/runtime_support_func.h
+++ b/src/compiler/llvm/runtime_support_llvm_func.h
@@ -23,7 +23,7 @@
 
   enum RuntimeId {
 #define DEFINE_RUNTIME_SUPPORT_FUNC_ID(ID, NAME) ID,
-#include "runtime_support_func_list.h"
+#include "runtime_support_llvm_func_list.h"
     RUNTIME_SUPPORT_FUNC_LIST(DEFINE_RUNTIME_SUPPORT_FUNC_ID)
 #undef RUNTIME_SUPPORT_FUNC_LIST
 #undef DEFINE_RUNTIME_SUPPORT_FUNC_ID
diff --git a/src/compiler/oat_writer.cc b/src/compiler/oat_writer.cc
new file mode 100644
index 0000000..0bfa4ec
--- /dev/null
+++ b/src/compiler/oat_writer.cc
@@ -0,0 +1,906 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "oat_writer.h"
+
+#include <zlib.h>
+
+#include "base/stl_util.h"
+#include "base/unix_file/fd_file.h"
+#include "class_linker.h"
+#include "dex_file-inl.h"
+#include "gc/space/space.h"
+#include "mirror/abstract_method-inl.h"
+#include "mirror/array.h"
+#include "mirror/class_loader.h"
+#include "mirror/object-inl.h"
+#include "os.h"
+#include "output_stream.h"
+#include "safe_map.h"
+#include "scoped_thread_state_change.h"
+#include "verifier/method_verifier.h"
+
+namespace art {
+
+bool OatWriter::Create(OutputStream& output_stream,
+                       const std::vector<const DexFile*>& dex_files,
+                       uint32_t image_file_location_oat_checksum,
+                       uint32_t image_file_location_oat_begin,
+                       const std::string& image_file_location,
+                       const CompilerDriver& driver) {
+  OatWriter oat_writer(dex_files,
+                       image_file_location_oat_checksum,
+                       image_file_location_oat_begin,
+                       image_file_location,
+                       &driver);
+  return oat_writer.Write(output_stream);
+}
+
+OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files,
+                     uint32_t image_file_location_oat_checksum,
+                     uint32_t image_file_location_oat_begin,
+                     const std::string& image_file_location,
+                     const CompilerDriver* compiler)
+  : compiler_driver_(compiler),
+    dex_files_(&dex_files),
+    image_file_location_oat_checksum_(image_file_location_oat_checksum),
+    image_file_location_oat_begin_(image_file_location_oat_begin),
+    image_file_location_(image_file_location),
+    oat_header_(NULL),
+    size_dex_file_alignment_(0),
+    size_executable_offset_alignment_(0),
+    size_oat_header_(0),
+    size_oat_header_image_file_location_(0),
+    size_dex_file_(0),
+    size_interpreter_to_interpreter_entry_(0),
+    size_interpreter_to_quick_entry_(0),
+    size_portable_resolution_trampoline_(0),
+    size_quick_resolution_trampoline_(0),
+    size_stubs_alignment_(0),
+    size_code_size_(0),
+    size_code_(0),
+    size_code_alignment_(0),
+    size_mapping_table_(0),
+    size_vmap_table_(0),
+    size_gc_map_(0),
+    size_oat_dex_file_location_size_(0),
+    size_oat_dex_file_location_data_(0),
+    size_oat_dex_file_location_checksum_(0),
+    size_oat_dex_file_offset_(0),
+    size_oat_dex_file_methods_offsets_(0),
+    size_oat_class_status_(0),
+    size_oat_class_method_offsets_(0) {
+
+  size_t offset = InitOatHeader();
+  offset = InitOatDexFiles(offset);
+  offset = InitDexFiles(offset);
+  offset = InitOatClasses(offset);
+  offset = InitOatCode(offset);
+  offset = InitOatCodeDexFiles(offset);
+
+  CHECK_EQ(dex_files_->size(), oat_dex_files_.size());
+  CHECK(image_file_location.empty() == compiler->IsImage());
+}
+
+OatWriter::~OatWriter() {
+  delete oat_header_;
+  STLDeleteElements(&oat_dex_files_);
+  STLDeleteElements(&oat_classes_);
+}
+
+size_t OatWriter::InitOatHeader() {
+  // create the OatHeader
+  oat_header_ = new OatHeader(compiler_driver_->GetInstructionSet(),
+                              dex_files_,
+                              image_file_location_oat_checksum_,
+                              image_file_location_oat_begin_,
+                              image_file_location_);
+  size_t offset = sizeof(*oat_header_);
+  offset += image_file_location_.size();
+  return offset;
+}
+
+size_t OatWriter::InitOatDexFiles(size_t offset) {
+  // create the OatDexFiles
+  for (size_t i = 0; i != dex_files_->size(); ++i) {
+    const DexFile* dex_file = (*dex_files_)[i];
+    CHECK(dex_file != NULL);
+    OatDexFile* oat_dex_file = new OatDexFile(offset, *dex_file);
+    oat_dex_files_.push_back(oat_dex_file);
+    offset += oat_dex_file->SizeOf();
+  }
+  return offset;
+}
+
+size_t OatWriter::InitDexFiles(size_t offset) {
+  // calculate the offsets within OatDexFiles to the DexFiles
+  for (size_t i = 0; i != dex_files_->size(); ++i) {
+    // dex files are required to be 4 byte aligned
+    size_t original_offset = offset;
+    offset = RoundUp(offset, 4);
+    size_dex_file_alignment_ += offset - original_offset;
+
+    // set offset in OatDexFile to DexFile
+    oat_dex_files_[i]->dex_file_offset_ = offset;
+
+    const DexFile* dex_file = (*dex_files_)[i];
+    offset += dex_file->GetHeader().file_size_;
+  }
+  return offset;
+}
+
+size_t OatWriter::InitOatClasses(size_t offset) {
+  // create the OatClasses
+  // calculate the offsets within OatDexFiles to OatClasses
+  for (size_t i = 0; i != dex_files_->size(); ++i) {
+    const DexFile* dex_file = (*dex_files_)[i];
+    for (size_t class_def_index = 0;
+         class_def_index < dex_file->NumClassDefs();
+         class_def_index++) {
+      oat_dex_files_[i]->methods_offsets_[class_def_index] = offset;
+      const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
+      const byte* class_data = dex_file->GetClassData(class_def);
+      uint32_t num_methods = 0;
+      if (class_data != NULL) {  // ie not an empty class, such as a marker interface
+        ClassDataItemIterator it(*dex_file, class_data);
+        size_t num_direct_methods = it.NumDirectMethods();
+        size_t num_virtual_methods = it.NumVirtualMethods();
+        num_methods = num_direct_methods + num_virtual_methods;
+      }
+
+      ClassReference class_ref(dex_file, class_def_index);
+      CompiledClass* compiled_class = compiler_driver_->GetCompiledClass(class_ref);
+      mirror::Class::Status status;
+      if (compiled_class != NULL) {
+        status = compiled_class->GetStatus();
+      } else if (verifier::MethodVerifier::IsClassRejected(class_ref)) {
+        status = mirror::Class::kStatusError;
+      } else {
+        status = mirror::Class::kStatusNotReady;
+      }
+
+      OatClass* oat_class = new OatClass(offset, status, num_methods);
+      oat_classes_.push_back(oat_class);
+      offset += oat_class->SizeOf();
+    }
+    oat_dex_files_[i]->UpdateChecksum(*oat_header_);
+  }
+  return offset;
+}
+
+size_t OatWriter::InitOatCode(size_t offset) {
+  // calculate the offsets within OatHeader to executable code
+  size_t old_offset = offset;
+  // required to be on a new page boundary
+  offset = RoundUp(offset, kPageSize);
+  oat_header_->SetExecutableOffset(offset);
+  size_executable_offset_alignment_ = offset - old_offset;
+  if (compiler_driver_->IsImage()) {
+    InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
+    oat_header_->SetInterpreterToInterpreterEntryOffset(offset);
+    interpreter_to_interpreter_entry_.reset(compiler_driver_->CreateInterpreterToInterpreterEntry());
+    offset += interpreter_to_interpreter_entry_->size();
+
+    offset = CompiledCode::AlignCode(offset, instruction_set);
+    oat_header_->SetInterpreterToQuickEntryOffset(offset);
+    interpreter_to_quick_entry_.reset(compiler_driver_->CreateInterpreterToQuickEntry());
+    offset += interpreter_to_quick_entry_->size();
+
+    offset = CompiledCode::AlignCode(offset, instruction_set);
+    oat_header_->SetPortableResolutionTrampolineOffset(offset);
+    portable_resolution_trampoline_.reset(compiler_driver_->CreatePortableResolutionTrampoline());
+    offset += portable_resolution_trampoline_->size();
+
+    offset = CompiledCode::AlignCode(offset, instruction_set);
+    oat_header_->SetQuickResolutionTrampolineOffset(offset);
+    quick_resolution_trampoline_.reset(compiler_driver_->CreateQuickResolutionTrampoline());
+    offset += quick_resolution_trampoline_->size();
+  } else {
+    oat_header_->SetInterpreterToInterpreterEntryOffset(0);
+    oat_header_->SetInterpreterToQuickEntryOffset(0);
+    oat_header_->SetPortableResolutionTrampolineOffset(0);
+    oat_header_->SetQuickResolutionTrampolineOffset(0);
+  }
+  return offset;
+}
+
+size_t OatWriter::InitOatCodeDexFiles(size_t offset) {
+  size_t oat_class_index = 0;
+  for (size_t i = 0; i != dex_files_->size(); ++i) {
+    const DexFile* dex_file = (*dex_files_)[i];
+    CHECK(dex_file != NULL);
+    offset = InitOatCodeDexFile(offset, oat_class_index, *dex_file);
+  }
+  return offset;
+}
+
+size_t OatWriter::InitOatCodeDexFile(size_t offset,
+                                     size_t& oat_class_index,
+                                     const DexFile& dex_file) {
+  for (size_t class_def_index = 0;
+       class_def_index < dex_file.NumClassDefs();
+       class_def_index++, oat_class_index++) {
+    const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
+    offset = InitOatCodeClassDef(offset, oat_class_index, class_def_index, dex_file, class_def);
+    oat_classes_[oat_class_index]->UpdateChecksum(*oat_header_);
+  }
+  return offset;
+}
+
+size_t OatWriter::InitOatCodeClassDef(size_t offset,
+                                      size_t oat_class_index, size_t class_def_index,
+                                      const DexFile& dex_file,
+                                      const DexFile::ClassDef& class_def) {
+  const byte* class_data = dex_file.GetClassData(class_def);
+  if (class_data == NULL) {
+    // empty class, such as a marker interface
+    return offset;
+  }
+  ClassDataItemIterator it(dex_file, class_data);
+  CHECK_EQ(oat_classes_[oat_class_index]->method_offsets_.size(),
+           it.NumDirectMethods() + it.NumVirtualMethods());
+  // Skip fields
+  while (it.HasNextStaticField()) {
+    it.Next();
+  }
+  while (it.HasNextInstanceField()) {
+    it.Next();
+  }
+  // Process methods
+  size_t class_def_method_index = 0;
+  while (it.HasNextDirectMethod()) {
+    bool is_native = (it.GetMemberAccessFlags() & kAccNative) != 0;
+    offset = InitOatCodeMethod(offset, oat_class_index, class_def_index, class_def_method_index,
+                               is_native, it.GetMethodInvokeType(class_def), it.GetMemberIndex(),
+                               &dex_file);
+    class_def_method_index++;
+    it.Next();
+  }
+  while (it.HasNextVirtualMethod()) {
+    bool is_native = (it.GetMemberAccessFlags() & kAccNative) != 0;
+    offset = InitOatCodeMethod(offset, oat_class_index, class_def_index, class_def_method_index,
+                               is_native, it.GetMethodInvokeType(class_def), it.GetMemberIndex(),
+                               &dex_file);
+    class_def_method_index++;
+    it.Next();
+  }
+  DCHECK(!it.HasNext());
+  return offset;
+}
+
+size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index,
+                                    size_t __attribute__((unused)) class_def_index,
+                                    size_t class_def_method_index,
+                                    bool __attribute__((unused)) is_native,
+                                    InvokeType invoke_type,
+                                    uint32_t method_idx, const DexFile* dex_file) {
+  // derived from CompiledMethod if available
+  uint32_t code_offset = 0;
+  uint32_t frame_size_in_bytes = kStackAlignment;
+  uint32_t core_spill_mask = 0;
+  uint32_t fp_spill_mask = 0;
+  uint32_t mapping_table_offset = 0;
+  uint32_t vmap_table_offset = 0;
+  uint32_t gc_map_offset = 0;
+
+  OatClass* oat_class = oat_classes_[oat_class_index];
+#if defined(ART_USE_PORTABLE_COMPILER)
+  size_t oat_method_offsets_offset =
+      oat_class->GetOatMethodOffsetsOffsetFromOatHeader(class_def_method_index);
+#endif
+
+  CompiledMethod* compiled_method =
+      compiler_driver_->GetCompiledMethod(MethodReference(dex_file, method_idx));
+  if (compiled_method != NULL) {
+#if defined(ART_USE_PORTABLE_COMPILER)
+    compiled_method->AddOatdataOffsetToCompliledCodeOffset(
+        oat_method_offsets_offset + OFFSETOF_MEMBER(OatMethodOffsets, code_offset_));
+#else
+    const std::vector<uint8_t>& code = compiled_method->GetCode();
+    offset = compiled_method->AlignCode(offset);
+    DCHECK_ALIGNED(offset, kArmAlignment);
+    uint32_t code_size = code.size() * sizeof(code[0]);
+    CHECK_NE(code_size, 0U);
+    uint32_t thumb_offset = compiled_method->CodeDelta();
+    code_offset = offset + sizeof(code_size) + thumb_offset;
+
+    // Deduplicate code arrays
+    SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator code_iter = code_offsets_.find(&code);
+    if (code_iter != code_offsets_.end()) {
+      code_offset = code_iter->second;
+    } else {
+      code_offsets_.Put(&code, code_offset);
+      offset += sizeof(code_size);  // code size is prepended before code
+      offset += code_size;
+      oat_header_->UpdateChecksum(&code[0], code_size);
+    }
+#endif
+    frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
+    core_spill_mask = compiled_method->GetCoreSpillMask();
+    fp_spill_mask = compiled_method->GetFpSpillMask();
+
+    const std::vector<uint32_t>& mapping_table = compiled_method->GetMappingTable();
+    size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]);
+    mapping_table_offset = (mapping_table_size == 0) ? 0 : offset;
+
+    // Deduplicate mapping tables
+    SafeMap<const std::vector<uint32_t>*, uint32_t>::iterator mapping_iter = mapping_table_offsets_.find(&mapping_table);
+    if (mapping_iter != mapping_table_offsets_.end()) {
+      mapping_table_offset = mapping_iter->second;
+    } else {
+      mapping_table_offsets_.Put(&mapping_table, mapping_table_offset);
+      offset += mapping_table_size;
+      oat_header_->UpdateChecksum(&mapping_table[0], mapping_table_size);
+    }
+
+    const std::vector<uint16_t>& vmap_table = compiled_method->GetVmapTable();
+    size_t vmap_table_size = vmap_table.size() * sizeof(vmap_table[0]);
+    vmap_table_offset = (vmap_table_size == 0) ? 0 : offset;
+
+    // Deduplicate vmap tables
+    SafeMap<const std::vector<uint16_t>*, uint32_t>::iterator vmap_iter = vmap_table_offsets_.find(&vmap_table);
+    if (vmap_iter != vmap_table_offsets_.end()) {
+      vmap_table_offset = vmap_iter->second;
+    } else {
+      vmap_table_offsets_.Put(&vmap_table, vmap_table_offset);
+      offset += vmap_table_size;
+      oat_header_->UpdateChecksum(&vmap_table[0], vmap_table_size);
+    }
+
+    const std::vector<uint8_t>& gc_map = compiled_method->GetGcMap();
+    size_t gc_map_size = gc_map.size() * sizeof(gc_map[0]);
+    gc_map_offset = (gc_map_size == 0) ? 0 : offset;
+
+#if !defined(NDEBUG)
+    // We expect GC maps except when the class hasn't been verified or the method is native
+    ClassReference class_ref(dex_file, class_def_index);
+    CompiledClass* compiled_class = compiler_driver_->GetCompiledClass(class_ref);
+    mirror::Class::Status status;
+    if (compiled_class != NULL) {
+      status = compiled_class->GetStatus();
+    } else if (verifier::MethodVerifier::IsClassRejected(class_ref)) {
+      status = mirror::Class::kStatusError;
+    } else {
+      status = mirror::Class::kStatusNotReady;
+    }
+    CHECK(gc_map_size != 0 || is_native || status < mirror::Class::kStatusVerified)
+        << &gc_map << " " << gc_map_size << " " << (is_native ? "true" : "false") << " "
+        << (status < mirror::Class::kStatusVerified) << " " << status << " "
+        << PrettyMethod(method_idx, *dex_file);
+#endif
+
+    // Deduplicate GC maps
+    SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator gc_map_iter = gc_map_offsets_.find(&gc_map);
+    if (gc_map_iter != gc_map_offsets_.end()) {
+      gc_map_offset = gc_map_iter->second;
+    } else {
+      gc_map_offsets_.Put(&gc_map, gc_map_offset);
+      offset += gc_map_size;
+      oat_header_->UpdateChecksum(&gc_map[0], gc_map_size);
+    }
+  }
+
+  oat_class->method_offsets_[class_def_method_index]
+      = OatMethodOffsets(code_offset,
+                         frame_size_in_bytes,
+                         core_spill_mask,
+                         fp_spill_mask,
+                         mapping_table_offset,
+                         vmap_table_offset,
+                         gc_map_offset
+                         );
+
+  if (compiler_driver_->IsImage()) {
+    ClassLinker* linker = Runtime::Current()->GetClassLinker();
+    mirror::DexCache* dex_cache = linker->FindDexCache(*dex_file);
+    // Unchecked as we hold mutator_lock_ on entry.
+    ScopedObjectAccessUnchecked soa(Thread::Current());
+    mirror::AbstractMethod* method = linker->ResolveMethod(*dex_file, method_idx, dex_cache,
+                                                           NULL, NULL, invoke_type);
+    CHECK(method != NULL);
+    method->SetFrameSizeInBytes(frame_size_in_bytes);
+    method->SetCoreSpillMask(core_spill_mask);
+    method->SetFpSpillMask(fp_spill_mask);
+    method->SetOatMappingTableOffset(mapping_table_offset);
+    // Don't overwrite static method trampoline
+    if (!method->IsStatic() || method->IsConstructor() ||
+        method->GetDeclaringClass()->IsInitialized()) {
+      method->SetOatCodeOffset(code_offset);
+    } else {
+      method->SetEntryPointFromCompiledCode(NULL);
+    }
+    method->SetOatVmapTableOffset(vmap_table_offset);
+    method->SetOatNativeGcMapOffset(gc_map_offset);
+  }
+
+  return offset;
+}
+
+#define DCHECK_OFFSET() \
+  DCHECK_EQ(static_cast<off_t>(offset), out.Seek(0, kSeekCurrent))
+
+#define DCHECK_OFFSET_() \
+  DCHECK_EQ(static_cast<off_t>(offset_), out.Seek(0, kSeekCurrent))
+
+bool OatWriter::Write(OutputStream& out) {
+  if (!out.WriteFully(oat_header_, sizeof(*oat_header_))) {
+    PLOG(ERROR) << "Failed to write oat header to " << out.GetLocation();
+    return false;
+  }
+  size_oat_header_ += sizeof(*oat_header_);
+
+  if (!out.WriteFully(image_file_location_.data(), image_file_location_.size())) {
+    PLOG(ERROR) << "Failed to write oat header image file location to " << out.GetLocation();
+    return false;
+  }
+  size_oat_header_image_file_location_ += image_file_location_.size();
+
+  if (!WriteTables(out)) {
+    LOG(ERROR) << "Failed to write oat tables to " << out.GetLocation();
+    return false;
+  }
+
+  size_t code_offset = WriteCode(out);
+  if (code_offset == 0) {
+    LOG(ERROR) << "Failed to write oat code to " << out.GetLocation();
+    return false;
+  }
+
+  code_offset = WriteCodeDexFiles(out, code_offset);
+  if (code_offset == 0) {
+    LOG(ERROR) << "Failed to write oat code for dex files to " << out.GetLocation();
+    return false;
+  }
+
+  if (kIsDebugBuild) {
+    uint32_t size_total = 0;
+    #define DO_STAT(x) \
+      LOG(INFO) << #x "=" << PrettySize(x) << " (" << x << "B)"; \
+      size_total += x;
+
+    DO_STAT(size_dex_file_alignment_);
+    DO_STAT(size_executable_offset_alignment_);
+    DO_STAT(size_oat_header_);
+    DO_STAT(size_oat_header_image_file_location_);
+    DO_STAT(size_dex_file_);
+    DO_STAT(size_interpreter_to_interpreter_entry_);
+    DO_STAT(size_interpreter_to_quick_entry_);
+    DO_STAT(size_portable_resolution_trampoline_);
+    DO_STAT(size_quick_resolution_trampoline_);
+    DO_STAT(size_stubs_alignment_);
+    DO_STAT(size_code_size_);
+    DO_STAT(size_code_);
+    DO_STAT(size_code_alignment_);
+    DO_STAT(size_mapping_table_);
+    DO_STAT(size_vmap_table_);
+    DO_STAT(size_gc_map_);
+    DO_STAT(size_oat_dex_file_location_size_);
+    DO_STAT(size_oat_dex_file_location_data_);
+    DO_STAT(size_oat_dex_file_location_checksum_);
+    DO_STAT(size_oat_dex_file_offset_);
+    DO_STAT(size_oat_dex_file_methods_offsets_);
+    DO_STAT(size_oat_class_status_);
+    DO_STAT(size_oat_class_method_offsets_);
+    #undef DO_STAT
+
+    LOG(INFO) << "size_total=" << PrettySize(size_total) << " (" << size_total << "B)"; \
+    CHECK_EQ(size_total, static_cast<uint32_t>(out.Seek(0, kSeekCurrent)));
+  }
+
+  return true;
+}
+
+bool OatWriter::WriteTables(OutputStream& out) {
+  for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
+    if (!oat_dex_files_[i]->Write(this, out)) {
+      PLOG(ERROR) << "Failed to write oat dex information to " << out.GetLocation();
+      return false;
+    }
+  }
+  for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
+    uint32_t expected_offset = oat_dex_files_[i]->dex_file_offset_;
+    off_t actual_offset = out.Seek(expected_offset, kSeekSet);
+    if (static_cast<uint32_t>(actual_offset) != expected_offset) {
+      const DexFile* dex_file = (*dex_files_)[i];
+      PLOG(ERROR) << "Failed to seek to dex file section. Actual: " << actual_offset
+                  << " Expected: " << expected_offset << " File: " << dex_file->GetLocation();
+      return false;
+    }
+    const DexFile* dex_file = (*dex_files_)[i];
+    if (!out.WriteFully(&dex_file->GetHeader(), dex_file->GetHeader().file_size_)) {
+      PLOG(ERROR) << "Failed to write dex file " << dex_file->GetLocation() << " to " << out.GetLocation();
+      return false;
+    }
+    size_dex_file_ += dex_file->GetHeader().file_size_;
+  }
+  for (size_t i = 0; i != oat_classes_.size(); ++i) {
+    if (!oat_classes_[i]->Write(this, out)) {
+      PLOG(ERROR) << "Failed to write oat methods information to " << out.GetLocation();
+      return false;
+    }
+  }
+  return true;
+}
+
+size_t OatWriter::WriteCode(OutputStream& out) {
+  uint32_t offset = oat_header_->GetExecutableOffset();
+  off_t new_offset = out.Seek(size_executable_offset_alignment_, kSeekCurrent);
+  if (static_cast<uint32_t>(new_offset) != offset) {
+    PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
+                << " Expected: " << offset << " File: " << out.GetLocation();
+    return 0;
+  }
+  DCHECK_OFFSET();
+  if (compiler_driver_->IsImage()) {
+    InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
+    if (!out.WriteFully(&(*interpreter_to_interpreter_entry_)[0], interpreter_to_interpreter_entry_->size())) {
+      PLOG(ERROR) << "Failed to write interpreter to interpreter entry to " << out.GetLocation();
+      return false;
+    }
+    size_interpreter_to_interpreter_entry_ += interpreter_to_interpreter_entry_->size();
+    offset += interpreter_to_interpreter_entry_->size();
+    DCHECK_OFFSET();
+
+    uint32_t aligned_offset = CompiledCode::AlignCode(offset, instruction_set);
+    uint32_t alignment_padding = aligned_offset - offset;
+    out.Seek(alignment_padding, kSeekCurrent);
+    size_stubs_alignment_ += alignment_padding;
+    if (!out.WriteFully(&(*interpreter_to_quick_entry_)[0], interpreter_to_quick_entry_->size())) {
+      PLOG(ERROR) << "Failed to write interpreter to quick entry to " << out.GetLocation();
+      return false;
+    }
+    size_interpreter_to_quick_entry_ += interpreter_to_quick_entry_->size();
+    offset += alignment_padding + interpreter_to_quick_entry_->size();
+    DCHECK_OFFSET();
+
+    aligned_offset = CompiledCode::AlignCode(offset, instruction_set);
+    alignment_padding = aligned_offset - offset;
+    out.Seek(alignment_padding, kSeekCurrent);
+    size_stubs_alignment_ += alignment_padding;
+    if (!out.WriteFully(&(*portable_resolution_trampoline_)[0], portable_resolution_trampoline_->size())) {
+      PLOG(ERROR) << "Failed to write portable resolution trampoline to " << out.GetLocation();
+      return false;
+    }
+    size_portable_resolution_trampoline_ += portable_resolution_trampoline_->size();
+    offset += alignment_padding + portable_resolution_trampoline_->size();
+    DCHECK_OFFSET();
+
+    aligned_offset = CompiledCode::AlignCode(offset, instruction_set);
+    alignment_padding = aligned_offset - offset;
+    out.Seek(alignment_padding, kSeekCurrent);
+    size_stubs_alignment_ += alignment_padding;
+    if (!out.WriteFully(&(*quick_resolution_trampoline_)[0], quick_resolution_trampoline_->size())) {
+      PLOG(ERROR) << "Failed to write quick resolution trampoline to " << out.GetLocation();
+      return false;
+    }
+    size_quick_resolution_trampoline_ += quick_resolution_trampoline_->size();
+    offset += alignment_padding + quick_resolution_trampoline_->size();
+    DCHECK_OFFSET();
+  }
+  return offset;
+}
+
+size_t OatWriter::WriteCodeDexFiles(OutputStream& out, size_t code_offset) {
+  size_t oat_class_index = 0;
+  for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
+    const DexFile* dex_file = (*dex_files_)[i];
+    CHECK(dex_file != NULL);
+    code_offset = WriteCodeDexFile(out, code_offset, oat_class_index, *dex_file);
+    if (code_offset == 0) {
+      return 0;
+    }
+  }
+  return code_offset;
+}
+
+size_t OatWriter::WriteCodeDexFile(OutputStream& out, size_t code_offset, size_t& oat_class_index,
+                                   const DexFile& dex_file) {
+  for (size_t class_def_index = 0; class_def_index < dex_file.NumClassDefs();
+      class_def_index++, oat_class_index++) {
+    const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
+    code_offset = WriteCodeClassDef(out, code_offset, oat_class_index, dex_file, class_def);
+    if (code_offset == 0) {
+      return 0;
+    }
+  }
+  return code_offset;
+}
+
+void OatWriter::ReportWriteFailure(const char* what, uint32_t method_idx,
+                                   const DexFile& dex_file, OutputStream& out) const {
+  PLOG(ERROR) << "Failed to write " << what << " for " << PrettyMethod(method_idx, dex_file)
+      << " to " << out.GetLocation();
+}
+
+size_t OatWriter::WriteCodeClassDef(OutputStream& out,
+                                    size_t code_offset, size_t oat_class_index,
+                                    const DexFile& dex_file,
+                                    const DexFile::ClassDef& class_def) {
+  const byte* class_data = dex_file.GetClassData(class_def);
+  if (class_data == NULL) {
+    // ie. an empty class such as a marker interface
+    return code_offset;
+  }
+  ClassDataItemIterator it(dex_file, class_data);
+  // Skip fields
+  while (it.HasNextStaticField()) {
+    it.Next();
+  }
+  while (it.HasNextInstanceField()) {
+    it.Next();
+  }
+  // Process methods
+  size_t class_def_method_index = 0;
+  while (it.HasNextDirectMethod()) {
+    bool is_static = (it.GetMemberAccessFlags() & kAccStatic) != 0;
+    code_offset = WriteCodeMethod(out, code_offset, oat_class_index, class_def_method_index,
+                                  is_static, it.GetMemberIndex(), dex_file);
+    if (code_offset == 0) {
+      return 0;
+    }
+    class_def_method_index++;
+    it.Next();
+  }
+  while (it.HasNextVirtualMethod()) {
+    code_offset = WriteCodeMethod(out, code_offset, oat_class_index, class_def_method_index,
+                                  false, it.GetMemberIndex(), dex_file);
+    if (code_offset == 0) {
+      return 0;
+    }
+    class_def_method_index++;
+    it.Next();
+  }
+  return code_offset;
+}
+
+size_t OatWriter::WriteCodeMethod(OutputStream& out, size_t offset, size_t oat_class_index,
+                                  size_t class_def_method_index, bool is_static,
+                                  uint32_t method_idx, const DexFile& dex_file) {
+  const CompiledMethod* compiled_method =
+      compiler_driver_->GetCompiledMethod(MethodReference(&dex_file, method_idx));
+
+  OatMethodOffsets method_offsets =
+      oat_classes_[oat_class_index]->method_offsets_[class_def_method_index];
+
+
+  if (compiled_method != NULL) {  // ie. not an abstract method
+#if !defined(ART_USE_PORTABLE_COMPILER)
+    uint32_t aligned_offset = compiled_method->AlignCode(offset);
+    uint32_t aligned_code_delta = aligned_offset - offset;
+    if (aligned_code_delta != 0) {
+      off_t new_offset = out.Seek(aligned_code_delta, kSeekCurrent);
+      size_code_alignment_ += aligned_code_delta;
+      if (static_cast<uint32_t>(new_offset) != aligned_offset) {
+        PLOG(ERROR) << "Failed to seek to align oat code. Actual: " << new_offset
+                    << " Expected: " << aligned_offset << " File: " << out.GetLocation();
+        return 0;
+      }
+      offset += aligned_code_delta;
+      DCHECK_OFFSET();
+    }
+    DCHECK_ALIGNED(offset, kArmAlignment);
+    const std::vector<uint8_t>& code = compiled_method->GetCode();
+    uint32_t code_size = code.size() * sizeof(code[0]);
+    CHECK_NE(code_size, 0U);
+
+    // Deduplicate code arrays
+    size_t code_offset = offset + sizeof(code_size) + compiled_method->CodeDelta();
+    SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator code_iter = code_offsets_.find(&code);
+    if (code_iter != code_offsets_.end() && code_offset != method_offsets.code_offset_) {
+      DCHECK(code_iter->second == method_offsets.code_offset_)
+          << PrettyMethod(method_idx, dex_file);
+    } else {
+      DCHECK(code_offset == method_offsets.code_offset_) << PrettyMethod(method_idx, dex_file);
+      if (!out.WriteFully(&code_size, sizeof(code_size))) {
+        ReportWriteFailure("method code size", method_idx, dex_file, out);
+        return 0;
+      }
+      size_code_size_ += sizeof(code_size);
+      offset += sizeof(code_size);
+      DCHECK_OFFSET();
+      if (!out.WriteFully(&code[0], code_size)) {
+        ReportWriteFailure("method code", method_idx, dex_file, out);
+        return 0;
+      }
+      size_code_ += code_size;
+      offset += code_size;
+    }
+    DCHECK_OFFSET();
+#endif
+
+    const std::vector<uint32_t>& mapping_table = compiled_method->GetMappingTable();
+    size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]);
+
+    // Deduplicate mapping tables
+    SafeMap<const std::vector<uint32_t>*, uint32_t>::iterator mapping_iter =
+        mapping_table_offsets_.find(&mapping_table);
+    if (mapping_iter != mapping_table_offsets_.end() &&
+        offset != method_offsets.mapping_table_offset_) {
+      DCHECK((mapping_table_size == 0 && method_offsets.mapping_table_offset_ == 0)
+          || mapping_iter->second == method_offsets.mapping_table_offset_)
+          << PrettyMethod(method_idx, dex_file);
+    } else {
+      DCHECK((mapping_table_size == 0 && method_offsets.mapping_table_offset_ == 0)
+          || offset == method_offsets.mapping_table_offset_)
+          << PrettyMethod(method_idx, dex_file);
+      if (!out.WriteFully(&mapping_table[0], mapping_table_size)) {
+        ReportWriteFailure("mapping table", method_idx, dex_file, out);
+        return 0;
+      }
+      size_mapping_table_ += mapping_table_size;
+      offset += mapping_table_size;
+    }
+    DCHECK_OFFSET();
+
+    const std::vector<uint16_t>& vmap_table = compiled_method->GetVmapTable();
+    size_t vmap_table_size = vmap_table.size() * sizeof(vmap_table[0]);
+
+    // Deduplicate vmap tables
+    SafeMap<const std::vector<uint16_t>*, uint32_t>::iterator vmap_iter =
+        vmap_table_offsets_.find(&vmap_table);
+    if (vmap_iter != vmap_table_offsets_.end() &&
+        offset != method_offsets.vmap_table_offset_) {
+      DCHECK((vmap_table_size == 0 && method_offsets.vmap_table_offset_ == 0)
+          || vmap_iter->second == method_offsets.vmap_table_offset_)
+          << PrettyMethod(method_idx, dex_file);
+    } else {
+      DCHECK((vmap_table_size == 0 && method_offsets.vmap_table_offset_ == 0)
+          || offset == method_offsets.vmap_table_offset_)
+          << PrettyMethod(method_idx, dex_file);
+      if (!out.WriteFully(&vmap_table[0], vmap_table_size)) {
+        ReportWriteFailure("vmap table", method_idx, dex_file, out);
+        return 0;
+      }
+      size_vmap_table_ += vmap_table_size;
+      offset += vmap_table_size;
+    }
+    DCHECK_OFFSET();
+
+    const std::vector<uint8_t>& gc_map = compiled_method->GetGcMap();
+    size_t gc_map_size = gc_map.size() * sizeof(gc_map[0]);
+
+    // Deduplicate GC maps
+    SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator gc_map_iter =
+        gc_map_offsets_.find(&gc_map);
+    if (gc_map_iter != gc_map_offsets_.end() &&
+        offset != method_offsets.gc_map_offset_) {
+      DCHECK((gc_map_size == 0 && method_offsets.gc_map_offset_ == 0)
+          || gc_map_iter->second == method_offsets.gc_map_offset_)
+          << PrettyMethod(method_idx, dex_file);
+    } else {
+      DCHECK((gc_map_size == 0 && method_offsets.gc_map_offset_ == 0)
+          || offset == method_offsets.gc_map_offset_)
+          << PrettyMethod(method_idx, dex_file);
+      if (!out.WriteFully(&gc_map[0], gc_map_size)) {
+        ReportWriteFailure("GC map", method_idx, dex_file, out);
+        return 0;
+      }
+      size_gc_map_ += gc_map_size;
+      offset += gc_map_size;
+    }
+    DCHECK_OFFSET();
+  }
+
+  return offset;
+}
+
+OatWriter::OatDexFile::OatDexFile(size_t offset, const DexFile& dex_file) {
+  offset_ = offset;
+  const std::string& location(dex_file.GetLocation());
+  dex_file_location_size_ = location.size();
+  dex_file_location_data_ = reinterpret_cast<const uint8_t*>(location.data());
+  dex_file_location_checksum_ = dex_file.GetLocationChecksum();
+  dex_file_offset_ = 0;
+  methods_offsets_.resize(dex_file.NumClassDefs());
+}
+
+size_t OatWriter::OatDexFile::SizeOf() const {
+  return sizeof(dex_file_location_size_)
+          + dex_file_location_size_
+          + sizeof(dex_file_location_checksum_)
+          + sizeof(dex_file_offset_)
+          + (sizeof(methods_offsets_[0]) * methods_offsets_.size());
+}
+
+void OatWriter::OatDexFile::UpdateChecksum(OatHeader& oat_header) const {
+  oat_header.UpdateChecksum(&dex_file_location_size_, sizeof(dex_file_location_size_));
+  oat_header.UpdateChecksum(dex_file_location_data_, dex_file_location_size_);
+  oat_header.UpdateChecksum(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_));
+  oat_header.UpdateChecksum(&dex_file_offset_, sizeof(dex_file_offset_));
+  oat_header.UpdateChecksum(&methods_offsets_[0],
+                            sizeof(methods_offsets_[0]) * methods_offsets_.size());
+}
+
+bool OatWriter::OatDexFile::Write(OatWriter* oat_writer, OutputStream& out) const {
+  DCHECK_OFFSET_();
+  if (!out.WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
+    PLOG(ERROR) << "Failed to write dex file location length to " << out.GetLocation();
+    return false;
+  }
+  oat_writer->size_oat_dex_file_location_size_ += sizeof(dex_file_location_size_);
+  if (!out.WriteFully(dex_file_location_data_, dex_file_location_size_)) {
+    PLOG(ERROR) << "Failed to write dex file location data to " << out.GetLocation();
+    return false;
+  }
+  oat_writer->size_oat_dex_file_location_data_ += dex_file_location_size_;
+  if (!out.WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) {
+    PLOG(ERROR) << "Failed to write dex file location checksum to " << out.GetLocation();
+    return false;
+  }
+  oat_writer->size_oat_dex_file_location_checksum_ += sizeof(dex_file_location_checksum_);
+  if (!out.WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) {
+    PLOG(ERROR) << "Failed to write dex file offset to " << out.GetLocation();
+    return false;
+  }
+  oat_writer->size_oat_dex_file_offset_ += sizeof(dex_file_offset_);
+  if (!out.WriteFully(&methods_offsets_[0],
+                      sizeof(methods_offsets_[0]) * methods_offsets_.size())) {
+    PLOG(ERROR) << "Failed to write methods offsets to " << out.GetLocation();
+    return false;
+  }
+  oat_writer->size_oat_dex_file_methods_offsets_ +=
+      sizeof(methods_offsets_[0]) * methods_offsets_.size();
+  return true;
+}
+
+OatWriter::OatClass::OatClass(size_t offset, mirror::Class::Status status, uint32_t methods_count) {
+  offset_ = offset;
+  status_ = status;
+  method_offsets_.resize(methods_count);
+}
+
+size_t OatWriter::OatClass::GetOatMethodOffsetsOffsetFromOatHeader(
+    size_t class_def_method_index_) const {
+  return offset_ + GetOatMethodOffsetsOffsetFromOatClass(class_def_method_index_);
+}
+
+size_t OatWriter::OatClass::GetOatMethodOffsetsOffsetFromOatClass(
+    size_t class_def_method_index_) const {
+  return sizeof(status_)
+          + (sizeof(method_offsets_[0]) * class_def_method_index_);
+}
+
+size_t OatWriter::OatClass::SizeOf() const {
+  return GetOatMethodOffsetsOffsetFromOatClass(method_offsets_.size());
+}
+
+void OatWriter::OatClass::UpdateChecksum(OatHeader& oat_header) const {
+  oat_header.UpdateChecksum(&status_, sizeof(status_));
+  oat_header.UpdateChecksum(&method_offsets_[0],
+                            sizeof(method_offsets_[0]) * method_offsets_.size());
+}
+
+bool OatWriter::OatClass::Write(OatWriter* oat_writer, OutputStream& out) const {
+  DCHECK_OFFSET_();
+  if (!out.WriteFully(&status_, sizeof(status_))) {
+    PLOG(ERROR) << "Failed to write class status to " << out.GetLocation();
+    return false;
+  }
+  oat_writer->size_oat_class_status_ += sizeof(status_);
+  DCHECK_EQ(static_cast<off_t>(GetOatMethodOffsetsOffsetFromOatHeader(0)),
+            out.Seek(0, kSeekCurrent));
+  if (!out.WriteFully(&method_offsets_[0],
+                      sizeof(method_offsets_[0]) * method_offsets_.size())) {
+    PLOG(ERROR) << "Failed to write method offsets to " << out.GetLocation();
+    return false;
+  }
+  oat_writer->size_oat_class_method_offsets_ += sizeof(method_offsets_[0]) * method_offsets_.size();
+  DCHECK_EQ(static_cast<off_t>(GetOatMethodOffsetsOffsetFromOatHeader(method_offsets_.size())),
+            out.Seek(0, kSeekCurrent));
+  return true;
+}
+
+}  // namespace art
diff --git a/src/compiler/oat_writer.h b/src/compiler/oat_writer.h
new file mode 100644
index 0000000..b201d6b
--- /dev/null
+++ b/src/compiler/oat_writer.h
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_OAT_WRITER_H_
+#define ART_SRC_OAT_WRITER_H_
+
+#include <stdint.h>
+
+#include <cstddef>
+
+#include "compiler/driver/compiler_driver.h"
+#include "mem_map.h"
+#include "oat.h"
+#include "mirror/class.h"
+#include "safe_map.h"
+#include "UniquePtr.h"
+
+namespace art {
+
+class OutputStream;
+
+// OatHeader         variable length with count of D OatDexFiles
+//
+// OatDexFile[0]     one variable sized OatDexFile with offsets to Dex and OatClasses
+// OatDexFile[1]
+// ...
+// OatDexFile[D]
+//
+// Dex[0]            one variable sized DexFile for each OatDexFile.
+// Dex[1]            these are literal copies of the input .dex files.
+// ...
+// Dex[D]
+//
+// OatClass[0]       one variable sized OatClass for each of C DexFile::ClassDefs
+// OatClass[1]       contains OatClass entries with class status, offsets to code, etc.
+// ...
+// OatClass[C]
+//
+// padding           if necessary so that the following code will be page aligned
+//
+// CompiledMethod    one variable sized blob with the contents of each CompiledMethod
+// CompiledMethod
+// CompiledMethod
+// CompiledMethod
+// CompiledMethod
+// CompiledMethod
+// ...
+// CompiledMethod
+//
+class OatWriter {
+ public:
+  // Write an oat file. Returns true on success, false on failure.
+  static bool Create(OutputStream& out,
+                     const std::vector<const DexFile*>& dex_files,
+                     uint32_t image_file_location_oat_checksum,
+                     uint32_t image_file_location_oat_begin,
+                     const std::string& image_file_location,
+                     const CompilerDriver& compiler)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ private:
+  OatWriter(const std::vector<const DexFile*>& dex_files,
+            uint32_t image_file_location_oat_checksum,
+            uint32_t image_file_location_oat_begin,
+            const std::string& image_file_location,
+            const CompilerDriver* compiler) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ~OatWriter();
+
+  size_t InitOatHeader();
+  size_t InitOatDexFiles(size_t offset);
+  size_t InitDexFiles(size_t offset);
+  size_t InitOatClasses(size_t offset);
+  size_t InitOatCode(size_t offset)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  size_t InitOatCodeDexFiles(size_t offset)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  size_t InitOatCodeDexFile(size_t offset,
+                            size_t& oat_class_index,
+                            const DexFile& dex_file)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  size_t InitOatCodeClassDef(size_t offset,
+                             size_t oat_class_index, size_t class_def_index,
+                             const DexFile& dex_file,
+                             const DexFile::ClassDef& class_def)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  size_t InitOatCodeMethod(size_t offset, size_t oat_class_index, size_t class_def_index,
+                           size_t class_def_method_index, bool is_native, InvokeType type,
+                           uint32_t method_idx, const DexFile*)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  bool Write(OutputStream& out);
+  bool WriteTables(OutputStream& out);
+  size_t WriteCode(OutputStream& out);
+  size_t WriteCodeDexFiles(OutputStream& out, size_t offset);
+  size_t WriteCodeDexFile(OutputStream& out, size_t offset, size_t& oat_class_index,
+                          const DexFile& dex_file);
+  size_t WriteCodeClassDef(OutputStream& out, size_t offset, size_t oat_class_index,
+                           const DexFile& dex_file, const DexFile::ClassDef& class_def);
+  size_t WriteCodeMethod(OutputStream& out, size_t offset, size_t oat_class_index,
+                         size_t class_def_method_index, bool is_static, uint32_t method_idx,
+                         const DexFile& dex_file);
+
+  void ReportWriteFailure(const char* what, uint32_t method_idx, const DexFile& dex_file,
+                          OutputStream& out) const;
+
+  class OatDexFile {
+   public:
+    explicit OatDexFile(size_t offset, const DexFile& dex_file);
+    size_t SizeOf() const;
+    void UpdateChecksum(OatHeader& oat_header) const;
+    bool Write(OatWriter* oat_writer, OutputStream& out) const;
+
+    // Offset of start of OatDexFile from beginning of OatHeader. It is
+    // used to validate file position when writing.
+    size_t offset_;
+
+    // data to write
+    uint32_t dex_file_location_size_;
+    const uint8_t* dex_file_location_data_;
+    uint32_t dex_file_location_checksum_;
+    uint32_t dex_file_offset_;
+    std::vector<uint32_t> methods_offsets_;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(OatDexFile);
+  };
+
+  class OatClass {
+   public:
+    explicit OatClass(size_t offset, mirror::Class::Status status, uint32_t methods_count);
+    size_t GetOatMethodOffsetsOffsetFromOatHeader(size_t class_def_method_index_) const;
+    size_t GetOatMethodOffsetsOffsetFromOatClass(size_t class_def_method_index_) const;
+    size_t SizeOf() const;
+    void UpdateChecksum(OatHeader& oat_header) const;
+    bool Write(OatWriter* oat_writer, OutputStream& out) const;
+
+    // Offset of start of OatClass from beginning of OatHeader. It is
+    // used to validate file position when writing. For Portable, it
+    // is also used to calculate the position of the OatMethodOffsets
+    // so that code pointers within the OatMethodOffsets can be
+    // patched to point to code in the Portable .o ELF objects.
+    size_t offset_;
+
+    // data to write
+    mirror::Class::Status status_;
+    std::vector<OatMethodOffsets> method_offsets_;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(OatClass);
+  };
+
+  const CompilerDriver* const compiler_driver_;
+
+  // note OatFile does not take ownership of the DexFiles
+  const std::vector<const DexFile*>* dex_files_;
+
+  // dependencies on the image.
+  uint32_t image_file_location_oat_checksum_;
+  uint32_t image_file_location_oat_begin_;
+  std::string image_file_location_;
+
+  // data to write
+  OatHeader* oat_header_;
+  std::vector<OatDexFile*> oat_dex_files_;
+  std::vector<OatClass*> oat_classes_;
+  UniquePtr<const std::vector<uint8_t> > interpreter_to_interpreter_entry_;
+  UniquePtr<const std::vector<uint8_t> > interpreter_to_quick_entry_;
+  UniquePtr<const std::vector<uint8_t> > portable_resolution_trampoline_;
+  UniquePtr<const std::vector<uint8_t> > quick_resolution_trampoline_;
+
+  // output stats
+  uint32_t size_dex_file_alignment_;
+  uint32_t size_executable_offset_alignment_;
+  uint32_t size_oat_header_;
+  uint32_t size_oat_header_image_file_location_;
+  uint32_t size_dex_file_;
+  uint32_t size_interpreter_to_interpreter_entry_;
+  uint32_t size_interpreter_to_quick_entry_;
+  uint32_t size_portable_resolution_trampoline_;
+  uint32_t size_quick_resolution_trampoline_;
+  uint32_t size_stubs_alignment_;
+  uint32_t size_code_size_;
+  uint32_t size_code_;
+  uint32_t size_code_alignment_;
+  uint32_t size_mapping_table_;
+  uint32_t size_vmap_table_;
+  uint32_t size_gc_map_;
+  uint32_t size_oat_dex_file_location_size_;
+  uint32_t size_oat_dex_file_location_data_;
+  uint32_t size_oat_dex_file_location_checksum_;
+  uint32_t size_oat_dex_file_offset_;
+  uint32_t size_oat_dex_file_methods_offsets_;
+  uint32_t size_oat_class_status_;
+  uint32_t size_oat_class_method_offsets_;
+
+  template <class T> struct MapCompare {
+   public:
+    bool operator() (const T* const &a, const T* const &b) const {
+      return *a < *b;
+    }
+  };
+
+  // code mappings for deduplication
+  SafeMap<const std::vector<uint8_t>*, uint32_t, MapCompare<std::vector<uint8_t> > > code_offsets_;
+  SafeMap<const std::vector<uint16_t>*, uint32_t, MapCompare<std::vector<uint16_t> > > vmap_table_offsets_;
+  SafeMap<const std::vector<uint32_t>*, uint32_t, MapCompare<std::vector<uint32_t> > > mapping_table_offsets_;
+  SafeMap<const std::vector<uint8_t>*, uint32_t, MapCompare<std::vector<uint8_t> > > gc_map_offsets_;
+
+  DISALLOW_COPY_AND_ASSIGN(OatWriter);
+};
+
+}  // namespace art
+
+#endif  // ART_SRC_OAT_WRITER_H_