Add --image-classes to dex2oat

Change-Id: Ia88f9d302e0f9cd72be2199ee46d212d99864c67
diff --git a/Android.mk b/Android.mk
index 3d50015..809ee85 100644
--- a/Android.mk
+++ b/Android.mk
@@ -199,7 +199,7 @@
 $(eval $(call build-art-cache-oat,system/app/MusicFX.apk))
 $(eval $(call build-art-cache-oat,system/app/NetSpeed.apk))
 $(eval $(call build-art-cache-oat,system/app/NetworkLocation.apk))
-$(eval $(call build-art-cache-oat,system/app/NfcGoogle.apk))
+$(eval $(call build-art-cache-oat,system/app/Nfc.apk))
 $(eval $(call build-art-cache-oat,system/app/OneTimeInitializer.apk))
 $(eval $(call build-art-cache-oat,system/app/PackageInstaller.apk))
 $(eval $(call build-art-cache-oat,system/app/Phone.apk))
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 4b0cdfe..2001c06 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -169,6 +169,7 @@
 	src/org_apache_harmony_dalvik_ddmc_DdmServer.cc \
 	src/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc \
 	src/os_linux.cc \
+	src/primitive.cc \
 	src/reference_table.cc \
 	src/reflection.cc \
 	src/runtime.cc \
diff --git a/build/Android.oat.mk b/build/Android.oat.mk
index 6d72ded..9ea9e81 100644
--- a/build/Android.oat.mk
+++ b/build/Android.oat.mk
@@ -32,6 +32,8 @@
 IMG_HOST_BASE_ADDRESS   := 0x60000000
 IMG_TARGET_BASE_ADDRESS := 0x60000000
 
+PRELOADED_CLASSES := frameworks/base/preloaded-classes
+
 ########################################################################
 # A smaller libcore only oat file
 HOST_CORE_JARS := core-hostdex
@@ -50,13 +52,13 @@
 	@echo "host dex2oat: $@ ($?)"
 	@mkdir -p $(dir $@)
 	@rm -f $@
-	$(hide) $(DEX2OAT) --runtime-arg -Xms16m --runtime-arg -Xmx16m $(addprefix --dex-file=,$(filter-out $(DEX2OAT),$^)) --oat=$@ --image=$(HOST_CORE_IMG) --base=$(IMG_HOST_BASE_ADDRESS)
+	$(hide) $(DEX2OAT) --runtime-arg -Xms16m --runtime-arg -Xmx16m --image-classes=$(PRELOADED_CLASSES) $(addprefix --dex-file=,$(filter-out $(DEX2OAT),$^)) --oat=$@ --image=$(HOST_CORE_IMG) --base=$(IMG_HOST_BASE_ADDRESS)
 
 $(TARGET_CORE_OAT): $(TARGET_CORE_DEX) $(DEX2OAT_DEPENDENCY)
 	@echo "target dex2oat: $@ ($?)"
 	@mkdir -p $(dir $@)
 	@rm -f $@
-	$(hide) $(DEX2OAT) --runtime-arg -Xms32m --runtime-arg -Xmx32m $(addprefix --dex-file=,$(filter-out $(DEX2OAT),$^)) --oat=$@ --image=$(TARGET_CORE_IMG) --base=$(IMG_TARGET_BASE_ADDRESS) --host-prefix=$(PRODUCT_OUT)
+	$(hide) $(DEX2OAT) --runtime-arg -Xms16m --runtime-arg -Xmx16m --image-classes=$(PRELOADED_CLASSES) $(addprefix --dex-file=,$(filter-out $(DEX2OAT),$^)) --oat=$@ --image=$(TARGET_CORE_IMG) --base=$(IMG_TARGET_BASE_ADDRESS) --host-prefix=$(PRODUCT_OUT)
 
 $(HOST_CORE_IMG): $(HOST_CORE_OAT)
 
@@ -73,6 +75,6 @@
 	@echo "target dex2oat: $@ ($?)"
 	@mkdir -p $(dir $@)
 	@rm -f $@
-	$(hide) $(DEX2OAT) --runtime-arg -Xms256m --runtime-arg -Xmx256m $(addprefix --dex-file=,$(filter-out $(DEX2OAT),$^)) --oat=$@ --image=$(TARGET_BOOT_IMG) --base=$(IMG_TARGET_BASE_ADDRESS) --host-prefix=$(PRODUCT_OUT)
+	$(hide) $(DEX2OAT) --runtime-arg -Xms256m --runtime-arg -Xmx256m --image-classes=$(PRELOADED_CLASSES) $(addprefix --dex-file=,$(filter-out $(DEX2OAT),$^)) --oat=$@ --image=$(TARGET_BOOT_IMG) --base=$(IMG_TARGET_BASE_ADDRESS) --host-prefix=$(PRODUCT_OUT)
 
 $(TARGET_BOOT_IMG): $(TARGET_BOOT_OAT)
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 4598ae9..266c1f0 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -184,22 +184,24 @@
   DISALLOW_COPY_AND_ASSIGN(ObjectLock);
 };
 
-ClassLinker* ClassLinker::Create(const std::string& boot_class_path,
+ClassLinker* ClassLinker::Create(bool verbose,
+                                 const std::string& boot_class_path,
                                  InternTable* intern_table) {
   CHECK_NE(boot_class_path.size(), 0U);
-  UniquePtr<ClassLinker> class_linker(new ClassLinker(intern_table));
+  UniquePtr<ClassLinker> class_linker(new ClassLinker(verbose, intern_table));
   class_linker->Init(boot_class_path);
   return class_linker.release();
 }
 
-ClassLinker* ClassLinker::Create(InternTable* intern_table) {
-  UniquePtr<ClassLinker> class_linker(new ClassLinker(intern_table));
+ClassLinker* ClassLinker::Create(bool verbose, InternTable* intern_table) {
+  UniquePtr<ClassLinker> class_linker(new ClassLinker(verbose, intern_table));
   class_linker->InitFromImage();
   return class_linker.release();
 }
 
-ClassLinker::ClassLinker(InternTable* intern_table)
-    : dex_lock_("ClassLinker dex lock"),
+ClassLinker::ClassLinker(bool verbose, InternTable* intern_table)
+    : verbose_(verbose),
+      dex_lock_("ClassLinker dex lock"),
       classes_lock_("ClassLinker classes lock"),
       class_roots_(NULL),
       array_interfaces_(NULL),
@@ -633,9 +635,25 @@
   return oat_file;
 }
 
-const OatFile* ClassLinker::FindOatFile(const DexFile& dex_file) {
+const OatFile* ClassLinker::FindOpenedOatFileForDexFile(const DexFile& dex_file) {
+  for (size_t i = 0; i < oat_files_.size(); i++) {
+    const OatFile* oat_file = oat_files_[i];
+    DCHECK(oat_file != NULL);
+    if (oat_file->GetOatDexFile(dex_file.GetLocation())) {
+      return oat_file;
+    }
+  }
+  return NULL;
+}
+
+const OatFile* ClassLinker::FindOatFileForDexFile(const DexFile& dex_file) {
   MutexLock mu(dex_lock_);
-  const OatFile* oat_file = FindOatFile(OatFile::DexFilenameToOatFilename(dex_file.GetLocation()));
+  const OatFile* oat_file = FindOpenedOatFileForDexFile(dex_file);
+  if (oat_file != NULL) {
+    return oat_file;
+  }
+
+  oat_file = FindOatFileFromOatLocation(OatFile::DexFilenameToOatFilename(dex_file.GetLocation()));
   if (oat_file != NULL) {
     const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation());
     if (dex_file.GetHeader().checksum_ == oat_dex_file->GetDexFileChecksum()) {
@@ -658,44 +676,44 @@
   return oat_file;
 }
 
-const OatFile* ClassLinker::FindOpenedOatFile(const std::string& location) {
+const OatFile* ClassLinker::FindOpenedOatFileFromOatLocation(const std::string& oat_location) {
   for (size_t i = 0; i < oat_files_.size(); i++) {
     const OatFile* oat_file = oat_files_[i];
     DCHECK(oat_file != NULL);
-    if (oat_file->GetLocation() == location) {
+    if (oat_file->GetLocation() == oat_location) {
       return oat_file;
     }
   }
   return NULL;
 }
 
-const OatFile* ClassLinker::FindOatFile(const std::string& location) {
-  const OatFile* oat_file = FindOpenedOatFile(location);
+const OatFile* ClassLinker::FindOatFileFromOatLocation(const std::string& oat_location) {
+  const OatFile* oat_file = FindOpenedOatFileFromOatLocation(oat_location);
   if (oat_file != NULL) {
     return oat_file;
   }
 
-  oat_file = OatFile::Open(location, "", NULL);
+  oat_file = OatFile::Open(oat_location, "", NULL);
   if (oat_file == NULL) {
-    if (location.empty() || location[0] != '/') {
-      LOG(ERROR) << "Failed to open oat file from " << location;
+    if (oat_location.empty() || oat_location[0] != '/') {
+      LOG(ERROR) << "Failed to open oat file from " << oat_location;
       return NULL;
     }
 
     // not found in /foo/bar/baz.oat? try /data/art-cache/foo@bar@baz.oat
-    std::string cache_location = GetArtCacheFilenameOrDie(location);
-    oat_file = FindOpenedOatFile(cache_location);
+    std::string cache_location = GetArtCacheFilenameOrDie(oat_location);
+    oat_file = FindOpenedOatFileFromOatLocation(cache_location);
     if (oat_file != NULL) {
       return oat_file;
     }
     oat_file = OatFile::Open(cache_location, "", NULL);
     if (oat_file  == NULL) {
-      LOG(INFO) << "Failed to open oat file from " << location << " or " << cache_location << ".";
+      LOG(INFO) << "Failed to open oat file from " << oat_location << " or " << cache_location << ".";
       return NULL;
     }
   }
 
-  CHECK(oat_file != NULL) << location;
+  CHECK(oat_file != NULL) << oat_location;
   oat_files_.push_back(oat_file);
   return oat_file;
 }
@@ -1137,7 +1155,7 @@
   // Every kind of method should at least get an invoke stub from the oat_method.
   // non-abstract methods also get their code pointers.
   const OatFile::OatMethod oat_method = oat_class->GetOatMethod(method_index);
-  oat_method.LinkMethod(method.get());
+  oat_method.LinkMethodPointers(method.get());
 
   if (method->IsAbstract()) {
     method->SetCode(Runtime::Current()->GetAbstractMethodErrorStubArray()->GetData());
@@ -1218,7 +1236,7 @@
 
   UniquePtr<const OatFile::OatClass> oat_class;
   if (Runtime::Current()->IsStarted() && !ClassLoader::UseCompileTimeClassPath()) {
-    const OatFile* oat_file = FindOatFile(dex_file);
+    const OatFile* oat_file = FindOatFileForDexFile(dex_file);
     if (oat_file != NULL) {
       const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation());
       if (oat_dex_file != NULL) {
@@ -1632,6 +1650,15 @@
 }
 
 bool ClassLinker::InsertClass(const std::string& descriptor, Class* klass, bool image_class) {
+  if (verbose_) {
+    DexCache* dex_cache = klass->GetDexCache();
+    std::string source;
+    if (dex_cache != NULL) {
+      source += " from ";
+      source += dex_cache->GetLocation()->ToModifiedUtf8();
+    }
+    LOG(INFO) << "Loaded class " << descriptor << source;
+  }
   size_t hash = StringPieceHash()(descriptor);
   MutexLock mu(classes_lock_);
   Table::iterator it;
@@ -1645,6 +1672,28 @@
   return ((*it).second == klass);
 }
 
+bool ClassLinker::RemoveClass(const std::string& descriptor, const ClassLoader* class_loader) {
+  size_t hash = StringPieceHash()(descriptor);
+  MutexLock mu(classes_lock_);
+  typedef Table::const_iterator It;  // TODO: C++0x auto
+  // TODO: determine if its better to search classes_ or image_classes_ first
+  for (It it = classes_.find(hash), end = classes_.end(); it != end; ++it) {
+    Class* klass = it->second;
+    if (klass->GetDescriptor()->Equals(descriptor) && klass->GetClassLoader() == class_loader) {
+      classes_.erase(it);
+      return true;
+    }
+  }
+  for (It it = image_classes_.find(hash), end = image_classes_.end(); it != end; ++it) {
+    Class* klass = it->second;
+    if (klass->GetDescriptor()->Equals(descriptor) && klass->GetClassLoader() == class_loader) {
+      image_classes_.erase(it);
+      return true;
+    }
+  }
+  return false;
+}
+
 Class* ClassLinker::LookupClass(const std::string& descriptor, const ClassLoader* class_loader) {
   size_t hash = StringPieceHash()(descriptor);
   MutexLock mu(classes_lock_);
@@ -1858,6 +1907,10 @@
       global_stats->class_init_time_ns += (t1 - t0);
       thread_stats->class_init_time_ns += (t1 - t0);
       klass->SetStatus(Class::kStatusInitialized);
+      if (verbose_) {
+        LOG(INFO) << "Initialized class " << klass->GetDescriptor()->ToModifiedUtf8()
+                  << " from " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8();
+      }
     }
     lock.NotifyAll();
   }
diff --git a/src/class_linker.h b/src/class_linker.h
index 5032d9f..d212c59 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -45,10 +45,10 @@
 class ClassLinker {
  public:
   // Creates the class linker by boot strapping from dex files.
-  static ClassLinker* Create(const std::string& boot_class_path, InternTable* intern_table);
+  static ClassLinker* Create(bool verbose, const std::string& boot_class_path, InternTable* intern_table);
 
   // Creates the class linker from one or more images.
-  static ClassLinker* Create(InternTable* intern_table);
+  static ClassLinker* Create(bool verbose, InternTable* intern_table);
 
   ~ClassLinker();
 
@@ -70,6 +70,10 @@
 
   Class* FindPrimitiveClass(char type);
 
+  // General class unloading is not supported, this is used to prune
+  // unwanted classes during image writing.
+  bool RemoveClass(const std::string& descriptor, const ClassLoader* class_loader);
+
   void DumpAllClasses(int flags) const;
 
   void DumpForSigQuit(std::ostream& os) const;
@@ -219,8 +223,8 @@
   const OatFile* GenerateOatFile(const std::string& filename);
 
   // Find, possibily opening, an OatFile corresponding to a DexFile
-  const OatFile* FindOatFile(const DexFile& dex_file);
-  const OatFile* FindOatFile(const std::string& location);
+  const OatFile* FindOatFileForDexFile(const DexFile& dex_file);
+  const OatFile* FindOatFileFromOatLocation(const std::string& location);
 
   // TODO: replace this with multiple methods that allocate the correct managed type.
   template <class T>
@@ -243,7 +247,7 @@
   pid_t GetDexLockOwner(); // For SignalCatcher.
 
  private:
-  explicit ClassLinker(InternTable*);
+  explicit ClassLinker(bool verbose, InternTable*);
 
   // Initialize class linker by bootstraping from dex files
   void Init(const std::string& boot_class_path);
@@ -354,11 +358,14 @@
     return dex_caches_;
   }
 
-  const OatFile* FindOpenedOatFile(const std::string& location);
+  const OatFile* FindOpenedOatFileForDexFile(const DexFile& dex_file);
+  const OatFile* FindOpenedOatFileFromOatLocation(const std::string& oat_location);
 
   Method* CreateProxyConstructor(SirtRef<Class>& klass);
   Method* CreateProxyMethod(SirtRef<Class>& klass, SirtRef<Method>& prototype, ObjectArray<Class>* throws);
 
+  const bool verbose_;
+
   std::vector<const DexFile*> boot_class_path_;
 
   std::vector<const DexFile*> dex_files_;
@@ -457,11 +464,11 @@
   InternTable* intern_table_;
 
   friend class CommonTest;
-  FRIEND_TEST(DexCacheTest, Open);
-  friend class ObjectTest;
-  FRIEND_TEST(ObjectTest, AllocObjectArray);
-  FRIEND_TEST(ExceptionTest, FindExceptionHandler);
   friend class ImageWriter;  // for GetClassRoots
+  friend class ObjectTest;
+  FRIEND_TEST(DexCacheTest, Open);
+  FRIEND_TEST(ExceptionTest, FindExceptionHandler);
+  FRIEND_TEST(ObjectTest, AllocObjectArray);
   DISALLOW_COPY_AND_ASSIGN(ClassLinker);
 };
 
diff --git a/src/common_test.h b/src/common_test.h
index f2a18e5..d140d40 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -97,6 +97,24 @@
     MakeExecutable(&code[0], code.size());
   }
 
+  // Create an OatMethod based on pointers (for unit tests)
+  OatFile::OatMethod CreateOatMethod(const void* code,
+                                     const size_t frame_size_in_bytes,
+                                     const uint32_t core_spill_mask,
+                                     const uint32_t fp_spill_mask,
+                                     const uint32_t* mapping_table,
+                                     const uint16_t* vmap_table,
+                                     const Method::InvokeStub* invoke_stub) {
+      return OatFile::OatMethod(NULL,
+                                reinterpret_cast<uint32_t>(code),
+                                frame_size_in_bytes,
+                                core_spill_mask,
+                                fp_spill_mask,
+                                reinterpret_cast<uint32_t>(mapping_table),
+                                reinterpret_cast<uint32_t>(vmap_table),
+                                reinterpret_cast<uint32_t>(invoke_stub));
+  }
+
   void MakeExecutable(Method* method) {
     CHECK(method != NULL);
 
@@ -123,26 +141,26 @@
       const void* method_code
           = CompiledMethod::CodePointer(&code[0], compiled_method->GetInstructionSet());
       LOG(INFO) << "MakeExecutable " << PrettyMethod(method) << " code=" << method_code;
-      OatFile::OatMethod oat_method(method_code,
-                                    compiled_method->GetFrameSizeInBytes(),
-                                    compiled_method->GetCoreSpillMask(),
-                                    compiled_method->GetFpSpillMask(),
-                                    &compiled_method->GetMappingTable()[0],
-                                    &compiled_method->GetVmapTable()[0],
-                                    method_invoke_stub);
-      oat_method.LinkMethod(method);
+      OatFile::OatMethod oat_method = CreateOatMethod(method_code,
+                                                      compiled_method->GetFrameSizeInBytes(),
+                                                      compiled_method->GetCoreSpillMask(),
+                                                      compiled_method->GetFpSpillMask(),
+                                                      &compiled_method->GetMappingTable()[0],
+                                                      &compiled_method->GetVmapTable()[0],
+                                                      method_invoke_stub);
+      oat_method.LinkMethodPointers(method);
     } else {
       MakeExecutable(runtime_->GetAbstractMethodErrorStubArray());
       const void* method_code = runtime_->GetAbstractMethodErrorStubArray()->GetData();
       LOG(INFO) << "MakeExecutable " << PrettyMethod(method) << " code=" << method_code;
-      OatFile::OatMethod oat_method(method_code,
-                                    kStackAlignment,
-                                    0,
-                                    0,
-                                    NULL,
-                                    NULL,
-                                    method_invoke_stub);
-      oat_method.LinkMethod(method);
+      OatFile::OatMethod oat_method = CreateOatMethod(method_code,
+                                                      kStackAlignment,
+                                                      0,
+                                                      0,
+                                                      NULL,
+                                                      NULL,
+                                                      method_invoke_stub);
+      oat_method.LinkMethodPointers(method);
     }
   }
 
@@ -221,7 +239,7 @@
             runtime_->CreateCalleeSaveMethod(instruction_set, type), type);
       }
     }
-    compiler_.reset(new Compiler(instruction_set, false));
+    compiler_.reset(new Compiler(instruction_set, false, NULL));
 
     Heap::VerifyHeap();  // Check for heap corruption before the test
   }
diff --git a/src/compiler.cc b/src/compiler.cc
index a3655c6..fba767d 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -35,12 +35,18 @@
   ByteArray* CreateJniDlysmLookupStub();
 }
 
-Compiler::Compiler(InstructionSet instruction_set, bool image)
+Compiler::Compiler(InstructionSet instruction_set,
+                   bool image,
+                   const std::set<std::string>* image_classes)
     : instruction_set_(instruction_set),
       jni_compiler_(instruction_set),
       image_(image),
+      image_classes_(image_classes),
       verbose_(false) {
   CHECK(!Runtime::Current()->IsStarted());
+  if (!image_) {
+    CHECK(image_classes_ == NULL);
+  }
 }
 
 Compiler::~Compiler() {
@@ -83,50 +89,62 @@
 }
 
 void Compiler::CompileAll(const ClassLoader* class_loader,
-    const std::vector<const DexFile*>& dex_files) {
+                          const std::vector<const DexFile*>& dex_files) {
   DCHECK(!Runtime::Current()->IsStarted());
-  for (size_t i = 0; i != dex_files.size(); ++i) {
-    ResolveDexFile(class_loader, *dex_files[i]);
-  }
-  for (size_t i = 0; i != dex_files.size(); ++i) {
-    VerifyDexFile(class_loader, *dex_files[i]);
-  }
-  for (size_t i = 0; i != dex_files.size(); ++i) {
-    InitializeClassesWithoutClinit(class_loader, *dex_files[i]);
-  }
-  for (size_t i = 0; i != dex_files.size(); ++i) {
-    CompileDexFile(class_loader, *dex_files[i]);
-  }
-  for (size_t i = 0; i != dex_files.size(); ++i) {
-    SetCodeAndDirectMethodsDexFile(*dex_files[i]);
-  }
+
+  PreCompile(class_loader, dex_files);
+  Compile(class_loader, dex_files);
+  PostCompile(class_loader, dex_files);
 }
 
 void Compiler::CompileOne(const Method* method) {
   DCHECK(!Runtime::Current()->IsStarted());
+
   const ClassLoader* class_loader = method->GetDeclaringClass()->GetClassLoader();
-  Resolve(class_loader);
-  Verify(class_loader);
-  InitializeClassesWithoutClinit(class_loader);
+
   // Find the dex_file
   const DexCache* dex_cache = method->GetDeclaringClass()->GetDexCache();
   const DexFile& dex_file = Runtime::Current()->GetClassLinker()->FindDexFile(dex_cache);
+  std::vector<const DexFile*> dex_files;
+  dex_files.push_back(&dex_file);
+
+  PreCompile(class_loader, dex_files);
+
   uint32_t method_idx = method->GetDexMethodIndex();
   const DexFile::CodeItem* code_item = dex_file.GetCodeItem(method->GetCodeItemOffset());
   CompileMethod(code_item, method->GetAccessFlags(), method_idx, class_loader, dex_file);
-  SetCodeAndDirectMethods(class_loader);
+
+  PostCompile(class_loader, dex_files);
 }
 
-void Compiler::Resolve(const ClassLoader* class_loader) {
-  const std::vector<const DexFile*>& class_path
-      = ClassLoader::GetCompileTimeClassPath(class_loader);
-  for (size_t i = 0; i != class_path.size(); ++i) {
-    const DexFile* dex_file = class_path[i];
+void Compiler::Resolve(const ClassLoader* class_loader,
+                       const std::vector<const DexFile*>& dex_files) {
+  for (size_t i = 0; i != dex_files.size(); ++i) {
+    const DexFile* dex_file = dex_files[i];
     CHECK(dex_file != NULL);
     ResolveDexFile(class_loader, *dex_file);
   }
 }
 
+void Compiler::PreCompile(const ClassLoader* class_loader,
+                          const std::vector<const DexFile*>& dex_files) {
+  Resolve(class_loader, dex_files);
+  Verify(class_loader, dex_files);
+  InitializeClassesWithoutClinit(class_loader, dex_files);
+}
+
+void Compiler::PostCompile(const ClassLoader* class_loader,
+                           const std::vector<const DexFile*>& dex_files) {
+  SetCodeAndDirectMethods(dex_files);
+}
+
+bool Compiler::IsImageClass(const std::string& descriptor) const {
+  if (image_classes_ == NULL) {
+    return true;
+  }
+  return image_classes_->find(descriptor) != image_classes_->end();
+}
+
 // Return true if the class should be skipped during compilation. We
 // never skip classes in the boot class loader. However, if we have a
 // non-boot class loader and we can resolve the class in the boot
@@ -157,8 +175,10 @@
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   DexCache* dex_cache = class_linker->FindDexCache(dex_file);
 
-  // Strings are easy, they always are simply resolved to literals in the same file
-  if (IsImage()) {  // Only resolve when we'll have an image, so compiler won't choose fast path
+  // Strings are easy in that they always are simply resolved to literals in the same file
+  if (image_ && image_classes_ == NULL) {
+    // TODO: Add support for loading strings referenced by image_classes_
+    // See also Compiler::CanAssumeTypeIsPresentInDexCache.
     for (size_t string_idx = 0; string_idx < dex_cache->NumStrings(); string_idx++) {
       class_linker->ResolveString(dex_file, string_idx, dex_cache);
     }
@@ -235,11 +255,10 @@
   }
 }
 
-void Compiler::Verify(const ClassLoader* class_loader) {
-  const std::vector<const DexFile*>& class_path
-      = ClassLoader::GetCompileTimeClassPath(class_loader);
-  for (size_t i = 0; i != class_path.size(); ++i) {
-    const DexFile* dex_file = class_path[i];
+void Compiler::Verify(const ClassLoader* class_loader,
+                      const std::vector<const DexFile*>& dex_files) {
+  for (size_t i = 0; i != dex_files.size(); ++i) {
+    const DexFile* dex_file = dex_files[i];
     CHECK(dex_file != NULL);
     VerifyDexFile(class_loader, *dex_file);
   }
@@ -275,11 +294,10 @@
   dex_file.ChangePermissions(PROT_READ);
 }
 
-void Compiler::InitializeClassesWithoutClinit(const ClassLoader* class_loader) {
-  const std::vector<const DexFile*>& class_path
-      = ClassLoader::GetCompileTimeClassPath(class_loader);
-  for (size_t i = 0; i != class_path.size(); ++i) {
-    const DexFile* dex_file = class_path[i];
+void Compiler::InitializeClassesWithoutClinit(const ClassLoader* class_loader,
+                                              const std::vector<const DexFile*>& dex_files) {
+  for (size_t i = 0; i != dex_files.size(); ++i) {
+    const DexFile* dex_file = dex_files[i];
     CHECK(dex_file != NULL);
     InitializeClassesWithoutClinit(class_loader, *dex_file);
   }
@@ -309,11 +327,10 @@
   }
 }
 
-void Compiler::Compile(const ClassLoader* class_loader) {
-  const std::vector<const DexFile*>& class_path
-      = ClassLoader::GetCompileTimeClassPath(class_loader);
-  for (size_t i = 0; i != class_path.size(); ++i) {
-    const DexFile* dex_file = class_path[i];
+void Compiler::Compile(const ClassLoader* class_loader,
+                       const std::vector<const DexFile*>& dex_files) {
+  for (size_t i = 0; i != dex_files.size(); ++i) {
+    const DexFile* dex_file = dex_files[i];
     CHECK(dex_file != NULL);
     CompileDexFile(class_loader, *dex_file);
   }
@@ -410,7 +427,7 @@
 }
 
 const CompiledInvokeStub* Compiler::FindInvokeStub(bool is_static, const char* shorty) const {
-  std::string key = MakeInvokeStubKey(is_static, shorty);
+  const std::string key = MakeInvokeStubKey(is_static, shorty);
   InvokeStubTable::const_iterator it = compiled_invoke_stubs_.find(key);
   if (it == compiled_invoke_stubs_.end()) {
     return NULL;
@@ -435,11 +452,9 @@
   return it->second;
 }
 
-void Compiler::SetCodeAndDirectMethods(const ClassLoader* class_loader) {
-  const std::vector<const DexFile*>& class_path
-      = ClassLoader::GetCompileTimeClassPath(class_loader);
-  for (size_t i = 0; i != class_path.size(); ++i) {
-    const DexFile* dex_file = class_path[i];
+void Compiler::SetCodeAndDirectMethods(const std::vector<const DexFile*>& dex_files) {
+  for (size_t i = 0; i != dex_files.size(); ++i) {
+    const DexFile* dex_file = dex_files[i];
     CHECK(dex_file != NULL);
     SetCodeAndDirectMethodsDexFile(*dex_file);
   }
diff --git a/src/compiler.h b/src/compiler.h
index a8ea205..5203ffb 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -13,6 +13,7 @@
 #include "runtime.h"
 #include "unordered_map.h"
 
+#include <set>
 #include <string>
 
 namespace art {
@@ -20,13 +21,18 @@
 class Compiler {
  public:
   // Create a compiler targeting the requested "instruction_set".
-  // "image" should be true if image specific optimizations should be enabled.
-  explicit Compiler(InstructionSet instruction_set, bool image);
+  // "image" should be true if image specific optimizations should be
+  // enabled.  "image_classes" lets the compiler know what classes it
+  // can assume will be in the image, with NULL implying all available
+  // classes.
+  explicit Compiler(InstructionSet instruction_set,
+                    bool image,
+                    const std::set<std::string>* image_classes);
 
   ~Compiler();
 
   void CompileAll(const ClassLoader* class_loader,
-                  const std::vector<const DexFile*>& class_path);
+                  const std::vector<const DexFile*>& dex_files);
 
   // Compile a single Method
   void CompileOne(const Method* method);
@@ -65,20 +71,29 @@
 
   // Callbacks from OAT/ART compiler to see what runtime checks must be generated
   bool CanAssumeTypeIsPresentInDexCache(const DexCache* dex_cache, uint32_t type_idx) const {
-    return IsImage() && dex_cache->GetResolvedTypes()->Get(type_idx) != NULL;
+    if (!IsImage()) {
+      return false;
+    }
+    Class* resolved_class = dex_cache->GetResolvedTypes()->Get(type_idx);
+    if (resolved_class == NULL) {
+      return false;
+    }
+    return IsImageClass(resolved_class->GetDescriptor()->ToModifiedUtf8());
   }
   bool CanAssumeStringIsPresentInDexCache(const DexCache* dex_cache, uint32_t string_idx) const {
-    return IsImage() && dex_cache->GetStrings()->Get(string_idx) != NULL;
+    // TODO: Add support for loading strings referenced by image_classes_
+    // See also Compiler::ResolveDexFile
+    return IsImage() && image_classes_ == NULL && dex_cache->GetResolvedString(string_idx) != NULL;
   }
   bool CanAccessTypeWithoutChecks(uint32_t referrer_idx, const DexCache* dex_cache,
                                   const DexFile& dex_file, uint32_t type_idx) const {
-    Class* resolved_class = dex_cache->GetResolvedTypes()->Get(type_idx);
+    Class* resolved_class = dex_cache->GetResolvedType(type_idx);
     // We should never ask whether a type needs access checks to raise a verification error,
     // all other cases where this following test could fail should have been rewritten by the
     // verifier to verification errors. Also need to handle a lack of knowledge at compile time.
 #ifndef NDEBUG
-    Class* referrer_class = dex_cache->GetResolvedTypes()
-        ->Get(dex_file.GetMethodId(referrer_idx).class_idx_);
+    const DexFile::MethodId& method_id = dex_file.GetMethodId(referrer_idx);
+    Class* referrer_class = dex_cache->GetResolvedType(method_id.class_idx_);
     DCHECK(resolved_class == NULL || referrer_class == NULL ||
            referrer_class->CanAccess(resolved_class));
 #endif
@@ -86,19 +101,27 @@
   }
 
  private:
+
+  // Checks if class specified by type_idx is one of the image_classes_
+  bool IsImageClass(const std::string& descriptor) const;
+
+  void PreCompile(const ClassLoader* class_loader, const std::vector<const DexFile*>& dex_files);
+  void PostCompile(const ClassLoader* class_loader, const std::vector<const DexFile*>& dex_files);
+
   // Attempt to resolve all type, methods, fields, and strings
   // referenced from code in the dex file following PathClassLoader
   // ordering semantics.
-  void Resolve(const ClassLoader* class_loader);
+  void Resolve(const ClassLoader* class_loader, const std::vector<const DexFile*>& dex_files);
   void ResolveDexFile(const ClassLoader* class_loader, const DexFile& dex_file);
 
-  void Verify(const ClassLoader* class_loader);
+  void Verify(const ClassLoader* class_loader, const std::vector<const DexFile*>& dex_files);
   void VerifyDexFile(const ClassLoader* class_loader, const DexFile& dex_file);
 
-  void InitializeClassesWithoutClinit(const ClassLoader* class_loader);
+  void InitializeClassesWithoutClinit(const ClassLoader* class_loader, const std::vector<const DexFile*>& dex_files);
   void InitializeClassesWithoutClinit(const ClassLoader* class_loader, const DexFile& dex_file);
 
-  void Compile(const ClassLoader* class_loader);
+  void Compile(const ClassLoader* class_loader,
+               const std::vector<const DexFile*>& dex_files);
   void CompileDexFile(const ClassLoader* class_loader, const DexFile& dex_file);
   void CompileClass(const DexFile::ClassDef& class_def, const ClassLoader* class_loader,
                     const DexFile& dex_file);
@@ -107,7 +130,7 @@
 
   // After compiling, walk all the DexCaches and set the code and
   // method pointers of CodeAndDirectMethods entries in the DexCaches.
-  void SetCodeAndDirectMethods(const ClassLoader* class_loader);
+  void SetCodeAndDirectMethods(const std::vector<const DexFile*>& dex_files);
   void SetCodeAndDirectMethodsDexFile(const DexFile& dex_file);
 
   void InsertInvokeStub(bool is_static, const char* shorty,
@@ -139,6 +162,8 @@
 
   bool image_;
 
+  const std::set<std::string>* image_classes_;
+
   bool verbose_;
 
   DISALLOW_COPY_AND_ASSIGN(Compiler);
diff --git a/src/dalvik_system_DexFile.cc b/src/dalvik_system_DexFile.cc
index 6ad92ba..cf4443b 100644
--- a/src/dalvik_system_DexFile.cc
+++ b/src/dalvik_system_DexFile.cc
@@ -222,7 +222,7 @@
     return JNI_TRUE;
   }
 
-  const OatFile* oat_file = class_linker->FindOatFile(*dex_file.get());
+  const OatFile* oat_file = class_linker->FindOatFileForDexFile(*dex_file.get());
   if (oat_file == NULL) {
     return JNI_TRUE;
   }
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index 231ca9c..0e4c224 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -4,6 +4,8 @@
 #include <stdlib.h>
 #include <sys/file.h>
 
+#include <iostream>
+#include <fstream>
 #include <string>
 #include <vector>
 
@@ -29,13 +31,16 @@
           "      Example: --dex-file=/system/framework/core.jar\n"
           "\n");
   fprintf(stderr,
-          "  --image=<file.art>: specifies the required output image filename.\n"
+          "  --oat=<file.oat>: specifies the required oat filename.\n"
+          "      Example: --oat=/data/art-cache/boot.oat\n"
+          "\n");
+  fprintf(stderr,
+          "  --image=<file.art>: specifies the output image filename.\n"
           "      Example: --image=/data/art-cache/boot.art\n"
           "\n");
-  // TODO: remove this by inferring from --image
   fprintf(stderr,
-          "  --oat=<file.oat>: specifies the required oat filename.\n"
-          "      Example: --image=/data/art-cache/boot.oat\n"
+          "  --image-classes=<classname-file>: specifies classes to include in an image.\n"
+          "      Example: --image=frameworks/base/preloaded-classes\n"
           "\n");
   fprintf(stderr,
           "  --base=<hex-address>: specifies the base address when creating a boot image.\n"
@@ -46,10 +51,6 @@
           "      Example: --boot-image=/data/art-cache/boot.art\n"
           "\n");
   fprintf(stderr,
-          "  --method may be used to limit compilation to a subset of methods.\n"
-          "      Example: --method=Ljava/lang/Object;<init>()V\n"
-          "\n");
-  fprintf(stderr,
           "  --host-prefix may be used to translate host paths to target paths during\n"
           "      cross compilation.\n"
           "      Example: --host-prefix=out/target/product/crespo\n"
@@ -94,33 +95,190 @@
   bool do_unlink_;
 };
 
-// Returns true if dex_files has a dex with the named location.
-bool DexFilesContains(const std::vector<const DexFile*>& dex_files, const std::string& location) {
-  for (size_t i = 0; i < dex_files.size(); ++i) {
-    if (dex_files[i]->GetLocation() == location) {
+class Dex2Oat {
+ public:
+
+  static Dex2Oat* Create(Runtime::Options& options) {
+    UniquePtr<Runtime> runtime(CreateRuntime(options));
+    if (runtime.get() == NULL) {
+      return NULL;
+    }
+    return new Dex2Oat(runtime.release());
+  }
+
+  ~Dex2Oat() {
+    delete runtime_;
+  }
+
+  // Make a list of descriptors for classes to include in the image
+  const std::set<std::string>* GetImageClassDescriptors(const char* image_classes_filename) {
+    UniquePtr<std::ifstream> image_classes_file(new std::ifstream(image_classes_filename, std::ifstream::in));
+    if (image_classes_file.get() == NULL) {
+      LOG(ERROR) << "Failed to open image classes file " << image_classes_filename;
+      return NULL;
+    }
+
+    // Load all the classes specifed in the file
+    ClassLinker* class_linker = runtime_->GetClassLinker();
+    while (image_classes_file->good()) {
+      std::string dot;
+      std::getline(*image_classes_file.get(), dot);
+      if (StringPiece(dot).starts_with("#") || dot.empty()) {
+        continue;
+      }
+      std::string descriptor = DotToDescriptor(dot.c_str());
+      SirtRef<Class> klass(class_linker->FindSystemClass(descriptor));
+      if (klass.get() == NULL) {
+        LOG(WARNING) << "Failed to find class " << descriptor;
+        Thread::Current()->ClearException();
+      }
+    }
+    image_classes_file->close();
+
+    // We walk the roots looking for classes so that we'll pick up the
+    // above classes plus any classes them depend on such super
+    // classes, interfaces, and the required ClassLinker roots.
+    UniquePtr<std::set<std::string> > image_classes(new std::set<std::string>());
+    class_linker->VisitClasses(ClassVisitor, image_classes.get());
+    CHECK_NE(image_classes->size(), 0U);
+    return image_classes.release();
+  }
+
+  bool CreateOatFile(const std::string& boot_image_option,
+                     const std::vector<const char*>& dex_filenames,
+                     const std::string& host_prefix,
+                     File* oat_file,
+                     bool image,
+                     const std::set<std::string>* image_classes) {
+    // SirtRef and ClassLoader creation needs to come after Runtime::Create
+    UniquePtr<SirtRef<ClassLoader> > class_loader(new SirtRef<ClassLoader>(NULL));
+    if (class_loader.get() == NULL) {
+      LOG(ERROR) << "Failed to create SirtRef for class loader";
+      return false;
+    }
+
+    std::vector<const DexFile*> dex_files;
+    if (!boot_image_option.empty()) {
+      ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+      DexFile::OpenDexFiles(dex_filenames, dex_files, host_prefix);
+      std::vector<const DexFile*> class_path_files(dex_files);
+      OpenClassPathFiles(runtime_->GetClassPath(), class_path_files);
+      for (size_t i = 0; i < class_path_files.size(); i++) {
+        class_linker->RegisterDexFile(*class_path_files[i]);
+      }
+      class_loader.get()->reset(PathClassLoader::AllocCompileTime(class_path_files));
+    } else {
+      dex_files = runtime_->GetClassLinker()->GetBootClassPath();
+    }
+
+    Compiler compiler(instruction_set_, image, image_classes);
+    compiler.CompileAll(class_loader->get(), dex_files);
+
+    if (!OatWriter::Create(oat_file, class_loader->get(), compiler)) {
+      LOG(ERROR) << "Failed to create oat file " << oat_file->name();
+      return false;
+    }
+    return true;
+  }
+
+  bool CreateImageFile(const char* image_filename,
+                       uintptr_t image_base,
+                       const std::set<std::string>* image_classes,
+                       const std::string& oat_filename,
+                       const std::string& host_prefix) {
+    // If we have an existing boot image, position new space after its oat file
+    if (Heap::GetSpaces().size() > 1) {
+      Space* last_image_space = Heap::GetSpaces()[Heap::GetSpaces().size()-2];
+      CHECK(last_image_space != NULL);
+      CHECK(last_image_space->IsImageSpace());
+      CHECK(!Heap::GetSpaces()[Heap::GetSpaces().size()-1]->IsImageSpace());
+      byte* oat_limit_addr = last_image_space->GetImageHeader().GetOatLimitAddr();
+      image_base = RoundUp(reinterpret_cast<uintptr_t>(oat_limit_addr), kPageSize);
+    }
+
+    ImageWriter image_writer(image_classes);
+    if (!image_writer.Write(image_filename, image_base, oat_filename, host_prefix)) {
+      LOG(ERROR) << "Failed to create image file " << image_filename;
+      return false;
+    }
+    return true;
+  }
+
+ private:
+
+  Dex2Oat(Runtime* runtime) : runtime_(runtime) {}
+
+  static Runtime* CreateRuntime(Runtime::Options& options) {
+    Runtime* runtime = Runtime::Create(options, false);
+    if (runtime == NULL) {
+      LOG(ERROR) << "Failed to create runtime";
+      return NULL;
+    }
+
+    // if we loaded an existing image, we will reuse values from the image roots.
+    if (!runtime->HasJniDlsymLookupStub()) {
+      runtime->SetJniDlsymLookupStub(Compiler::CreateJniDlysmLookupStub(instruction_set_));
+    }
+    if (!runtime->HasAbstractMethodErrorStubArray()) {
+      runtime->SetAbstractMethodErrorStubArray(Compiler::CreateAbstractMethodErrorStub(instruction_set_));
+    }
+    for (int i = 0; i < Runtime::kLastTrampolineMethodType; i++) {
+      Runtime::TrampolineType type = Runtime::TrampolineType(i);
+      if (!runtime->HasResolutionStubArray(type)) {
+        runtime->SetResolutionStubArray(Compiler::CreateResolutionStub(instruction_set_, type), type);
+      }
+    }
+    for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
+      Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i);
+      if (!runtime->HasCalleeSaveMethod(type)) {
+        runtime->SetCalleeSaveMethod(runtime->CreateCalleeSaveMethod(instruction_set_, type), type);
+      }
+    }
+    return runtime;
+  }
+
+  static bool ClassVisitor(Class* klass, void* arg) {
+    std::set<std::string>* image_classes = reinterpret_cast<std::set<std::string>*>(arg);
+    if (klass->IsArrayClass() || klass->IsPrimitive()) {
       return true;
     }
+    image_classes->insert(klass->GetDescriptor()->ToModifiedUtf8());
+    return true;
   }
-  return false;
-}
 
-// Appends to dex_files any elements of class_path that it doesn't already
-// contain. This will open those dex files as necessary.
-void OpenClassPathFiles(const std::string& class_path, std::vector<const DexFile*>& dex_files) {
-  std::vector<std::string> parsed;
-  Split(class_path, ':', parsed);
-  for (size_t i = 0; i < parsed.size(); ++i) {
-    if (DexFilesContains(dex_files, parsed[i])) {
-      continue;
-    }
-    const DexFile* dex_file = DexFile::Open(parsed[i], Runtime::Current()->GetHostPrefix());
-    if (dex_file == NULL) {
-      LOG(WARNING) << "Failed to open dex file " << parsed[i];
-    } else {
-      dex_files.push_back(dex_file);
+  // Appends to dex_files any elements of class_path that it doesn't already
+  // contain. This will open those dex files as necessary.
+  static void OpenClassPathFiles(const std::string& class_path, std::vector<const DexFile*>& dex_files) {
+    std::vector<std::string> parsed;
+    Split(class_path, ':', parsed);
+    for (size_t i = 0; i < parsed.size(); ++i) {
+      if (DexFilesContains(dex_files, parsed[i])) {
+        continue;
+      }
+      const DexFile* dex_file = DexFile::Open(parsed[i], Runtime::Current()->GetHostPrefix());
+      if (dex_file == NULL) {
+        LOG(WARNING) << "Failed to open dex file " << parsed[i];
+      } else {
+        dex_files.push_back(dex_file);
+      }
     }
   }
-}
+
+  // Returns true if dex_files has a dex with the named location.
+  static bool DexFilesContains(const std::vector<const DexFile*>& dex_files, const std::string& location) {
+    for (size_t i = 0; i < dex_files.size(); ++i) {
+      if (dex_files[i]->GetLocation() == location) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  Runtime* runtime_;
+  static const InstructionSet instruction_set_ = kThumb2;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Dex2Oat);
+};
 
 int dex2oat(int argc, char** argv) {
   // Skip over argv[0].
@@ -133,9 +291,9 @@
   }
 
   std::vector<const char*> dex_filenames;
-  std::vector<const char*> method_names;
   std::string oat_filename;
   const char* image_filename = NULL;
+  const char* image_classes_filename = NULL;
   std::string boot_image_option;
   uintptr_t image_base = 0;
   std::string host_prefix;
@@ -148,12 +306,12 @@
     }
     if (option.starts_with("--dex-file=")) {
       dex_filenames.push_back(option.substr(strlen("--dex-file=")).data());
-    } else if (option.starts_with("--method=")) {
-      method_names.push_back(option.substr(strlen("--method=")).data());
     } else if (option.starts_with("--oat=")) {
       oat_filename = option.substr(strlen("--oat=")).data();
     } else if (option.starts_with("--image=")) {
       image_filename = option.substr(strlen("--image=")).data();
+    } else if (option.starts_with("--image-classes=")) {
+      image_classes_filename = option.substr(strlen("--image-classes=")).data();
     } else if (option.starts_with("--base=")) {
       const char* image_base_str = option.substr(strlen("--base=")).data();
       char* end;
@@ -181,18 +339,24 @@
     }
   }
 
-  if (oat_filename == NULL) {
+  if (oat_filename.empty()) {
     fprintf(stderr, "--oat file name not specified\n");
     return EXIT_FAILURE;
   }
 
-  if (image_filename == NULL && boot_image_option.empty()) {
+  bool image = (image_filename != NULL);
+  if (!image && boot_image_option.empty()) {
     fprintf(stderr, "Either --image or --boot-image must be specified\n");
     return EXIT_FAILURE;
   }
 
-  if (dex_filenames.empty()) {
-    fprintf(stderr, "no --dex-file values specified\n");
+  if (image_classes_filename != NULL && !image) {
+    fprintf(stderr, "--image-classes should only be used with --image\n");
+    return EXIT_FAILURE;
+  }
+
+  if (image_classes_filename != NULL && !boot_image_option.empty()) {
+    fprintf(stderr, "--image-classes should not be used with --boot-image\n");
     return EXIT_FAILURE;
   }
 
@@ -220,7 +384,7 @@
   }
 
   // Handles removing the file on failure and unlocking on both failure and success.
-  FileJanitor file_janitor(oat_filename, fd);
+  FileJanitor oat_file_janitor(oat_filename, fd);
 
   // If we won the creation race, block trying to take the lock (since we're going to be doing
   // the work, we need the lock). If we lost the creation race, spin trying to take the lock
@@ -252,7 +416,7 @@
     // TODO: check the creator did a good job by checking the header.
     LOG(INFO) << "Another process finished working on " << oat_filename;
     // Job done.
-    file_janitor.KeepFile();
+    oat_file_janitor.KeepFile();
     return EXIT_SUCCESS;
   }
 
@@ -281,122 +445,47 @@
   for (size_t i = 0; i < runtime_args.size(); i++) {
     options.push_back(std::make_pair(runtime_args[i], reinterpret_cast<void*>(NULL)));
   }
-  UniquePtr<Runtime> runtime(Runtime::Create(options, false));
-  if (runtime.get() == NULL) {
-    LOG(ERROR) << "Could not create runtime";
-    return EXIT_FAILURE;
-  }
-  ClassLinker* class_linker = runtime->GetClassLinker();
 
-  // If we have an existing boot image, position new space after its oat file
-  if (Heap::GetSpaces().size() > 1) {
-    Space* last_image_space = Heap::GetSpaces()[Heap::GetSpaces().size()-2];
-    CHECK(last_image_space != NULL);
-    CHECK(last_image_space->IsImageSpace());
-    CHECK(!Heap::GetSpaces()[Heap::GetSpaces().size()-1]->IsImageSpace());
-    byte* oat_limit_addr = last_image_space->GetImageHeader().GetOatLimitAddr();
-    image_base = RoundUp(reinterpret_cast<uintptr_t>(oat_limit_addr), kPageSize);
-  }
+  UniquePtr<Dex2Oat> dex2oat(Dex2Oat::Create(options));
 
-  // ClassLoader creation needs to come after Runtime::Create
-  SirtRef<ClassLoader> class_loader(NULL);
-  std::vector<const DexFile*> dex_files;
-  if (!boot_image_option.empty()) {
-    DexFile::OpenDexFiles(dex_filenames, dex_files, host_prefix);
-    std::vector<const DexFile*> class_path_files(dex_files);
-    OpenClassPathFiles(runtime->GetClassPath(), class_path_files);
-    for (size_t i = 0; i < class_path_files.size(); i++) {
-      class_linker->RegisterDexFile(*class_path_files[i]);
-    }
-    class_loader.reset(PathClassLoader::AllocCompileTime(class_path_files));
-  } else {
-    dex_files = runtime->GetClassLinker()->GetBootClassPath();
-  }
-
-  // if we loaded an existing image, we will reuse values from the image roots.
-  if (!runtime->HasJniDlsymLookupStub()) {
-    runtime->SetJniDlsymLookupStub(Compiler::CreateJniDlysmLookupStub(kThumb2));
-  }
-  if (!runtime->HasAbstractMethodErrorStubArray()) {
-    runtime->SetAbstractMethodErrorStubArray(Compiler::CreateAbstractMethodErrorStub(kThumb2));
-  }
-  for (int i = 0; i < Runtime::kLastTrampolineMethodType; i++) {
-    Runtime::TrampolineType type = Runtime::TrampolineType(i);
-    if (!runtime->HasResolutionStubArray(type)) {
-      runtime->SetResolutionStubArray(Compiler::CreateResolutionStub(kThumb2, type), type);
-    }
-  }
-  for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
-    Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i);
-    if (!runtime->HasCalleeSaveMethod(type)) {
-      runtime->SetCalleeSaveMethod(runtime->CreateCalleeSaveMethod(kThumb2, type), type);
-    }
-  }
-  Compiler compiler(kThumb2, image_filename != NULL);
-  if (method_names.empty()) {
-    compiler.CompileAll(class_loader.get(), dex_files);
-  } else {
-    for (size_t i = 0; i < method_names.size(); i++) {
-      // names are actually class_descriptor + name + signature.
-      // example: Ljava/lang/Object;<init>()V
-      StringPiece method_name = method_names[i];
-      size_t end_of_class_descriptor = method_name.find(';');
-      if (end_of_class_descriptor == method_name.npos) {
-        LOG(ERROR) << "Could not find class descriptor in method " << method_name << "'";
-        return EXIT_FAILURE;
-      }
-      end_of_class_descriptor++;  // want to include ;
-      std::string class_descriptor = method_name.substr(0, end_of_class_descriptor).ToString();
-      size_t end_of_name = method_name.find('(', end_of_class_descriptor);
-      if (end_of_name == method_name.npos) {
-        LOG(ERROR) << "Could not find start of method signature in method '" << method_name << "'";
-        return EXIT_FAILURE;
-      }
-      std::string name = method_name.substr(end_of_class_descriptor,
-                                            end_of_name - end_of_class_descriptor).ToString();
-      std::string signature = method_name.substr(end_of_name).ToString();
-
-      Class* klass = class_linker->FindClass(class_descriptor, class_loader.get());
-      if (klass == NULL) {
-        LOG(ERROR) << "Could not find class for descriptor '" << class_descriptor
-            << "' in method '" << method_name << "'";
-        return EXIT_FAILURE;
-      }
-      Method* method = klass->FindDirectMethod(name, signature);
-      if (method == NULL) {
-          method = klass->FindVirtualMethod(name, signature);
-      }
-      if (method == NULL) {
-        LOG(ERROR) << "Could not find method '" << method_name << "' with signature '"
-            << signature << "' in class '" << class_descriptor << "' for method argument '"
-            << method_name << "'";
-        return EXIT_FAILURE;
-      }
-      compiler.CompileOne(method);
+  // If --image-classes was specified, calculate the full list classes to include in the image
+  UniquePtr<const std::set<std::string> > image_classes(NULL);
+  if (image_classes_filename != NULL) {
+    image_classes.reset(dex2oat->GetImageClassDescriptors(image_classes_filename));
+    if (image_classes.get() == NULL) {
+      LOG(ERROR) << "Failed to create list of image classes from " << image_classes_filename;
+      return EXIT_FAILURE;
     }
   }
 
-  if (!OatWriter::Create(oat_file.get(), class_loader.get(), compiler)) {
-    LOG(ERROR) << "Failed to create oat file " << oat_file->name();
+  if (!dex2oat->CreateOatFile(boot_image_option,
+                              dex_filenames,
+                              host_prefix,
+                              oat_file.get(),
+                              image,
+                              image_classes.get())) {
+    LOG(ERROR) << "Failed to create oat file" << oat_filename;
     return EXIT_FAILURE;
   }
 
-  if (image_filename == NULL) {
-    file_janitor.KeepFile();
-    LOG(INFO) << "Oat file written successfully " << oat_file->name();
+  if (!image) {
+    oat_file_janitor.KeepFile();
+    LOG(INFO) << "Oat file written successfully " << oat_filename;
     return EXIT_SUCCESS;
   }
-  CHECK(compiler.IsImage());
 
-  ImageWriter image_writer;
-  if (!image_writer.Write(image_filename, image_base, oat_file->name(), host_prefix)) {
-    LOG(ERROR) << "Failed to create image file " << image_filename;
+  if (!dex2oat->CreateImageFile(image_filename,
+                                image_base,
+                                image_classes.get(),
+                                oat_filename,
+                                host_prefix)) {
     return EXIT_FAILURE;
   }
 
-  // We wrote the file successfully, and want to keep it.
+  // We wrote the oat file successfully, and want to keep it.
+  oat_file_janitor.KeepFile();
+  LOG(INFO) << "Oat file written successfully " << oat_filename;
   LOG(INFO) << "Image written successfully " << image_filename;
-  file_janitor.KeepFile();
   return EXIT_SUCCESS;
 }
 
diff --git a/src/dex_file.cc b/src/dex_file.cc
index 208479e..d7517c4 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -45,7 +45,7 @@
                         reinterpret_cast<const DexFile::ClassDef*>(NULL));
 }
 
-void DexFile::OpenDexFiles(std::vector<const char*>& dex_filenames,
+void DexFile::OpenDexFiles(const std::vector<const char*>& dex_filenames,
                            std::vector<const DexFile*>& dex_files,
                            const std::string& strip_location_prefix) {
   for (size_t i = 0; i < dex_filenames.size(); i++) {
diff --git a/src/dex_file.h b/src/dex_file.h
index 92aa794..a7026d6 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -176,7 +176,7 @@
                                         const ClassPath& class_path);
 
   // Opens a collection of .dex files
-  static void OpenDexFiles(std::vector<const char*>& dex_filenames,
+  static void OpenDexFiles(const std::vector<const char*>& dex_filenames,
                            std::vector<const DexFile*>& dex_files,
                            const std::string& strip_location_prefix);
 
diff --git a/src/image_test.cc b/src/image_test.cc
index 812b281..6901482 100644
--- a/src/image_test.cc
+++ b/src/image_test.cc
@@ -29,7 +29,7 @@
     EXPECT_TRUE(klass != NULL) << descriptor;
   }
 
-  ImageWriter writer;
+  ImageWriter writer(NULL);
   ScratchFile tmp_image;
   const uintptr_t requested_image_base = 0x60000000;
   bool success_image = writer.Write(tmp_image.GetFilename(), requested_image_base,
diff --git a/src/image_writer.cc b/src/image_writer.cc
index cdb7bd0..adc7b78 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -9,6 +9,7 @@
 #include "UniquePtr.h"
 #include "class_linker.h"
 #include "class_loader.h"
+#include "compiled_method.h"
 #include "dex_cache.h"
 #include "file.h"
 #include "globals.h"
@@ -23,8 +24,10 @@
 
 namespace art {
 
-bool ImageWriter::Write(const char* image_filename, uintptr_t image_base,
-                        const std::string& oat_filename, const std::string& strip_location_prefix) {
+bool ImageWriter::Write(const char* image_filename,
+                        uintptr_t image_base,
+                        const std::string& oat_filename,
+                        const std::string& strip_location_prefix) {
   CHECK(image_filename != NULL);
 
   CHECK_NE(image_base, 0U);
@@ -36,16 +39,29 @@
   source_space_ = spaces[spaces.size()-1];
   CHECK(!source_space_->IsImageSpace());
 
+  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];
+    if (InSourceSpace(dex_cache)) {
+      dex_caches_.insert(dex_cache);
+    }
+  }
+
   oat_file_.reset(OatFile::Open(oat_filename, strip_location_prefix, NULL));
   if (oat_file_.get() == NULL) {
     LOG(ERROR) << "Failed to open oat file " << oat_filename;
     return false;
   }
 
-  if (!Init()) {
+  if (!AllocMemory()) {
     return false;
   }
+  PruneNonImageClasses();
   Heap::CollectGarbage();
+#ifndef NDEBUG
+  CheckNonImageClassesRemoved();
+#endif
   Heap::DisableCardMarking();
   CalculateNewObjectOffsets();
   CopyAndFixupObjects();
@@ -63,7 +79,7 @@
   return true;
 }
 
-bool ImageWriter::Init() {
+bool ImageWriter::AllocMemory() {
   size_t size = source_space_->Size();
   int prot = PROT_READ | PROT_WRITE;
   size_t length = RoundUp(size, kPageSize);
@@ -75,6 +91,96 @@
   return true;
 }
 
+bool ImageWriter::IsImageClass(const Class* klass) {
+  if (image_classes_ == NULL) {
+    return true;
+  }
+  while (klass->IsArrayClass()) {
+    klass = klass->GetComponentType();
+  }
+  if (klass->IsPrimitive()) { 
+    return true;
+  }
+  const std::string descriptor = klass->GetDescriptor()->ToModifiedUtf8();
+  return image_classes_->find(descriptor) != image_classes_->end();
+}
+
+
+struct NonImageClasses {
+  ImageWriter* image_writer;
+  std::set<std::string>* non_image_classes;
+};
+
+void ImageWriter::PruneNonImageClasses() {
+  if (image_classes_ == NULL) {
+    return;
+  }
+  Runtime* runtime = Runtime::Current();
+  ClassLinker* class_linker = runtime->GetClassLinker();
+
+  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);
+
+  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, NULL);
+  }
+
+  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++) {
+      Method* method = dex_cache->GetResolvedMethod(i);
+      if (method != NULL && !IsImageClass(method->GetDeclaringClass())) {
+        dex_cache->SetResolvedMethod(i, NULL);
+        Runtime::TrampolineType type = Runtime::GetTrampolineType(method);
+        ByteArray* res_trampoline = runtime->GetResolutionStubArray(type);
+        dex_cache->GetCodeAndDirectMethods()->SetResolvedDirectMethodTrampoline(i, res_trampoline);
+      }
+    }
+    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(klass->GetDescriptor()->ToModifiedUtf8());
+  }
+  return true;
+}
+
+void ImageWriter::CheckNonImageClassesRemoved() {
+  if (image_classes_ == NULL) {
+    return;
+  }
+  Heap::GetLiveBits()->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();
+  CHECK(image_writer->IsImageClass(klass)) << klass->GetDescriptor()->ToModifiedUtf8();
+}
+
 void ImageWriter::CalculateNewObjectOffsetsCallback(Object* obj, void* arg) {
   DCHECK(obj != NULL);
   DCHECK(arg != NULL);
@@ -104,17 +210,6 @@
   }
 
   image_writer->AssignImageOffset(obj);
-
-  // sniff out the DexCaches on this pass for use on the next pass
-  if (obj->IsClass()) {
-    Class* klass = obj->AsClass();
-    DexCache* dex_cache = klass->GetDexCache();
-    if (dex_cache != NULL) {
-      image_writer->dex_caches_.insert(dex_cache);
-    } else {
-      DCHECK(klass->IsArrayClass() || klass->IsPrimitive()) << PrettyClass(klass);
-    }
-  }
 }
 
 ObjectArray<Object>* ImageWriter::CreateImageRoots() const {
@@ -123,18 +218,12 @@
   Class* object_array_class = class_linker->FindSystemClass("[Ljava/lang/Object;");
 
   // build an Object[] of all the DexCaches used in the source_space_
-  const std::vector<DexCache*>& all_dex_caches = class_linker->GetDexCaches();
-  std::vector<DexCache*> source_space_dex_caches;
-  for (size_t i = 0; i < all_dex_caches.size(); i++) {
-    DexCache* dex_cache = all_dex_caches[i];
-    if (InSourceSpace(dex_cache)) {
-      source_space_dex_caches.push_back(dex_cache);
-    }
-  }
   ObjectArray<Object>* dex_caches = ObjectArray<Object>::Alloc(object_array_class,
-                                                               source_space_dex_caches.size());
-  for (size_t i = 0; i < source_space_dex_caches.size(); i++) {
-      dex_caches->Set(i, source_space_dex_caches[i]);
+                                                               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
@@ -245,15 +334,15 @@
   FixupStaticFields(orig, copy);
 }
 
-const void* FixupCode(const ByteArray* copy_code_array, const void* orig_code) {
+static uint32_t FixupCode(const ByteArray* copy_code_array, uint32_t orig_code) {
   // TODO: change to DCHECK when all code compiling
   if (copy_code_array == NULL) {
-    return NULL;
+    return 0;
   }
-  const void* copy_code = copy_code_array->GetData();
+  uint32_t copy_code = reinterpret_cast<uint32_t>(copy_code_array->GetData());
   // TODO: remember InstructionSet with each code array so we know if we need to do thumb fixup?
-  if ((reinterpret_cast<uintptr_t>(orig_code) % 2) == 1) {
-    return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(copy_code) + 1);
+  if ((orig_code % 2) == 1) {
+    return copy_code + 1;
   }
   return copy_code;
 }
@@ -266,7 +355,7 @@
 
   // Every type of method can have an invoke stub
   uint32_t invoke_stub_offset = orig->GetOatInvokeStubOffset();
-  const byte* invoke_stub = (invoke_stub_offset != 0) ? (oat_base_ + invoke_stub_offset) : 0;
+  const byte* invoke_stub = GetOatAddress(invoke_stub_offset);
   copy->invoke_stub_ = reinterpret_cast<const Method::InvokeStub*>(invoke_stub);
 
   if (orig->IsAbstract()) {
@@ -279,7 +368,7 @@
 
   // Non-abstract methods typically have code
   uint32_t code_offset = orig->GetOatCodeOffset();
-  const byte* code = (code_offset != 0) ? (oat_base_ + code_offset) : 0;
+  const byte* code = GetOatAddress(code_offset);
   copy->code_ = code;
 
   if (orig->IsNative()) {
@@ -291,11 +380,11 @@
   } else {
     // normal (non-abstract non-native) methods have mapping tables to relocate
     uint32_t mapping_table_off = orig->GetOatMappingTableOffset();
-    const byte* mapping_table = (mapping_table_off != 0) ? (oat_base_ + mapping_table_off) : 0;
+    const byte* mapping_table = GetOatAddress(mapping_table_off);
     copy->mapping_table_ = reinterpret_cast<const uint32_t*>(mapping_table);
 
     uint32_t vmap_table_offset = orig->GetOatVmapTableOffset();
-    const byte* vmap_table = (vmap_table_offset != 0) ? (oat_base_ + vmap_table_offset) : 0;
+    const byte* vmap_table = GetOatAddress(vmap_table_offset);
     copy->vmap_table_ = reinterpret_cast<const uint16_t*>(vmap_table);
   }
 }
@@ -387,9 +476,10 @@
     if (orig_method != NULL && !InSourceSpace(orig_method)) {
       continue;
     }
-    // if it was resolved in the original, resolve it in the copy
-    if (orig_method == NULL || (orig_method->IsStatic() &&
-                                !orig_method->GetDeclaringClass()->IsInitialized())) {
+    // if it was unresolved or a resolved static method in an uninit class, use a resolution stub
+    // we need to use the stub in the static method case to ensure <clinit> is run.
+    if (orig_method == NULL 
+        || (orig_method->IsStatic() && !orig_method->GetDeclaringClass()->IsInitialized())) {
       uint32_t orig_res_stub_code = orig_cadms->Get(CodeAndDirectMethods::CodeIndex(i));
       if (orig_res_stub_code == 0) {
         continue;  // NULL maps the same in the image and the original
@@ -400,22 +490,13 @@
       if (!InSourceSpace(orig_res_stub_array)) {
         continue;
       }
-      // Compute the delta from the start of the resolution stub to its starting code.
-      // For ARM and X86 this is 0, for Thumb2 it is 1.
-      static size_t res_stub_delta = 0xFFFF;
-      if (res_stub_delta == 0xFFFF) {
-        uint32_t orig_res_stub_array_data =
-            reinterpret_cast<uint32_t>(orig_res_stub_array->GetData());
-        res_stub_delta = orig_res_stub_code - orig_res_stub_array_data;
-        DCHECK(res_stub_delta == 0 || res_stub_delta == 1);
-      }
       // Compute address in image of resolution stub and the code address
       ByteArray* image_res_stub_array = down_cast<ByteArray*>(GetImageAddress(orig_res_stub_array));
-      int32_t image_res_stub_code =
-          reinterpret_cast<int32_t>(image_res_stub_array->GetData()) + res_stub_delta;
+      uint32_t image_res_stub_code = FixupCode(image_res_stub_array, orig_res_stub_code);
       // Put the image code address in the array
       copy_cadms->Set(CodeAndDirectMethods::CodeIndex(i), image_res_stub_code);
     } else if (orig_method->IsDirect()) {
+      // if it was resolved in the original, resolve it in the copy
       Method* copy_method = down_cast<Method*>(GetLocalAddress(orig_method));
       copy_cadms->Set(CodeAndDirectMethods::CodeIndex(i),
                       reinterpret_cast<int32_t>(copy_method->code_));
diff --git a/src/image_writer.h b/src/image_writer.h
index ec17ebf..4e95ee4 100644
--- a/src/image_writer.h
+++ b/src/image_writer.h
@@ -6,6 +6,8 @@
 #include <stdint.h>
 
 #include <cstddef>
+#include <set>
+#include <string>
 
 #include "UniquePtr.h"
 #include "dex_cache.h"
@@ -20,14 +22,18 @@
 // Write a Space built during compilation for use during execution.
 class ImageWriter {
  public:
-  ImageWriter() : source_space_(NULL), image_top_(0), image_base_(NULL) {}
-  bool Write(const char* image_filename, uintptr_t image_base,
-             const std::string& oat_filename, const std::string& strip_location_prefix);
+  ImageWriter(const std::set<std::string>* image_classes)
+      : source_space_(NULL), image_top_(0), image_base_(NULL), image_classes_(image_classes) {}
+
   ~ImageWriter() {}
 
+  bool Write(const char* image_filename,
+             uintptr_t image_base,
+             const std::string& oat_filename,
+             const std::string& strip_location_prefix);
  private:
 
-  bool Init();
+  bool AllocMemory();
 
   // we use the lock word to store the offset of the object in the image
   void AssignImageOffset(Object* object) {
@@ -82,6 +88,22 @@
     return reinterpret_cast<Object*>(dst);
   }
 
+  const byte* GetOatAddress(uint32_t offset) const {
+    DCHECK_LT(offset, oat_file_->GetSize());
+    if (offset == 0) {
+      return NULL;
+    }
+    return oat_base_ + offset;
+  }
+
+  bool IsImageClass(const Class* klass);
+
+  void PruneNonImageClasses();
+  static bool NonImageClassesVisitor(Class* c, void* arg);
+
+  void CheckNonImageClassesRemoved();
+  static void CheckNonImageClassesRemovedCallback(Object* obj, void* arg);
+
   void CalculateNewObjectOffsets();
   ObjectArray<Object>* CreateImageRoots() const;
   static void CalculateNewObjectOffsetsCallback(Object* obj, void* arg);
@@ -114,6 +136,9 @@
   // Target image base address for the output image
   byte* image_base_;
 
+  // Set of classes to be include in the image, or NULL for all.
+  const std::set<std::string>* image_classes_;
+
   // Target oat base address for the pointers from the output image to its oat file
   const byte* oat_base_;
 
diff --git a/src/oat_file.cc b/src/oat_file.cc
index 383bc2a..55493e8 100644
--- a/src/oat_file.cc
+++ b/src/oat_file.cc
@@ -173,54 +173,69 @@
 const OatFile::OatMethod OatFile::OatClass::GetOatMethod(uint32_t method_index) const {
   const OatMethodOffsets& oat_method_offsets = methods_pointer_[method_index];
   return OatMethod(
-      GetOatPointer<const void*>(oat_method_offsets.code_offset_),
+      oat_file_->GetBase(),
+      oat_method_offsets.code_offset_,
       oat_method_offsets.frame_size_in_bytes_,
       oat_method_offsets.core_spill_mask_,
       oat_method_offsets.fp_spill_mask_,
-      GetOatPointer<const uint32_t*>(oat_method_offsets.mapping_table_offset_),
-      GetOatPointer<const uint16_t*>(oat_method_offsets.vmap_table_offset_),
-      GetOatPointer<const Method::InvokeStub*>(oat_method_offsets.invoke_stub_offset_));
+      oat_method_offsets.mapping_table_offset_,
+      oat_method_offsets.vmap_table_offset_,
+      oat_method_offsets.invoke_stub_offset_);
 }
 
-OatFile::OatMethod::OatMethod(const void* code,
+OatFile::OatMethod::OatMethod(const byte* base,
+                              const uint32_t code_offset,
                               const size_t frame_size_in_bytes,
                               const uint32_t core_spill_mask,
                               const uint32_t fp_spill_mask,
-                              const uint32_t* mapping_table,
-                              const uint16_t* vmap_table,
-                              const Method::InvokeStub* invoke_stub)
-  : code_(code),
+                              const uint32_t mapping_table_offset,
+                              const uint32_t vmap_table_offset,
+                              const uint32_t invoke_stub_offset)
+  : base_(base),
+    code_offset_(code_offset),
     frame_size_in_bytes_(frame_size_in_bytes),
     core_spill_mask_(core_spill_mask),
     fp_spill_mask_(fp_spill_mask),
-    mapping_table_(mapping_table),
-    vmap_table_(vmap_table),
-    invoke_stub_(invoke_stub) {
+    mapping_table_offset_(mapping_table_offset),
+    vmap_table_offset_(vmap_table_offset),
+    invoke_stub_offset_(invoke_stub_offset) {
 
 #ifndef NDEBUG
-  if (mapping_table != NULL) {  // implies non-native, non-stub code
-    if (vmap_table_ == NULL) {
+  if (mapping_table_offset_ != 0) {  // implies non-native, non-stub code
+    if (vmap_table_offset_ == 0) {
       DCHECK_EQ(0U, static_cast<uint32_t>(__builtin_popcount(core_spill_mask_) + __builtin_popcount(fp_spill_mask_)));
     } else {
+      const uint16_t* vmap_table_ = reinterpret_cast<const uint16_t*>(base_ + vmap_table_offset_);
       DCHECK_EQ(vmap_table_[0], static_cast<uint32_t>(__builtin_popcount(core_spill_mask_) + __builtin_popcount(fp_spill_mask_)));
     }
   } else {
-    DCHECK(vmap_table_ == NULL);
+    DCHECK(vmap_table_offset_ == 0);
   }
 #endif
 }
 
 OatFile::OatMethod::~OatMethod() {}
 
-void OatFile::OatMethod::LinkMethod(Method* method) const {
+void OatFile::OatMethod::LinkMethodPointers(Method* method) const {
   CHECK(method != NULL);
-  method->SetCode(code_);
+  method->SetCode(GetCode());
   method->SetFrameSizeInBytes(frame_size_in_bytes_);
   method->SetCoreSpillMask(core_spill_mask_);
   method->SetFpSpillMask(fp_spill_mask_);
-  method->SetMappingTable(mapping_table_);
-  method->SetVmapTable(vmap_table_);
-  method->SetInvokeStub(invoke_stub_);
+  method->SetMappingTable(GetMappingTable());
+  method->SetVmapTable(GetVmapTable());
+  method->SetInvokeStub(GetInvokeStub());
+}
+
+void OatFile::OatMethod::LinkMethodOffsets(Method* method) const {
+  CHECK(method != NULL);
+  method->SetOatCodeOffset(GetCodeOffset());
+  method->SetFrameSizeInBytes(GetFrameSizeInBytes());
+  method->SetCoreSpillMask(GetCoreSpillMask());
+  method->SetFpSpillMask(GetFpSpillMask());
+  method->SetOatMappingTableOffset(GetMappingTableOffset());
+  method->SetOatVmapTableOffset(GetVmapTableOffset());
+  method->SetOatInvokeStubOffset(GetInvokeStubOffset());
 }
 
 }  // namespace art
diff --git a/src/oat_file.h b/src/oat_file.h
index 2c39e9d..0e22719 100644
--- a/src/oat_file.h
+++ b/src/oat_file.h
@@ -37,27 +37,79 @@
 
   class OatMethod {
    public:
-    // Create an OatMethod backed by an OatFile
-    OatMethod(const void* code,
-              const size_t frame_size_in_bytes,
-              const uint32_t core_spill_mask,
-              const uint32_t fp_spill_mask,
-              const uint32_t* mapping_table,
-              const uint16_t* vmap_table,
-              const Method::InvokeStub* invoke_stub);
+    // Link Method for execution using the contents of this OatMethod
+    void LinkMethodPointers(Method* method) const;
+
+    // Link Method for image writing using the contents of this OatMethod
+    void LinkMethodOffsets(Method* method) const;
+
+    uint32_t GetCodeOffset() const {
+      return code_offset_;
+    }
+    size_t GetFrameSizeInBytes() const {
+      return frame_size_in_bytes_;
+    }
+    uint32_t GetCoreSpillMask() const {
+      return core_spill_mask_;
+    }
+    uint32_t GetFpSpillMask() const {
+      return fp_spill_mask_;
+    }
+    uint32_t GetMappingTableOffset() const {
+      return mapping_table_offset_;
+    }
+    uint32_t GetVmapTableOffset() const {
+      return vmap_table_offset_;
+    }
+    uint32_t GetInvokeStubOffset() const {
+      return invoke_stub_offset_;
+    }
+
+    const void* GetCode() const {
+      return GetOatPointer<const void*>(code_offset_);
+    }
+    const uint32_t* GetMappingTable() const {
+      return GetOatPointer<const uint32_t*>(mapping_table_offset_);
+    }
+    const uint16_t* GetVmapTable() const {
+      return GetOatPointer<const uint16_t*>(vmap_table_offset_);
+    }
+    const Method::InvokeStub* GetInvokeStub() const {
+      return GetOatPointer<const Method::InvokeStub*>(invoke_stub_offset_);
+    }
 
     ~OatMethod();
 
-    // Link Method using the contents of this OatMethod
-    void LinkMethod(Method* method) const;
+    // Create an OatMethod with offsets relative to the given base address
+    OatMethod(const byte* base,
+              const uint32_t code_offset,
+              const size_t frame_size_in_bytes,
+              const uint32_t core_spill_mask,
+              const uint32_t fp_spill_mask,
+              const uint32_t mapping_table_offset,
+              const uint32_t vmap_table_offset,
+              const uint32_t invoke_stub_offset);
 
-    const void* code_;
+   private:
+    template<class T>
+    T GetOatPointer(uint32_t offset) const {
+      if (offset == 0) {
+        return NULL;
+      }
+      return reinterpret_cast<T>(base_ + offset);
+    }
+
+    const byte* base_;
+
+    uint32_t code_offset_;
     size_t frame_size_in_bytes_;
     uint32_t core_spill_mask_;
     uint32_t fp_spill_mask_;
-    const uint32_t* mapping_table_;
-    const uint16_t* vmap_table_;
-    const Method::InvokeStub* invoke_stub_;
+    uint32_t mapping_table_offset_;
+    uint32_t vmap_table_offset_;
+    uint32_t invoke_stub_offset_;
+
+    friend class OatClass;
   };
 
   class OatClass {
@@ -72,16 +124,6 @@
    private:
     OatClass(const OatFile* oat_file, const OatMethodOffsets* methods_pointer);
 
-    template<class T>
-    T GetOatPointer(uint32_t offset) const {
-      if (offset == 0) {
-        return NULL;
-      }
-      T pointer = reinterpret_cast<T>(oat_file_->GetBase() + offset);
-      CHECK_LT(pointer, reinterpret_cast<T>(oat_file_->GetLimit()));
-      return pointer;
-    }
-
     const OatFile* oat_file_;
     const OatMethodOffsets* methods_pointer_;
 
diff --git a/src/oat_test.cc b/src/oat_test.cc
index 17a00e4..e4af31e 100644
--- a/src/oat_test.cc
+++ b/src/oat_test.cc
@@ -15,7 +15,7 @@
 
   SirtRef<ClassLoader> class_loader(NULL);
   if (compile) {
-    compiler_.reset(new Compiler(kThumb2, false));
+    compiler_.reset(new Compiler(kThumb2, false, NULL));
     compiler_->CompileAll(class_loader.get(), class_linker->GetBootClassPath());
   }
 
@@ -56,12 +56,12 @@
                                                                  method->GetDexMethodIndex()));
 
       if (compiled_method == NULL) {
-        EXPECT_TRUE(oat_method.code_ == NULL) << PrettyMethod(method) << " " << oat_method.code_;
-        EXPECT_EQ(oat_method.frame_size_in_bytes_, static_cast<uint32_t>(kStackAlignment));
-        EXPECT_EQ(oat_method.core_spill_mask_, 0U);
-        EXPECT_EQ(oat_method.fp_spill_mask_, 0U);
+        EXPECT_TRUE(oat_method.GetCode() == NULL) << PrettyMethod(method) << " " << oat_method.GetCode();
+        EXPECT_EQ(oat_method.GetFrameSizeInBytes(), static_cast<uint32_t>(kStackAlignment));
+        EXPECT_EQ(oat_method.GetCoreSpillMask(), 0U);
+        EXPECT_EQ(oat_method.GetFpSpillMask(), 0U);
       } else {
-        const void* oat_code = oat_method.code_;
+        const void* oat_code = oat_method.GetCode();
         uintptr_t oat_code_aligned = RoundDown(reinterpret_cast<uintptr_t>(oat_code), 2);
         oat_code = reinterpret_cast<const void*>(oat_code_aligned);
 
@@ -70,9 +70,9 @@
         EXPECT_EQ(0, memcmp(oat_code, &code[0], code_size))
             << PrettyMethod(method) << " " << code_size;
         CHECK_EQ(0, memcmp(oat_code, &code[0], code_size));
-        EXPECT_EQ(oat_method.frame_size_in_bytes_, compiled_method->GetFrameSizeInBytes());
-        EXPECT_EQ(oat_method.core_spill_mask_, compiled_method->GetCoreSpillMask());
-        EXPECT_EQ(oat_method.fp_spill_mask_, compiled_method->GetFpSpillMask());
+        EXPECT_EQ(oat_method.GetFrameSizeInBytes(), compiled_method->GetFrameSizeInBytes());
+        EXPECT_EQ(oat_method.GetCoreSpillMask(), compiled_method->GetCoreSpillMask());
+        EXPECT_EQ(oat_method.GetFpSpillMask(), compiled_method->GetFpSpillMask());
       }
     }
     for (size_t i = 0; i < num_virtual_methods; i++, method_index++) {
@@ -83,12 +83,12 @@
                                                                  method->GetDexMethodIndex()));
 
       if (compiled_method == NULL) {
-        EXPECT_TRUE(oat_method.code_ == NULL) << PrettyMethod(method) << " " << oat_method.code_;
-        EXPECT_EQ(oat_method.frame_size_in_bytes_, static_cast<uint32_t>(kStackAlignment));
-        EXPECT_EQ(oat_method.core_spill_mask_, 0U);
-        EXPECT_EQ(oat_method.fp_spill_mask_, 0U);
+        EXPECT_TRUE(oat_method.GetCode() == NULL) << PrettyMethod(method) << " " << oat_method.GetCode();
+        EXPECT_EQ(oat_method.GetFrameSizeInBytes(), static_cast<uint32_t>(kStackAlignment));
+        EXPECT_EQ(oat_method.GetCoreSpillMask(), 0U);
+        EXPECT_EQ(oat_method.GetFpSpillMask(), 0U);
       } else {
-        const void* oat_code = oat_method.code_;
+        const void* oat_code = oat_method.GetCode();
         EXPECT_TRUE(oat_code != NULL) << PrettyMethod(method);
         uintptr_t oat_code_aligned = RoundDown(reinterpret_cast<uintptr_t>(oat_code), 2);
         oat_code = reinterpret_cast<const void*>(oat_code_aligned);
@@ -98,9 +98,9 @@
         EXPECT_EQ(0, memcmp(oat_code, &code[0], code_size))
             << PrettyMethod(method) << " " << code_size;
         CHECK_EQ(0, memcmp(oat_code, &code[0], code_size));
-        EXPECT_EQ(oat_method.frame_size_in_bytes_, compiled_method->GetFrameSizeInBytes());
-        EXPECT_EQ(oat_method.core_spill_mask_, compiled_method->GetCoreSpillMask());
-        EXPECT_EQ(oat_method.fp_spill_mask_, compiled_method->GetFpSpillMask());
+        EXPECT_EQ(oat_method.GetFrameSizeInBytes(), compiled_method->GetFrameSizeInBytes());
+        EXPECT_EQ(oat_method.GetCoreSpillMask(), compiled_method->GetCoreSpillMask());
+        EXPECT_EQ(oat_method.GetFpSpillMask(), compiled_method->GetFpSpillMask());
       }
     }
   }
diff --git a/src/oatdump.cc b/src/oatdump.cc
index 2d5732f..ac9449f 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -177,23 +177,19 @@
     os << StringPrintf("\t%d: %s %s (method_idx=%d)\n",
                        method_index, name, signature.c_str(), method_idx);
     os << StringPrintf("\t\tcode: %p (offset=%08x)\n",
-                       oat_method.code_,
-                       reinterpret_cast<const byte*>(oat_method.code_) - oat_file.GetBase());
+                       oat_method.GetCode(), oat_method.GetCodeOffset());
     os << StringPrintf("\t\tframe_size_in_bytes: %d\n",
-                       oat_method.frame_size_in_bytes_);
+                       oat_method.GetFrameSizeInBytes());
     os << StringPrintf("\t\tcore_spill_mask: %08x\n",
-                       oat_method.core_spill_mask_);
+                       oat_method.GetCoreSpillMask());
     os << StringPrintf("\t\tfp_spill_mask: %08x\n",
-                       oat_method.fp_spill_mask_);
+                       oat_method.GetFpSpillMask());
     os << StringPrintf("\t\tmapping_table: %p (offset=%08x)\n",
-                       oat_method.mapping_table_,
-                       reinterpret_cast<const byte*>(oat_method.mapping_table_) - oat_file.GetBase());
+                       oat_method.GetMappingTable(), oat_method.GetMappingTableOffset());
     os << StringPrintf("\t\tvmap_table: %p (offset=%08x)\n",
-                       oat_method.vmap_table_,
-                       reinterpret_cast<const byte*>(oat_method.vmap_table_) - oat_file.GetBase());
+                       oat_method.GetVmapTable(), oat_method.GetVmapTableOffset());
     os << StringPrintf("\t\tinvoke_stub: %p (offset=%08x)\n",
-                       oat_method.invoke_stub_,
-                       reinterpret_cast<const byte*>(oat_method.invoke_stub_) - oat_file.GetBase());
+                       oat_method.GetInvokeStub(), oat_method.GetInvokeStubOffset());
   }
 };
 
@@ -268,7 +264,7 @@
       os << " (" << oat_location << ")";
     }
     os << "\n";
-    const OatFile* oat_file = class_linker->FindOatFile(oat_location);
+    const OatFile* oat_file = class_linker->FindOatFileFromOatLocation(oat_location);
     if (oat_file == NULL) {
       os << "NOT FOUND\n";
       os << std::flush;
@@ -353,8 +349,10 @@
         DCHECK(method->GetGcMap() == NULL) << PrettyMethod(method);
         DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method);
       } else {
-        size_t register_map_bytes = method->GetGcMap()->SizeOf();
-        state->stats_.register_map_bytes += register_map_bytes;
+        if (method->GetGcMap() != NULL) {
+          size_t register_map_bytes = method->GetGcMap()->SizeOf();
+          state->stats_.register_map_bytes += register_map_bytes;
+        }
 
         if (method->GetMappingTable() != NULL) {
           size_t pc_mapping_table_bytes = method->GetMappingTableLength();
diff --git a/src/object.cc b/src/object.cc
index 8cf79c2..abf8310 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -209,100 +209,100 @@
 }
 
 bool Field::GetBoolean(const Object* object) const {
-  DCHECK(GetPrimitiveType() == Primitive::kPrimBoolean) << PrettyField(this);
+  DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimBoolean) << PrettyField(this);
   return Get32(object);
 }
 
 void Field::SetBoolean(Object* object, bool z) const {
-  DCHECK(GetPrimitiveType() == Primitive::kPrimBoolean) << PrettyField(this);
+  DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimBoolean) << PrettyField(this);
   Set32(object, z);
 }
 
 int8_t Field::GetByte(const Object* object) const {
-  DCHECK(GetPrimitiveType() == Primitive::kPrimByte) << PrettyField(this);
+  DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimByte) << PrettyField(this);
   return Get32(object);
 }
 
 void Field::SetByte(Object* object, int8_t b) const {
-  DCHECK(GetPrimitiveType() == Primitive::kPrimByte) << PrettyField(this);
+  DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimByte) << PrettyField(this);
   Set32(object, b);
 }
 
 uint16_t Field::GetChar(const Object* object) const {
-  DCHECK(GetPrimitiveType() == Primitive::kPrimChar) << PrettyField(this);
+  DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimChar) << PrettyField(this);
   return Get32(object);
 }
 
 void Field::SetChar(Object* object, uint16_t c) const {
-  DCHECK(GetPrimitiveType() == Primitive::kPrimChar) << PrettyField(this);
+  DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimChar) << PrettyField(this);
   Set32(object, c);
 }
 
 int16_t Field::GetShort(const Object* object) const {
-  DCHECK(GetPrimitiveType() == Primitive::kPrimShort) << PrettyField(this);
+  DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimShort) << PrettyField(this);
   return Get32(object);
 }
 
 void Field::SetShort(Object* object, int16_t s) const {
-  DCHECK(GetPrimitiveType() == Primitive::kPrimShort) << PrettyField(this);
+  DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimShort) << PrettyField(this);
   Set32(object, s);
 }
 
 int32_t Field::GetInt(const Object* object) const {
-  DCHECK(GetPrimitiveType() == Primitive::kPrimInt) << PrettyField(this);
+  DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimInt) << PrettyField(this);
   return Get32(object);
 }
 
 void Field::SetInt(Object* object, int32_t i) const {
-  DCHECK(GetPrimitiveType() == Primitive::kPrimInt) << PrettyField(this);
+  DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimInt) << PrettyField(this);
   Set32(object, i);
 }
 
 int64_t Field::GetLong(const Object* object) const {
-  DCHECK(GetPrimitiveType() == Primitive::kPrimLong) << PrettyField(this);
+  DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimLong) << PrettyField(this);
   return Get64(object);
 }
 
 void Field::SetLong(Object* object, int64_t j) const {
-  DCHECK(GetPrimitiveType() == Primitive::kPrimLong) << PrettyField(this);
+  DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimLong) << PrettyField(this);
   Set64(object, j);
 }
 
 float Field::GetFloat(const Object* object) const {
-  DCHECK(GetPrimitiveType() == Primitive::kPrimFloat) << PrettyField(this);
+  DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimFloat) << PrettyField(this);
   JValue float_bits;
   float_bits.i = Get32(object);
   return float_bits.f;
 }
 
 void Field::SetFloat(Object* object, float f) const {
-  DCHECK(GetPrimitiveType() == Primitive::kPrimFloat) << PrettyField(this);
+  DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimFloat) << PrettyField(this);
   JValue float_bits;
   float_bits.f = f;
   Set32(object, float_bits.i);
 }
 
 double Field::GetDouble(const Object* object) const {
-  DCHECK(GetPrimitiveType() == Primitive::kPrimDouble) << PrettyField(this);
+  DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimDouble) << PrettyField(this);
   JValue double_bits;
   double_bits.j = Get64(object);
   return double_bits.d;
 }
 
 void Field::SetDouble(Object* object, double d) const {
-  DCHECK(GetPrimitiveType() == Primitive::kPrimDouble) << PrettyField(this);
+  DCHECK_EQ(GetPrimitiveType(), Primitive::kPrimDouble) << PrettyField(this);
   JValue double_bits;
   double_bits.d = d;
   Set64(object, double_bits.j);
 }
 
 Object* Field::GetObject(const Object* object) const {
-  CHECK(GetPrimitiveType() == Primitive::kPrimNot) << PrettyField(this);
+  CHECK_EQ(GetPrimitiveType(), Primitive::kPrimNot) << PrettyField(this);
   return GetObj(object);
 }
 
 void Field::SetObject(Object* object, const Object* l) const {
-  CHECK(GetPrimitiveType() == Primitive::kPrimNot) << PrettyField(this);
+  CHECK_EQ(GetPrimitiveType(), Primitive::kPrimNot) << PrettyField(this);
   SetObj(object, l);
 }
 
diff --git a/src/primitive.cc b/src/primitive.cc
new file mode 100644
index 0000000..16ca0fe
--- /dev/null
+++ b/src/primitive.cc
@@ -0,0 +1,43 @@
+/*
+ * 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 "primitive.h"
+
+namespace art {
+
+static const char* kTypeNames[] = {
+  "PrimNot",
+  "PrimBoolean",
+  "PrimByte",
+  "PrimChar",
+  "PrimShort",
+  "PrimInt",
+  "PrimLong",
+  "PrimFloat",
+  "PrimDouble",
+  "PrimVoid",
+};
+std::ostream& operator<<(std::ostream& os, const Primitive::Type& type) {
+  int32_t int_type = static_cast<int32_t>(type);
+  if (type >= Primitive::kPrimNot && type <= Primitive::kPrimVoid) {
+    os << kTypeNames[int_type];
+  } else {
+    os << "Type[" << int_type << "]";
+  }
+  return os;
+}
+
+}  // namespace art
diff --git a/src/primitive.h b/src/primitive.h
index 240892f..5d41966 100644
--- a/src/primitive.h
+++ b/src/primitive.h
@@ -116,6 +116,8 @@
   DISALLOW_IMPLICIT_CONSTRUCTORS(Primitive);
 };
 
+std::ostream& operator<<(std::ostream& os, const Primitive::Type& state);
+
 }  // namespace art
 
 #endif  // ART_SRC_PRIMITIVE_H_
diff --git a/src/runtime.cc b/src/runtime.cc
index 656fdb8..f52bca8 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -446,10 +446,12 @@
   // Restore main thread state to kNative as expected by native code
   Thread::Current()->SetState(Thread::kNative);
 
-  InitNativeMethods();
-
   started_ = true;
 
+  // InitNativeMethods needs to be after started_ so that the classes
+  // it touches will have methods linked to the oat file if necessary.
+  InitNativeMethods();
+
   Thread::FinishStartup();
 
   if (!is_zygote_) {
@@ -564,9 +566,10 @@
   Thread::Current()->SetState(Thread::kRunnable);
 
   CHECK_GE(Heap::GetSpaces().size(), 1U);
+  bool verbose_class = options->IsVerbose("class");
   class_linker_ = ((Heap::GetSpaces()[0]->IsImageSpace())
-                   ? ClassLinker::Create(intern_table_)
-                   : ClassLinker::Create(options->boot_class_path_, intern_table_));
+                   ? ClassLinker::Create(verbose_class, intern_table_)
+                   : ClassLinker::Create(verbose_class, options->boot_class_path_, intern_table_));
 
   if (IsVerboseStartup()) {
     LOG(INFO) << "Runtime::Init exiting";
@@ -793,7 +796,7 @@
   resolution_stub_array_[type] = resolution_stub_array;
 }
 
-Method* Runtime::CreateCalleeSaveMethod(InstructionSet insns, CalleeSaveType type) {
+Method* Runtime::CreateCalleeSaveMethod(InstructionSet instruction_set, CalleeSaveType type) {
   Class* method_class = Method::GetMethodClass();
   SirtRef<Method> method(down_cast<Method*>(method_class->AllocObject()));
   method->SetDeclaringClass(method_class);
@@ -811,7 +814,7 @@
   method->SetSignature(intern_table_->InternStrong("()V"));
   CHECK(method->GetSignature() != NULL);
   method->SetCode(NULL);
-  if ((insns == kThumb2) || (insns == kArm)) {
+  if ((instruction_set == kThumb2) || (instruction_set == kArm)) {
     uint32_t ref_spills = (1 << art::arm::R5) | (1 << art::arm::R6)  | (1 << art::arm::R7) |
                           (1 << art::arm::R8) | (1 << art::arm::R10) | (1 << art::arm::R11);
     uint32_t arg_spills = (1 << art::arm::R1) | (1 << art::arm::R2) | (1 << art::arm::R3);
@@ -836,7 +839,7 @@
     method->SetFrameSizeInBytes(frame_size);
     method->SetCoreSpillMask(core_spills);
     method->SetFpSpillMask(fp_spills);
-  } else if (insns == kX86) {
+  } else if (instruction_set == kX86) {
     method->SetFrameSizeInBytes(32);
     method->SetCoreSpillMask((1 << art::x86::EBX) | (1 << art::x86::EBP) | (1 << art::x86::ESI) |
                              (1 << art::x86::EDI));
diff --git a/src/runtime.h b/src/runtime.h
index 50f9ed1..1d9a3d1 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -190,13 +190,13 @@
     kRefsAndArgs,
     kLastCalleeSaveType  // Value used for iteration
   };
-  Method* CreateCalleeSaveMethod(InstructionSet insns, CalleeSaveType type);
+  Method* CreateCalleeSaveMethod(InstructionSet instruction_set, CalleeSaveType type);
   bool HasCalleeSaveMethod(CalleeSaveType type) const;
   Method* GetCalleeSaveMethod(CalleeSaveType type) const;
   void SetCalleeSaveMethod(Method* method, CalleeSaveType type);
 
-  Method* CreateRefOnlyCalleeSaveMethod(InstructionSet insns);
-  Method* CreateRefAndArgsCalleeSaveMethod(InstructionSet insns);
+  Method* CreateRefOnlyCalleeSaveMethod(InstructionSet instruction_set);
+  Method* CreateRefAndArgsCalleeSaveMethod(InstructionSet instruction_set);
 
   int32_t GetStat(int kind);