Working dex2oat and oatexec

adb shell dex2oatd --dex-file=/system/framework/core.jar     --image=/system/framework/boot.oat --base=0x50000000 "'--method=Ljava/lang/System;logI(Ljava/lang/String;)V'" "'--method=Ljava/lang/System;log(CLjava/lang/String;Ljava/lang/Throwable;)V'"
adb shell dex2oatd --boot-dex-file=/system/framework/core.jar --boot=/system/framework/boot.oat --dex-file=/system/framework/art-test-dex-HelloWorld.jar --image=/system/framework/art-test-dex-HelloWorld.oat
adb shell oatexecd -Xbootclasspath:/system/framework/core.jar -Xbootimage:/system/framework/boot.oat -classpath /system/framework/art-test-dex-HelloWorld.jar -Ximage:/system/framework/art-test-dex-HelloWorld.oat HelloWorld

09-05 17:58:18.912  2385  2385 I System  : Hello, world!

Change-Id: I53e534068584f0c3a837313e4d517a0e4a7154fc
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 7cd320e..211b87d 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -56,12 +56,14 @@
 };
 
 ClassLinker* ClassLinker::Create(const std::vector<const DexFile*>& boot_class_path,
-    InternTable* intern_table, Space* space) {
+                                 const std::vector<const DexFile*>& class_path,
+                                 InternTable* intern_table, Space* space) {
+  CHECK_NE(boot_class_path.size(), 0U);
   UniquePtr<ClassLinker> class_linker(new ClassLinker(intern_table));
   if (space == NULL) {
-    class_linker->Init(boot_class_path);
+    class_linker->Init(boot_class_path, class_path);
   } else {
-    class_linker->Init(boot_class_path, space);
+    class_linker->Init(boot_class_path, class_path, space);
   }
   // TODO: check for failure during initialization
   return class_linker.release();
@@ -76,7 +78,8 @@
       intern_table_(intern_table) {
 }
 
-void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path) {
+void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path,
+                       const std::vector<const DexFile*>& class_path) {
   CHECK(!init_done_);
 
   // java_lang_Class comes first, its needed for AllocClass
@@ -160,13 +163,18 @@
 
   // now that these are registered, we can use AllocClass() and AllocObjectArray
 
-  // setup boot_class_path_ now that we can use AllocObjectArray to
-  // create DexCache instances
+  // setup boot_class_path_ and register class_path now that we can
+  // use AllocObjectArray to create DexCache instances
   for (size_t i = 0; i != boot_class_path.size(); ++i) {
     const DexFile* dex_file = boot_class_path[i];
     CHECK(dex_file != NULL);
     AppendToBootClassPath(*dex_file);
   }
+  for (size_t i = 0; i != class_path.size(); ++i) {
+    const DexFile* dex_file = class_path[i];
+    CHECK(dex_file != NULL);
+    RegisterDexFile(*dex_file);
+  }
 
   // Field and Method are necessary so that FindClass can link members
   Class* java_lang_reflect_Field = AllocClass(java_lang_Class, sizeof(FieldClass));
@@ -366,16 +374,13 @@
   typedef std::tr1::unordered_map<std::string, ClassRoot> Table;
   Table descriptor_to_class_root;
 
-  struct DexCacheHash {
-    size_t operator()(art::DexCache* const& obj) const {
-      return reinterpret_cast<size_t>(&obj);
-    }
-  };
   typedef std::tr1::unordered_set<DexCache*, DexCacheHash> Set;
   Set dex_caches;
 };
 
-void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path, Space* space) {
+void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path,
+                       const std::vector<const DexFile*>& class_path,
+                       Space* space) {
   CHECK(!init_done_);
 
   HeapBitmap* heap_bitmap = Heap::GetLiveBits();
@@ -400,6 +405,7 @@
   }
 
   // reinit intern table
+  // TODO: remove interned_array, make all strings in image interned (and remove space argument)
   ObjectArray<Object>* interned_array = space->GetImageHeader().GetInternedArray();
   for (int32_t i = 0; i < interned_array->GetLength(); i++) {
     String* string = interned_array->Get(i)->AsString();
@@ -418,14 +424,27 @@
     std::string location = dex_cache->GetLocation()->ToModifiedUtf8();
     location_to_dex_cache[location] = dex_cache;
   }
+  CHECK_EQ(boot_class_path.size() + class_path.size(),
+           location_to_dex_cache.size());
 
   // reinit boot_class_path with DexFile arguments and found DexCaches
   for (size_t i = 0; i != boot_class_path.size(); ++i) {
     const DexFile* dex_file = boot_class_path[i];
     CHECK(dex_file != NULL);
     DexCache* dex_cache = location_to_dex_cache[dex_file->GetLocation()];
+    CHECK(dex_cache != NULL) << dex_file->GetLocation();
     AppendToBootClassPath(*dex_file, dex_cache);
   }
+
+  // register class_path with DexFile arguments and found DexCaches
+  for (size_t i = 0; i != class_path.size(); ++i) {
+    const DexFile* dex_file = class_path[i];
+    CHECK(dex_file != NULL);
+    DexCache* dex_cache = location_to_dex_cache[dex_file->GetLocation()];
+    CHECK(dex_cache != NULL) << dex_file->GetLocation();
+    RegisterDexFile(*dex_file, dex_cache);
+  }
+
   String::SetClass(GetClassRoot(kJavaLangString));
   Field::SetClass(GetClassRoot(kJavaLangReflectField));
   Method::SetClass(GetClassRoot(kJavaLangReflectMethod));
@@ -452,10 +471,15 @@
     return;
   }
   Class* klass = obj->AsClass();
-  CHECK(klass->GetClassLoader() == NULL);
+  // TODO: restore ClassLoader's list of DexFiles after image load
+  // CHECK(klass->GetClassLoader() == NULL);
+  const ClassLoader* class_loader = klass->GetClassLoader();
+  if (class_loader != NULL) {
+    // TODO: replace this hack with something based on command line arguments
+    Thread::Current()->SetClassLoaderOverride(class_loader);
+  }
 
   std::string descriptor = klass->GetDescriptor()->ToModifiedUtf8();
-
   // restore class to ClassLinker::classes_ table
   state->class_linker->InsertClass(descriptor, klass);
 
@@ -900,7 +924,7 @@
 }
 
 void ClassLinker::AppendToBootClassPath(const DexFile& dex_file, DexCache* dex_cache) {
-  CHECK(dex_cache != NULL);
+  CHECK(dex_cache != NULL) << dex_file.GetLocation();
   boot_class_path_.push_back(&dex_file);
   RegisterDexFile(dex_file, dex_cache);
 }
@@ -910,7 +934,8 @@
 }
 
 void ClassLinker::RegisterDexFile(const DexFile& dex_file, DexCache* dex_cache) {
-  CHECK(dex_cache != NULL);
+  CHECK(dex_cache != NULL) << dex_file.GetLocation();
+  CHECK(dex_cache->GetLocation()->Equals(dex_file.GetLocation()));
   dex_files_.push_back(&dex_file);
   dex_caches_.push_back(dex_cache);
 }
@@ -921,7 +946,7 @@
         return *dex_files_[i];
     }
   }
-  CHECK(false) << "Could not find DexFile";
+  CHECK(false) << "Failed to find DexFile for DexCache " << dex_cache->GetLocation()->ToModifiedUtf8();
   return *dex_files_[-1];
 }
 
@@ -931,7 +956,7 @@
         return dex_caches_[i];
     }
   }
-  CHECK(false) << "Could not find DexCache";
+  CHECK(false) << "Failed to find DexCache for DexFile " << dex_file.GetLocation();
   return NULL;
 }
 
@@ -1544,7 +1569,7 @@
     return false;
   }
   if (!klass->CanAccess(super)) {
-    LG << "Superclass " << super->GetDescriptor()->ToModifiedUtf8() << " is  inaccessible";  // TODO: IllegalAccessError
+    LG << "Superclass " << super->GetDescriptor()->ToModifiedUtf8() << " is inaccessible";  // TODO: IllegalAccessError
     return false;
   }
 #ifndef NDEBUG