Working ClassLoader

Change-Id: Ia1122165e47f846a1d4506111849f830d9f14c1b
diff --git a/Android.mk b/Android.mk
index 97bf41a..9a53fd0 100644
--- a/Android.mk
+++ b/Android.mk
@@ -166,7 +166,7 @@
 # oatdump targets
 
 .PHONY: dump-oat
-dump-oat: dump-oat-core dump-oat-boot dump-oat-Calculator
+dump-oat: dump-oat-core dump-oat-boot # dump-oat-Calculator # TODO: restore when oatdump can dump an oat without an image
 
 .PHONY: dump-oat-core
 dump-oat-core: $(TARGET_CORE_OAT) $(OATDUMP)
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 605c48b..a45c644 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -27,6 +27,7 @@
 
 art_cflags := \
 	-O2 \
+	-O0 \
 	-ggdb3 \
 	-Wall \
 	-Werror \
@@ -178,6 +179,7 @@
 
 TEST_COMMON_SRC_FILES := \
 	src/class_linker_test.cc \
+	src/compiler_test.cc \
 	src/dex_cache_test.cc \
 	src/dex_file_test.cc \
 	src/dex_instruction_visitor_test.cc \
@@ -198,8 +200,7 @@
 	src/runtime_test.cc \
 	src/space_test.cc \
 	src/utils_test.cc \
-	src/zip_archive_test.cc \
-	src/compiler_test.cc
+	src/zip_archive_test.cc
 
 TEST_TARGET_SRC_FILES := \
 	$(TEST_COMMON_SRC_FILES)
diff --git a/build/Android.oattest.mk b/build/Android.oattest.mk
index b3dee96..6dfbf99 100644
--- a/build/Android.oattest.mk
+++ b/build/Android.oattest.mk
@@ -40,7 +40,7 @@
 # TODO: change DEX2OATD (and perhaps $(2) boot oat) to order-only prerequisite when output is stable
 $(patsubst %.apk,%.oat,$(patsubst %.jar,%.oat,$(1))): $(1) $(2) $(DEX2OAT)
 	@echo "target dex2oat: $$@ ($$<)"
-	$(hide) $(DEX2OAT) -Xms16m -Xmx16m --boot-image=$(patsubst %.oat,%.art,$(2)) $(addprefix --dex-file=,$$<) --oat=$$@ --image=$$(patsubst %.oat,%.art,$$@) --host-prefix=$(PRODUCT_OUT)
+	$(hide) $(DEX2OAT) -Xms16m -Xmx16m --boot-image=$(patsubst %.oat,%.art,$(2)) $(addprefix --dex-file=,$$<) --oat=$$@ --host-prefix=$(PRODUCT_OUT)
 endef
 
 ########################################################################
@@ -64,7 +64,7 @@
 test-art-target-oat-$(1): test-art-target-sync
 	adb shell touch /sdcard/test-art-target-oat-$(1)
 	adb shell rm /sdcard/test-art-target-oat-$(1)
-	adb shell sh -c "oatexecd -Ximage:/system/framework/core.art -classpath /system/framework/art-test-dex-$(1).jar -Ximage:/system/framework/art-test-dex-$(1).art $(1) $(2) && touch /sdcard/test-art-target-oat-$(1)"
+	adb shell sh -c "oatexecd -Ximage:/system/framework/core.art -classpath /system/framework/art-test-dex-$(1).jar $(1) $(2) && touch /sdcard/test-art-target-oat-$(1)"
 	$(hide) (adb pull /sdcard/test-art-target-oat-$(1) /tmp/ && echo test-art-target-oat-$(1) PASSED) || (echo test-art-target-oat-$(1) FAILED && exit 1)
 	$(hide) rm /tmp/test-art-target-oat-$(1)
 
diff --git a/oat_process/app_main.cpp b/oat_process/app_main.cpp
index e769907..53321f1 100644
--- a/oat_process/app_main.cpp
+++ b/oat_process/app_main.cpp
@@ -82,52 +82,6 @@
         free(slashClassName);
 
         mClass = reinterpret_cast<jclass>(env->NewGlobalRef(mClass));
-
-        // TODO: remove this ClassLoader code
-        jclass ApplicationLoaders = env->FindClass("android/app/ApplicationLoaders");
-        jmethodID getDefault = env->GetStaticMethodID(ApplicationLoaders,
-                                                      "getDefault",
-                                                      "()Landroid/app/ApplicationLoaders;");
-        jfieldID mLoaders = env->GetFieldID(ApplicationLoaders, "mLoaders", "Ljava/util/Map;");
-        jclass BootClassLoader = env->FindClass("java/lang/BootClassLoader");
-        jmethodID getInstance = env->GetStaticMethodID(BootClassLoader,
-                                                       "getInstance",
-                                                       "()Ljava/lang/BootClassLoader;");
-        jclass ClassLoader = env->FindClass("java/lang/ClassLoader");
-        jfieldID parent = env->GetFieldID(ClassLoader, "parent", "Ljava/lang/ClassLoader;");
-        jclass Map = env->FindClass("java/util/Map");
-        jmethodID put = env->GetMethodID(Map,
-                                         "put",
-                                         "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
-        jclass BaseDexClassLoader = env->FindClass("dalvik/system/BaseDexClassLoader");
-        jfieldID originalPath = env->GetFieldID(BaseDexClassLoader, "originalPath", "Ljava/lang/String;");
-        jfieldID pathList = env->GetFieldID(BaseDexClassLoader, "pathList", "Ldalvik/system/DexPathList;");
-        jclass DexPathList = env->FindClass("dalvik/system/DexPathList");
-        jmethodID init = env->GetMethodID(DexPathList,
-                                          "<init>",
-                                          "(Ljava/lang/ClassLoader;Ljava/lang/String;Ljava/lang/String;Ljava/io/File;)V");
-
-        // Set the parent of our pre-existing ClassLoader to the non-null BootClassLoader.getInstance()
-        const art::ClassLoader* class_loader_object = art::Thread::Current()->GetClassLoaderOverride();
-        jobject class_loader = art::AddLocalReference<jobject>(env, class_loader_object);
-        jobject boot_class_loader = env->CallStaticObjectMethod(BootClassLoader, getInstance);
-        env->SetObjectField(class_loader, parent, boot_class_loader);
-
-        // Create a DexPathList
-        jstring dex_path = env->NewStringUTF("/system/app/Calculator.apk");
-        jstring library_path = env->NewStringUTF("/data/data/com.android.calculator2/lib");
-        jobject dex_path_list = env->NewObject(DexPathList, init,
-                                               boot_class_loader, dex_path, library_path, NULL);
-
-        // Set DexPathList into our pre-existing ClassLoader
-        env->SetObjectField(class_loader, pathList, dex_path_list);
-        env->SetObjectField(class_loader, originalPath, dex_path);
-
-        // Stash our pre-existing ClassLoader into ApplicationLoaders.getDefault().mLoaders
-        // under the expected name.
-        jobject application_loaders = env->CallStaticObjectMethod(ApplicationLoaders, getDefault);
-        jobject loaders = env->GetObjectField(application_loaders, mLoaders);
-        env->CallObjectMethod(loaders, put, dex_path, class_loader);
     }
 
     virtual void onStarted()
@@ -209,14 +163,12 @@
         }
     }
 
-    // TODO: remove Calculator special case
-    int oatArgc = argc + 2;
+    // TODO: remove when we default the boot image
+    int oatArgc = argc + 1;
     const char* oatArgv[oatArgc];
     if (strcmp(argv[0], "-Ximage:/system/framework/boot.art") != 0) {
-        LOG(INFO) << "Adding oat arguments";
+        LOG(INFO) << "Adding image arguments";
         oatArgv[0] = "-Ximage:/system/framework/boot.art";
-        oatArgv[1] = "-Ximage:/system/app/Calculator.art";
-        setenv("CLASSPATH", "/system/app/Calculator.apk", 1);
         memcpy(oatArgv + (oatArgc - argc), argv, argc * sizeof(*argv));
         argv = oatArgv;
         argc = oatArgc;
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 8ca633b..3f30b9e 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -436,10 +436,9 @@
       java_lang_ref_WeakReference->GetAccessFlags() |
           kAccClassIsReference | kAccClassIsWeakReference);
 
-  // Setup the ClassLoaders, adjusting the object_size_ as necessary
+  // Setup the ClassLoaders, verifying the object_size_
   Class* java_lang_ClassLoader = FindSystemClass("Ljava/lang/ClassLoader;");
-  CHECK_LT(java_lang_ClassLoader->GetObjectSize(), sizeof(ClassLoader));
-  java_lang_ClassLoader->SetObjectSize(sizeof(ClassLoader));
+  CHECK_EQ(java_lang_ClassLoader->GetObjectSize(), sizeof(ClassLoader));
   SetClassRoot(kJavaLangClassLoader, java_lang_ClassLoader);
 
   Class* dalvik_system_BaseDexClassLoader = FindSystemClass("Ldalvik/system/BaseDexClassLoader;");
@@ -539,6 +538,7 @@
 }
 
 OatFile* ClassLinker::OpenOat(const Space* space) {
+  MutexLock mu(lock_);
   const Runtime* runtime = Runtime::Current();
   if (runtime->IsVerboseStartup()) {
     LOG(INFO) << "ClassLinker::OpenOat entering";
@@ -568,6 +568,37 @@
   return oat_file;
 }
 
+const OatFile* ClassLinker::FindOatFile(const DexFile& dex_file) {
+  MutexLock mu(lock_);
+  std::string dex_file_location = dex_file.GetLocation();
+  std::string location(dex_file_location);
+  CHECK(StringPiece(location).ends_with(".dex")
+        || StringPiece(location).ends_with(".zip")
+        || StringPiece(location).ends_with(".jar")
+        || StringPiece(location).ends_with(".apk"));
+  location.erase(location.size()-3);
+  location += "oat";
+  // TODO: check if dex_file matches an OatDexFile location and checksum
+  return FindOatFile(location);
+}
+
+const OatFile* ClassLinker::FindOatFile(const std::string& 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) {
+      return oat_file;
+    }
+  }
+
+  const OatFile* oat_file = OatFile::Open(location, "", NULL);
+  if (oat_file == NULL) {
+    LOG(ERROR) << "Failed to open oat file " << location;
+    return NULL;
+  }
+  return oat_file;
+}
+
 void ClassLinker::InitFromImage() {
   const Runtime* runtime = Runtime::Current();
   if (runtime->IsVerboseStartup()) {
@@ -599,8 +630,8 @@
                      << " referenced from oat file as " << dex_file_location;
         }
 
-        const OatFile::OatDexFile& oat_dex_file = oat_file->GetOatDexFile(dex_file_location);
-        CHECK_EQ(dex_file->GetHeader().checksum_, oat_dex_file.GetDexFileChecksum());
+        const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file_location);
+        CHECK_EQ(dex_file->GetHeader().checksum_, oat_dex_file->GetDexFileChecksum());
 
         RegisterDexFile(*dex_file, dex_cache);
       }
@@ -653,21 +684,13 @@
     class_linker->intern_table_->RegisterStrong(obj->AsString());
     return;
   }
-  if (!obj->IsClass()) {
+  if (obj->IsClass()) {
+    // restore class to ClassLinker::classes_ table
+    Class* klass = obj->AsClass();
+    std::string descriptor = klass->GetDescriptor()->ToModifiedUtf8();
+    class_linker->InsertClass(descriptor, klass);
     return;
   }
-  Class* klass = obj->AsClass();
-  // 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
-  class_linker->InsertClass(descriptor, klass);
 }
 
 // Keep in sync with InitCallback. Anything we visit, we need to
@@ -759,100 +782,10 @@
       length);
 }
 
-Class* ClassLinker::FindClass(const StringPiece& descriptor,
-                              const ClassLoader* class_loader) {
-  // TODO: remove this contrived parent class loader check when we have a real ClassLoader.
-  if (class_loader != NULL) {
-    Class* klass = FindClass(descriptor, NULL);
-    if (klass != NULL) {
-      return klass;
-    }
-    Thread::Current()->ClearException();
-  }
-
+Class* EnsureResolved(Class* klass) {
+  DCHECK(klass != NULL);
+  // Wait for the class if it has not already been linked.
   Thread* self = Thread::Current();
-  DCHECK(self != NULL);
-  CHECK(!self->IsExceptionPending()) << PrettyTypeOf(self->GetException());
-  // Find the class in the loaded classes table.
-  Class* klass = LookupClass(descriptor, class_loader);
-  if (klass == NULL) {
-    // Class is not yet loaded.
-    if (descriptor[0] == '[' && descriptor[1] != '\0') {
-      return CreateArrayClass(descriptor, class_loader);
-    }
-    const DexFile::ClassPath& class_path = ((class_loader != NULL)
-                                            ? ClassLoader::GetClassPath(class_loader)
-                                            : boot_class_path_);
-    DexFile::ClassPathEntry pair = DexFile::FindInClassPath(descriptor, class_path);
-    if (pair.second == NULL) {
-      std::string name(PrintableString(descriptor));
-      ThrowNoClassDefFoundError("Class %s not found in class loader %p", name.c_str(), class_loader);
-      return NULL;
-    }
-    const DexFile& dex_file = *pair.first;
-    const DexFile::ClassDef& dex_class_def = *pair.second;
-    DexCache* dex_cache = FindDexCache(dex_file);
-    // Load the class from the dex file.
-    if (!init_done_) {
-      // finish up init of hand crafted class_roots_
-      if (descriptor == "Ljava/lang/Object;") {
-        klass = GetClassRoot(kJavaLangObject);
-      } else if (descriptor == "Ljava/lang/Class;") {
-        klass = GetClassRoot(kJavaLangClass);
-      } else if (descriptor == "Ljava/lang/String;") {
-        klass = GetClassRoot(kJavaLangString);
-      } else if (descriptor == "Ljava/lang/reflect/Constructor;") {
-        klass = GetClassRoot(kJavaLangReflectConstructor);
-      } else if (descriptor == "Ljava/lang/reflect/Field;") {
-        klass = GetClassRoot(kJavaLangReflectField);
-      } else if (descriptor == "Ljava/lang/reflect/Method;") {
-        klass = GetClassRoot(kJavaLangReflectMethod);
-      } else {
-        klass = AllocClass(SizeOfClass(dex_file, dex_class_def));
-      }
-    } else {
-      klass = AllocClass(SizeOfClass(dex_file, dex_class_def));
-    }
-    if (!klass->IsResolved()) {
-      klass->SetDexCache(dex_cache);
-      LoadClass(dex_file, dex_class_def, klass, class_loader);
-      // Check for a pending exception during load
-      if (self->IsExceptionPending()) {
-        return NULL;
-      }
-      ObjectLock lock(klass);
-      klass->SetClinitThreadId(self->GetTid());
-      // Add the newly loaded class to the loaded classes table.
-      bool success = InsertClass(descriptor, klass);  // TODO: just return collision
-      if (!success) {
-        // We may fail to insert if we raced with another thread.
-        klass->SetClinitThreadId(0);
-        klass = LookupClass(descriptor, class_loader);
-        CHECK(klass != NULL);
-        return klass;
-      } else {
-        // Finish loading (if necessary) by finding parents
-        CHECK(!klass->IsLoaded());
-        if (!LoadSuperAndInterfaces(klass, dex_file)) {
-          // Loading failed.
-          CHECK(self->IsExceptionPending());
-          lock.NotifyAll();
-          return NULL;
-        }
-        CHECK(klass->IsLoaded());
-        // Link the class (if necessary)
-        CHECK(!klass->IsResolved());
-        if (!LinkClass(klass)) {
-          // Linking failed.
-          CHECK(self->IsExceptionPending());
-          lock.NotifyAll();
-          return NULL;
-        }
-        CHECK(klass->IsResolved());
-      }
-    }
-  }
-  // Link the class if it has not already been linked.
   if (!klass->IsResolved() && !klass->IsErroneous()) {
     ObjectLock lock(klass);
     // Check for circular dependencies between classes.
@@ -871,8 +804,134 @@
     return NULL;
   }
   // Return the loaded class.  No exceptions should be pending.
-  CHECK(klass->IsResolved()) << descriptor;
-  CHECK(!self->IsExceptionPending()) << descriptor << " " << PrettyTypeOf(self->GetException());
+  CHECK(klass->IsResolved()) << PrettyClass(klass);
+  CHECK(!self->IsExceptionPending())
+      << PrettyClass(klass) << " " << PrettyTypeOf(self->GetException());
+  return klass;
+}
+
+Class* ClassLinker::FindClass(const std::string& descriptor,
+                              const ClassLoader* class_loader) {
+  CHECK_NE(descriptor.size(), 0U);
+  Thread* self = Thread::Current();
+  DCHECK(self != NULL);
+  CHECK(!self->IsExceptionPending()) << PrettyTypeOf(self->GetException());
+  // Find the class in the loaded classes table.
+  Class* klass = LookupClass(descriptor, class_loader);
+  if (klass != NULL) {
+    return EnsureResolved(klass);
+  }
+  if (descriptor.size() == 1) {
+    // only the descriptors of primitive types should be 1 character long
+    return FindPrimitiveClass(descriptor[0]);
+  }
+  // Class is not yet loaded.
+  if (descriptor[0] == '[') {
+    return CreateArrayClass(descriptor, class_loader);
+  }
+  if (class_loader == NULL) {
+    DexFile::ClassPathEntry pair = DexFile::FindInClassPath(descriptor, boot_class_path_);
+    if (pair.second == NULL) {
+      std::string name(PrintableString(descriptor));
+      ThrowNoClassDefFoundError("Class %s not found in boot class loader", name.c_str());
+      return NULL;
+    }
+    return DefineClass(descriptor, NULL, *pair.first, *pair.second);
+  }
+
+  if (ClassLoader::UseCompileTimeClassPath()) {
+    const std::vector<const DexFile*>& class_path
+        = ClassLoader::GetCompileTimeClassPath(class_loader);
+    DexFile::ClassPathEntry pair = DexFile::FindInClassPath(descriptor, class_path);
+    if (pair.second == NULL) {
+      return FindSystemClass(descriptor);
+    }
+    return DefineClass(descriptor, class_loader, *pair.first, *pair.second);
+  }
+
+  std::string class_name_string = DescriptorToDot(descriptor);
+  ScopedThreadStateChange(self, Thread::kNative);
+  JNIEnv* env = self->GetJniEnv();
+  jclass c = AddLocalReference<jclass>(env, GetClassRoot(kJavaLangClassLoader));
+  CHECK(c != NULL);
+  // TODO: cache method?
+  jmethodID mid = env->GetMethodID(c, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
+  CHECK(mid != NULL);
+  jobject class_name_object = env->NewStringUTF(class_name_string.c_str());
+  if (class_name_string == NULL) {
+    return NULL;
+  }
+  jobject class_loader_object = AddLocalReference<jobject>(env, class_loader);
+  jobject result = env->CallObjectMethod(class_loader_object, mid, class_name_object);
+  Class* klass_result = Decode<Class*>(env, result);
+  env->DeleteLocalRef(result);
+  env->DeleteLocalRef(class_name_object);
+  env->DeleteLocalRef(c);
+  return klass_result;
+}
+
+Class* ClassLinker::DefineClass(const std::string& descriptor,
+                                const ClassLoader* class_loader,
+                                const DexFile& dex_file,
+                                const DexFile::ClassDef& dex_class_def) {
+  Class* klass;
+  // Load the class from the dex file.
+  if (!init_done_) {
+    // finish up init of hand crafted class_roots_
+    if (descriptor == "Ljava/lang/Object;") {
+      klass = GetClassRoot(kJavaLangObject);
+    } else if (descriptor == "Ljava/lang/Class;") {
+      klass = GetClassRoot(kJavaLangClass);
+    } else if (descriptor == "Ljava/lang/String;") {
+      klass = GetClassRoot(kJavaLangString);
+    } else if (descriptor == "Ljava/lang/reflect/Constructor;") {
+      klass = GetClassRoot(kJavaLangReflectConstructor);
+    } else if (descriptor == "Ljava/lang/reflect/Field;") {
+      klass = GetClassRoot(kJavaLangReflectField);
+    } else if (descriptor == "Ljava/lang/reflect/Method;") {
+      klass = GetClassRoot(kJavaLangReflectMethod);
+    } else {
+      klass = AllocClass(SizeOfClass(dex_file, dex_class_def));
+    }
+  } else {
+    klass = AllocClass(SizeOfClass(dex_file, dex_class_def));
+  }
+  klass->SetDexCache(FindDexCache(dex_file));
+  LoadClass(dex_file, dex_class_def, klass, class_loader);
+  // Check for a pending exception during load
+  Thread* self = Thread::Current();
+  if (self->IsExceptionPending()) {
+    return NULL;
+  }
+  ObjectLock lock(klass);
+  klass->SetClinitThreadId(self->GetTid());
+  // Add the newly loaded class to the loaded classes table.
+  bool success = InsertClass(descriptor, klass);  // TODO: just return collision
+  if (!success) {
+    // We may fail to insert if we raced with another thread.
+    klass->SetClinitThreadId(0);
+    klass = LookupClass(descriptor, class_loader);
+    CHECK(klass != NULL);
+    return klass;
+  }
+  // Finish loading (if necessary) by finding parents
+  CHECK(!klass->IsLoaded());
+  if (!LoadSuperAndInterfaces(klass, dex_file)) {
+    // Loading failed.
+    CHECK(self->IsExceptionPending());
+    lock.NotifyAll();
+    return NULL;
+  }
+  CHECK(klass->IsLoaded());
+  // Link the class (if necessary)
+  CHECK(!klass->IsResolved());
+  if (!LinkClass(klass)) {
+    // Linking failed.
+    CHECK(self->IsExceptionPending());
+    lock.NotifyAll();
+    return NULL;
+  }
+  CHECK(klass->IsResolved());
   return klass;
 }
 
@@ -991,18 +1050,36 @@
     }
   }
 
+  UniquePtr<const OatFile::OatClass> oat_class;
+  if (Runtime::Current()->IsStarted() && !ClassLoader::UseCompileTimeClassPath()) {
+    const OatFile* oat_file = FindOatFile(dex_file);
+    if (oat_file != NULL) {
+      const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation());
+      if (oat_dex_file != NULL) {
+        uint32_t class_def_index;
+        bool found = dex_file.FindClassDefIndex(descriptor, class_def_index);
+        CHECK(found) << descriptor;
+        oat_class.reset(oat_dex_file->GetOatClass(class_def_index));
+      }
+    }
+  }
+  size_t method_index = 0;
+
   // Load direct methods.
   if (num_direct_methods != 0) {
     // TODO: append direct methods to class object
     klass->SetDirectMethods(AllocObjectArray<Method>(num_direct_methods));
     uint32_t last_idx = 0;
-    for (size_t i = 0; i < num_direct_methods; ++i) {
+    for (size_t i = 0; i < num_direct_methods; ++i, ++method_index) {
       DexFile::Method dex_method;
       dex_file.dexReadClassDataMethod(&class_data, &dex_method, &last_idx);
       Method* meth = AllocMethod();
       klass->SetDirectMethod(i, meth);
       LoadMethod(dex_file, dex_method, klass, meth);
-      // TODO: register maps
+      if (oat_class.get() != NULL) {
+        const OatFile::OatMethod oat_method = oat_class->GetOatMethod(method_index);
+        oat_method.LinkMethod(meth);
+      }
     }
   }
 
@@ -1011,13 +1088,16 @@
     // TODO: append virtual methods to class object
     klass->SetVirtualMethods(AllocObjectArray<Method>(num_virtual_methods));
     uint32_t last_idx = 0;
-    for (size_t i = 0; i < num_virtual_methods; ++i) {
+    for (size_t i = 0; i < num_virtual_methods; ++i, ++method_index) {
       DexFile::Method dex_method;
       dex_file.dexReadClassDataMethod(&class_data, &dex_method, &last_idx);
       Method* meth = AllocMethod();
       klass->SetVirtualMethod(i, meth);
       LoadMethod(dex_file, dex_method, klass, meth);
-      // TODO: register maps
+      if (oat_class.get() != NULL) {
+        const OatFile::OatMethod oat_method = oat_class->GetOatMethod(method_index);
+        oat_method.LinkMethod(meth);
+      }
     }
   }
 }
@@ -1130,18 +1210,42 @@
   RegisterDexFile(dex_file, dex_cache);
 }
 
-void ClassLinker::RegisterDexFile(const DexFile& dex_file) {
-  RegisterDexFile(dex_file, AllocDexCache(dex_file));
+bool ClassLinker::IsDexFileRegisteredLocked(const DexFile& dex_file) const {
+  lock_.AssertHeld();
+  for (size_t i = 0; i != dex_files_.size(); ++i) {
+    if (dex_files_[i] == &dex_file) {
+        return true;
+    }
+  }
+  return false;
 }
 
-void ClassLinker::RegisterDexFile(const DexFile& dex_file, DexCache* dex_cache) {
+bool ClassLinker::IsDexFileRegistered(const DexFile& dex_file) const {
   MutexLock mu(lock_);
+  return IsDexFileRegistered(dex_file);
+}
+
+void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file, DexCache* dex_cache) {
+  lock_.AssertHeld();
   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);
 }
 
+void ClassLinker::RegisterDexFile(const DexFile& dex_file) {
+  MutexLock mu(lock_);
+  if (IsDexFileRegisteredLocked(dex_file)) {
+    return;
+  }
+  RegisterDexFileLocked(dex_file, AllocDexCache(dex_file));
+}
+
+void ClassLinker::RegisterDexFile(const DexFile& dex_file, DexCache* dex_cache) {
+  MutexLock mu(lock_);
+  RegisterDexFileLocked(dex_file, dex_cache);
+}
+
 const DexFile& ClassLinker::FindDexFile(const DexCache* dex_cache) const {
   MutexLock mu(lock_);
   for (size_t i = 0; i != dex_caches_.size(); ++i) {
@@ -1191,7 +1295,7 @@
 // array class; that always comes from the base element class.
 //
 // Returns NULL with an exception raised on failure.
-Class* ClassLinker::CreateArrayClass(const StringPiece& descriptor,
+Class* ClassLinker::CreateArrayClass(const std::string& descriptor,
                                      const ClassLoader* class_loader) {
   CHECK_EQ('[', descriptor[0]);
 
@@ -1259,7 +1363,7 @@
   if (new_class->GetDescriptor() != NULL) {
     DCHECK(new_class->GetDescriptor()->Equals(descriptor));
   } else {
-    new_class->SetDescriptor(intern_table_->InternStrong(descriptor.ToString().c_str()));
+    new_class->SetDescriptor(intern_table_->InternStrong(descriptor.c_str()));
   }
   Class* java_lang_Object = GetClassRoot(kJavaLangObject);
   new_class->SetSuperClass(java_lang_Object);
@@ -1339,14 +1443,14 @@
   return NULL;
 }
 
-bool ClassLinker::InsertClass(const StringPiece& descriptor, Class* klass) {
+bool ClassLinker::InsertClass(const std::string& descriptor, Class* klass) {
   size_t hash = StringPieceHash()(descriptor);
   MutexLock mu(lock_);
   Table::iterator it = classes_.insert(std::make_pair(hash, klass));
   return ((*it).second == klass);
 }
 
-Class* ClassLinker::LookupClass(const StringPiece& descriptor, const ClassLoader* class_loader) {
+Class* ClassLinker::LookupClass(const std::string& descriptor, const ClassLoader* class_loader) {
   size_t hash = StringPieceHash()(descriptor);
   MutexLock mu(lock_);
   typedef Table::const_iterator It;  // TODO: C++0x auto
@@ -2290,12 +2394,7 @@
   Class* resolved = dex_cache->GetResolvedType(type_idx);
   if (resolved == NULL) {
     const char* descriptor = dex_file.dexStringByTypeIdx(type_idx);
-    if (descriptor[1] == '\0') {
-      // only the descriptors of primitive types should be 1 character long
-      resolved = FindPrimitiveClass(descriptor[0]);
-    } else {
-      resolved = FindClass(descriptor, class_loader);
-    }
+    resolved = FindClass(descriptor, class_loader);
     if (resolved != NULL) {
       Class* check = resolved;
       while (check->IsArrayClass()) {
diff --git a/src/class_linker.h b/src/class_linker.h
index 6d17a10..67bb35c 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -50,23 +50,38 @@
 
   // Finds a class by its descriptor, loading it if necessary.
   // If class_loader is null, searches boot_class_path_.
-  Class* FindClass(const StringPiece& descriptor, const ClassLoader* class_loader);
+  Class* FindClass(const std::string& descriptor, const ClassLoader* class_loader);
+
+  Class* FindSystemClass(const std::string& descriptor) {
+    return FindClass(descriptor, NULL);
+  }
+
+  // Define a new a class based on a ClassDef from a DexFile
+  Class* DefineClass(const std::string& descriptor, const ClassLoader* class_loader,
+                     const DexFile& dex_file, const DexFile::ClassDef& dex_class_def);
 
   // Finds a class by its descriptor, returning NULL if it isn't wasn't loaded
   // by the given 'class_loader'.
-  Class* LookupClass(const StringPiece& descriptor, const ClassLoader* class_loader);
+  Class* LookupClass(const std::string& descriptor, const ClassLoader* class_loader);
 
   Class* FindPrimitiveClass(char type);
 
-  Class* FindSystemClass(const StringPiece& descriptor) {
-    return FindClass(descriptor, NULL);
-  }
-
   void DumpAllClasses(int flags) const;
 
   size_t NumLoadedClasses() const;
 
   // Resolve a String with the given index from the DexFile, storing the
+  // result in the DexCache. The referrer is used to identify the
+  // target DexCache and ClassLoader to use for resolution.
+  String* ResolveString(uint32_t string_idx, const Method* referrer) {
+    Class* declaring_class = referrer->GetDeclaringClass();
+    DexCache* dex_cache = declaring_class->GetDexCache();
+    // TODO: we could check for a dex cache hit here
+    const DexFile& dex_file = FindDexFile(dex_cache);
+    return ResolveString(dex_file, string_idx, dex_cache);
+  }
+
+  // Resolve a String with the given index from the DexFile, storing the
   // result in the DexCache.
   String* ResolveString(const DexFile& dex_file, uint32_t string_idx, DexCache* dex_cache);
 
@@ -175,6 +190,8 @@
 
   const DexFile& FindDexFile(const DexCache* dex_cache) const;
   DexCache* FindDexCache(const DexFile& dex_file) const;
+  bool IsDexFileRegistered(const DexFile& dex_file) const;
+  const OatFile* FindOatFile(const std::string& location);
 
   // TODO: replace this with multiple methods that allocate the correct managed type.
   template <class T>
@@ -228,7 +245,7 @@
                                   Class::PrimitiveType type);
 
 
-  Class* CreateArrayClass(const StringPiece& descriptor,
+  Class* CreateArrayClass(const std::string& descriptor,
                           const ClassLoader* class_loader);
 
   void AppendToBootClassPath(const DexFile& dex_file);
@@ -261,7 +278,13 @@
 
   // Inserts a class into the class table.  Returns true if the class
   // was inserted.
-  bool InsertClass(const StringPiece& descriptor, Class* klass);
+  bool InsertClass(const std::string& descriptor, Class* klass);
+
+  void RegisterDexFileLocked(const DexFile& dex_file, DexCache* dex_cache);
+  bool IsDexFileRegisteredLocked(const DexFile& dex_file) const;
+
+  // Find, possibily opening, an OatFile corresponding to a DexFile
+  const OatFile* FindOatFile(const DexFile& dex_file);
 
   bool InitializeClass(Class* klass, bool can_run_clinit);
   bool WaitForInitializeClass(Class* klass, Thread* self, ObjectLock& lock);
@@ -314,7 +337,7 @@
   std::vector<const DexFile*> dex_files_;
   std::vector<DexCache*> dex_caches_;
 
-  // multimap from a StringPiece hash code of a class descriptor to
+  // multimap from a string hash code of a class descriptor to
   // Class* instances. Results should be compared for a matching
   // Class::descriptor_ and Class::class_loader_.
   typedef std::tr1::unordered_multimap<size_t, Class*> Table;
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index 264b669..8ad2a20 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -15,7 +15,7 @@
 
 class ClassLinkerTest : public CommonTest {
  protected:
-  void AssertNonExistentClass(const StringPiece& descriptor) {
+  void AssertNonExistentClass(const std::string& descriptor) {
     EXPECT_TRUE(class_linker_->FindSystemClass(descriptor) == NULL);
     Thread* self = Thread::Current();
     EXPECT_TRUE(self->IsExceptionPending());
@@ -25,11 +25,11 @@
     EXPECT_TRUE(exception->InstanceOf(exception_class));
   }
 
-  void AssertPrimitiveClass(const StringPiece& descriptor) {
+  void AssertPrimitiveClass(const std::string& descriptor) {
     AssertPrimitiveClass(descriptor, class_linker_->FindSystemClass(descriptor));
   }
 
-  void AssertPrimitiveClass(const StringPiece& descriptor, const Class* primitive) {
+  void AssertPrimitiveClass(const std::string& descriptor, const Class* primitive) {
     ASSERT_TRUE(primitive != NULL);
     ASSERT_TRUE(primitive->GetClass() != NULL);
     ASSERT_EQ(primitive->GetClass(), primitive->GetClass()->GetClass());
@@ -62,8 +62,8 @@
     EXPECT_TRUE(primitive->GetIfTable() == NULL);
   }
 
-  void AssertArrayClass(const StringPiece& array_descriptor,
-                        const StringPiece& component_type,
+  void AssertArrayClass(const std::string& array_descriptor,
+                        const std::string& component_type,
                         const ClassLoader* class_loader) {
     Class* array = class_linker_->FindClass(array_descriptor, class_loader);
     EXPECT_TRUE(array->GetComponentType()->GetDescriptor()->Equals(component_type));
@@ -71,7 +71,7 @@
     AssertArrayClass(array_descriptor, array);
   }
 
-  void AssertArrayClass(const StringPiece& array_descriptor, Class* array) {
+  void AssertArrayClass(const std::string& array_descriptor, Class* array) {
     ASSERT_TRUE(array != NULL);
     ASSERT_TRUE(array->GetClass() != NULL);
     ASSERT_EQ(array->GetClass(), array->GetClass()->GetClass());
@@ -142,7 +142,7 @@
     EXPECT_TRUE(field->GetType() != NULL);
   }
 
-  void AssertClass(const StringPiece& descriptor, Class* klass) {
+  void AssertClass(const std::string& descriptor, Class* klass) {
     EXPECT_TRUE(klass->GetDescriptor()->Equals(descriptor));
     if (klass->GetDescriptor()->Equals(String::AllocFromModifiedUtf8("Ljava/lang/Object;"))) {
       EXPECT_FALSE(klass->HasSuperClass());
@@ -259,7 +259,7 @@
               total_num_reference_instance_fields == 0);
   }
 
-  void AssertDexFileClass(ClassLoader* class_loader, const StringPiece& descriptor) {
+  void AssertDexFileClass(ClassLoader* class_loader, const std::string& descriptor) {
     ASSERT_TRUE(descriptor != NULL);
     Class* klass = class_linker_->FindSystemClass(descriptor);
     ASSERT_TRUE(klass != NULL);
@@ -668,11 +668,11 @@
 }
 
 TEST_F(ClassLinkerTest, FindClass_Primitives) {
-  StringPiece expected = "BCDFIJSZV";
+  const std::string expected("BCDFIJSZV");
   for (int ch = 0; ch < 255; ch++) {
     char* s = reinterpret_cast<char*>(&ch);
-    StringPiece descriptor(s, 1);
-    if (expected.find(ch) == StringPiece::npos) {
+    const std::string descriptor(s, 1);
+    if (expected.find(ch) == std::string::npos) {
       AssertNonExistentClass(descriptor);
     } else {
       AssertPrimitiveClass(descriptor);
@@ -932,7 +932,7 @@
   // case 2, get the initialized storage from StaticsFromCode.getS0
 
   const ClassLoader* class_loader = LoadDex("StaticsFromCode");
-  const DexFile* dex_file = ClassLoader::GetClassPath(class_loader)[0];
+  const DexFile* dex_file = ClassLoader::GetCompileTimeClassPath(class_loader)[0];
   CHECK(dex_file != NULL);
 
   Class* klass = class_linker_->FindClass("LStaticsFromCode;", class_loader);
diff --git a/src/class_loader.cc b/src/class_loader.cc
index 8f8e829..94a212f 100644
--- a/src/class_loader.cc
+++ b/src/class_loader.cc
@@ -7,20 +7,35 @@
 
 namespace art {
 
-const std::vector<const DexFile*>& ClassLoader::GetClassPath(const ClassLoader* class_loader) {
+bool ClassLoader::use_compile_time_class_path = false;
+ClassLoader::Table ClassLoader::compile_time_class_paths_;
+
+const std::vector<const DexFile*>& ClassLoader::GetCompileTimeClassPath(const ClassLoader* class_loader) {
+  Runtime* runtime = Runtime::Current();
   if (class_loader == NULL) {
-    return Runtime::Current()->GetClassLinker()->GetBootClassPath();
+    return runtime->GetClassLinker()->GetBootClassPath();
   }
-  return class_loader->class_path_;
+  CHECK(ClassLoader::UseCompileTimeClassPath());
+  Table::const_iterator it = compile_time_class_paths_.find(class_loader);
+  CHECK(it != compile_time_class_paths_.end());
+  return it->second;
+}
+
+void ClassLoader::SetCompileTimeClassPath(const ClassLoader* class_loader,
+                                          std::vector<const DexFile*>& class_path) {
+  CHECK(!Runtime::Current()->IsStarted());
+  use_compile_time_class_path = true;
+  compile_time_class_paths_[class_loader] = class_path;
 }
 
 // TODO: get global references for these
 Class* PathClassLoader::dalvik_system_PathClassLoader_ = NULL;
 
-const PathClassLoader* PathClassLoader::Alloc(std::vector<const DexFile*> dex_files) {
+const PathClassLoader* PathClassLoader::AllocCompileTime(std::vector<const DexFile*>& dex_files) {
+  CHECK(!Runtime::Current()->IsStarted());
   DCHECK(dalvik_system_PathClassLoader_ != NULL);
   PathClassLoader* p = down_cast<PathClassLoader*>(dalvik_system_PathClassLoader_->AllocObject());
-  p->SetClassPath(dex_files);
+  SetCompileTimeClassPath(p, dex_files);
   return p;
 }
 
diff --git a/src/class_loader.h b/src/class_loader.h
index 80444f5..8fe6a09 100644
--- a/src/class_loader.h
+++ b/src/class_loader.h
@@ -7,19 +7,17 @@
 
 #include "dex_file.h"
 #include "object.h"
+#include "unordered_map.h"
 
 namespace art {
 
 // C++ mirror of java.lang.ClassLoader
-// TODO: add MANAGED when class_path_ removed
-class ClassLoader : public Object {
+class MANAGED ClassLoader : public Object {
  public:
-  static const std::vector<const DexFile*>& GetClassPath(const ClassLoader* class_loader);
-
-  void SetClassPath(std::vector<const DexFile*>& class_path) {
-    DCHECK_EQ(class_path_.size(), 0U);
-    // TODO: use setter
-    class_path_ = class_path;
+  static const std::vector<const DexFile*>& GetCompileTimeClassPath(const ClassLoader* class_loader);
+  static void SetCompileTimeClassPath(const ClassLoader* class_loader, std::vector<const DexFile*>& class_path);
+  static bool UseCompileTimeClassPath() {
+    return use_compile_time_class_path;
   }
 
  private:
@@ -27,8 +25,10 @@
   Object* packages_;
   ClassLoader* parent_;
 
-  // TODO: remove once we can create a real PathClassLoader
-  std::vector<const DexFile*> class_path_;
+  typedef std::tr1::unordered_map<const ClassLoader*, std::vector<const DexFile*>, ObjectIdentityHash> Table;
+  static Table compile_time_class_paths_;
+
+  static bool use_compile_time_class_path;
 
   friend struct ClassLoaderOffsets;  // for verifying offset information
   DISALLOW_IMPLICIT_CONSTRUCTORS(ClassLoader);
@@ -50,7 +50,7 @@
 // TODO: add MANAGED when class_path_ removed
 class PathClassLoader : public BaseDexClassLoader {
  public:
-  static const PathClassLoader* Alloc(std::vector<const DexFile*> dex_files);
+  static const PathClassLoader* AllocCompileTime(std::vector<const DexFile*>& dex_files);
   static void SetClass(Class* dalvik_system_PathClassLoader);
   static void ResetClass();
  private:
diff --git a/src/common_test.h b/src/common_test.h
index 950020d..024cde9 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -210,7 +210,7 @@
             runtime_->CreateCalleeSaveMethod(instruction_set, type), type);
       }
     }
-    compiler_.reset(new Compiler(instruction_set));
+    compiler_.reset(new Compiler(instruction_set, false));
 
     Heap::VerifyHeap();  // Check for heap corruption before the test
   }
@@ -301,7 +301,7 @@
     class_linker_->RegisterDexFile(*dex_file);
     std::vector<const DexFile*> dex_files;
     dex_files.push_back(dex_file);
-    return PathClassLoader::Alloc(dex_files);
+    return PathClassLoader::AllocCompileTime(dex_files);
   }
 
   const DexFile* OpenTestDexFile(const char* name) {
@@ -326,12 +326,24 @@
     class_linker_->RegisterDexFile(*dex_file);
     std::vector<const DexFile*> class_path;
     class_path.push_back(dex_file);
-    const ClassLoader* class_loader = PathClassLoader::Alloc(class_path);
+    const ClassLoader* class_loader = PathClassLoader::AllocCompileTime(class_path);
     CHECK(class_loader != NULL);
     Thread::Current()->SetClassLoaderOverride(class_loader);
     return class_loader;
   }
 
+  void CompileClass(const ClassLoader* class_loader, const char* class_name) {
+    std::string class_descriptor = DotToDescriptor(class_name);
+    Class* klass = class_linker_->FindClass(class_descriptor, class_loader);
+    CHECK(klass != NULL) << "Class not found " << class_name;
+    for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
+      CompileMethod(klass->GetDirectMethod(i));
+    }
+    for (size_t i = 0; i < klass->NumVirtualMethods(); i++) {
+      CompileMethod(klass->GetVirtualMethod(i));
+    }
+  }
+
   void CompileMethod(Method* method) {
     CHECK(method != NULL);
     compiler_->CompileOne(method);
diff --git a/src/compiler.cc b/src/compiler.cc
index 3b98ea0..b62c40b 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -31,8 +31,11 @@
   ByteArray* X86CreateResolutionTrampoline(Runtime::TrampolineType type);
 }
 
-Compiler::Compiler(InstructionSet instruction_set)
-    : instruction_set_(instruction_set), jni_compiler_(instruction_set), verbose_(false) {
+Compiler::Compiler(InstructionSet instruction_set, bool image)
+    : instruction_set_(instruction_set),
+      jni_compiler_(instruction_set),
+      image_(image),
+      verbose_(false) {
   CHECK(!Runtime::Current()->IsStarted());
 }
 
@@ -82,7 +85,8 @@
 }
 
 void Compiler::Resolve(const ClassLoader* class_loader) {
-  const std::vector<const DexFile*>& class_path = ClassLoader::GetClassPath(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];
     CHECK(dex_file != NULL);
@@ -92,11 +96,13 @@
 
 void Compiler::ResolveDexFile(const ClassLoader* class_loader, const DexFile& dex_file) {
   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
-  DexCache* dex_cache = class_linker->FindDexCache(dex_file);
-  for (size_t string_idx = 0; string_idx < dex_cache->NumStrings(); string_idx++) {
-    class_linker->ResolveString(dex_file, string_idx, dex_cache);
+  if (IsImage()) {  // Only resolve when we'll have an image, so compiler won't choose fast path
+    for (size_t string_idx = 0; string_idx < dex_cache->NumStrings(); string_idx++) {
+      class_linker->ResolveString(dex_file, string_idx, dex_cache);
+    }
   }
 
   // Class derived values are more complicated, they require the linker and loader.
@@ -188,7 +194,8 @@
 }
 
 void Compiler::Verify(const ClassLoader* class_loader) {
-  const std::vector<const DexFile*>& class_path = ClassLoader::GetClassPath(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];
     CHECK(dex_file != NULL);
@@ -227,7 +234,8 @@
 }
 
 void Compiler::InitializeClassesWithoutClinit(const ClassLoader* class_loader) {
-  const std::vector<const DexFile*>& class_path = ClassLoader::GetClassPath(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];
     CHECK(dex_file != NULL);
@@ -260,7 +268,8 @@
 }
 
 void Compiler::Compile(const ClassLoader* class_loader) {
-  const std::vector<const DexFile*>& class_path = ClassLoader::GetClassPath(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];
     CHECK(dex_file != NULL);
@@ -323,7 +332,7 @@
 }
 
 const CompiledMethod* Compiler::GetCompiledMethod(const Method* method) const {
-    MethodTable::const_iterator it = compiled_methods_.find(method);
+  MethodTable::const_iterator it = compiled_methods_.find(method);
   if (it == compiled_methods_.end()) {
     return NULL;
   }
@@ -341,7 +350,8 @@
 }
 
 void Compiler::SetCodeAndDirectMethods(const ClassLoader* class_loader) {
-  const std::vector<const DexFile*>& class_path = ClassLoader::GetClassPath(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];
     CHECK(dex_file != NULL);
diff --git a/src/compiler.h b/src/compiler.h
index 6059a2a..0fc68df 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -16,7 +16,9 @@
 
 class Compiler {
  public:
-  explicit Compiler(InstructionSet instruction_set);
+  // 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);
 
   ~Compiler();
 
@@ -26,14 +28,18 @@
   // Compile a single Method
   void CompileOne(const Method* method);
 
-  void SetVerbose(bool verbose) {
-    verbose_ = verbose;
-  }
-
   InstructionSet GetInstructionSet() const {
     return instruction_set_;
   }
 
+  bool IsImage() const {
+    return image_;
+  }
+
+  void SetVerbose(bool verbose) {
+    verbose_ = verbose;
+  }
+
   bool IsVerbose() const {
     return verbose_;
   }
@@ -81,6 +87,8 @@
   typedef std::tr1::unordered_map<const Method*, CompiledInvokeStub*, ObjectIdentityHash> InvokeStubTable;
   InvokeStubTable compiled_invoke_stubs_;
 
+  bool image_;
+
   bool verbose_;
 
   DISALLOW_COPY_AND_ASSIGN(Compiler);
diff --git a/src/compiler_test.cc b/src/compiler_test.cc
index f261406..1066783 100644
--- a/src/compiler_test.cc
+++ b/src/compiler_test.cc
@@ -39,7 +39,8 @@
   }
 
   void MakeAllExecutable(const ClassLoader* class_loader) {
-    const std::vector<const DexFile*>& class_path = ClassLoader::GetClassPath(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];
       CHECK(dex_file != NULL);
diff --git a/src/dalvik_system_DexFile.cc b/src/dalvik_system_DexFile.cc
index 3c373d5..977abc8 100644
--- a/src/dalvik_system_DexFile.cc
+++ b/src/dalvik_system_DexFile.cc
@@ -14,7 +14,11 @@
  * limitations under the License.
  */
 
+#include "class_loader.h"
+#include "class_linker.h"
+#include "dex_file.h"
 #include "logging.h"
+#include "runtime.h"
 #include "ScopedUtfChars.h"
 
 #include "JniConstants.h" // Last to avoid problems with LOG redefinition.
@@ -80,20 +84,61 @@
   if (env->ExceptionOccurred()) {
     return 0;
   }
-  UNIMPLEMENTED(WARNING) << sourceName.c_str();
-  return 0;
+  const DexFile* dex_file = DexFile::Open(sourceName.c_str(), "");
+  if (dex_file == NULL) {
+    jniThrowExceptionFmt(env, "java/io/IOException", "unable to open DEX file: %s",
+                         sourceName.c_str());
+    return NULL;
+  }
+  return static_cast<jint>(reinterpret_cast<uintptr_t>(dex_file));
+}
+
+static const DexFile* toDexFile(JNIEnv* env, int dex_file_address) {
+  const DexFile* dex_file = reinterpret_cast<const DexFile*>(static_cast<uintptr_t>(dex_file_address));
+  if ((dex_file == NULL)) {
+    jniThrowNullPointerException(env, "dex_file == null");
+  }
+  return dex_file;
 }
 
 void DexFile_closeDexFile(JNIEnv* env, jclass, jint cookie) {
-  UNIMPLEMENTED(WARNING);
+  const DexFile* dex_file = toDexFile(env, cookie);
+  if (dex_file == NULL) {
+    return;
+  }
+  if (Runtime::Current()->GetClassLinker()->IsDexFileRegistered(*dex_file)) {
+    return;
+  }
+  delete dex_file;
 }
 
 jclass DexFile_defineClass(JNIEnv* env, jclass, jstring javaName, jobject javaLoader, jint cookie) {
-  UNIMPLEMENTED(ERROR);
-  return NULL;
+  const DexFile* dex_file = toDexFile(env, cookie);
+  if (dex_file == NULL) {
+    return NULL;
+  }
+  String* name = Decode<String*>(env, javaName);
+  const char* class_name = name->ToModifiedUtf8().c_str();
+  const std::string descriptor = DotToDescriptor(class_name);
+  const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor);
+  if (dex_class_def == NULL) {
+    jniThrowExceptionFmt(env, "Ljava/lang/NoClassDefFoundError;", "Class %s not found", class_name);
+    return NULL;
+  }
+
+  Object* class_loader_object = Decode<Object*>(env, javaLoader);
+  ClassLoader* class_loader = down_cast<ClassLoader*>(class_loader_object);
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  class_linker->RegisterDexFile(*dex_file);
+  Class* result = class_linker->DefineClass(descriptor, class_loader, *dex_file, *dex_class_def);
+  return AddLocalReference<jclass>(env, result);
 }
 
 jobjectArray DexFile_getClassNameList(JNIEnv* env, jclass, jint cookie) {
+  const DexFile* dex_file = toDexFile(env, cookie);
+  if (dex_file == NULL) {
+    return NULL;
+  }
   UNIMPLEMENTED(ERROR);
   return NULL;
 }
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index d5db436..b6a12835 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -124,8 +124,8 @@
    return EXIT_FAILURE;
   }
 
-  if (image_filename == NULL) {
-   fprintf(stderr, "--image file name not specified\n");
+  if (image_filename == NULL && boot_image_option.empty()) {
+   fprintf(stderr, "Either --image or --boot-image must be specified\n");
    return EXIT_FAILURE;
   }
 
@@ -190,7 +190,7 @@
     for (size_t i = 0; i < dex_files.size(); i++) {
       class_linker->RegisterDexFile(*dex_files[i]);
     }
-    class_loader = PathClassLoader::Alloc(dex_files);
+    class_loader = PathClassLoader::AllocCompileTime(dex_files);
   }
 
   // if we loaded an existing image, we will reuse values from the image roots.
@@ -212,7 +212,7 @@
       runtime->SetCalleeSaveMethod(runtime->CreateCalleeSaveMethod(kThumb2, type), type);
     }
   }
-  Compiler compiler(kThumb2);
+  Compiler compiler(kThumb2, image_filename != NULL);
   if (method_names.empty()) {
     compiler.CompileAll(class_loader);
   } else {
@@ -263,6 +263,11 @@
     return EXIT_FAILURE;
   }
 
+  if (image_filename == NULL) {
+    return EXIT_SUCCESS;
+  }
+  CHECK(compiler.IsImage());
+
   ImageWriter image_writer;
   if (!image_writer.Write(image_filename, image_base, oat_filename, host_prefix)) {
     fprintf(stderr, "Failed to create image file %s\n", image_filename);
diff --git a/src/dex_cache.cc b/src/dex_cache.cc
index d24c436..4eb18a5 100644
--- a/src/dex_cache.cc
+++ b/src/dex_cache.cc
@@ -30,6 +30,15 @@
   Set(kResolvedFields,           resolved_fields);
   Set(kCodeAndDirectMethods,     code_and_direct_methods);
   Set(kInitializedStaticStorage, initialized_static_storage);
+
+  Runtime* runtime = Runtime::Current();
+  if (runtime->IsStarted()) {
+    Runtime::TrampolineType unknown_method_resolution_type = Runtime::GetTrampolineType(NULL);
+    ByteArray* res_trampoline = runtime->GetResolutionStubArray(unknown_method_resolution_type);
+    for (size_t i = 0; i < NumResolvedMethods(); i++) {
+      code_and_direct_methods->SetResolvedDirectMethodTrampoline(i, res_trampoline);
+    }
+  }
 }
 
 }  // namespace art
diff --git a/src/dex_file.h b/src/dex_file.h
index 45cd33e..468ce4d 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -437,8 +437,13 @@
   }
 
   // Returns the prototype of a method id.
-  const char* GetMethodPrototype(const MethodId& method_id) const {
-    return dexStringById(method_id.proto_idx_);
+  const ProtoId& GetMethodPrototype(const MethodId& method_id) const {
+    return GetProtoId(method_id.proto_idx_);
+  }
+
+  // Returns the signature of a method id.
+  const std::string GetMethodSignature(const MethodId& method_id) const {
+    return CreateMethodDescriptor(method_id.proto_idx_, NULL);
   }
 
   // Returns the name of a method id.
diff --git a/src/dex_verifier.cc b/src/dex_verifier.cc
index 2908d58..d84e4cb 100644
--- a/src/dex_verifier.cc
+++ b/src/dex_verifier.cc
@@ -4934,11 +4934,11 @@
   if (res_method == NULL) {
     const DexFile::MethodId& method_id = dex_file->GetMethodId(dec_insn->vB_);
     const char* method_name = dex_file->GetMethodName(method_id);
-    const char* method_proto = dex_file->GetMethodPrototype(method_id);
+    std::string method_signature = dex_file->GetMethodSignature(method_id);
     const char* class_descriptor = dex_file->GetMethodClassDescriptor(method_id);
 
     LOG(ERROR) << "VFY: unable to resolve method " << dec_insn->vB_ << ": "
-               << class_descriptor << "." << method_name << " " << method_proto;
+               << class_descriptor << "." << method_name << " " << method_signature;
     return NULL;
   }
 
diff --git a/src/dex_verifier_test.cc b/src/dex_verifier_test.cc
index 39e14c4..89482bd 100644
--- a/src/dex_verifier_test.cc
+++ b/src/dex_verifier_test.cc
@@ -13,7 +13,7 @@
 
 class DexVerifierTest : public CommonTest {
  protected:
-  void VerifyClass(ClassLoader* class_loader, const StringPiece& descriptor) {
+  void VerifyClass(ClassLoader* class_loader, const std::string& descriptor) {
     ASSERT_TRUE(descriptor != NULL);
     Class* klass = class_linker_->FindSystemClass(descriptor);
 
diff --git a/src/image.h b/src/image.h
index 86b71e1..76db7e5 100644
--- a/src/image.h
+++ b/src/image.h
@@ -81,10 +81,14 @@
   };
 
   Object* GetImageRoot(ImageRoot image_root) const {
-    return reinterpret_cast<ObjectArray<Object>*>(image_roots_)->Get(image_root);
+    return GetImageRoots()->Get(image_root);
   }
 
  private:
+  ObjectArray<Object>* GetImageRoots() const {
+    return reinterpret_cast<ObjectArray<Object>*>(image_roots_);
+  }
+
   static const byte kImageMagic[4];
   static const byte kImageVersion[4];
 
@@ -107,6 +111,7 @@
   uint32_t image_roots_;
 
   friend class ImageWriter;
+  friend class ImageDump;  // For GetImageRoots()
 };
 
 }  // namespace art
diff --git a/src/image_writer.cc b/src/image_writer.cc
index 39f3e64..f3ecda0 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -25,6 +25,8 @@
 
 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);
   image_base_ = reinterpret_cast<byte*>(image_base);
 
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 9ca4034..277284a 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -2771,7 +2771,7 @@
       version = (*jni_on_load)(this, NULL);
     }
 
-    self->SetClassLoaderOverride(old_class_loader);;
+    self->SetClassLoaderOverride(old_class_loader);
 
     if (version != JNI_VERSION_1_2 &&
     version != JNI_VERSION_1_4 &&
diff --git a/src/oat_file.cc b/src/oat_file.cc
index 95ef64c..8a4aa9a 100644
--- a/src/oat_file.cc
+++ b/src/oat_file.cc
@@ -123,12 +123,21 @@
   return mem_map_->GetLimit();
 }
 
-const OatFile::OatDexFile& OatFile::GetOatDexFile(const std::string& dex_file_location) {
+const OatFile::OatDexFile* OatFile::GetOatDexFile(const std::string& dex_file_location) const {
   Table::const_iterator it = oat_dex_files_.find(dex_file_location);
   if (it == oat_dex_files_.end()) {
-    LOG(FATAL) << "Failed to find OatDexFile for DexFile " << dex_file_location;
+    LOG(WARNING) << "Failed to find OatDexFile for DexFile " << dex_file_location;
+    return NULL;
   }
-  return *it->second;
+  return it->second;
+}
+
+std::vector<const OatFile::OatDexFile*> OatFile::GetOatDexFiles() const {
+  std::vector<const OatFile::OatDexFile*> result;
+  for (Table::const_iterator it = oat_dex_files_.begin(); it != oat_dex_files_.end(); ++it ) {
+    result.push_back(it->second);
+  }
+  return result;
 }
 
 OatFile::OatDexFile::OatDexFile(const OatFile* oat_file,
@@ -142,11 +151,11 @@
 
 OatFile::OatDexFile::~OatDexFile() {}
 
-const OatFile::OatClass OatFile::OatDexFile::GetOatClass(uint32_t class_def_index) const {
+const OatFile::OatClass* OatFile::OatDexFile::GetOatClass(uint32_t class_def_index) const {
   uint32_t methods_offset = classes_pointer_[class_def_index];
   const byte* methods_pointer = oat_file_->GetBase() + methods_offset;
   CHECK_LT(methods_pointer, oat_file_->GetLimit());
-  return OatClass(oat_file_, reinterpret_cast<const OatMethodOffsets*>(methods_pointer));
+  return new OatClass(oat_file_, reinterpret_cast<const OatMethodOffsets*>(methods_pointer));
 }
 
 OatFile::OatClass::OatClass(const OatFile* oat_file, const OatMethodOffsets* methods_pointer)
@@ -186,7 +195,7 @@
 
 OatFile::OatMethod::~OatMethod() {}
 
-void OatFile::OatMethod::LinkMethod(Method* method) {
+void OatFile::OatMethod::LinkMethod(Method* method) const {
   CHECK(method != NULL);
   method->SetCode(code_);
   method->SetFrameSizeInBytes(frame_size_in_bytes_);
diff --git a/src/oat_file.h b/src/oat_file.h
index 0472c16..9f95b3b 100644
--- a/src/oat_file.h
+++ b/src/oat_file.h
@@ -47,7 +47,7 @@
     ~OatMethod();
 
     // Link Method using the contents of this OatMethod
-    void LinkMethod(Method* method);
+    void LinkMethod(Method* method) const;
 
     const void* code_;
     size_t frame_size_in_bytes_;
@@ -65,7 +65,7 @@
     // defintion. direct methods come first, followed by virtual
     // methods. note that runtime created methods such as miranda
     // methods are not included.
-    const OatMethod GetOatMethod(uint32_t method_idx) const;
+    const OatMethod GetOatMethod(uint32_t method_index) const;
     ~OatClass();
 
    private:
@@ -89,7 +89,11 @@
 
   class OatDexFile {
    public:
-    const OatClass GetOatClass(uint32_t class_def_index) const;
+    const OatClass* GetOatClass(uint32_t class_def_index) const;
+
+    const std::string& GetDexFileLocation() const {
+      return dex_file_location_;
+    }
 
     uint32_t GetDexFileChecksum() const {
       return dex_file_checksum_;
@@ -111,7 +115,8 @@
     DISALLOW_COPY_AND_ASSIGN(OatDexFile);
   };
 
-  const OatDexFile& GetOatDexFile(const std::string& dex_file_location);
+  const OatDexFile* GetOatDexFile(const std::string& dex_file_location) const;
+  std::vector<const OatDexFile*> GetOatDexFiles() const;
 
   size_t GetSize() const {
     return GetLimit() - GetBase();
@@ -137,6 +142,7 @@
 
   friend class OatClass;
   friend class OatDexFile;
+  friend class OatDump;  // For GetBase and GetLimit
   DISALLOW_COPY_AND_ASSIGN(OatFile);
 };
 
diff --git a/src/oat_test.cc b/src/oat_test.cc
index 3137728..392a822 100644
--- a/src/oat_test.cc
+++ b/src/oat_test.cc
@@ -14,7 +14,7 @@
 
   const ClassLoader* class_loader = NULL;
   if (compile) {
-    compiler_.reset(new Compiler(kThumb2));
+    compiler_.reset(new Compiler(kThumb2, false));
     compiler_->CompileAll(class_loader);
   }
 
@@ -33,7 +33,7 @@
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
 
   const DexFile& dex_file = *java_lang_dex_file_.get();
-  const OatFile::OatDexFile& oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation());
+  const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation());
   for (size_t i = 0; i < dex_file.NumClassDefs(); i++) {
     const DexFile::ClassDef& class_def = dex_file.GetClassDef(i);
     const byte* class_data = dex_file.GetClassData(class_def);
@@ -41,14 +41,14 @@
     size_t num_virtual_methods = header.virtual_methods_size_;
     const char* descriptor = dex_file.GetClassDescriptor(class_def);
 
-    const OatFile::OatClass oat_class = oat_dex_file.GetOatClass(i);
+    UniquePtr<const OatFile::OatClass> oat_class(oat_dex_file->GetOatClass(i));
 
     Class* klass = class_linker->FindClass(descriptor, class_loader);
 
     size_t method_index = 0;
     for (size_t i = 0; i < klass->NumDirectMethods(); i++, method_index++) {
       Method* method = klass->GetDirectMethod(i);
-      const OatFile::OatMethod oat_method = oat_class.GetOatMethod(method_index);
+      const OatFile::OatMethod oat_method = oat_class->GetOatMethod(method_index);
       const CompiledMethod* compiled_method = compiler_->GetCompiledMethod(method);
 
       if (compiled_method == NULL) {
@@ -75,7 +75,7 @@
     }
     for (size_t i = 0; i < num_virtual_methods; i++, method_index++) {
       Method* method = klass->GetVirtualMethod(i);
-      const OatFile::OatMethod oat_method = oat_class.GetOatMethod(method_index);
+      const OatFile::OatMethod oat_method = oat_class->GetOatMethod(method_index);
       const CompiledMethod* compiled_method = compiler_->GetCompiledMethod(method);
 
       if (compiled_method == NULL) {
diff --git a/src/oat_writer.cc b/src/oat_writer.cc
index 0722520..99c9361 100644
--- a/src/oat_writer.cc
+++ b/src/oat_writer.cc
@@ -13,7 +13,7 @@
 bool OatWriter::Create(const std::string& filename,
                        const ClassLoader* class_loader,
                        const Compiler& compiler) {
-  const std::vector<const DexFile*>& dex_files = ClassLoader::GetClassPath(class_loader);
+  const std::vector<const DexFile*>& dex_files = ClassLoader::GetCompileTimeClassPath(class_loader);
   OatWriter oat_writer(dex_files, class_loader, compiler);
   return oat_writer.Write(filename);
 }
diff --git a/src/oatdump.cc b/src/oatdump.cc
index 8113c2b..4d99647 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -26,7 +26,11 @@
           "    Example: adb shell oatdump --image=/system/framework/boot.art\n"
           "\n");
   fprintf(stderr,
-          "  --image=<file.art>: specifies the required input image filename.\n"
+          "  --oat=<file.oat>: specifies an input oat filename.\n"
+          "      Example: --image=/system/framework/boot.oat\n"
+          "\n");
+  fprintf(stderr,
+          "  --image=<file.art>: specifies an input image filename.\n"
           "      Example: --image=/system/framework/boot.art\n"
           "\n");
   fprintf(stderr,
@@ -52,15 +56,168 @@
   "kStaticResolutionStubArray",
   "kUnknownMethodResolutionStubArray",
   "kCalleeSaveMethod",
+  "kRefsOnlySaveMethod",
+  "kRefsAndArgsSaveMethod",
   "kOatLocation",
   "kDexCaches",
   "kClassRoots",
 };
 
 class OatDump {
+ public:
+  static void Dump(const std::string& oat_filename,
+                   const std::string& host_prefix,
+                   std::ostream& os,
+                   const OatFile& oat_file) {
+    const OatHeader& oat_header = oat_file.GetOatHeader();
+
+    os << "MAGIC:\n";
+    os << oat_header.GetMagic() << "\n\n";
+
+    os << "CHECKSUM:\n";
+    os << StringPrintf("%08x\n\n", oat_header.GetChecksum());
+
+    os << "DEX FILE COUNT:\n";
+    os << oat_header.GetDexFileCount() << "\n\n";
+
+    os << "EXECUTABLE OFFSET:\n";
+    os << StringPrintf("%08x\n\n", oat_header.GetExecutableOffset());
+
+    os << "BASE:\n";
+    os << oat_file.GetBase() << "\n\n";
+
+    os << "LIMIT:\n";
+    os << oat_file.GetLimit() << "\n\n";
+
+    os << std::flush;
+
+    std::vector<const OatFile::OatDexFile*> oat_dex_files = oat_file.GetOatDexFiles() ;
+    for (size_t i = 0; i < oat_dex_files.size(); i++) {
+      const OatFile::OatDexFile* oat_dex_file = oat_dex_files[i];
+      CHECK(oat_dex_file != NULL);
+      DumpOatDexFile(host_prefix, os, oat_file, *oat_dex_file);
+    }
+  }
+
+ private:
+  static void DumpOatDexFile(const std::string& host_prefix,
+                             std::ostream& os,
+                             const OatFile& oat_file,
+                             const OatFile::OatDexFile& oat_dex_file) {
+    os << "OAT DEX FILE:\n";
+    std::string dex_file_location = oat_dex_file.GetDexFileLocation();
+    os << "location: " << dex_file_location;
+    if (!host_prefix.empty()) {
+      dex_file_location = host_prefix + dex_file_location;
+      os << " (" << dex_file_location << ")\n";
+    }
+    os << StringPrintf("checksum: %08x\n", oat_dex_file.GetDexFileChecksum());
+    const DexFile* dex_file = DexFile::Open(dex_file_location, "");
+    if (dex_file == NULL) {
+      os << "NOT FOUND\n\n";
+      return;
+    }
+    for (size_t class_def_index = 0; class_def_index < dex_file->NumClassDefs(); class_def_index++) {
+      const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
+      const char* descriptor = dex_file->GetClassDescriptor(class_def);
+      os << StringPrintf("%d: %s (type_ide=%d)\n", class_def_index, descriptor, class_def.class_idx_);
+      UniquePtr<const OatFile::OatClass> oat_class(oat_dex_file.GetOatClass(class_def_index));
+      CHECK(oat_class.get() != NULL);
+      DumpOatClass(os, oat_file, *oat_class.get(), *dex_file, class_def);
+    }
+
+    os << std::flush;
+  }
+
+  static void DumpOatClass(std::ostream& os,
+                           const OatFile& oat_file,
+                           const OatFile::OatClass& oat_class,
+                           const DexFile& dex_file,
+                           const DexFile::ClassDef& class_def) {
+    const byte* class_data = dex_file.GetClassData(class_def);
+    DexFile::ClassDataHeader header = dex_file.ReadClassDataHeader(&class_data);
+    size_t num_static_fields = header.static_fields_size_;
+    size_t num_instance_fields = header.instance_fields_size_;
+    size_t num_direct_methods = header.direct_methods_size_;
+    size_t num_virtual_methods = header.virtual_methods_size_;
+    uint32_t method_index = 0;
+
+    // just skipping through the fields to advance class_data
+    if (num_static_fields != 0) {
+      uint32_t last_idx = 0;
+      for (size_t i = 0; i < num_static_fields; ++i) {
+        DexFile::Field dex_field;
+        dex_file.dexReadClassDataField(&class_data, &dex_field, &last_idx);
+      }
+    }
+    if (num_instance_fields != 0) {
+      uint32_t last_idx = 0;
+      for (size_t i = 0; i < num_instance_fields; ++i) {
+        DexFile::Field dex_field;
+        dex_file.dexReadClassDataField(&class_data, &dex_field, &last_idx);
+      }
+    }
+
+    if (num_direct_methods != 0) {
+      uint32_t last_idx = 0;
+      for (size_t i = 0; i < num_direct_methods; ++i, method_index++) {
+        DexFile::Method dex_method;
+        dex_file.dexReadClassDataMethod(&class_data, &dex_method, &last_idx);
+        const OatFile::OatMethod oat_method = oat_class.GetOatMethod(method_index);
+        DumpOatMethod(os, method_index, oat_file, oat_method, dex_file, dex_method);
+      }
+    }
+    if (num_virtual_methods != 0) {
+      uint32_t last_idx = 0;
+      for (size_t i = 0; i < num_virtual_methods; ++i, method_index++) {
+        DexFile::Method dex_method;
+        dex_file.dexReadClassDataMethod(&class_data, &dex_method, &last_idx);
+        const OatFile::OatMethod oat_method = oat_class.GetOatMethod(method_index);
+        DumpOatMethod(os, method_index, oat_file, oat_method, dex_file, dex_method);
+      }
+    }
+    os << std::flush;
+  }
+  static void DumpOatMethod(std::ostream& os,
+                            uint32_t method_index,
+                            const OatFile& oat_file,
+                            const OatFile::OatMethod& oat_method,
+                            const DexFile& dex_file,
+                            const DexFile::Method& dex_method) {
+    const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method.method_idx_);
+    const char* name = dex_file.GetMethodName(method_id);
+    std::string signature = dex_file.GetMethodSignature(method_id);
+    os << StringPrintf("\t%d: %s %s (method_idx=%d)\n",
+                       method_index, name, signature.c_str(), dex_method.method_idx_);
+    os << StringPrintf("\t\tcode: %p (offset=%08x)\n",
+                       oat_method.code_,
+                       reinterpret_cast<const byte*>(oat_method.code_) - oat_file.GetBase());
+    os << StringPrintf("\t\tframe_size_in_bytes: %d\n",
+                       oat_method.frame_size_in_bytes_);
+    os << StringPrintf("\t\treturn_pc_offset_in_bytes: %d\n",
+                       oat_method.return_pc_offset_in_bytes_);
+    os << StringPrintf("\t\tcore_spill_mask: %08x\n",
+                       oat_method.core_spill_mask_);
+    os << StringPrintf("\t\tfp_spill_mask: %08x\n",
+                       oat_method.fp_spill_mask_);
+    os << StringPrintf("\t\tmapping_table: %p (offset=%08x)\n",
+                       oat_method.mapping_table_,
+                       reinterpret_cast<const byte*>(oat_method.mapping_table_) - oat_file.GetBase());
+    os << StringPrintf("\t\tvmap_table: %p (offset=%08x)\n",
+                       oat_method.vmap_table_,
+                       reinterpret_cast<const byte*>(oat_method.vmap_table_) - oat_file.GetBase());
+    os << StringPrintf("\t\tinvoke_stub: %p (offset=%08x)\n",
+                       oat_method.invoke_stub_,
+                       reinterpret_cast<const byte*>(oat_method.invoke_stub_) - oat_file.GetBase());
+  }
+
+};
+
+class ImageDump {
 
  public:
   static void Dump(const std::string& image_filename,
+                   const std::string& host_prefix,
                    std::ostream& os,
                    Space& image_space,
                    const ImageHeader& image_header) {
@@ -70,10 +227,17 @@
     os << "IMAGE BASE:\n";
     os << reinterpret_cast<void*>(image_header.GetImageBaseAddr()) << "\n\n";
 
+    os << "OAT CHECKSUM:\n";
+    os << StringPrintf("%08x\n\n", image_header.GetOatChecksum());
+
     os << "OAT BASE:\n";
     os << reinterpret_cast<void*>(image_header.GetOatBaseAddr()) << "\n\n";
 
+    os << "OAT LIMIT:\n";
+    os << reinterpret_cast<void*>(image_header.GetOatLimitAddr()) << "\n\n";
+
     os << "ROOTS:\n";
+    os << reinterpret_cast<void*>(image_header.GetImageRoots()) << "\n";
     CHECK_EQ(arraysize(image_roots_descriptions_), size_t(ImageHeader::kImageRootsMax));
     for (int i = 0; i < ImageHeader::kImageRootsMax; i++) {
       ImageHeader::ImageRoot image_root = static_cast<ImageHeader::ImageRoot>(i);
@@ -93,10 +257,10 @@
     os << "\n";
 
     os << "OBJECTS:\n" << std::flush;
-    OatDump state(image_space, os);
+    ImageDump state(image_space, os);
     HeapBitmap* heap_bitmap = Heap::GetLiveBits();
     DCHECK(heap_bitmap != NULL);
-    heap_bitmap->Walk(OatDump::Callback, &state);
+    heap_bitmap->Walk(ImageDump::Callback, &state);
     os << "\n";
 
     os << "STATS:\n" << std::flush;
@@ -107,22 +271,41 @@
     size_t alignment_bytes = RoundUp(header_bytes, kObjectAlignment) - header_bytes;
     state.stats_.alignment_bytes += alignment_bytes;
     state.stats_.Dump(os);
+    os << "\n";
 
     os << std::flush;
+
+    os << "OAT LOCATION:\n" << std::flush;
+    Object* oat_location_object = image_header.GetImageRoot(ImageHeader::kOatLocation);
+    std::string oat_location = oat_location_object->AsString()->ToModifiedUtf8();
+    ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+    os << oat_location;
+    if (!host_prefix.empty()) {
+      oat_location = host_prefix + oat_location;
+      os << " (" << oat_location << ")\n";
+    }
+    const OatFile* oat_file = class_linker->FindOatFile(oat_location);
+    if (oat_file == NULL) {
+      os << "NOT FOUND\n";
+      os << std::flush;
+      return;
+    }
+    os << "\n";
+    os << std::flush;
+
+    OatDump::Dump(oat_location, host_prefix, os, *oat_file);
   }
 
  private:
 
-  OatDump(const Space& dump_space, std::ostream& os) : dump_space_(dump_space), os_(os) {
-  }
+  ImageDump(const Space& dump_space, std::ostream& os) : dump_space_(dump_space), os_(os) {}
 
-  ~OatDump() {
-  }
+  ~ImageDump() {}
 
   static void Callback(Object* obj, void* arg) {
     DCHECK(obj != NULL);
     DCHECK(arg != NULL);
-    OatDump* state = reinterpret_cast<OatDump*>(arg);
+    ImageDump* state = reinterpret_cast<ImageDump*>(arg);
     if (!state->InDumpSpace(obj)) {
       return;
     }
@@ -319,7 +502,6 @@
                          / static_cast<double>(dex_instruction_bytes));
       os << "\n";
       os << std::flush;
-
     }
   } stats_;
 
@@ -327,7 +509,7 @@
   const Space& dump_space_;
   std::ostream& os_;
 
-  DISALLOW_COPY_AND_ASSIGN(OatDump);
+  DISALLOW_COPY_AND_ASSIGN(ImageDump);
 };
 
 int oatdump(int argc, char** argv) {
@@ -336,10 +518,11 @@
   argc--;
 
   if (argc == 0) {
-    fprintf(stderr, "no arguments specified\n");
+    fprintf(stderr, "No arguments specified\n");
     usage();
   }
 
+  const char* oat_filename = NULL;
   const char* image_filename = NULL;
   const char* boot_image_filename = NULL;
   std::string host_prefix;
@@ -348,7 +531,9 @@
 
   for (int i = 0; i < argc; i++) {
     const StringPiece option(argv[i]);
-    if (option.starts_with("--image=")) {
+    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("--boot-image=")) {
       boot_image_filename = option.substr(strlen("--boot-image=")).data();
@@ -358,21 +543,36 @@
       const char* filename = option.substr(strlen("--output=")).data();
       out.reset(new std::ofstream(filename));
       if (!out->good()) {
-        fprintf(stderr, "failed to open output filename %s\n", filename);
+        fprintf(stderr, "Failed to open output filename %s\n", filename);
         usage();
       }
       os = out.get();
     } else {
-      fprintf(stderr, "unknown argument %s\n", option.data());
+      fprintf(stderr, "Unknown argument %s\n", option.data());
       usage();
     }
   }
 
-  if (image_filename == NULL) {
-   fprintf(stderr, "--image file name not specified\n");
+  if (image_filename == NULL && oat_filename == NULL) {
+   fprintf(stderr, "Either --image or --oat must be specified\n");
    return EXIT_FAILURE;
   }
 
+  if (image_filename != NULL && oat_filename != NULL) {
+   fprintf(stderr, "Either --image or --oat must be specified but not both\n");
+   return EXIT_FAILURE;
+  }
+
+  if (oat_filename != NULL) {
+    const OatFile* oat_file = OatFile::Open(oat_filename, "", NULL);
+    if (oat_file == NULL) {
+      fprintf(stderr, "Failed to open oat file from %s\n", oat_filename);
+      return EXIT_FAILURE;
+    }
+    OatDump::Dump(oat_filename, host_prefix, *os, *oat_file);
+    return EXIT_SUCCESS;
+  }
+
   Runtime::Options options;
   std::string image_option;
   std::string oat_option;
@@ -383,9 +583,11 @@
     boot_image_option += boot_image_filename;
     options.push_back(std::make_pair(boot_image_option.c_str(), reinterpret_cast<void*>(NULL)));
   }
-  image_option += "-Ximage:";
-  image_option += image_filename;
-  options.push_back(std::make_pair(image_option.c_str(), reinterpret_cast<void*>(NULL)));
+  if (image_filename != NULL) {
+    image_option += "-Ximage:";
+    image_option += image_filename;
+    options.push_back(std::make_pair(image_option.c_str(), reinterpret_cast<void*>(NULL)));
+  }
 
   if (!host_prefix.empty()) {
     options.push_back(std::make_pair("host-prefix", host_prefix.c_str()));
@@ -393,7 +595,7 @@
 
   UniquePtr<Runtime> runtime(Runtime::Create(options, false));
   if (runtime.get() == NULL) {
-    fprintf(stderr, "could not create runtime\n");
+    fprintf(stderr, "Failed to create runtime\n");
     return EXIT_FAILURE;
   }
 
@@ -401,10 +603,10 @@
   CHECK(image_space != NULL);
   const ImageHeader& image_header = image_space->GetImageHeader();
   if (!image_header.IsValid()) {
-    fprintf(stderr, "invalid image header %s\n", image_filename);
+    fprintf(stderr, "Invalid image header %s\n", image_filename);
     return EXIT_FAILURE;
   }
-  OatDump::Dump(image_filename, *os, *image_space, image_header);
+  ImageDump::Dump(image_filename, host_prefix, *os, *image_space, image_header);
   return EXIT_SUCCESS;
 }
 
diff --git a/src/object.cc b/src/object.cc
index 58ffa6b..33cd802 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -309,7 +309,7 @@
     }
     ++p; // Either the ';' or the primitive type.
 
-    StringPiece descriptor(start, (p - start));
+    std::string descriptor(start, (p - start));
     return class_linker->FindClass(descriptor, cl);
   } else if (*p == 'L') {
     const char* start = p;
@@ -318,7 +318,7 @@
     }
     ++p;
     StringPiece descriptor(start, (p - start));
-    return class_linker->FindClass(descriptor, cl);
+    return class_linker->FindClass(descriptor.ToString(), cl);
   } else {
     return class_linker->FindPrimitiveClass(*p++);
   }
diff --git a/src/object_test.cc b/src/object_test.cc
index 6b1f818..1c317e6 100644
--- a/src/object_test.cc
+++ b/src/object_test.cc
@@ -178,7 +178,7 @@
 TEST_F(ObjectTest, StaticFieldFromCode) {
   // pretend we are trying to access 'Static.s0' from StaticsFromCode.<clinit>
   const ClassLoader* class_loader = LoadDex("StaticsFromCode");
-  const DexFile* dex_file = ClassLoader::GetClassPath(class_loader)[0];
+  const DexFile* dex_file = ClassLoader::GetCompileTimeClassPath(class_loader)[0];
   CHECK(dex_file != NULL);
 
   Class* klass = class_linker_->FindClass("LStaticsFromCode;", class_loader);
diff --git a/src/runtime.cc b/src/runtime.cc
index 64df1d3..c733bfe 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -7,8 +7,10 @@
 #include <limits>
 #include <vector>
 
+#include "ScopedLocalRef.h"
 #include "UniquePtr.h"
 #include "class_linker.h"
+#include "class_loader.h"
 #include "heap.h"
 #include "image.h"
 #include "intern_table.h"
@@ -307,6 +309,29 @@
   return instance_;
 }
 
+void CreateSystemClassLoader() {
+  if (ClassLoader::UseCompileTimeClassPath()) {
+    return;
+  }
+
+  Thread* self = Thread::Current();
+
+  // Must be in the kNative state for calling native methods.
+  CHECK_EQ(self->GetState(), Thread::kNative);
+
+  JNIEnv* env = self->GetJniEnv();
+  ScopedLocalRef<jclass> c(env, env->FindClass("java/lang/ClassLoader"));
+  CHECK(c.get() != NULL);
+  jmethodID mid = env->GetStaticMethodID(c.get(),
+                                         "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
+  CHECK(mid != NULL);
+  ScopedLocalRef<jobject> result(env, env->CallStaticObjectMethod(c.get(), mid));
+  CHECK(result.get() != NULL);
+
+  ClassLoader* class_loader = Decode<ClassLoader*>(env, result.get());
+  Thread::Current()->SetClassLoaderOverride(class_loader);
+}
+
 void Runtime::Start() {
   if (IsVerboseStartup()) {
     LOG(INFO) << "Runtime::Start entering";
@@ -327,6 +352,8 @@
 
   StartDaemonThreads();
 
+  CreateSystemClassLoader();
+
   Thread::Current()->GetJniEnv()->locals.AssertEmpty();
 
   if (IsVerboseStartup()) {
@@ -338,6 +365,10 @@
   signal_catcher_ = new SignalCatcher;
 
   Thread* self = Thread::Current();
+
+  // Must be in the kNative state for calling native methods.
+  CHECK_EQ(self->GetState(), Thread::kNative);
+
   JNIEnv* env = self->GetJniEnv();
   ScopedLocalRef<jclass> c(env, env->FindClass("java/lang/Daemons"));
   CHECK(c.get() != NULL);
@@ -408,7 +439,7 @@
   JNIEnv* env = self->GetJniEnv();
 
   // Must be in the kNative state for calling native methods (JNI_OnLoad code).
-  ScopedThreadStateChange tsc(self, Thread::kNative);
+  CHECK_EQ(self->GetState(), Thread::kNative);
 
   // First set up JniConstants, which is used by both the runtime's built-in native
   // methods and libcore.
@@ -581,8 +612,9 @@
 }
 
 void Runtime::SetJniStubArray(ByteArray* jni_stub_array) {
-  CHECK(jni_stub_array != NULL);
-  CHECK(jni_stub_array_ == NULL || jni_stub_array_ == jni_stub_array);
+  CHECK(jni_stub_array != NULL)  << " jni_stub_array=" << jni_stub_array;
+  CHECK(jni_stub_array_ == NULL || jni_stub_array_ == jni_stub_array)
+      << "jni_stub_array_=" << jni_stub_array_ << " jni_stub_array=" << jni_stub_array;
   jni_stub_array_ = jni_stub_array;
 }
 
diff --git a/src/runtime.h b/src/runtime.h
index bb6bfda..65a54e9 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -25,6 +25,7 @@
 template<class T> class PrimitiveArray;
 typedef PrimitiveArray<int8_t> ByteArray;
 class ClassLinker;
+class ClassLoader;
 class DexFile;
 class Heap;
 class InternTable;
@@ -245,6 +246,9 @@
 
   Method* callee_save_method_[kLastCalleeSaveType];
 
+  // As returned by ClassLoader.getSystemClassLoader()
+  ClassLoader* system_class_loader_;
+
   bool started_;
 
   // Hooks supported by JNI_CreateJavaVM
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index c7a04ec..23bb2f514 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -669,6 +669,17 @@
   return InitializeStaticStorage(type_idx, referrer, self);
 }
 
+String* ResolveStringFromCode(const Method* referrer, uint32_t string_idx) {
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  return class_linker->ResolveString(string_idx, referrer);
+}
+
+extern "C" String* artResolveStringFromCode(Method* referrer, int32_t string_idx,
+                                            Thread* self, Method** sp) {
+  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+  return ResolveStringFromCode(referrer, string_idx);
+}
+
 extern "C" int artUnlockObjectFromCode(Object* obj, Thread* self, Method** sp) {
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   DCHECK(obj != NULL);  // Assumed to have been checked before entry
diff --git a/src/runtime_support.h b/src/runtime_support.h
index 2d34f9b..9c7fc3e 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -44,6 +44,7 @@
   extern "C" void* art_get_obj_static_from_code(uint32_t, void*);
   extern "C" void art_handle_fill_data_from_code(void*, void*);
   extern "C" void* art_initialize_static_storage_from_code(uint32_t, void*);
+  extern "C" void* art_resolve_string_from_code(void*, uint32_t);
   extern "C" void art_invoke_interface_trampoline(uint32_t, void*);
   extern "C" int art_set32_static_from_code(uint32_t, void*, int32_t);
   extern "C" int art_set64_static_from_code(uint32_t, void*, int64_t);
diff --git a/src/runtime_support_asm.S b/src/runtime_support_asm.S
index 38eaf82..f1a6d63 100644
--- a/src/runtime_support_asm.S
+++ b/src/runtime_support_asm.S
@@ -256,7 +256,7 @@
     SETUP_REF_ONLY_CALLEE_SAVE_FRAME           @ save callee saves in case of GC
     mov    r2, r9                              @ pass Thread::Current
     mov    r3, sp                              @ pass SP
-    @ ClassLinker::InitializeStaticStorageFromCode(uint32_t type_idx, Method* referrer, Thread*, SP)
+    @ artInitializeStaticStorageFromCode(uint32_t type_idx, Method* referrer, Thread*, SP)
     bl     artInitializeStaticStorageFromCode
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
     cmp    r0, #0                              @ success if result is non-null
@@ -373,6 +373,24 @@
     bxeq   lr                            @ return on success
     DELIVER_PENDING_EXCEPTION
 
+    .global art_resolve_string_from_code
+    .extern artResolveStringFromCode
+    /*
+     * Entry from managed code to resolve a string, this stub will
+     * allocate a String and deliver an exception on error. On
+     * success the String is returned.
+     */
+ art_resolve_string_from_code:
+    SETUP_REF_ONLY_CALLEE_SAVE_FRAME           @ save callee saves in case of GC
+    mov    r2, r9                              @ pass Thread::Current
+    mov    r3, sp                              @ pass SP
+    @ artResolveStringFromCode(Method* referrer, uint32_t type_idx, Thread*, SP)
+    bl     artResolveStringFromCode
+    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    cmp    r0, #0                              @ success if result is non-null
+    bxne   lr                                  @ return on success
+    DELIVER_PENDING_EXCEPTION
+
     .global art_alloc_object_from_code
     .extern artAllocObjectFromCode
     /*
diff --git a/src/thread.cc b/src/thread.cc
index 400da0c..4dcef55 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -61,12 +61,6 @@
 static Method* gThreadGroup_removeThread = NULL;
 static Method* gUncaughtExceptionHandler_uncaughtException = NULL;
 
-// TODO: flesh out and move to appropriate location
-String* ResolveStringFromCode(Method* method, int32_t string_idx) {
-  UNIMPLEMENTED(FATAL) << "Resolve string; handle OOM";
-  return NULL;  // Must return valid string or if exception, doesn't return
-}
-
 // TODO: move to appropriate location
 static void ObjectInitFromCode(Object* o) {
   Class* c = o->GetClass();
@@ -118,6 +112,7 @@
   pGetObjStatic = art_get_obj_static_from_code;
   pHandleFillArrayDataFromCode = art_handle_fill_data_from_code;
   pInitializeStaticStorage = art_initialize_static_storage_from_code;
+  pResolveStringFromCode = art_resolve_string_from_code;
   pInvokeInterfaceTrampoline = art_invoke_interface_trampoline;
   pSet32Static = art_set32_static_from_code;
   pSet64Static = art_set64_static_from_code;
@@ -144,7 +139,6 @@
   pInstanceofNonTrivialFromCode = Class::IsAssignableFromCode;
   pObjectInit = ObjectInitFromCode;
   pResolveMethodFromCode = ResolveMethodFromCode;
-  pResolveStringFromCode = ResolveStringFromCode;
   pThrowAbstractMethodErrorFromCode = ThrowAbstractMethodErrorFromCode;
   pUnresolvedDirectMethodTrampolineFromCode = UnresolvedDirectMethodTrampolineFromCode;
 }
diff --git a/src/thread.h b/src/thread.h
index 52e01f2..884aa64 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -82,7 +82,7 @@
   };
 
   // Space to throw a StackOverflowError in.
-  static const size_t kStackOverflowReservedBytes = 3 * KB;
+  static const size_t kStackOverflowReservedBytes = 4 * KB;
 
   static const size_t kDefaultStackSize = 64 * KB;
 
@@ -139,7 +139,7 @@
   void (*pLockObjectFromCode)(void*);
   void (*pObjectInit)(Object*);
   void (*pResolveMethodFromCode)(Method*, uint32_t);
-  String* (*pResolveStringFromCode)(Method*, int32_t);
+  void* (*pResolveStringFromCode)(void*, uint32_t);
   int (*pSet32Static)(uint32_t, void*, int32_t);
   int (*pSet64Static)(uint32_t, void*, int64_t);
   int (*pSetObjStatic)(uint32_t, void*, void*);
diff --git a/src/utils.cc b/src/utils.cc
index 48ae2ae..86fa312 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -198,6 +198,14 @@
   return descriptor;
 }
 
+std::string DescriptorToDot(const std::string& descriptor) {
+  DCHECK_EQ(descriptor[0], 'L');
+  DCHECK_EQ(descriptor[descriptor.size()-1], ';');
+  std::string dot = descriptor.substr(1, descriptor.size()-2);
+  std::replace(dot.begin(), dot.end(), '/', '.');
+  return dot;
+}
+
 std::string JniShortName(const Method* m) {
   Class* declaring_class = m->GetDeclaringClass();
 
diff --git a/src/utils.h b/src/utils.h
index 5470f7f..4f58c52 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -176,6 +176,9 @@
 // Turn "java.lang.String" into "Ljava/lang/String;".
 std::string DotToDescriptor(const char* class_name);
 
+// Turn "Ljava/lang/String;" into "java.lang.String".
+std::string DescriptorToDot(const std::string& descriptor);
+
 // Tests whether 's' is a valid class name.
 // name_or_descriptor
 //     true  => "java/lang/String"
diff --git a/test/003-omnibus-opcodes/build b/test/003-omnibus-opcodes/build
index 2a09167..6ee341b 100644
--- a/test/003-omnibus-opcodes/build
+++ b/test/003-omnibus-opcodes/build
@@ -29,5 +29,4 @@
     --boot-image=${ANDROID_PRODUCT_OUT}/system/framework/core.art \
     --dex-file=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME.jar \
     --oat=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME.oat \
-    --image=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME.art \
     --host-prefix=${ANDROID_PRODUCT_OUT}
diff --git a/test/023-many-interfaces/build b/test/023-many-interfaces/build
index 10c1c06..88201a2 100644
--- a/test/023-many-interfaces/build
+++ b/test/023-many-interfaces/build
@@ -31,5 +31,4 @@
     --boot-image=${ANDROID_PRODUCT_OUT}/system/framework/core.art \
     --dex-file=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME.jar \
     --oat=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME.oat \
-    --image=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME.art \
     --host-prefix=${ANDROID_PRODUCT_OUT}
diff --git a/test/056-const-string-jumbo/build b/test/056-const-string-jumbo/build
index 22c9646..fbd4116 100644
--- a/test/056-const-string-jumbo/build
+++ b/test/056-const-string-jumbo/build
@@ -50,5 +50,4 @@
     --boot-image=${ANDROID_PRODUCT_OUT}/system/framework/core.art \
     --dex-file=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME.jar \
     --oat=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME.oat \
-    --image=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME.art \
     --host-prefix=${ANDROID_PRODUCT_OUT}
diff --git a/test/085-old-style-inner-class/build b/test/085-old-style-inner-class/build
index db6a5dd..a08c98b 100644
--- a/test/085-old-style-inner-class/build
+++ b/test/085-old-style-inner-class/build
@@ -32,5 +32,4 @@
     --boot-image=${ANDROID_PRODUCT_OUT}/system/framework/core.art \
     --dex-file=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME.jar \
     --oat=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME.oat \
-    --image=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME.art \
     --host-prefix=${ANDROID_PRODUCT_OUT}
diff --git a/test/etc/default-build b/test/etc/default-build
index a2e9066..c3cdd79 100755
--- a/test/etc/default-build
+++ b/test/etc/default-build
@@ -32,7 +32,6 @@
     --boot-image=${ANDROID_PRODUCT_OUT}/system/framework/core.art \
     --dex-file=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME.jar \
     --oat=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME.oat \
-    --image=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME.art \
     --host-prefix=${ANDROID_PRODUCT_OUT}
 
 if [ -r src-ex ]; then
@@ -52,6 +51,5 @@
         --boot-image=${ANDROID_PRODUCT_OUT}/system/framework/core.art \
         --dex-file=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME-ex.jar \
         --oat=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME-ex.oat \
-        --image=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME-ex.art \
         --host-prefix=${ANDROID_PRODUCT_OUT}
 fi
diff --git a/test/etc/push-and-run-test-jar b/test/etc/push-and-run-test-jar
index 8bbf8d8..79b0605 100755
--- a/test/etc/push-and-run-test-jar
+++ b/test/etc/push-and-run-test-jar
@@ -136,7 +136,7 @@
 else
   cmdline="cd /data; oatexecd \
       -Ximage:/system/framework/core.art \
-      -Ximage:/system/framework/$TEST_NAME.art \
+      -cp /system/framework/$TEST_NAME.jar \
       Main"
   #cmdline="cd /data; dalvikvm $DEX_VERIFY $DEX_OPTIMIZE $DEX_DEBUG \
   #    $GC_OPTS -cp test.jar -Xint:${INTERP} -ea Main"