Add --image-classes to dex2oat

Change-Id: Ia88f9d302e0f9cd72be2199ee46d212d99864c67
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();
   }